【opencv】自适应尺寸模板匹配

opencv自带的模板匹配常规做法:

1.转换灰度图

	cvtColor(img_template, img_template, CV_RGB2GRAY);
    cvtColor(org, org, CV_RGB2GRAY);

2.matchTemplate模版匹配
matchTemplate(const CvArr* image, //待搜索图像
constCvArr* templ, //模板图像
CvArr* result, //匹配结果
int method );//计算匹配程度的方法

关于参数 method:
CV_TM_SQDIFF平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED归一化平方差匹配法
CV_TM_CCORR_NORMED归一化相关匹配法
CV_TM_CCOEFF_NORMED归一化相关系数匹配法

Mat result;
result.create(org.dims,org.size,org.type());
matchTemplate(org, img_template, result, 0);

3.minMaxLoc寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置.
void minMaxLoc( const Mat& src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, const Mat& mask=Mat() );
函数的形参有的是指针类型,这样是为了传递最大值和最小值

 Point minPoint;
 Point maxPoint;
 double *minVal ;
 double *maxVal ;
 minMaxLoc(result, minVal,maxVal,&minPoint,&maxPoint);
  1. 显示匹配后图像:
 Rect rect(minPoint.x,minPoint.y,template_cols,template_rows);
 Mat image = org.clone();
 rectangle(image,rect,Scalar(0,0,255));
 imshow("window",image);
 waitKey(0);

matchTemplate模版匹配,检测图像中标注的匹配区域与模版的尺寸大小一致;若是目标在检测图像中的大小比例不定(如拍摄距离的远近),若是想要得到较好的匹配效果,则必须准备出各个尺寸大小的模版,每次选择出比较吻合的模版,也显然是非常不合适的;
项目中,目标物体的拍摄距离不固定,最近距离拍摄与最远距离拍摄,目标在不同距离拍摄图像中的尺寸可能相差多达一倍;
因此有一个自适应尺寸模版匹配的想法:
1.载入模版图像,令它循环每次缩放一定比例,再进行模版匹配;
2.得到了在模版不同缩放比例下的多个匹配后的roi图像,对所有得到的roi图像与初始的模版图像一一进行相似度比较,从中选出相似度最高的匹配图像,还可以得到最佳匹配度的缩放因子(这是我这个算法的主要目的,得到缩放因子,从而可以判断目标物体与摄像头的距离,作为重要参数供项目使用)

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;


//相似度匹配算法之灰度值方差匹配法:
double get_variance(Mat&a ,Mat&b)
{
    if(a.rows!=b.rows || a.cols != b.cols ||a.channels()!=b.channels())
    {
        printf("not the same size!\n");
        return 0;
    }

    //处理图像相似度
    //1.求出每一行到灰度值均值,加入容器,作为特征值;
    //2.求出灰度值总平均值与每行平均值的方差;
    //3.行行比较与模版方差的接近程度
    
    
    vector<double> variance_a;
    vector<double> variance_b;
    double var_a =0;
    double var_b =0;
    double sum_a =0;
    double sum_b =0;
    double mean_a;
    double mean_b;
    double sum_variance=0.0;
    //将每行灰度值均值存入容器
    for(int i=0; i<a.rows; i++){
         mean_a =0;
         mean_b =0;
        for(int j=0; j< a.cols; j++){
            mean_a += a.at<uchar>(i,j);
            mean_b += b.at<uchar>(i,j);
        }
        mean_a /=(double)(a.rows*a.cols);
        mean_b /=(double)(a.rows*a.cols);
        sum_a += mean_a;
        sum_b += mean_b;
        variance_a.push_back(mean_a);
        variance_b.push_back(mean_b);
    }
    //全图灰度值均值
    mean_a = sum_a / (double)variance_a.size();
    mean_b = sum_b / (double)variance_b.size();
    //灰度值方差之差累加
    for(int i =0; i<variance_a.size(); i++){
        var_a = (variance_a[i] - mean_a)*(variance_a[i] - mean_a);
        var_b = (variance_b[i] - mean_b)*(variance_b[i] - mean_b);
        sum_variance += abs(var_a - var_b);
    }
    
    return sum_variance;
}




