opencv(19)---模板匹配及应用

本文介绍模板匹配技术的基本概念、应用场景及实现方法。重点讲解OpenCV中的matchTemplate()函数使用细节,包括不同匹配方法的选择、结果图像的归一化处理及匹配结果的定位。并提供单模板、视频模板和多模板匹配的实现案例。
摘要由CSDN通过智能技术生成

基本概念

模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。模板匹配不是基于直方图的, 而是通过在输入图像上滑动图像块(模板)同时比对相似度, 来对模板和输入图像进行匹配的一种方法。

缺点

(1)不适应角度变换和旋转
(2)不适应尺度变换

这里写图片描述

应用

①目标查找定位
②运动物体跟踪
③其他…

模板匹配—matchTemplate()

函数原型

void matchTemplate( InputArray image, InputArray templ,
                    OutputArray result, int method, InputArray mask = noArray() );
  • image: 待搜索图像(大图)
  • templ: 搜索模板, 需和原图一样的数据类型且尺寸不能大于源图像
  • result: 比较结果的映射图像, 其必须为单通道, 32位浮点型图像, 如果原图(待搜索图像)尺寸为W x H, 而templ尺寸为 w x h, 则result尺寸一定是(W-w+1)x(H-h+1)
  • method: 指定的匹配方法, 有如下6种:
    CV_TM_SQDIFF——平方差匹配法(最好匹配0)
    CV_TM_SQDIFF_NORMED——归一化平方差匹配法(最好匹配0)
    CV_TM_CCORR——相关匹配法(最坏匹配0)
    CV_TM_CCORR_NORMED——归一化相关匹配法(最坏匹配0)
    CV_TM_CCOEFF——系数匹配法(最好匹配1)
    CV_TM_CCOEFF_NORMED——化相关系数匹配法(最好匹配1)
    这里写图片描述

通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价). 最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案.

矩阵归一化—normalize()

函数原型

void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
                int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
  • src: 输入原图像, Mat类型
  • dst: 输出结果图像, 需要和原图一样的尺寸和类型
  • alpha: 归一化后的最小值, 默认值1
  • beta:归一化后的最大值, 默认值0
  • norm_type: 归一化类型, 可选NORM_INF, NORM_L1, NORM_L2(默认)等
  • dtype: 默认值-1, 此参数为负值时, 输出矩阵和src有同样类型
  • mask: 可选的掩码操作

寻找最值—minMaxLoc()

函数原型

void minMaxLoc(InputArray src, CV_OUT double* minVal,
                            CV_OUT double* maxVal = 0, CV_OUT Point* minLoc = 0,
                            CV_OUT Point* maxLoc = 0, InputArray mask = noArray());

作用是:在数组中找到全局最大值和最小值

  • src: 输入原图像, 单通道图像
  • minVal: 返回最小值的指针, 若无需返回, 则设置0
  • maxVal: 返回最大值的指针, 若无需返回, 则设置0
  • minLoc: 返回最小位置的指针,若无需返回, 则设置0
  • maxLoc:返回最大位置的指针,若无需返回, 则设置0
  • mask: 可选的掩码操作

单模版匹配

步骤

1.创建结果映射图片
需要计算出结果映射图片的行和列数
(1)结果映射图片的宽

int width=src.cols-temp.cols+1;//result宽度

(2)结果映射图片的高

int height=src.rows-temp.rows+1;//result高度

(3)创建结果映射图片

Mat result(height,width,CV_32FC1);

Mat的构造函数

Mat(int rows, int cols, int type);

2.化相关系数匹配

matchTemplate(src,temp,result,CV_TM_CCOEFF_NORMED);//化相关系数匹配最佳值

3.归一化系数

normalize(result,result,0,1,NORM_MINMAX,-1);//归一化0到1

4.获得矩阵中的最大最小值

minMaxLoc(result,&minValue,&maxValue,&minLoc,&maxLoc);//获得矩阵中的最大值和最小值及其位置

代码

Mat temp=imread("D:\\1\\temp.png");
Mat src=imread("D:\\1\\src.png");
Mat dst=src.clone();//对原图的备份
imshow("temp",temp);
imshow("src",src);

int width=src.cols-temp.cols+1;//result宽度
int height=src.rows-temp.rows+1;//result高度

Mat result(height,width,CV_32FC1);//创建结果映射图像
matchTemplate(src,temp,result,CV_TM_CCOEFF_NORMED);//化相关系数匹配最佳值
imshow("result",result);


normalize(result,result,0,1,NORM_MINMAX,-1);//归一化0到1

double minValue,maxValue;
Point minLoc,maxLoc;
minMaxLoc(result,&minValue,&maxValue,&minLoc,&maxLoc);//获得矩阵中的最大值和最小值及其位置

cout<<"minValue:"<<minValue<<endl;
cout<<"maxValue:"<<maxValue<<endl;

rectangle(dst,maxLoc,Point(maxLoc.x+temp.cols,maxLoc.y+temp.rows),Scalar(0,255,0),2,8);
imshow("dst",dst);
waitKey(0);

视频模版匹配

代码

