1 模板匹配的概念与原理
模板匹配是一项在一幅图像中寻找与另一幅图像最匹配部分的技术。模板匹配不是基于直方图,而是通过在输入图像上滑动图像块,对实际的图像块和输入图像进行匹配
2 模板匹配:matchTemplate()函数
说明:matchTemplate()用于匹配出和模板重叠的图像区域
void matchTemplate(InputArray image,InputArray temp1,OutputArray result,int method)
- 第一个参数:待搜索的图像
- 第二个参数:搜索模板,要和源图像有一样的数据类型
- 第三个参数:比较结果的映射图像。如果图像尺寸是W * H,而temp的尺寸是 w * h,则输出参数result是:(W-w+1) x(H-h+1)
- 第四个参数:匹配方法。提供六种方法如下
1)平方差匹配法 method=TM_SQDIF
说明:这类方法利用平方差来进行匹配,最好匹配为0,而若匹配越差,匹配值则越大。即计算出来值越小,越相关
2)归一化平方差匹配法 method=TM_SQDIFF_NORMED
说明:计算出来的值越接近0,越相关
3)相关匹配法:method = TM_CCORR
说明:这类算法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果。即计算出来的值越大越相关。
4)归一化相关匹配法:method = TM_CCORR_NORMED
说明:即计算出来的值越接近1,越相关
5)系数匹配算法:method = TM_CCOEFF
说明:这类方法将模板对其均值的相对值与图像对其均值的相关值进行匹配,1标识完美匹配,-1表示最坏匹配,0表示没有任何关系
6)归一化相关系数匹配法 method= TM_CCOEFF_NORMED
3 模板匹配综合示例
1)minMaxLoc()函数相关API
说明:在一个数组中找到全局最小值和全局最大值。
void minMaxLoc(src, minVal, maxVal, minLoc, maxLoc, mask)
minMaxLoc函数找到最小值和最大值元素值以及它们的位置。极值在整个数组中搜索出来的,或者,如果掩膜不是一个空数组,那么将在一个特殊的数组中搜寻。该函数不能用于多通道数组。如果你需要在所有通道中找到最小或者最大值,那么需要先使用Mat::reshape,将它重构成一个单通道数组。
2)normalize()函数相关API
说明:缩放和移位数组元素,以便指定的标准(alpha)或最小(alpha)和最大(beta)数组值获得指定的值。
void normalize(src,dst,alpha=1, beta=0,NORM_MINMAX, dtype=-1, Mat());
参数1:InputArray类型的src,输入数组(图像)。
参数2:OutputArray类似的dst,输出数组(图像),与输入图像类型尺寸一样。
参数3:alpha,表示range normalization模式的最小值。有默认值为1。
参数4:beta,表示range normalization模式的最大值,不用于norm normalization(范数归一化)模式。有默认值为0。
参数5:normType,表示归一化的类型,可以有以下的取值:
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)。
NORM_L1:归一化数组的L1-范数(绝对值的和)。
NORM_L2:归一化数组的(欧几里德)L2-范数。
参数6:有默认值为-1。dtype为负数时,输出数组的type与输入数组的type相同;否则,出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype)。
参数7:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
3)rectangle()函数相关API
void rectangle(img, Point(j,i), Point(j + img4.cols, i + img4.rows), Scalar(255, 255, 0), 2, 8);
- iamge:被处理的图片
- Point(j,i):代表矩形左上点的坐标
- Point(j + cols, i + rows):代表矩形右下点的坐标
- Scalar:颜色
- 2:代表线条宽度
- 8:是线型,默认取8
示例代码(在星空中寻找月亮)
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; #define WINDOW_NAME1 "【原始图】" #define WINDOW_NAME2 "【效果图】" Mat g_srcImage; Mat g_templateImage; Mat g_resultImage; int g_nMatchMethod; int g_nMaxTrackbarNum = 5; void on_Matching(int, void *); int main() { g_srcImage = imread("E:\\Pec\\星空.jpg", 1); g_templateImage = imread("E:\\Pec\\明月.jpg", 1); namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE); namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE); imshow("明月", g_templateImage); createTrackbar("Method:", WINDOW_NAME1, &g_nMatchMethod, g_nMaxTrackbarNum, on_Matching); on_Matching(0, 0); waitKey(0); return 0; } void on_Matching(int, void *) { Mat srcImage; g_srcImage.copyTo(srcImage); //初始化输出的矩阵 int resultImage_cols = g_srcImage.cols - g_templateImage.cols + 1; int resultImage_rows = g_srcImage.rows - g_templateImage.rows + 1; g_resultImage.create(resultImage_cols, resultImage_rows, 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;//最大值位置、最小值位置 Point matchLocation; minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation, Mat()); //对于方法SQDIFF 和 SQDIFF_NOMED,越小的数值有更高的匹配结果 if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == TM_SQDIFF_NORMED) { matchLocation = minLocation; } else { matchLocation = maxLocation; } //画出矩形,显示结果 rectangle(srcImage, matchLocation, Point(matchLocation.x + g_templateImage.cols, matchLocation.y + g_templateImage.rows), Scalar(0, 255, 0), 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(WINDOW_NAME1, srcImage); imshow(WINDOW_NAME2, g_resultImage); }
1)原图以及寻找的子图
2)找到明月的效果图以及匹配图
平方差匹配算法(SQDIFF)
相关系数匹配法(TM_COEFF)