OpenCV学习之模板匹配

模板匹配的概念与原理就不说了,《OpenCV3编程入门》这本书第9.5节有介绍,不过比较简洁,至于看不看得懂就NBCS了嘻嘻,毕竟本人也是看得一知半解。那么本次呢,主要就是针对该书中的9.5.3的示例程序,解释几个部分的代码,由于本人也是初学,所以全凭个人理解,所以讲不一定很高深,大家不要逼太紧靴靴!

示例程序

本来觉得代码没必要贴出来的,但怕有些人太懒噜不想看书,或者是书都没有的可人儿逼太紧,还是秉着做好事、说好话、存好心的三好精神,在下方贴出整个代码吧。由于本人自己敲得,所以和书上顺序神马的不一样,但总体是没有什么问题的靴靴!

#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;

Mat g_srcImage, g_templateImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum = 5;

void on_Matching(int, void*)//回调函数
{
	Mat srcImage;
	g_srcImage.copyTo(srcImage);
	//初始化用于结果输出的矩阵
	int resultImage_rows = g_srcImage.rows - g_templateImage.rows + 1;
	int resultImage_cols = g_srcImage.cols - g_templateImage.cols + 1;
	g_resultImage.create(resultImage_rows, resultImage_cols, CV_32FC1);
	//进行匹配和标准化
	matchTemplate(g_srcImage, g_templateImage, g_resultImage, g_nMatchMethod);
	normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX, -1, Mat());//归一化数据
	//通过函数minMaxLoc定位最匹配的位置
	double minValue, maxValue;
	Point minLocation, maxLocation, matchLocation;
	minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat());
	//使用方法SQDIFF和SQDIFF_NORMED,越小的数值有着更高的匹配结果,而其余的方法,数值越大匹配效果越好
	if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == CV_TM_SQDIFF_NORMED)
		matchLocation = minLocation;
	else
		matchLocation = maxLocation;
	//绘制出矩形,并显示最终结果
	rectangle(srcImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);
	rectangle(g_resultImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);

	imshow("【原始图片】", srcImage);
	imshow("【效果窗口】", g_resultImage);
}

int main()
{
	g_srcImage = imread("linlin.jpg");
	g_templateImage = imread("linlinface.PNG");

	namedWindow("【原始图片】", CV_WINDOW_AUTOSIZE);
	namedWindow("【效果窗口】", CV_WINDOW_AUTOSIZE);

	createTrackbar("方法", "【原始图片】", &g_nMatchMethod, g_nMaxTrackbarNum, on_Matching);
	on_Matching(0, 0);

	waitKey(0);
	return 0;
}

代码讲解

int resultImage_rows = g_srcImage.rows - g_templateImage.rows + 1;
int resultImage_cols = g_srcImage.cols - g_templateImage.cols + 1;

这两行主要是求Mat变量g_resultImage的长宽,即尺寸,该变量对应的就是matchTemplate()函数中都第三个参数result,比较结果的映射图像。至于为什么这么求,书中有提到必须是(W-w+1)x(H-h+1),原理是什么书上也没提呕!个人理解,可能跟模板匹配的原理有关。模板匹配是通过一个图像模板,在整幅输入图像上移动这个模块来寻找图像中相似的最优匹配。至于映射效果呢,其实就是为了方便比较,所以要缩小尺寸来放大匹配部分,方便进行比较不同方法的匹配效果。Of course,一切都是本人理解的靴靴,至于是不是这样的本人清者自清。当然,也欢迎知道的童鞋在评论方留言厚!

matchTemplate(g_srcImage, g_templateImage, g_resultImage, g_nMatchMethod);
normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX, -1, Mat());

第一行就是调用matchTemplate()函数,没什么好说的,主要是第二行的normalize()函数,有篇文章写得比较详细,大家可以看看:opencv函数介绍(1)——normalize按这篇文章来讲,应该是范围归一化数据,运用Image Watch可以看到归一化后的g_resultImage图像的像素值都在(0,1)之间,正好符合normalize()函数中的0,1的上下限,效果图如下:
在这里插入图片描述

rectangle(srcImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);
rectangle(g_resultImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 0, 255), 2, 8, 0);

然后就是绘制矩形的代码,原图和映射图像分别绘制,其实就是匹配的区域而已。简单介绍一下rectangle()函数的参数,方便大家使用厚!
第一个参数,要绘制矩形的图像;
第二个参数,矩形的左上角坐标,也就是求得的匹配位置的坐标点;
第三个参数,矩形的右下角坐标,代码中是左上角横纵坐标加上模板图像的长宽求得,容易理解,因为矩形要和模板一样惹;
第四个参数,矩形的边的颜色厚,BGR颜色你自己调靴靴;
第五个参数,thickness线宽;
第六个参数,lineType线型;
第七个参数,int shift=0??,我也没看明白,应该是与坐标点有关,选默认值就好了噜。

g_templateImage = imread(“linlinface.PNG”);

这个书上也没解释呕,真素懒死噜!想直接用代码的人可能就会懵逼厚,这是个啥图?其实细看书的话还是能明白的,就是模板图像厚,也就是你想要匹配的部分,你从原图中截个图就好噜,so easy的靴靴!

实验效果

其它没什么好说的了,给大家看看效果吧!选用的是宇宙天后的婊情嘻嘻,映射结果就不给大家看了,意思都一样,结果如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,只有方法二(相关匹配法)不本质,没有成功匹配到天后的美貌,真素不努力,迟早被吸。其它的方法都成功匹配到了,相差都不大,都是畏惧神淋罢了嘻嘻!

发布了17 篇原创文章 · 获赞 3 · 访问量 1810

猜你喜欢

转载自blog.csdn.net/weixin_43350361/article/details/88774947