模板匹配介绍
模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。
所以模板匹配首先需要一个模板图像T(给定的子图像)
另外需要一个待检测的图像-源图像S
工作方法,在带检测图像上,从左到右,从上向下计算模板图像与重叠子图像的匹配度,匹配程度越大,两者相同的可能性越大。
OpenCV中提供了六种常见的匹配算法如下: 计算公式参考 源码 TemplateMatchModes 的注释
1. 计算平方不同 计算出来的值越小,越相关 TM_SQDIFF = 0
2. 计算相关性 计算出来的值越大,越相关 TM_CCORR = 2
3. 计算相关系数 计算出来的值越大,越相关 TM_CCOEFF = 4
4. 计算归一化平方不同 计算出来的值越接近0,越相关 TM_SQDIFF_NORMED = 1
5. 计算归一化相关性 计算出来的值越接近1,越相关 TM_CCORR_NORMED = 3
6. 计算归一化相关系数 计算出来的值越接近1,越相关 TM_CCOEFF_NORMED = 5 建议使用归一化的方法
matchTemplate(
InputArray image,// 源图像,必须是8-bit或者32-bit浮点数图像
InputArray templ,// 模板图像,类型与输入图像一致
OutputArray result,// 输出结果,必须是单通道32位浮点数,假设源图像WxH,模板图像wxh, 则结果必须为W-w+1, H-h+1的大小。
int method,// 使用的匹配方法
InputArray mask=noArray()//(optional)
)
代码
#include "../common/common.hpp"
static Mat src, temp, dst;
static char title[] = "ret28";
static int match_method = TM_SQDIFF;
static int max_track = 5;
static void match(int, void*);
void main(int argc, char** argv)
{
src = imread(getCVImagesPath("images/test1.png"), IMREAD_COLOR);
temp = imread(getCVImagesPath("images/sample.png"), IMREAD_COLOR);
namedWindow(title, CV_WINDOW_AUTOSIZE);
createTrackbar("match:", title, &match_method, max_track, match);
match(0, 0);
waitKey(0);
}
void match(int, void*)
{
int width = src.cols - temp.cols + 1;
int height = src.rows - temp.rows + 1;
Mat result(width, height, CV_32FC1);
matchTemplate(src, temp, result, match_method, Mat());//当TM_CCORR时,匹配不准确,OpenCV本身算法导致的?
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());//matchTemplate的计算结果不定,归一
Point minLoc;
Point maxLoc;
double min, max;
src.copyTo(dst);
minMaxLoc(result, &min, &max, &minLoc, &maxLoc, Mat());//寻找result中最大值,最小值,及它们所在的位置
Point temLoc;
if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED) {
temLoc = minLoc;
}
else {
temLoc = maxLoc;
}
// 绘制矩形
rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, LINE_8);
rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, LINE_8);
imshow(title, result);
imshow("matchTemplate", dst);
}
效果图