概念
模板匹配就是在一幅图像中寻找与模板图像最相似的区域。
效果图对比
●源图像
●模板图像
●匹配结果
函数讲解
●函数原型
○c++
void matchTemplate( InputArray image, InputArray templ,
OutputArray result, int method, InputArray mask = noArray() )
○Android
void matchTemplate(Mat image, Mat templ, Mat result, int method, Mat mask)
●参数解释
○image:输入图像,必须为8位或者32位的浮点型。
○templ:用于搜索的模板图像,必须小于输入图像并且是一样的数据类型。
○result:匹配结果图像。必须是单通道32位浮点型,且大小是(W-w+1)*(H-h+1),其中W,H分别为输入图像的宽和高,w,h分别为模板图像的宽和高。
○method:模板匹配的方法。
○mask :蒙版。
函数使用
●c++中
#include
using namespace cv;
Mat srcImg; //原始图像
Mat templImg; //模板图像
Mat resultImg; //匹配结果图像
int matchMethod; //匹配方法index
int maxTrackbar = 5; //滑动条范围(与匹配方法个数对应)
const char* imageWindow = "Source Image"; //原始图像显示窗口
const char* resultWindow = "Result Window"; //匹配结果图像显示窗口
void MatchingMethod(int, void*);
int main() {
srcImg = imread("C:/Users/Administrator/Desktop/zhenhun.jpeg");//原图像
templImg = imread("C:/Users/Administrator/Desktop/zhenhun_temp.jpg");//模板图像
if (srcImg.empty()|| templImg.empty()) {
return -1;
}
// 创建显示窗口
namedWindow(imageWindow, CV_WINDOW_AUTOSIZE);
namedWindow(resultWindow, CV_WINDOW_AUTOSIZE);
imshow("temp", templImg);
// 创建滑动条
const char* trackbarLabel =
"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";
//参数:滑动条名称 显示窗口名称 匹配方法index 滑动条范围 回调函数
createTrackbar(trackbarLabel, imageWindow, &matchMethod, maxTrackbar, MatchingMethod);
MatchingMethod(0, 0);
waitKey(0);
return 0;
}
/// 函数定义 ///
void MatchingMethod(int, void*) //匹配函数
{
// 深拷贝用于显示
Mat displayImg;
srcImg.copyTo(displayImg);
// 创建匹配结果图像,为每个模板位置存储匹配结果
// 匹配结果图像大小为:(W-w+1)*(H-h+1)
int result_cols = srcImg.cols - templImg.cols + 1;
int result_rows = srcImg.rows - templImg.rows + 1;
resultImg.create(result_cols, result_rows, CV_32FC1);
// 进行匹配并归一化
matchTemplate(srcImg, templImg, resultImg, matchMethod);
normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1, Mat());
// 使用minMaxLoc找出最佳匹配
double minVal, maxVal;
Point minLoc, maxLoc, matchLoc;
minMaxLoc(resultImg, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
// 对于CV_TM_SQDIFF和 CV_TM_SQDIFF_NORMED这两种方法,最小值为最佳匹配;对于别的方法最大值为最佳匹配
if (matchMethod == CV_TM_SQDIFF || matchMethod == CV_TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
// 在原始图像和匹配结果图像中以最佳匹配点为左上角标出最佳匹配框
rectangle(displayImg, matchLoc, Point(matchLoc.x + templImg.cols, matchLoc.y + templImg.rows), Scalar::all(0), 2, 8, 0);
rectangle(resultImg, matchLoc, Point(matchLoc.x + templImg.cols, matchLoc.y + templImg.rows), Scalar::all(0), 2, 8, 0);
imshow(imageWindow, displayImg);
imshow(resultWindow, resultImg);
return;
}
●Android中
private Bitmap matchTemplate(){
Bitmap bitmapSrc = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_matchtemplate);//原图像
Bitmap bitmapTemp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_template);//模板图像
Mat src = new Mat();
Mat temp = new Mat();
//将Bitmap对象转换为Mat对象
Utils.bitmapToMat(bitmapSrc,src);
Utils.bitmapToMat(bitmapTemp,temp);
// 创建匹配结果图像,为每个模板位置存储匹配结果
// 匹配结果图像大小为:(W-w+1)*(H-h+1)
int result_cols = src.cols() - temp.cols() + 1;
int result_rows = src.rows() - temp.rows() + 1;
Mat resultImg = new Mat(result_cols, result_rows, CV_32FC1);
// 进行匹配并归一化
int matchMethod = Imgproc.TM_SQDIFF;//这里也可以使用其他方法
Imgproc.matchTemplate(src, temp, resultImg, matchMethod);
Core.normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1, new Mat());
// 使用minMaxLoc找出最佳匹配
Point minLoc, maxLoc, matchLoc;
Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(resultImg);
minLoc = minMaxLocResult.minLoc;
maxLoc = minMaxLocResult.maxLoc;
// 对于CV_TM_SQDIFF和 CV_TM_SQDIFF_NORMED这两种方法,最小值为最佳匹配;对于别的方法最大值为最佳匹配
if (matchMethod == Imgproc.TM_SQDIFF || matchMethod == Imgproc.TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
//绘制矩形
Imgproc.rectangle(src,matchLoc,new Point(matchLoc.x+temp.cols(),matchLoc.y+temp.rows()),new Scalar(0,0,0),2,LINE_AA,0);
//将Mat转换为Bitmap
Utils.matToBitmap(src,bitmapSrc);
//释放资源
bitmapTemp.recycle();
temp.release();
src.release();
resultImg.release();
return bitmapSrc;
}
扩展
本文是参考这篇文章写的想要深入了解的朋友可以看一下:OpenCV中的模板匹配方法及其应用