版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
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博客
7.1 角点检测
角点是特征点的一种,是指在图像中具有尖锐变化的像素点,例如像素值最大或最小的点、线段的顶点、两直线的交点等,它通常具有一些特征,如灰度值变化较大、梯度变化较大、边缘交汇处等。在计算机视觉领域中,角点通常被用作特征点的一种,用于目标检测、图像配准、三维重建等任务中。
7.1.1 ConvertScaleAbs
CvInvoke.ConvertScaleAbs用于对图像进行线性变换并将结果转换为无符号的8位整型图像。它可以将图像中的像素值进行缩放和偏移,常用于图像增强、特征提取等任务中。该方法的声明如下:
Public Shared Sub ConvertScaleAbs(src As Emgu.CV.IInputArray, dst As Emgu.CV.IOutputArray, scale As Double, shift As Double)
参数说明:
- src:要进行线性变换的源图像。
- dst:变换后的目标图像。
- scale:变换中的缩放比例。
- shift:变换中的偏移量。
注意:ConvertScaleAbs方法只能将结果转换为无符号的8位整型图像,如果需要转换为其他类型的图像(比如CV32F、Cv16U等),可以使用CvInvoke.ConvertScale方法。
【代码位置:frmChapter7】Button1_Click
'ConvertScaleAbs
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim msrc As New Mat("c:\lessons\lena.jpg", ImreadModes.Color)
ImageBox1.Image = msrc
Dim mdst As New Mat
CvInvoke.ConvertScaleAbs(msrc, mdst, 1.5, 10)
ImageBox2.Image = mdst
End Sub
输出结果如下图所示:
图7-1 图像线性变换结果
可以看出,ConvertScaleAbs实际有两个作用:1、对图像像素点进行线性变换;2、对于非CV8U的图像,转为CV8U。
7.1.2 Normalize
CvInvoke.Normalize用于对图像进行归一化处理。它可以将图像中的像素值按照一定的规则进行缩放,使得像素值的范围在指定的范围内,常用于图像增强、特征提取等任务中。该方法的声明如下:
Public Shared Sub Normalize(src As Emgu.CV.IInputArray, dst As Emgu.CV.IOutputArray, Optional alpha As Double = 1, Optional beta As Double = 0, Optional normType As Emgu.CV.CvEnum.NormType = 4, Optional dType As Emgu.CV.CvEnum.DepthType = -1, Optional mask As Emgu.CV.IInputArray = Nothing)
参数说明:
- src:要进行归一化处理的源图像。
- dst:归一化处理后的图像。
- alpha:下限范围。
- beta:上限范围,只在normType =NormType.MinMax时起作用。。
- normType:归一化处理中的算法类型,这是一个NormType枚举类型,可以选择NormType.MinMax、NormType.L1、NormType.L2等。当设置为MinMax时,Normalize()会把原矩阵中的值范围从最小值-最大值,按比例变换到alpha-beta的范围。
- dType:归一化处理后的目标图像的深度类型。
- mask:可选参数,表示要进行归一化处理的像素点的掩码图像,只有掩码图像中像素值为非零的像素点才会进行归一化处理。
【代码位置:frmChapter7】Button2_Click
'Normalize
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim msrc As New Mat("c:\lessons\lena.jpg", ImreadModes.Color)
ImageBox1.Image = msrc
Dim mdst As New Mat
CvInvoke.Normalize(msrc, mdst, 50, 200, NormType.MinMax)
ImageBox2.Image = mdst
End Sub
输出结果如下图所示:
图7-2 图像归一化处理
7.1.3 CornerHarris
Harris角点检测算法是一种经典的角点检测算法,由Chris Harris和Mike Stephens在1988年提出。该算法通过计算图像中每个像素的响应函数值,来确定图像中的角点位置。
在使用EmguCV进行图像处理时,CvInvoke.CornerHarris方法用于检测图像中的角点。该方法基于Harris角点检测算法,可以识别出图像中的角点位置,其声明如下:
Public Shared Sub CornerHarris(image As Emgu.CV.IInputArray, harrisResponse As Emgu.CV.IOutputArray, blockSize As Integer, Optional apertureSize As Integer = 3, Optional k As Double = 0.04, Optional borderType As Emgu.CV.CvEnum.BorderType = 4)
参数说明:
- image:待检测的图像。必须是CV8U或者CV32F的单通道图像。
- harrisResponse:输出的角点响应图像,存放Harris评价系数的矩阵,这是一个CV32F的单通道图像,和image图像大小一致。
- blockSize:以当前像素为中心的邻域大小。通常是一个大于1的奇数。
- apertureSize:Sobel算子的大小。通常是一个大于1的奇数。
- k:Harris评价系数的权重系数,通常取值范围为0.04- 0.06。
- borderType:边界模式,用于处理图像边界情况。
【代码位置:frmChapter7】Button3_Click
'CornerHarris
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim m As New Mat("c:\lessons\chess.jpg", ImreadModes.Color)
'获得灰度图像
Dim mgray As New Mat
CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray)
ImageBox1.Image = mgray
'大小同mgray,存放评价系数的CV32F矩阵
Dim mhr As New Mat
'检测角点
CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04)
'归一化处理,之后处理的是存放评价系数的CV32F矩阵
Dim mn As New Mat
CvInvoke.Normalize(mhr, mn, 0, 255, NormType.MinMax)
'图像转为CV8U
Dim mabs As New Mat
CvInvoke.ConvertScaleAbs(mn, mabs, 1, 0)
'二值化
Dim madp As New Mat
CvInvoke.Threshold(mabs, madp, 100, 255, ThresholdType.Binary)
'由于之前二值化了,这里只需要获得非0值的点
Dim ps As New VectorOfPoint
CvInvoke.FindNonZero(madp, ps)
'绘制出角点
Dim mdst As New Mat
mdst = m.Clone
For i As Integer = 0 To ps.Size - 1
CvInvoke.Circle(mdst, ps(i), 20, New MCvScalar(0, 0, 255), -1)
Next
ImageBox2.Image = mdst
End Sub
输出结果如下图所示:
图7-3 棋盘上的角点
7.1.4 CornerSubPix
在数字图像处理领域中,亚像素级别(Subpixel Level)指的是比像素级别更细小的精度。像素级别指的是图像上的最小单位,通常是一个正方形的颜色区域。而亚像素级别则指的是像素内部的更细小的精度,例如像素内部的小数点位数。使用亚像素级别的精度可以提高图像处理的精度和准确度。例如,在角点检测任务中,使用亚像素级别的定位可以提高角点定位的精度,从而提高图像特征匹配的准确度。使用亚像素级别的精度需要借助于一些图像处理算法,例如插值算法、滤波算法等。
在使用EmguCV进行图像处理时,CvInvoke.CornerSubPix方法用于在亚像素级别上对角点进行精确化处理。该方法通过迭代优化提高角点的精度和准确性。该方法声明如下:
Public Shared Sub CornerSubPix(image As Emgu.CV.IInputArray, corners As Emgu.CV.IInputOutputArray, win As System.Drawing.Size, zeroZone As System.Drawing.Size, criteria As Emgu.CV.Structure.MCvTermCriteria)
参数说明:
- image:待处理的图像。
- corners:角点的位置数组,通常是通过CornerHarris等方法检测到的初始角点。这个参数既是输入也是输出。
- win:表示搜索窗口的大小。通常是一个大于1的奇数,表示在某个角点周围的邻域内进行亚像素级别的优化。
- zeroZone:表示搜索窗口中心的边界区域,通常是一个Size对象,用于将搜索窗口的中心排除在优化过程之外。
- criteria:表示优化过程的迭代终止准则,它是一个McvTermCriteria类,可以设置最大迭代次数和最小变化量的阈值。其中:
- maxIter:最大迭代次数,当迭代次数达到该值时,迭代终止。
- epsilon:迭代精度,当每一步迭代的变化量小于该值时,迭代终止。
下面的代码表示最大迭代次数为30次,每一步迭代的变化量小于0.01时,迭代终止:
Dim criteria As New MCvTermCriteria(30, 0.01)
【代码位置:frmChapter7】Button4_Click、getMax、outputMatdata32F1C、PointFToPoint
'CornerSubPix
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim m As New Mat("c:\learnEmgucv\chess.jpg", ImreadModes.Color)
'获得灰度图像
Dim mgray As New Mat
CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray)
ImageBox1.Image = mgray
'大小同mgray,存放评价系数的CV32F矩阵
Dim mhr As New Mat
'检测角点
CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04)
Dim vopf As New VectorOfPointF
vopf = outputMatdata32F1C(mhr)
CvInvoke.CornerSubPix(mgray, vopf, New Drawing.Size(5, 5), New Drawing.Size(-1, -1), New MCvTermCriteria(100, 0.01))
'绘制出角点
Dim mdst As New Mat
mdst = m.Clone
For i As Integer = 0 To vopf.Size - 1
CvInvoke.Circle(mdst, PointFToPoint(vopf(i)), 20, New MCvScalar(0, 0, 255), -1)
Next
ImageBox2.Image = mdst
End Sub
'获得矩阵中的最大值,用来后面计算阈值 '
Private Function getMax(ByVal m As Mat) As Single
Dim maxvalues() As Double
Dim minvalues() As Double
Dim maxposes() As Point
Dim minposes() As Point
'只能查找每个通道的最大值和最小值,而不是查找每个通道的所有最大值和最小值
'最大值和最小值的位置,也只是返回最先的那个。
m.MinMax(minvalues, maxvalues, minposes, maxposes)
'返回矩阵中的最大值
Return maxvalues(0)
End Function
'输出符合条件的点
Private Function outputMatdata32F1C(ByVal m As Mat) As VectorOfPointF
'设置阈值
Dim threshold As Single
threshold = 0.01 * getMax(m)
'为了计算方便,将m转为Matrix
'这里m是32F,所以使用Single
Dim matr As New Matrix(Of Single)(m.Size)
'Mat的CopyTo方法
m.CopyTo(matr)
Dim corners As New VectorOfPointF
Dim colcount As Integer = matr.Cols
Dim rowcount As Integer = matr.Rows
Dim lstPf As New List(Of PointF)
For i As Integer = 0 To rowcount - 1
For j As Integer = 0 To colcount - 1
Dim outSingle As Single = matr(i, j)
'存储大于阈值的点坐标
If outSingle > threshold Then
lstPf.Add(New PointF(j, i))
End If
Next
Next
'获得VectorOfPointF
corners.Push(lstPf.ToArray)
Return corners
End Function
'将PointF转Point方法
Public Shared Function PointFToPoint(ByVal pf As PointF) As Point
Return New Point(CInt(pf.X), CInt(pf.Y))
End Function
输出结果如下图所示:
图7-4 棋盘上的角点
【代码位置:frmChapter7】Button5_Click
'直接CornerHarris和CornerSubPix的比较
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim m As New Mat("c:\learnEmgucv\lena.jpg", ImreadModes.Color)
'获得灰度图像
Dim mgray As New Mat
CvInvoke.CvtColor(m, mgray, ColorConversion.Bgr2Gray)
'大小同mgray,存放评价系数的CV32F矩阵
Dim mhr As New Mat
'检测角点
CvInvoke.CornerHarris(mgray, mhr, 2, 3, 0.04)
'设定阈值
Dim threshold As Single
threshold = 0.01 * getMax(mhr)
'二值化,分离不符合阈值的点
Dim mtsd As New Mat
CvInvoke.Threshold(mhr, mtsd, threshold, 255, ThresholdType.Binary)
'获得非0值的点
Dim ps As New VectorOfPoint
CvInvoke.FindNonZero(mtsd, ps)
'绘制出角点
Dim mdst As New Mat
mdst = m.Clone
For i As Integer = 0 To ps.Size - 1
CvInvoke.Circle(mdst, ps(i), 2, New MCvScalar(0, 0, 255), -1)
Next
ImageBox1.Image = mdst
Dim vopf As New VectorOfPointF
vopf = outputMatdata32F1C(mhr)
CvInvoke.CornerSubPix(mgray, vopf, New Drawing.Size(5, 5), New Drawing.Size(-1, -1), New MCvTermCriteria(100, 0.01))
'绘制出角点
Dim mdst2 As New Mat
mdst2 = m.Clone
For i As Integer = 0 To vopf.Size - 1
CvInvoke.Circle(mdst2, PointFToPoint(vopf(i)), 2, New MCvScalar(0, 0, 255), -1)
Next
ImageBox2.Image = mdst2
End Sub
输出结果如下图所示:
图7-5 直接CornerHarris和CornerSubPix后的比较