int main(int argc, const char * argv[])
{
	//加载图像
	Mat org = imread("------");
	Mat my_template = imread("----------");
	cvtColor(my_template, my_template, CV_RGB2GRAY);
    cvtColor(org, org, CV_RGB2GRAY);

	
	int best_index ;	//存储最佳匹配的序号
    double  min_diff;	//存储最小的方差值之差
    Rect best_rect;		//存储最佳的匹配框
	//循环缩放,当前模版为最大尺寸,每次循环缩小5%,循环10次
	for(int index =0; index <10; index ++)
	{
		//获得缩放后的模版
		Mat temp_template = my_template.clone();
        int new_rows =my_template.rows - index * 0.05*my_template.rows;
        int new_cols =my_template.cols - index * 0.05 *my_template.cols;
        resize(temp_template, temp_template, Size(new_cols,new_rows));
		
		//模版匹配
		Mat result;
        result.create(org.dims,org.size,org.type());
        matchTemplate(org, temp_template, result, 0);
		
		//获取模版匹配得到的rect
		Point minPoint;
        Point maxPoint;
        double *minVal ;
        double *maxVal ;
        minMaxLoc(result, minVal,maxVal,&minPoint,&maxPoint);
        Rect rect(minPoint.x,minPoint.y,new_cols,new_rows);
	
		//显示
		Mat image_show = org.clone();
		rectangle(image_show,rect,Scalar(0,0,255));
		imshow("window",image_show);
		waitkey(0);
		
		//获取匹配部分的roi图像
		Mat result_img = org.clone();
		Mat result_img_roi =result_img(rect);
		//相似度比较部分:
		//比较相似度的算法很多,各有所长,这里用的是一个灰度值方差的相似度比较
		//variance_diff表示灰度值方差,方差越小,相似度越高;
		double variance_diff = get_variance(result_img_roi,temp_template) ;
		
		//默认值为index=0时获取的值;方便与之后的值最比较
		if(index == 0){
            min_diff = variance_diff ;
            best_index = index;
            best_rect = rect;
        }
        //当前值与目前的最小方差做比较
        if(variance_diff < min_diff ){
            min_diff = variance_diff ;
            best_index = index;
            best_rect = rect;
        }
	}//for
	
	Mat image_show = org.clone();
	rectangle(org, best_rect, Scalar(0,255,0),3);
    imshow("result",org);
    waitKey(0);
}

上效果图:

大模版匹配小目标:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
相似度比较结果:
在这里插入图片描述

大模版匹配大目标(模版图片没有更换):

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述


后记:

这是我刚接触图像算法不久的时候写的,现在感觉有点幼稚,只是在正常模板匹配中加入了一个循环缩放。实际上有非常多更好的方式来达到相同的效果,比如深度学习中的目标检测。
后面推荐一些:

1.opencv-cascade 级联分类器
参考博客:关于opencv-CascadeClassifier(级联分类器)的初步认识

2.yolo目标检测
参考博客:
【darknet-yolo系列】在window10下安装GPU版的darknet

【darknet-yolo系列】yolov3 训练模型操作流程(包含所有资源下载)

  • 13
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
OpenCV是一个开源计算机视觉库,提供了丰富的图像处理和计算机视觉算法。其中之一是多角度模板匹配,用于在图像中寻找多个不同角度的模板。 多角度模板匹配是指对于给定的一个模板图像,通过在输入图像上不同的旋转角度下进行匹配,以找到与模板最相似的图像区域。该过程包含以下步骤: 1. 选择模板图像:首先需要选择一个具有代表性的模板图像,作为模板匹配的目标。模板可以是任何感兴趣的对象或特征。 2. 生成旋转图像:使用旋转矩阵,可以将模板图像在指定的角度范围内进行旋转。这样可以生成一系列旋转后的模板图像。 3. 模板匹配:对于旋转后的每一个模板图像,使用OpenCV提供的模板匹配函数,例如cv2.matchTemplate(),在输入图像上进行匹配操作。该函数会给出每个匹配区域的相似度得分。 4. 寻找最佳匹配:对于每个旋转角度,找到最高的相似度得分及其对应的匹配位置,即为最佳匹配结果。 5. 显示结果:根据最佳匹配结果的位置信息,在原始图像上绘制矩形框或其他标记,以显示匹配的位置。 从原理上来说,多角度模板匹配关键是旋转矩阵的生成和模板匹配的实现。旋转矩阵的生成可以使用OpenCV的cv2.getRotationMatrix2D()函数,该函数可以设置旋转中心和旋转角度,输出旋转矩阵。模板匹配可以使用OpenCV的cv2.matchTemplate()函数,该函数可以选择不同的匹配方法(如平方差匹配、相关性匹配、归一化相关性匹配)。 总结来说,通过OpenCV的多角度模板匹配功能,可以方便地在图像中寻找目标对象在不同角度下的位置,用于目标检测、目标识别、姿态估计等应用。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值