Mat frame;
Mat templateImg = imread("D:\\1\\green.jpg");
Mat resultImg;
VideoCapture cap("D:\\1\\1.mp4");
if(!cap.isOpened())
return;
int resultImg_cols;
int resultImg_rows;

while(1)
{
cap>>frame;
//判断视频有没有读完
if(frame.empty())
   break;
Mat showImg = frame.clone();

//设置result图像
resultImg_cols = frame.cols -  templateImg.cols + 1;
resultImg_rows = frame.rows -  templateImg.rows + 1;
resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);

//模版匹配
matchTemplate(frame, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //化相关系数匹配法(最好匹配1)
//归一化
normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1);

double minValue, maxValue;
Point minLoc, maxLoc;
Point matchLoc;
//寻找最大最小
minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);
//cout<<"max_value= "<<maxValue<<endl;
//cout<<"min_value= "<<minValue<<endl;
//设定匹配程度
if(maxValue>=0.7)
   rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);

imshow("frame", frame);
imshow("result", showImg);
if(27 == waitKey(10))
   break;
}

destroyAllWindows();

运行结果

这里写图片描述

多模版匹配–方式1

代码

Mat srcImg = imread("D:\\1\\src.png");
Mat templateImg = imread("D:\\1\\temp.png");
Mat resultImg;
Mat showImg = srcImg.clone();

int resultImg_cols = srcImg.cols -  templateImg.cols + 1;
int resultImg_rows = srcImg.rows -  templateImg.rows + 1;

resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);
matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //化相关系数匹配法(最好匹配1)
normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1);
Mat midImg = resultImg.clone();



//多目标模板匹配---方法一
double matchValue;
int count0=0;
int tempW=0, tempH=0;
char matchRate[10];

//将resultImage中的像素进行逐个判断
for(int i=0; i<resultImg_rows; i++)
{
    for(int j=0; j<resultImg_cols; j++)
    {   
        //获取匹配系数
        matchValue = resultImg.at<float>(i, j);
        //往matchRate中输入此像素的matchValue
        sprintf(matchRate, "%0.2f", matchValue);
        //设置满足条件
        if(matchValue>=0.85 && (abs(j - tempW)>5) && (abs(i - tempH)>5) )
        {
            count0++;
            putText(showImg, matchRate, Point(j-5, i-5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);
            rectangle(showImg, Point(j, i), Point(j + templateImg.cols, i + templateImg.rows), Scalar(0, 255, 0), 2);
            tempW = j;
            tempH = i;
        }
    }
}
cout<<"count="<<count0<<endl;
imshow("resultImg", resultImg);
imshow("dst", showImg);

运行结果

这里写图片描述

这里写图片描述

知识点讲解

1.

 if(matchValue>=0.85 && (abs(j - tempW)>5) && (abs(i - tempH)>5) )

用于限制条件。如果对后面的abs不加限制,出来的效果如下
这里写图片描述

多模板匹配–方式2

代码

Mat srcImg = imread("D:\\1\\src.png");
 Mat templateImg = imread("D:\\1\\temp.png");
 Mat resultImg;
 Mat showImg = srcImg.clone();

 int resultImg_cols = srcImg.cols -  templateImg.cols + 1;
 int resultImg_rows = srcImg.rows -  templateImg.rows + 1;

 resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);
 matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //化相关系数匹配法(最好匹配1)
 normalize(resultImg, resultImg, 0, 1, NORM_MINMAX, -1);
 Mat midImg = resultImg.clone();



 //多目标模板匹配---方法二
 double minValue, maxValue;
 Point minLoc, maxLoc;
 Point matchLoc;
 char matchRate[10];

 minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);
 cout<<"max_value= "<<maxValue<<endl;
 sprintf(matchRate, "%0.2f", maxValue);
 putText(showImg, matchRate, Point(maxLoc.x - 5, maxLoc.y - 5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);
 rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);

 for(int i=0; i<100; i++)
 {
     int startX = maxLoc.x - 4;
     int startY = maxLoc.y - 4;
     int endX = maxLoc.x + 4;
     int endY = maxLoc.y + 4;
     if(startX<0 || startY<0)
     {
         startX = 0;
         startY = 0;
     }
     if(endX > resultImg.cols - 1 || endY > resultImg.rows - 1)
     {
         endX = resultImg.cols - 1;
         endY = resultImg.rows- 1;
     }
     Mat temp = Mat::zeros(endX - startX, endY - startY, CV_32FC1);
     //Mat ROI = resultImg(Rect(Point(startX, startY), temp.cols, temp.rows));
     temp.copyTo(resultImg(Rect(startX, startY, temp.cols, temp.rows)));
     minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);
     if(maxValue<0.8)
         break;

     cout<<"max_value= "<<maxValue<<endl;
     sprintf(matchRate, "%0.2f", maxValue);
     putText(showImg, matchRate, Point(maxLoc.x - 5, maxLoc.y - 5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);
     rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);

 }
 imshow("midImg", midImg);
 imshow("resultImg", resultImg);
 imshow("dst", showImg);

 waitKey(0);

运行结果

这里写图片描述

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值