模板匹配(createTrackbar函数这样用)
一、模板匹配
模板匹配(TemplateMatching)就是在一幅图像中寻找和模板图像(template)最相似的区域,该方法原理简单计算速度快,能够应用于目标识别,目标跟踪等多个领域。
二、原理
1、cv::TM_SQDIFF:该方法使用平方差进行匹配,因此最佳的匹配结果在结果为0处,值越大匹配结果越差。
2、cv::TM_SQDIFF_NORMED:该方法使用归一化的平方差进行匹配,最佳匹配也在结果为0处。
3、cv::TM_CCORR:相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差。
4、cv::TM_CCORR_NORMED:归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。
5、cv::TM_CCOEFF:相关性系数匹配方法,该方法使用源图像与其均值的差、模板与其均值的差二者之间的相关性进行匹配,最佳匹配结果在值等于1处,最差匹配结果在值等于-1处,值等于0直接表示二者不相关。
6、cv::TM_CCOEFF_NORMED:归一化的相关性系数匹配方法,正值表示匹配的结果较好,负值则表示匹配的效果较差,也是值越大,匹配效果也好。
三、API
matchTemplate(
InputArrray image, //源图像
InputArray templ, //模板图像
OutputArray result,//输出结果 必须是单通道32位浮点数,假设源图像WxH,模版图像 w*h,到结果必须为W-w+1,H-h+1的大小
int method); // 匹配方法,使用不同的方法产生的结果的意义可能不太一样,有些返回的值越大表示匹配程度越好,而有些方法返回的值越小表示匹配程度越好
关于参数 method:
TM_SQDIFF平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
TM_CCORR相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
TM_CCOEFF相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
TM_SQDIFF_NORMED归一化平方差匹配法
TM_CCORR_NORMED归一化相关匹配法
TM_CCOEFF_NORMED归一化相关系数匹配法
四、示例代码
#include "mainwindow.h"
#include <QApplication>
#include <imgproc.hpp>
#define MYPICTUREPATH "D:/Datum/Qt/Qt-Res/pic/"
using namespace std;
using namespace cv;
/// 全局变量 ///
Mat img; //原始图像
Mat templ; //模板图像
Mat result; //匹配结果图像
const char* image_window = "Source Image";//原始图像显示窗口
const char* result_window = "Result window";//匹配结果图像显示窗口
bool useMask;
int maxTrackbar = 5; //滑动条最大值(与匹配方法个数对应)
/// 函数声明 ///
void MatchingMethod( int match_method, void* ); //匹配函数
int main(int argc, char *argv[]) {
//! [0]
// 加载原始图像和模板图像
img = imread(MYPICTUREPATH "zhenhun.jpg");
templ = imread(MYPICTUREPATH "zhenhun_templ.jpg");
//! 创建显示窗口
namedWindow(image_window, WINDOW_AUTOSIZE);
namedWindow(result_window, WINDOW_AUTOSIZE);
//! 创建滑动条
String trackbar_label = "Method: \n \
0: TM_SQDIFF \n \
1: TM_SQDIFF_NORMED \n \
2: TM_CCORR \n \
3: TM_CCORR_NORMED \n \
4: TM_COEFF \n \
5: TM_COEFF_NORMED";
//! 参数:
//! 1滑动条名称
//! 2显示窗口名称
//! 3设置滑块初始值位置,设置为NULL
//! 4滑动条的最大值
//! 5回调函数,如:void MatchingMethod( int match_method, void*
//! );//滑动条的value会传给match_method 6用户传给回调函数的数据(默认值为0)
createTrackbar(trackbar_label, image_window, NULL, maxTrackbar, MatchingMethod);
MatchingMethod(0, NULL);
//! [0]
QApplication a(argc, argv);
return a.exec();
}
void MatchingMethod(int match_method, void *) {
Mat imgDisplay;
img.copyTo( imgDisplay );
// 匹配结果图像result为每个模板位置存储匹配结果
// 匹配结果图像result大小为:(W-w+1)*(H-h+1)
// 对于TM_SQDIFF和
// TM_SQDIFF_NORMED这两种方法,最小值为最佳匹配;对于别的方法最大值为最佳匹配
bool method_accepts_mask = (TM_SQDIFF == match_method || match_method == TM_CCORR_NORMED);
if (useMask && method_accepts_mask) {
//{ matchTemplate( img, templ, result, match_method, mask); }
matchTemplate(img, templ, result, match_method);
} else {
matchTemplate(img, templ, result, match_method);
}
if (match_method % 2 == 0) {
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
}
double minVal, maxVal;
Point minLoc, maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
cout << "minVal =" << minVal << minLoc << endl;
cout << "maxVal =" << maxVal << maxLoc << endl;
cout << "(86,368)=" << result.at<float>(86, 368) << endl;
qDebug() << "---------------"<<match_method<<"----------------";
if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED) {
matchLoc = minLoc;
} else {
matchLoc = maxLoc;
}
// 在原始图像和匹配结果图像中以最佳匹配点为左上角标出最佳匹配框
rectangle( imgDisplay, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), CV_RGB(255,0,0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(255), 2, 8, 0 );
imshow( image_window, imgDisplay );
imshow( result_window, result );
//return;
}
五、匹配结果显示
六、疑问
匹配方法为TM_CCORR时,匹配结果好像不正确?