opencv模板匹配步骤及Code
首先介绍一下模板匹配的适用场景:
1、图像检索
2、目标跟踪
简单的说,模板匹配最主要的功能就是在一幅图像中去寻找和另一幅模板图像中相似度最高的部分,这就是模板匹配。
比如,在下面这图片中:
我们要在上面这幅图片中寻找下面这位女团成员的头像:
使用模板匹配后的寻找结果如下图所示:
接下来看一下opencv中的模板匹配的具体用法吧。
我将模板匹配的步骤分割如下:
步骤一:读取图片
code:
cv::Mat img1 = cv::imread("C:\\Users\\Administrator\\Desktop\\tmp.png");
cv::Mat img2 = cv::imread("C:\\Users\\Administrator\\Desktop\\tmp1.png");
步骤二:创建一个空画布用来绘制匹配结果
code:
cv::Mat dstImg;
dstImg.create(img1.dims,img1.size,img1.type());
cv::imshow("createImg",dstImg);
步骤三:匹配,最后一个参数为匹配方式
code:
cv::matchTemplate(img1, img2, dstImg, 0);
步骤四:归一化图像矩阵,可省略
code:
cv::normalize(dstImg, dstImg, 0, 1, 32);
步骤五:获取最大或最小匹配系数
code:
//首先是从得到的 输出矩阵中得到 最大或最小值(平方差匹配方式是越小越好,所以在这种方式下,找到最小位置)
//找矩阵的最小位置的函数是 minMaxLoc函数
cv::Point minPoint;
cv::Point maxPoint;
double *minVal = 0;
double *maxVal = 0;
cv::minMaxLoc(dstImg, minVal, maxVal, &minPoint,&maxPoint);
步骤六:开始正式绘制
code:
cv::rectangle(img1, minPoint, cv::Point(minPoint.x + img2.cols, minPoint.y + img2.rows), cv::Scalar(0,255,0), 2, 8);
cv::imshow("【匹配后的图像】", img1);
cv::rectangle(dstImg, minPoint, cv::Point(minPoint.x + img2.cols, minPoint.y + img2.rows), cv::Scalar(0,0,0), 2, 8);
cv::imshow("【匹配后的计算过程图像】", dstImg);
cv::waitKey(0);
函数介绍
void cv::matchTemplate(
cv::InputArray image, // 用于搜索的输入图像
cv::InputArray templ, // 用于匹配的模板,和image类型相同
cv::OutputArray result, // 匹配结果图像
int method // 用于比较的方法
)
参数解释:
InputArray Image: 待搜索的图像,且图像必须为8-bit或32-bit的浮点型图像
InputArray templ: 用于进行模板匹配的模板图像,类型和原图像一致,但是尺寸不能大于原图像
OutputArray result: 模板搜索结果输出图像,必须为单通道32-bit位浮点型图像,如果图像尺寸是WxH而template尺寸是wxh,则此参数result一定是(W-w+1)x(H-h+1)
int method: 模板匹配计算类型,共6种,将在下面进行简单介绍
InputArray mask=noArray(): 图像匹配时用的掩膜板,必须和模板图像有相同的数据类型和尺寸
在OpenCV中提供了6种匹配度量方法。
(1).平方差匹配法CV_TM_SQDIFF
(2)归一化平方差匹配法CV_TM_SQDIFF_NORMED
(3)相关匹配法CV_TM_CCORR
(4)归一化相关匹配法CV_TM_CCORR_NORMED
(5)系数匹配法CV_TM_CCOEFF
(6)化相关系数匹配法CV_TMCCOEFF_NORMED
通常来讲,随着从简单测量方法(平方差)到更复杂的测量方法(相关系数法),我们可以获得越来越准确的匹配。然而这同时也会以越来越大的计算量为代价。对于选取何种方法,针对不同的匹配情况进行对此分析比较,选取更适合自己应用场景同时兼顾速度和精度的最佳方案。
注意
值得注意的是对于方法SQDIFF和SQDIFF_NORMED两种方法来讲,越小的值就有着更高的匹配结果,而其余的方法则是数值越大匹配效果越好。
void cv::minMaxLoc ( InputArray src,
double * minVal,
double * maxVal = 0,
Point * minLoc = 0,
Point * maxLoc = 0,
InputArray mask = noArray()
)
参数解释:
InputArray src:输入的单通道数组
*double minVal:double类型指针,返回最小值,如果没有定义返回NULL
double maxVal:同上,返回最大值
Point minLoc=0:Point类型的指针,在二维图像中返回最小值的位置坐标,如果没有定义返回NULL
*Point maxLoc=0: **Point同上,返回最大位置坐标
InputArray mask=noArray():可选掩膜
完整代码:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
void main()
{
//步骤一:读取图片
cv::Mat img1 = cv::imread("C:\\Users\\Administrator\\Desktop\\tmp.png");
cv::Mat img2 = cv::imread("C:\\Users\\Administrator\\Desktop\\tmp1.png");
cv::imshow("【被查找的图像】", img1);
cv::imshow("【模版图像】", img2);
//步骤二:创建一个空画布用来绘制匹配结果
cv::Mat dstImg;
dstImg.create(img1.dims,img1.size,img1.type());
cv::imshow("createImg",dstImg);
//步骤三:匹配,最后一个参数为匹配方式,共有6种,详细请查阅函数介绍
cv::matchTemplate(img1, img2, dstImg, 0);
//步骤四:归一化图像矩阵,可省略
cv::normalize(dstImg, dstImg, 0, 1, 32);
//步骤五:获取最大或最小匹配系数
//首先是从得到的 输出矩阵中得到 最大或最小值(平方差匹配方式是越小越好,所以在这种方式下,找到最小位置)
//找矩阵的最小位置的函数是 minMaxLoc函数
cv::Point minPoint;
cv::Point maxPoint;
double *minVal = 0;
double *maxVal = 0;
cv::minMaxLoc(dstImg, minVal, maxVal, &minPoint,&maxPoint);
//步骤六:开始正式绘制
cv::rectangle(img1, minPoint, cv::Point(minPoint.x + img2.cols, minPoint.y + img2.rows), cv::Scalar(0,255,0), 2, 8);
cv::imshow("【匹配后的图像】", img1);
cv::rectangle(dstImg, minPoint, cv::Point(minPoint.x + img2.cols, minPoint.y + img2.rows), cv::Scalar(0,0,0), 3, 8);
cv::imshow("【匹配后的计算过程图像】", dstImg);
cv::waitKey(0);
如果觉得博主的文章对您有所帮助,记得关注一下呦!您的支持就是我不断更新下去的最强动力。
如有不对的地方请指正,谢谢
有需要深度学习及机器视觉相关开发环境的可加博主QQ获取,有问题请联系下方QQ直接与博主本人交流。博主会定期更新视觉相关算法使用及实际项目讲解,谢谢各位
博主QQ:2021907249