模板匹配不是基于直方图的,而是通过在输入图像上滑动图像块,对实际图像块和输入图像进行匹配的一种匹配方法。
实现模板匹配:matchTemplate()函数
用于匹配出和模板重叠的图像区域;
函数原型C++
void matchTemplate( InputArray image, InputArray temp1, OutputArray result, int method )
【1】InputArray类型的image,待搜索的图像,且需为8位或32位浮点型图像;
【2】InputArray类型的temp1,搜索模板,需和源图片有一样的数据类型,且尺寸不能大于源图像;
【3】OutputArray类型的result,比较结果的映射图像,其必须为单通道、32位浮点型图像,如果图像尺寸是W x H而temp1尺寸是wxh,则此参数result一定是(W-w + 1)x(H-h+1);
【4】int类型的method,指定的匹配方法,提供一下6种方法:
- 平方差匹配法 method = TM_SQDIFF,使用平方差来进行匹配,最好匹配为0。
而若匹配越差,匹配值则越大。(说明最黑的地方是匹配最好的地方) - 归一化平方差匹配法:method = TM_SQDIFF_NORMED,最好匹配为0。
- 相关匹配法:method = TM_CCORR,这类方法才用模板和图像间的乘法操作,所以较大
的数表示匹配程序较高,0标识最坏的匹配效果。 - 归一化相关匹配法 method = TM_CCORR_NORMED;最坏匹配为0。
- 系数匹配法method = TM_CCOEFF;最好匹配为1;
- 化相关系数匹配法method = TM_CCOEFF_NORMED;最好匹配为1。
通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配。然而,这同时也会以越来越大的计算量为代价。比较科学的办法是对所有这些方法多次测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案。
程序实例:
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
Mat g_srcImage, g_tempalteImage, g_resultImage;
int g_nMatchMethod;
int g_nMaxTrackbarNum = 5;
void on_matching(int, void*)
{
Mat srcImage;
g_srcImage.copyTo(srcImage);
int resultImage_cols = g_srcImage.cols - g_tempalteImage.cols + 1;
int resultImage_rows = g_srcImage.rows - g_tempalteImage.rows + 1;
g_resultImage.create(resultImage_cols, resultImage_rows, CV_32FC1);
matchTemplate(g_srcImage, g_tempalteImage, g_resultImage, g_nMatchMethod);
normalize(g_resultImage, g_resultImage, 0, 1, NORM_MINMAX, -1, Mat());
double minValue, maxValue;
Point minLocation, maxLocation, matchLocation;
minMaxLoc(g_resultImage, &minValue, &maxValue, &minLocation, &maxLocation);
if (g_nMatchMethod == TM_SQDIFF || g_nMatchMethod == CV_TM_SQDIFF_NORMED)
{
matchLocation = minLocation;
}
else
{
matchLocation = maxLocation;
}
rectangle(srcImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);
rectangle(g_resultImage, matchLocation, Point(matchLocation.x + g_tempalteImage.cols, matchLocation.y + g_tempalteImage.rows), Scalar(0, 0, 255), 2, 8, 0);
imshow("原始图", srcImage);
imshow("效果图", g_resultImage);
}
int main()
{
g_srcImage = imread("curry.jpg");
if (!g_srcImage.data)
{
cout << "原始图读取失败" << endl;
return -1;
}
g_tempalteImage = imread("curry2.jpg");
if (!g_tempalteImage.data)
{
cout << "模板图读取失败" << endl;
return -1;
}
imshow("g_srcImage", g_srcImage);
imshow("g_tempalteImage", g_tempalteImage);
namedWindow("原始图", CV_WINDOW_AUTOSIZE);
namedWindow("效果图", CV_WINDOW_AUTOSIZE);
createTrackbar("方法", "原始图", &g_nMatchMethod, g_nMaxTrackbarNum, on_matching);
on_matching(0, NULL);
waitKey(0);
return 0;
}
可以看到有些方法也是匹配不上的;
原始图片:
模板图片:
运行结果