1:需求:在原图中,有多个特征点和模板图像一模一样,因此,寻找原图中中心位置最近的特征点位(模板匹配详解);原图如下所示:
模板图像:
2:现要求匹配找到距离原图中心位置最近的特征位置;例如,在下图中找到红色十字标记处。
3:模板匹配,全局搜索相似特征位置,并且标记出,结果如下:
4:想要的结果位置,下图用红色方框标记:
5:代码如下:
private Point MatchTemplate(Mat tempalte, Mat srcPic, double matchValue)
{
using (Mat result = new Mat()) //匹配结果
{ //模板匹配
double minVul;
double maxVul;
Point tempPoint = new Point();
OpenCvSharp.Point minLoc = new OpenCvSharp.Point(0, 0);
OpenCvSharp.Point maxLoc = new OpenCvSharp.Point(0, 0);
//OpenCvSharp.Point matchLoc = new OpenCvSharp.Point(0, 0);
Cv2.MatchTemplate(srcPic, tempalte, result, TemplateMatchModes.CCoeffNormed);//CCoeffNormed 最好匹配为1,值越小匹配越差 xxxNormed的算法
//Cv2.Normalize(result, result, 0, 1, NormTypes.MinMax, -1);//归一化
Cv2.MinMaxLoc(result, out minVul, out maxVul, out minLoc, out maxLoc);//查找极值
//matchLoc = maxLoc;//图像中左上角的坐标位置(应该叫min)
//result.Set(matchLoc.Y, matchLoc.X, 0);//改变最大值为最小值
//Mat mask = srcPic.Clone();//复制整个矩阵
//画框显示 :对角线画框,起点和终点,都用Point,线宽
//if (maxVul > matchValue)
//{
// Cv2.Rectangle(mask, matchLoc, new OpenCvSharp.Point(matchLoc.X + tempalte.Cols, matchLoc.Y + tempalte.Rows), Scalar.Green, 2);//2代表画的线条的宽细程度
//}
//循环查找 画框显示
double minDistance = int.MaxValue;
//double threshold = 0.71;
int minLocX = int.MaxValue;
int minLocY = int.MaxValue;
Mat maskMulti = srcPic.Clone();//复制整个矩阵
for (int i = 1; i < result.Rows - tempalte.Rows; i += tempalte.Rows)//行遍历
{
for (int j = 1; j < result.Cols - tempalte.Cols; j += tempalte.Cols)//列遍历
{
Rect roi = new Rect(j, i, tempalte.Cols, tempalte.Rows); //建立感兴趣
Mat RoiResult = new Mat(result, roi);
Cv2.MinMaxLoc(RoiResult, out minVul, out maxVul, out minLoc, out maxLoc);//查找极值
//matchLoc = maxLoc;//最大值坐标
if (maxVul > matchValue)
{
double dis = CalculateDistance((j + maxLoc.X), (i + maxLoc.Y), (result.Width / 2), (result.Height / 2));
if (dis < minDistance)
{
minDistance = dis;
minLocY = j + maxLoc.X;
minLocX = i + maxLoc.Y;
// File.AppendAllText(System.AppDomain.CurrentDomain.BaseDirectory + @"Log\LogError\log" + DateTime.Now.ToString("yyyyMMdd")
//+ "imgInfo.txt", "minDistance:" + minDistance + " maxLocX:" + minLocX + " maxLocY" + minLocY + "\r\n");
}
//画框显示
Cv2.Rectangle(maskMulti, new OpenCvSharp.Point(j + maxLoc.X, i + maxLoc.Y), new OpenCvSharp.Point(j + maxLoc.X + tempalte.Cols, i + maxLoc.Y + tempalte.Rows), Scalar.Green, 2);
//string axis = '(' + Convert.ToString(i + maxLoc.Y) + ',' + Convert.ToString(j + maxLoc.X) + ')';
//Cv2.PutText(maskMulti, axis, new OpenCvSharp.Point(j + maxLoc.X, i + maxLoc.Y), HersheyFonts.HersheyPlain, 1, Scalar.Red, 1, LineTypes.Link4);
}
}
}
if (minDistance < int.MaxValue)
{
tempPoint.X = minLocY;
tempPoint.Y = minLocX;
}
Cv2.ImWrite(@"save\" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".png", maskMulti);
return tempPoint;//OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mask);
}
}
double CalculateDistance(double x1, double y1, double x2, double y2)
{
double distance = Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2));
return distance;
}
如有不正确地方,欢迎指正。
附1:Cv2.MatchTemplate函数参数详解:
cv2.matchTemplate() 是模板匹配的函数之一,其参数如下:
image | 待匹配的图像,应该是一个灰度图像。 |
template | 模板图像,应该是一个灰度图像。 |
method | 匹配方法,有6种不同的方法可以选择,分别是: |
cv2.TM_CCOEFF | 相关系数匹配法。 |
cv2.TM_CCOEFF_NORMED | 归一化的相关系数匹配法。 |
cv2.TM_CCORR | 相关匹配法。 |
cv2.TM_CCORR_NORMED | 归一化的相关匹配法。 |
cv2.TM_SQDIFF | 平方差匹配法。 |
cv2.TM_SQDIFF_NORMED | 归一化的平方差匹配法。 |
result | 匹配结果数组,必须是单通道32位浮点数类型的数组。 |
mask | 需要匹配的区域,可以不指定。 |
use_mask | 是否要使用掩膜,可以不指定。 |
其中,匹配方法是最重要的参数,不同的方法适用于不同的情况。下面介绍各种匹配方法的具体作用:
cv2.TM_CCOEFF | 相关系数匹配法。计算模板图像与待匹配图像的线性相关系数,该值越大则表示匹配度越高。适用于模板图像和待匹配图像的亮度差异较小的情况。 |
cv2.TM_CCOEFF_NORMED | 归一化的相关系数匹配法。计算模板图像与待匹配图像的归一化线性相关系数,该值越大则表示匹配度越高。适用于模板图像和待匹配图像的亮度差异较大的情况。 |
cv2.TM_CCORR | 相关匹配法。计算模板图像与待匹配图像的互相关系数,该值越大则表示匹配度越高。适用于模板图像和待匹配图像的亮度变化较小、平移变化较大的情况。 |
cv2.TM_CCORR_NORMED | 归一化的相关匹配法。计算模板图像与待匹配图像的归一化互相关系数,该值越大则表示匹配度越高。适用于模板图像和待匹配图像的亮度变化较大、平移变化较大的情况。 |
cv2.TM_SQDIFF | 平方差匹配法。计算模板图像与待匹配图像的平方差,该值越小则表示匹配度越高。适用于模板图像的亮度与待匹配图像有很大差异的情况。 |
cv2.TM_SQDIFF_NORMED | 归一化的平方差匹配法。计算模板图像与待匹配图像的归一化平方差,该值越小则表示匹配度越高。适用于模板图像的亮度与待匹配图像有较大差异的情况。 |
使用不同的匹配方法,可以适应不同的场景,提高匹配的准确性。需要根据具体情况选择合适的匹配方法。
附2:Cv2.MinMaxLoc函数参数详解:
cv2.minMaxLoc()
是OpenCV中用于查找图像中最小值和最大值位置的函数,其参数如下:
src |
输入的单通道数组图像。 |
mask |
可选的掩膜。如果传入了掩膜,则只会查找掩膜图像中非零像素处的最值。 |
minVal |
返回最小值。 |
maxVal |
返回最大值。 |
minLoc |
返回最小值所在的位置。 |
maxLoc |
返回最大值所在的位置。 |
该函数能够在图像中查找最大值和最小值,以及它们的位置。其中,最大值和最小值的位置分别被保存在maxLoc
和minLoc
中,可以结合这些位置进行后续的图像处理工作。
问:Cv2.MatchTemplate方法之后使用到Cv2.MinMaxLoc函数,为什么?
答:在使用cv2.matchTemplate()
方法进行模板匹配时,可能会存在多个匹配位置或存在误匹配的情况。因此,在匹配结果中需要用cv2.minMaxLoc()
函数寻找最大值/最小值和它们的位置,以保证匹配结果的准确性。
具体来说,在使用cv2.matchTemplate()
方法匹配模板图像和待匹配图像后,会生成一个匹配矩阵,其中每个数值表示这个位置的匹配程度。最大或最小值出现在匹配矩阵中,需要通过cv2.minMaxLoc()
函数获取这些值对应的坐标。文章来源:https://www.toymoban.com/news/detail-819695.html
例如,我们可以通过将匹配矩阵进行归一化(即获取矩阵中数值最大/最小值处的位置),来获取匹配度最高/最低的位置。这样可以排除掉一些误匹配的位置,提高匹配的准确性。文章来源地址https://www.toymoban.com/news/detail-819695.html
到了这里,关于OpenCv案例(十二):基于OpenCVSharp学习之模板匹配寻找距离中心位置最近的目标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!