模板匹配就是在整个图像区域找出与给定模板匹配的小块区域。匹配过程中需要源图像(I)和模板图像(T),将模板图像在原图像上滑动并一一比对,得到结果图(R),值最大(或最小,依算法而定)的点表明这里的匹配度最高。
1 matchTemplate()函数
void matchTemplate(InputArray img, InputArray temp, OutputArray result, int method)
其中,img为源图像,temp为模板图像,result为结果图,结果图的尺寸为(img.row-temp.row+1)*(img.col-temp.col+1)。
这里OpenCV提供了六种常见的匹配算法:
1 TM_SQDIFF
计算平方差,结果值越小越相关
\[R(x,y)=\sum\limits_{x',y'}(T(x',y')-I(x+x',y+y'))^2\]2 TM_SQDIFF_NORMED
计算归一化的平方差,结果值越接近0越相关
\[R(x,y)=\frac{\sum\limits_{x',y'}(T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum\limits_{x',y'}T(x',y')^2\cdot\sum\limits_{x',y'}I(x+x',y+y')^2}}\]3 TM_CCORR
计算相关性,结果值越大越相关
\[R(x,y)=\sum\limits_{x',y'}(T(x',y')\cdot I(x+x',y+y'))\]4 TM_CCORR_NORMED
计算归一化相关性,结果值越接近1越相关
\[R(x,y)=\frac{\sum\limits_{x',y'}(T(x',y')\cdot I(x+x',y+y'))}{\sqrt{\sum\limits_{x',y'}T(x',y')^2\cdot\sum\limits_{x',y'}I(x+x',y+y')^2}}\]5 TM_CCOEFF
计算相关系数,结果值越大越相关
\[R(x,y)=\sum\limits_{x',y'}(T'(x',y')\cdot I'(x+x',y+y'))\]where
\[T'(x',y')=T(x',y')-1/(w\cdot h)\cdot\sum_{x'',y''}T(x'',y'')\] \[I'(x+x',y+y')=I(x+x',y+y')-1/(w\cdot h)\cdot\sum_{x'',y''}I(x+x'',y+y'')\]6 TM_CCOEFF_NORMED
计算归一化相关系数,结果值越接近1越相关
\[R(x,y)=\frac{\sum\limits_{x',y'}(T'(x',y')\cdot I'(x+x',y+y'))}{\sqrt{\sum\limits_{x',y'}T'(x',y')^2\cdot\sum\limits_{x',y'}I'(x+x',y+y')^2}}\]2 minMaxLoc()函数
使用上述函数得到结果图后,使用minMaxLoc()函数可以找到图像中最大值和最小值的位置,具体使用方法如下:
void minMaxLoc(InputArray img, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())
其中,img为输入图像,minVal为最小值,maxVal为最大值,minLoc为最小值的位置,maxLoc为最大值的位置,mask为掩膜。
如果matchTemplate()函数中定义的方法为平方差或归一化的平方差,结果图中值越小的地方匹配度越好,这时候就需要找矩阵中的最小值及其位置,也就是minVal和minLoc。如果使用了其它四种方法,则需要找结果图中的最大值及其位置,也就是maxVal和maxLoc。
3 示例
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main()
{
Mat img, templ, result;
img = imread("F://OpenCV//img//image_origin.jpg"); //读取源图像
templ = imread("F://OpenCV//img//temp_origin.jpg"); //读取模板图像
result.create(img.rows - templ.rows + 1, img.cols - templ.cols + 1, CV_32FC1); //创建结果图
matchTemplate(img, templ, result, TM_SQDIFF_NORMED);
//模板匹配,这里使用的是归一化平方差方法,这里只对归一化的三种方法TM_SQDIFF_NORMED, TM_CCORR_NORMED, TM_CCOEFF_NORMED进行测试
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); //寻找最大最小值的位置
rectangle(img, maxLoc, Point(maxLoc.x + templ.cols, maxLoc.y + templ.rows), Scalar::all(0), 3); //画出匹配后的矩形框
imshow("img", img);
imshow("result", result);
waitKey(0);
return 0;
}