1.目的
(1)使用openCV函数matchTemplate()在输入图像中搜索图像块
(2)使用openCV函数minMaxLoc()寻找数组中的最大或者最小值
2.原理
[1]模板匹配
给定一个图像块,搜索配对的图像块,当模板是矩形时候,并不一定所有的矩形块内容都是相关的,在这种情况下,可以利用掩码分离有用信息。
[2]工作原理
输入:原图像,模板
目标:寻找最高的匹配块
搜索:比较模板和原图像,通过滑动形式配对模板。
搜索过程是从左到右,从上到下,逐个像素像素遍历的过程,通过计算每一次滑动过程的配对效果的好坏确定最佳匹配模块,并将度量结果存储在结果矩阵R中。矩阵R中的每一个位置(x,y)包含了配对度量。
如上图所示,红色圆圈中的亮点区域表示匹配高的区域,黑色的矩形框框表示匹配区域,实际过程中,我们通过minMaxLoc函数在结果矩阵R中寻找最佳匹配。
PS:如果使用掩码,则需要输入原图像,模板,掩码。掩码的维度必须和模板一致,并且拥有CV_8U和CV_32F的深度以及和模板具有相同通道数。CV_8U的掩码必须是二进制值,CV_32F则是在[0,1]之间的小数,掩码和模板对应相乘,获得经过掩码操作的模板。现在只有CV_TM_SQDIFF和CV_TM_CCORR_NORMED支持掩码操作。
[3]配对方法
<1>method=CV_TM_SQDIFF:平方差匹配法
<2>method=CV_TM_SQDIFF_NORMED:归一化平方差匹配法
<3>method=CV_TM_CCORR:相关匹配法
<4>method=CV_TM_CCORR_NORMED:归一化相关匹配法
<5>method=CV_TM_CCOEFF:相关系数匹配法
<6>method=CV_TM_CCOEFF_NORMED:归一化相关系数匹配法
3.部分代码解释
(1)minMaxLoc
/*
minMaxLoc参数解释
result:输入数组
minVal:数组最小值
maxVal:数组最大值
minLoc:数组最小值所在位置
maxLoc:数组最大值所在位置
Mat():掩码,没定义则为无掩码操作
*/
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
(2)matchTemplate
matchTemplate参数解释
img:输入图像
templ:模板
result:匹配结果,存储匹配过程中的度量值metric value
type:匹配方法
*/
matchTemplate(img, templ, result, type);
4.完整代码
(1)CommonInclude.h
#ifndef COMMON_INCLUDE
#define COMMON_INCLUDE
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
#endif
(2)Matching.cpp
#include"CommonInclude.h"
/*
配对方法0,1,2,3,4,5
*/
int type = 0;
int num_type = 5;
Mat img, templ, mask, result;
char windowResultName[] = "Matched";
char windowOriginName[] = "Origin";
void Matching(int, void*){
Mat display_img = img.clone();
/*
matchTemplate参数解释
img:输入图像
templ:模板
result:匹配结果,存储匹配过程中的度量值metric value
type:匹配方法
*/
matchTemplate(img, templ, result, type);
//归一化
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
double minVal, maxVal;
Point minLoc, maxLoc;
Point matchLoc;
//使用minMaxLoc函数确定数组的最值以及位置
/*
minMaxLoc参数解释
result:输入数组
minVal:数组最小值
maxVal:数组最大值
minLoc:数组最小值所在位置
maxLoc:数组最大值所在位置
Mat():掩码,没定义则为无掩码操作
*/
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
if( type == CV_TM_SQDIFF || type == CV_TM_SQDIFF_NORMED )
{
matchLoc = minLoc;
}else{
matchLoc = maxLoc;
}
//绘制匹配的区域
rectangle(display_img, matchLoc, Point(matchLoc.x+templ.cols, matchLoc.y+templ.rows), Scalar(0,0,0), 2, 8);
rectangle(result, matchLoc, Point(matchLoc.x+templ.cols, matchLoc.y+templ.rows), Scalar(0,0,0), 2, 8);
imshow(windowOriginName, img);
imshow(windowResultName,display_img);
imshow("result", result);
}
int main(int argc, char**argv){
if(argc<3){
cout << "more parameters are required!!!" << endl;
return(-1);
}
img = imread(argv[1]);
templ = imread(argv[2]);
//mask = imread(argv[3]);
if(!img.data || !templ.data){
cout << "error to read images!!!" << endl;
return(-1);
}
namedWindow(windowResultName, CV_WINDOW_AUTOSIZE);
const 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, windowResultName,&type, num_type, Matching);
Matching(0,0);
waitKey(0);
return(0);
}
参考文献
1.http://docs.opencv.org/master/de/da9/tutorial_template_matching.html