open cv模板匹配
模板匹配介绍(Template Match)
模板匹配:模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术
模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域
所以模板匹配首先需要一个模板图像T(给定的子图像)
另外需要一个待检测的图像S
工作方法:在待检测图像上,从左到右,从上向下计算模板图像与
重叠子图像的匹配度(这样的搜寻策略叫做滑动窗口) 匹配程度越大,两者相同的可能性越大
(工作原理类似于卷积操作 逐像素寻找匹配像素)
寻找子图像和目标图像直方数据的相似程度
!!!
模板匹配具有自身的局限性,主要表现在它只能进行平行移动
若原图像中的匹配目标发生旋转或大小变化,该算法无效
2、匹配算法方法介绍
opencv中提供了6种常见的匹配算法如下:
TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
TM_CCORR:计算相关性,计算出来的值越大,越相关
TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
3、相关API介绍
cv::matchTemplate
matchTemplate(
InputArray image,//源图像,必须是8bit或者32bit浮点数图像
InputArray templ,//模板图像,类型与输入图像一致
OutputArray result,//输出矩阵图像结果,必须是单通道32bit浮点数。例如:
假设原图像大小是WH,模板图像大小是wh,那么结果大小必须为(W-w+1)*(H-h+1)。
int method,//使用的模板匹配方法
InputArray mask=noArray()//(optional)//掩膜矩阵 选择操作区域 一般不使用
)
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
Mat src,roi,dst;
int method;//模板匹配方法
int MAXmethod = 6;//匹配方法最高值
void MatchDemo(int,void*);
int main()
{
src = imread("D:/实验台/机器视觉/测试图片/焊接.jpg");
roi = imread("D:/实验台/机器视觉/测试图片/焊接目标.jpg");
if (src.empty())//如果src这个数据库属性为空
{
cout << "无法打开" << endl;
return -1;
}
imshow("原图", src);
imshow("模板", roi);
namedWindow("模板匹配",CV_WINDOW_AUTOSIZE);
createTrackbar("匹配算法类型","模板匹配",&method, MAXmethod, MatchDemo);
MatchDemo(0, 0);
waitKey(0);
return 0;
}
void MatchDemo(int, void*)
{
//设置相似性匹配结果矩阵result的大小
int width = src.cols - roi.cols + 1; //每行横向移动只需移动raw_img.cols - mask_img_cols + 1次
int height = src.rows - roi.rows + 1;//每列纵向移动只需移动raw_img.cols - mask_img.cols + 1次
Mat result(height, width,CV_32FC1);//矩阵类型设置为32浮点型单通道图片 便于后期进行模板匹配计算
//在Mat类型变量访问时下标是反着写的,即:按照(y, x)的关系形式访问
imshow("生成的矩阵模板result",result);
printf("src col=%d src row=%d \n roi col=%d roi row=%d \n result col=%d result row=%d \n ", src.cols, src.rows, roi.cols, roi.rows, result.cols, result.rows);
matchTemplate(src,roi,result,method,Mat());//模板匹配
//模板目标匹配函数
//image:待匹配的源图像 必须是8位整数或32位浮点图像
//temp:匹配模板图像 必须不大于源图像并具有相同的数据类型
//result:保存计算出的每一个位置的相关系数结果的矩阵(通过minMaxloc函数确认矩阵的最大值和最小值) 必须是单通道32位浮点 如果image的尺寸为W x H,templ的尺寸为w x h,则result的尺寸为(W-w+1)x(H-h+1)
//模板匹配的算法
//掩膜 选取需要处理的矩阵范围 此处默认为不进行掩膜操作
imshow("未进行归一化的相关系数图", result);
//将模板匹配的相关系数归一化到0-1之间(适配模板匹配方法的阈值范围)
normalize(result,result,0,1,NORM_MINMAX,-1,Mat());
imshow("进行归一化的相关系数图", result);
//寻找最小值的位置和最大值的位置
Point minloc;//相关系数最小值的坐标
Point maxloc;//相关系数最大值的坐标
Point roiloc;//画矩形时坐标的最终选择位置
double min, max;
minMaxLoc(result, &min, &max, &minloc, &maxloc, Mat());
//在一个数组中找到全局最小值和全局最大值(此案例中我们给定的是一个保存每一个位置的相关系数结果的矩阵)
//result-输入的给定矩阵(之前匹配好的矩阵结果 单通道图像)任意单通道图像的图片都可以(src.[0,mask] 还可以设置掩膜)多通道图像在使用minMaxLoc()函数是不能给出其最大最小值坐标的 因为每个像素点其实有多个坐标
//min-参数表示返回的最小值,如果不需要,则使用NULL
//max-参数表示返回的最大值,如果不需要,则使用NULL
//minloc- 参数表示返回的最小位置的指针(在2D情况下) 如果不需要,则使用NULL
//maxloc-参数表示返回的最大位置的指针 (在2D情况下) 如果不需要,则使用NULL
//Mat()-建立掩膜 默认不建立掩膜
printf("显示返回的最小值和最大值min=%1f,max=%1f",min,max);//double的格式说明符为 1f
//此案例中 返回的min为0 max为1
/*
TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
TM_CCORR:计算相关性,计算出来的值越大,越相关
TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
*/
//因为这六种计算方法中 只有 CV_TM_SQDIFF和CV_TM_SQDIFF_NORMED是值越小越相关
if (method == CV_TM_SQDIFF || method == CV_TM_SQDIFF_NORMED)
{
//所以当使用的方法为CV_TM_SQDIFF或CV_TM_SQDIFF_NORMED时(0相关)
//选择返回相关性最小的坐标位置作为绘制矩形的坐标起点
roiloc = minloc;
}
else
{
//如果未使用这两个方法时(1相关)
//选择返回相关性最大的坐标位置指针作为绘制矩形的坐标起点
roiloc = maxloc;
}
printf("\n相关性最小的坐标位置 为 X=%d Y=%d", roiloc.x, roiloc.y);
printf("\n相关性最大的坐标位置 为 X=%d Y=%d", roiloc.x, roiloc.y);
printf("\n矩形绘制坐标起点为 X=%d Y=%d", roiloc.x, roiloc.y);
//对找到的位置点 进行几何形状矩形绘制
src.copyTo(dst);
rectangle(dst,Rect(roiloc.x,roiloc.y,roi.cols, roi.rows),Scalar(0,0,255),2,LINE_AA);//在原图上绘制矩形
rectangle(result, Rect(roiloc.x, roiloc.y, roi.cols, roi.rows), Scalar(0, 0, 255), 2, LINE_AA);//在相关性关系图上绘制矩形
//绘制矩形(目标图片,矩形(矩形顶点的X坐标位置,矩形顶点的Y坐标位置,矩形宽度,矩形高度),线框颜色,线宽,线类型)
//Point是对象类型,它有两个属性x, y,分别代表x, y坐标 所以我们可以用roiloc.x,roiloc.y确认绘制矩形的左上角的XY坐标
imshow("每一个位置的相关系数图",result);
imshow("模板匹配", dst);
}
基于模板匹配的焊缝识别
//模板匹配案例 交警识别
https://blog.csdn.net/qq_39861376/article/details/82191411?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase
matchTemplate()参数详解
函数原型
CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method );
image:待匹配的源图像
templ:模板图像
result:保存结果的矩阵,我们可以通过minMaxLoc() 确定结果矩阵的最大值和最小值的位置.
minMaxLoc()函数:查找全局最小和最大稀疏数组元素并返回其值及其位置
void minMaxLoc(const SparseMat& a, double* minVal,double* maxVal, int* minIdx=0, int* maxIdx=0);
a: 匹配结果矩阵
&minVal 和 &maxVal: 在矩阵 result 中存储的最小值和最大值
&minLoc 和 &maxLoc: 在结果矩阵中最小值和最大值的坐标.
method :模板匹配的算法
有以下六种:
enum { TM_SQDIFF=0, TM_SQDIFF_NORMED=1, TM_CCORR=2, TM_CCORR_NORMED=3, TM_CCOEFF=4, TM_CCOEFF_NORMED=5 };
TM_SQDIFF,TM_SQDIFF_NORMED匹配数值越低表示匹配效果越好,其它四种反之。
TM_SQDIFF_NORMED,TM_CCORR_NORMED,TM_CCOEFF_NORMED是标准化的匹配,得到的最大值,最小值范围在0~1之间,其它则需要自己对结果矩阵归一化。
不同的方法会得到差异很大的结果,可以通过测试选择最合适的方法。
模板匹配详解
https://blog.csdn.net/KYJL888/article/details/81480670
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
https://www.jianshu.com/p/749e206fd15d