参考资料:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matching/template_matching.html?highlight=%E6%A8%A1%E6%9D%BF%E5%8C%B9%E9%85%8D
模板匹配介绍
- 模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。
实现原理
- 首先,我们需要两幅图像:
1)模板图像(T):将和原图像比照的图像块
2)源图像(S):在这幅图像里,我们希望找到一块和模板匹配(T)的区域
我们的目标是检测最匹配的区域:
- 为了确定匹配区域, 我们不得不滑动模板图像和源图像进行比较:
- 滑动的意思是,将模板图像块,从左到右,从上到下,每次移动一个像素。
- 在每一个位置上,都进行一次度量计算来表明它是 “好” 或 “坏” 的匹配。
- 把度量值保存到结果图像矩阵®中,在R的每个位置(x,y)上都存有一个度量值。
- 最后,使用函数 minMaxLoc 来定位在矩阵 R 中的最大值点 (或者最小值),找到最匹配的区域。
匹配算法说明
-
a. 平方差匹配 method = CV_TM_SQDIFF
这类方法利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大.
-
b. 标准平方差匹配 method = CV_TM_SQDIFF_NORMED
-
c. 相关匹配 method = CV_TM_CCORR
这类方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果.
-
d. 标准相关匹配 method = CV_TM_CCORR_NORMED
-
e. 相关匹配 method = CV_TM_CCOEFF
这类方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列).
其中: -
f. 标准相关匹配 method = CV_TM_CCOEFF_NORMED
-
总结
①TM_SQDIFF是平方差匹配;TM_SQDIFF_NORMED是标准平方差匹配。利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大。
②TM_CCORR是相关性匹配;TM_CCORR_NORMED是标准相关性匹配。采用模板和图像间的乘法操作,数越大表示匹配程度较高, 0表示最坏的匹配效果。
③TM_CCOEFF是相关性系数匹配;TM_CCOEFF_NORMED是标准相关性系数匹配。将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。 -
再总结
随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价)。 -
相关性是(越接近1)越大越好;平方差是越小越好
API说明
- matchTemplate(
InputArray image, // 源图像,必须是8-bit或者32-bit浮点数图像
InputArray temp1, // 模板图像,类型与输入图像一致
OutputArray result, // 输出结果,必须是单通道32位浮点。如果image的尺寸为W * H,templ的尺寸为w * h,则result的尺寸为(W-w+1) * (H-h+1)
int method, // 匹配算法
InputArray mask=noArray()
)
完整程序示例
Mat src, temp, dst;
int match_method = 0;
void MatchDemo(int, void*);
const char* INPUT_Ima = "input image";
const char* OUTPUT = "output image";
const char* MATCH = "match image";
int main()
{
//加载图像并验证图像有效性
src = imread("E:/Image/lol1.jpg");
temp = imread("E:/Image/lol_al.jpg");
if (src.empty() || temp.empty())
{
cout << "could not load image..." << endl;
return 0;
}
namedWindow(INPUT_Ima, WINDOW_AUTOSIZE);
namedWindow(OUTPUT, WINDOW_AUTOSIZE);
namedWindow(MATCH, WINDOW_AUTOSIZE);
imshow(INPUT_Ima, src);
createTrackbar("type:", OUTPUT, &match_method, 5, MatchDemo);
MatchDemo(0, 0);
waitKey(0);
return 0;
}
void MatchDemo(int, void*)
{
//创建result
int width = src.cols - temp.cols + 1;
int height = src.rows - temp.rows + 1;
Mat result(height, width, CV_32FC1);
//模板匹配,二值化(二值化后result结果更明显,可不用)
matchTemplate(src, temp, result, match_method, Mat());
normalize(result, result, 0, 1, NORM_MINMAX);
//获取像素点最大值、最小值及其位置
Point minLoc, maxLoc, tempLoc;
double min, max;
minMaxLoc(result, &min, &max, &minLoc, &maxLoc);
src.copyTo(dst);
//根据不同算法获取不同(最大值或最小值)位置
if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED)
tempLoc = minLoc;
else
tempLoc = maxLoc;
//绘制区域
rectangle(dst, Rect(tempLoc.x, tempLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 1, LINE_AA);
rectangle(result, Rect(tempLoc.x, tempLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 1, LINE_AA);
imshow(MATCH, result);
imshow(OUTPUT, dst);
}
结果