【 OpenCV 】MatchTemplate函数参数详解及原理分析
模板匹配是在一幅图像中寻找一个特定目标的方法之一,这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否“相似”,当相似度足够高时,就认为找到了我们的目标。OpenCV提供了6种模板匹配算法。
MatchTemplate
MatchTemplate(InputArray image, InputArray templ, OutputArray result, int method);
image:输入一个待匹配的图像,支持8U或者32F。
templ:输入一个模板图像,与image相同类型。
result:输出保存结果的矩阵,32F类型。
method:要使用的数据比较方法。
1.result:
result是一个结果矩阵,假设待匹配图像为 I,宽高为(W,H),模板图像为 T,宽高为(w,h)。那么result的大小就为(W-w+1,H-h+1) 。
2.method
场景适用原理分析:
cv::TM_SQDIFF 判断 minVal 越小,效果越好
计算模板与目标图像的方差,由于是像素值差值的平方的和,所以值越小匹配程度越高;
cv::TM_SQDIFF_NORMED 判断 minVal 越接近0,效果越好
范化的cv::TM_SQDIFF,取值为0-1之间,完美匹配返回值为0;
cv::TM_CCORR 判断 maxVal 越大,效果越好
使用dot product计算匹配度,越高匹配度就好;
cv::TM_CCORR_NORMED 判断 maxVal 越接近1,效果越好
范化的cv::TM_CCORR,0-1之间,我用的这个;
cv::TM_CCOEFF 判断 maxVal 越大,效果越好
采用模板与目标图像像素与各自图像的平均值计算dot product,正值越大匹配度越高,负值越大图像的区别越大,但如果图像没有明显的特征(即图像中的像素值与平均值接近)则返回值越接近0;
cv::TM_CCOEFF_NORMED 判断 maxVal 越接近1,效果越好
范化的cv::TM_CCOEFF,-1 ~ 1之间。
优缺点与适用场景:
TM_CCORR:
**互相关算法**(cross-correlation)是一种经典的统计匹配算法,通过计算模板图像和匹配图像的互相关程度
,来确定匹配的程度。互相关程度
最大时的搜索窗口位置决定了模板图像在待匹配图像中的位置。
特点
擅长区分出(有颜色差异的)不同区域。
TM_SQDIFF:
误差平方和算法(Sum of Squared Differences,简称SSD算法),也叫差方和算法
优点
- 思路简单,容易理解(子图与模板图对应位置上,灰度值之差的绝对值总和,再求平均)。
- 运算过程简单,匹配精度高。
缺点
- 运算量偏大。
- 对噪声非常敏感。
TM_CCOEFF
均值漂移的互相关算法(Mean shifted cross correlation [Pearson correlation coefficient])。是互相关算法
(cross correlation)和均值漂移算法的结合。
优点
算法计算量小,简单易实现,很适合于实时跟踪场合
缺点
跟踪小目标和快速移动目标时常常失败,而且在全部遮挡情况下不能自我恢复跟踪
TM_CCORR_NORMED
归一化互相关(Normalized Cross Correlation method, NCC)匹配算法。
它是一个亮度、对比度线性不变量。
此算法的缺点是参与运算的特征点比较多,运算速度比较慢。
其他归一化算法
TM_SQDIFF_NORMED`和 `TM_CCOEFF_NORMED
实验比较
使用trackbar调节不同method
const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
createTrackbar(trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod);
MatchingMethod(0, 0);
模板匹配
void MatchingMethod(int, void*)
{
Mat img_display;
img.copyTo(img_display);
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create(result_rows, result_cols, CV_32FC1);
matchTemplate(img, templ, result, match_method);
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());//将结果归一化防止溢出,显示
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());//不同方法对应最小值与最大值不同
if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
rectangle(img_display, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar::all(0), 2, 8, 0);//绘制矩形
// rectangle(result, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar::all(0), 2, 8, 0);
imshow(image_window, img_display);
imshow(result_window, result);
imshow("template", templ);
return;
}
实验结果
TM_SQDIFF(mode 0)和TM_CCOEFF_NORMED(mode 5)进行对比:
TM_SQDIFF:
0对应最匹配位置;
TM_CCOEFF_NORMED:
1对应最匹配位置;
模板颜色改变后:
TM_CCORR(mode2)颜色区分不明显造成匹配错误:
TM_CCORR_normal(3)正确:
不同的匹配值不同,但大体能识别出正确的区域。
使用自己头像形变测试形变对于模板匹配的影响,结果上面大致相同。