今天看了王先生的一篇博客
http://www.cnblogs.com/xrwang/archive/2010/02/05/MatchTemplate.html
介绍了模板匹配,王先生是使用C#实现的,在此我使用C++实现;
在此引用王先生的摘要:
模板匹配的工作方式
模板匹配的工作方式跟直方图的反向投影基本一样,大致过程是这样的:通过在输入图像上滑动图像块对实际的图像块和输入图像进行匹配。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)用临时图像和模板图像进行对比,对比结果记为c;
(3)对比结果c,就是结果图像(0,0)处的像素值;
(4)切割输入图像从(0,1)至(10,11)的临时图像,对比,并记录到结果图像;
(5)重复(1)~(4)步直到输入图像的右下角。
大家可以看到,直方图反向投影对比的是直方图,而模板匹配对比的是图像的像素值;模板匹配比直方图反向投影速度要快一些,但是我个人认为直方图反向投影的鲁棒性会更好。
模板匹配的匹配方式
在OpenCv和EmguCv中支持以下6种对比方式:
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
计算公式:
代码实现:
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
/// 全局变量
Mat img; Mat templ; Mat result;
char* image_window = "Source Image";
char* result_window = "Result window";
int match_method=0;
int max_Trackbar = 5;
/// 函数声明
void MatchingMethod( int, void* );
int main()
{
string originalImageName = "/home/flyfire/image_video_data/people_3.jpg";
string matchImageName = "/home/flyfire/image_video_data/matchtemplate.jpg";
/// 载入原图像和模板块
img = imread( originalImageName );
templ = imread( matchImageName);
/// 创建窗口
namedWindow( image_window, CV_WINDOW_AUTOSIZE );
namedWindow( result_window, CV_WINDOW_AUTOSIZE );
/// 创建滑动条
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 );
waitKey(0);
return 0;
}
/**
* @函数 MatchingMethod
* @简单的滑动条回调函数
*/
void MatchingMethod( int, void* )
{
/// 将被显示的原图像
Mat img_display;
img.copyTo( img_display );
/// 创建输出结果的矩阵
int result_cols = img.cols ;
int result_rows = img.rows ;
result.create( result_rows,result_cols, CV_32FC1 );
/// 进行匹配和标准化
matchTemplate( img, templ, result, match_method );
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
/// 通过函数 minMaxLoc 定位最匹配的位置
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
/// 对于方法 SQDIFF 和 SQDIFF_NORMED, 越小的数值代表更高的匹配结果. 而对于其他方法, 数值越大匹配越好
if( match_method == CV_TM_SQDIFF || match_method == CV_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( result_window, result );
imshow( image_window, img_display );
return;
}
效果如下哦:
模板图片:
匹配图:
效果图:
SQDIFF:
SQDIFF_NORMED:
TM_CCORR :
TM_CCORR_NORMED:
TM_COEFF_NORMED: