版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。
教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客
教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客
笔者的博客网址:https://blog.csdn.net/uruseibest
教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记
学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客
学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客
6.4 霍夫变换
霍夫变换(Hough Transform)是一种在图像中检测几何形状的常用方法,最初用于检测直线,后来也扩展到检测其他形状,如圆、椭圆等。霍夫变换的核心思想是将图像空间中的特征点映射到参数空间中,并通过在参数空间中寻找峰值来检测形状。
霍夫变换的优点是对于图像中的形状检测具有较好的鲁棒性,对于存在噪声和遮挡的情况仍能有效检测。然而,它的计算复杂度较高,对于大型图像或复杂形状的检测可能会消耗较多的计算资源。
在Emgu.CV中,霍夫变换相关的函数有CvInvoke.HoughLinesP用于检测直线线段,CvInvoke.HoughLines用于直线检测,CvInvoke.HoughCircles用于圆检测等。这些函数可以方便地在图像中进行霍夫变换来检测不同形状的目标。
6.4.1 HoughLines
CvInvoke.HoughLines方法用于在图像中检测直线。该函数会返回检测到的直线的参数。该方法声明如下:
Public Shared Sub HoughLines(image As Emgu.CV.IInputArray, lines As Emgu.CV.IOutputArray, rho As Double, theta As Double, threshold As Integer, Optional srn As Double = 0, Optional stn As Double = 0)
参数说明:
- Image:输入源图像(一般为8位单通道二值图像)。
- lines:经过霍夫变换后检测线条的输出矢量。这里传入VectorOfPointF类型变量。返回的每一条线由两个元素的矢量(ρ, θ)表示, 其中ρ是离坐标原点的距离, θ是弧度线条旋转角度(0表示垂直线, n / 2度表示水平线)。
- rho:以像素为单位的距离精度, 可以认为是直线搜索时的步进尺寸的单位半径。
- theta:以弧度为单位的角度精度, 可以认为是直线搜索时的步进尺寸的角度单位,常设为 Math.PI / 180。
- threshold:直线检测的阈值,只有当检测到的点数大于该阈值时才认为是直线。
- srn:控制距离分辨率。将距离分辨率除以srn+1,从而减小距离分辨率。其默认值为0。该参数的值越大,累加器空间的距离分辨率就越低,检测到的直线数量也会相应地减少。
- stn:控制角度分辨率。将角度分辨率除以stn+1,从而减小角度分辨率。其默认值为0。该参数的值越大,累加器空间的角度分辨率就越低,检测到的直线数量也会相应地减少。
【代码位置:frmChapter6】Button16_Click
'HoughLines
Private Sub Button16_Click(sender As Object, e As EventArgs) Handles Button16.Click
Dim m1 As New Mat("C:\learnEmgucv\line.jpg", CvEnum.ImreadModes.AnyColor)
'边缘检测
Dim mid1 As New Mat
CvInvoke.Canny(m1, mid1, 80, 255, 3)
'二值化
Dim mid2 As New Mat
CvInvoke.Threshold(mid1, mid2, 125, 255, ThresholdType.Binary)
ImageBox1.Image = mid2
'HoughLines检测直线
Dim outlines As New VectorOfPointF
CvInvoke.HoughLines(mid2, outlines, 1, Math.PI / 180, 250, 0, 0)
Dim m2 As New Mat
m2 = mid1.Clone()
m2.SetTo(New MCvScalar(0))
'计算每条直线的起始坐标,并绘制出来
For i As Integer = 0 To outlines.Size - 1
Dim line As PointF = outlines(i)
Dim rho As Double = line.X
Dim theta As Double = line.Y
Dim a As Double = Math.Cos(theta)
Dim b As Double = Math.Sin(theta)
Dim x0 As Double = rho * a
Dim y0 As Double = rho * b
Dim pt1 As New Point
pt1.X = Math.Round(x0 + m2.Cols * (-b))
pt1.Y = Math.Round(y0 + m2.Rows * a)
Dim pt2 As New Point
pt2.X = Math.Round(x0 - m2.Cols * (-b))
pt2.Y = Math.Round(y0 - m2.Rows * a)
'绘制直线
CvInvoke.Line(m2, pt1, pt2, New MCvScalar(255), 2)
Next
ImageBox2.Image = m2
'减少检测到的点数
Dim outlines3 As New VectorOfPointF
CvInvoke.HoughLines(mid2, outlines3, 1, Math.PI / 180, 120, 0, 0)
Dim m3 As New Mat
m3 = mid1.Clone()
m3.SetTo(New MCvScalar(0))
Dim length3 As Double = Math.Max(m3.Rows, m3.Cols)
For i As Integer = 0 To outlines3.Size - 1
Dim line As PointF = outlines3(i)
Dim rho As Double = line.X
Dim theta As Double = line.Y
Dim a As Double = Math.Cos(theta)
Dim b As Double = Math.Sin(theta)
Dim x0 As Double = rho * a
Dim y0 As Double = rho * b
Dim pt1 As New Point
pt1.X = Math.Round(x0 + m2.Cols * (-b))
pt1.Y = Math.Round(y0 + m2.Rows * a)
Dim pt2 As New Point
pt2.X = Math.Round(x0 - m2.Cols * (-b))
pt2.Y = Math.Round(y0 - m2.Rows * a)
CvInvoke.Line(m3, pt1, pt2, New MCvScalar(255), 2)
Next
ImageBox3.Image = m3
End Sub
运行后如下图所示:
图6-17 直线检测结果
6.4.2 HoughLinesP
CvInvoke.HoughLinesP方法用于在图像中检测线段。该方法的两个声明如下:
Public Shared Sub HoughLinesP(image As Emgu.CV.IInputArray, lines As Emgu.CV.IOutputArray, rho As Double, theta As Double, threshold As Integer, Optional minLineLength As Double = 0, Optional maxGap As Double = 0)
Public Shared Function HoughLinesP(image As Emgu.CV.IInputArray, rho As Double, theta As Double, threshold As Integer, Optional minLineLength As Double = 0, Optional maxGap As Double = 0) As Emgu.CV.Structure.LineSegment2D()
参数解释:
- image:输入图像(Image(Of Gray, Byte)类型)。
- lines:经过霍夫变换后检测线条的输出矢量。VectorOfRect类型,每个成员是一个Rectangle类型,属性X 、Y、Width、Height分别表示第一个点的X、第一个点的Y,第二个点的X、第二个点的Y。
- rho:以像素为单位的距离精度。
- theta:以弧度为单位的角度精度。
- threshold:直线检测的阈值,只有当检测到的点数大于该阈值时才认为是直线。
- minLineLength:线段的最小长度,小于该长度的线段将被忽略。
- maxLineGap:线段之间的最大间隔,超过该间隔的线段将被认为是不同的线段。
返回值:
检测到的线段数组(LineSegment2D()类型)。
【代码位置:frmChapter6】Button17_Click
'HoughLinesP
Private Sub Button17_Click(sender As Object, e As EventArgs) Handles Button17.Click
Dim m1 As New Mat("C:\learnEmgucv\line.jpg", CvEnum.ImreadModes.AnyColor)
'边缘检测
Dim mid1 As New Mat
CvInvoke.Canny(m1, mid1, 80, 255, 3)
'二值化
Dim mid2 As New Mat
CvInvoke.Threshold(mid1, mid2, 125, 255, ThresholdType.Binary)
ImageBox1.Image = mid2
Dim outlines() As LineSegment2D
outlines = CvInvoke.HoughLinesP(mid2, 1, Math.PI / 180, 100, 0, 0)
Dim m2 As New Mat
m2 = mid1.Clone()
m2.SetTo(New MCvScalar(0))
'绘制检测出的线段
For i As Integer = 0 To outlines.Length - 1
CvInvoke.Line(m2, outlines(i).P1, outlines(i).P2, New MCvScalar(255), 2)
Next
ImageBox2.Image = m2
Dim outlines2 As New VectorOfRect()
CvInvoke.HoughLinesP(mid2, outlines2, 1, Math.PI / 180, 100, 5, 30)
Dim m3 As New Mat
m3 = mid1.Clone()
m3.SetTo(New MCvScalar(0))
For i As Integer = 0 To outlines2.Size - 1
CvInvoke.Line(m3, New Point(outlines2(i).X, outlines2(i).Y), New Point(outlines2(i).Width, outlines2(i).Height), New MCvScalar(255), 2)
Next
ImageBox3.Image = m3
End Sub
运行后如下图所示:
图6-18 线段检测结果
6.4.3 HoughCircles
CvInvoke.HoughCircles函数用于在图像中检测圆形,该方法声明如下:
Public Shared Function HoughCircles(image As Emgu.CV.IInputArray, method As Emgu.CV.CvEnum.HoughModes, dp As Double, minDist As Double, Optional param1 As Double = 100, Optional param2 As Double = 100, Optional minRadius As Integer = 0, Optional maxRadius As Integer = 0) As Emgu.CV.Structure.CircleF()
参数说明:
- image:8位单通道灰度源图像(或者传入的源图像是Image(Of Gray, Byte)类型)。
- method:霍夫变换的方法,可以选择HoughType.Gradient或HoughType.GradientAlt。
- dp:累加器图像的分辨率与输入图像的分辨率之比。例如,dp = 1,则累加器具有与输入图像相同的分辨率。如果dp = 2,则累加器的宽度和高度都是一半。
- minDist:检测到的圆心之间的最小距离,太小会多检,太大会漏检。
- param1:Canny边缘检测的高阈值。
- param2:圆心累加器阈值,只有当累加器图像中的值大于该阈值时才认为是圆心。相应的该阈值越小,可得到越多的圆。
- minRadius:达到检测要求的最小圆半径。
- maxRadius:达到检测要求的最大圆半径。
返回值:
检测到的圆形数组(CircleF()类型)。
【代码位置:frmChapter6】Button18_Click
'HoughCircles
Private Sub Button18_Click(sender As Object, e As EventArgs) Handles Button18.Click
Dim m1 As New Mat("C:\learnEmgucv\aoyun.jpg", CvEnum.ImreadModes.Grayscale)
ImageBox1.Image = m1
Dim mid1 As New Mat
CvInvoke.GaussianBlur(m1, mid1, New Drawing.Size(3, 3), 3)
ImageBox2.Image = mid1
Dim outcircle() As CircleF
outcircle = CvInvoke.HoughCircles(mid1, HoughModes.Gradient, 2, 50, 140, 220, 5)
Dim m2 As New Mat
m2 = mid1.Clone()
m2.SetTo(New MCvScalar(255))
For i As Integer = 0 To outcircle.Length - 1
CvInvoke.Circle(m2, New Point(Integer.Parse(outcircle(i).Center.X), Integer.Parse(outcircle(i).Center.Y)), outcircle(i).Radius, New MCvScalar(0), 2)
Next
ImageBox3.Image = m2
End Sub
运行后如下图所示:
图6-19 圆形检测结果
另外一个例子,代码同上,只是载入的图片不同:
【代码位置:frmChapter6】Button19_Click
……
Dim m1 As New Mat("C:\learnEmgucv\Matchimg.jpg", CvEnum.ImreadModes.Grayscale)
……
运行后如下图所示:
图6-20 圆形检测结果