opencv学习笔记(三十二)模板匹配

模板匹配的工作方式
模板匹配的工作方式跟直方图的反向投影基本一样,大致过程是这样的:通过在输入图像上滑动图像块对实际的图像块和输入图像进行匹配。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)用临时图像和模板图像进行对比,对比结果记为c;
(3)对比结果c,就是结果图像(0,0)处的像素值;
(4)切割输入图像从(0,1)至(10,11)的临时图像,对比,并记录到结果图像;
(5)重复(1)~(4)步直到输入图像的右下角。
大家可以看到,直方图反向投影对比的是直方图,而模板匹配对比的是图像的像素值;模板匹配比直方图反向投影速度要快一些,但是我个人认为直方图反向投影的鲁棒性会更好。
参考的是:
http://www.cnblogs.com/xrwang/archive/2010/02/05/MatchTemplate.html

cvMatchTemplate()函数
http://www.lxway.com/914114412.htm
定义:
void cvMatchTemplate(
const CvArr* image,
const CvArr* templ,
CvArr* result, int method
);
参数:
image:欲搜索的图像。它应该是单通道、8-比特或32-比特 浮点数图像
templ :搜索模板,不能大于输入图像,且与输入图像具有一样的数据类型
result :比较结果的映射图像。单通道、32-比特浮点数.。如果图像是 W×H 而 templ 是 w×h ,则 result 一定是 (W-w+1)×(H-h+1)。
所以在下面的程序中,才会有
int iwidth = src->width - temp1->width + 1;
int iheight = src->height - temp1->height + 1;
method 指定匹配方法:
在OpenCv和EmguCv中支持以下6种对比方式:
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
根据我的测试结果来看,上述几种匹配方式需要的计算时间比较接近(跟《学习OpenCv》书上说的不同),我们可以选择一个能适应场景的匹配方式。

cvMinMaxLoc()函数
通过使用 cvMinMaxLoc函数,我们确定结果矩阵 R 的最大值和最小值的位置。cvMinMaxLoc()必须对单通道做处理。
函数中的参数有:
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
格式:
cvMinMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
result: 匹配结果矩阵
&minVal 和 &maxVal: 在矩阵 result 中存储的最小值和最大值。该值是矩阵中的最大值和最小值。
&minLoc 和 &maxLoc: 在结果矩阵中最小值和最大值的坐标.
Mat(): 可选的掩模

程序实例:
代码来自:
http://www.lxway.com/914114412.htm

#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>

using namespace std;

void GetHSV(const IplImage *image,IplImage **h,IplImage **s,IplImage **v);

int main()
{
    IplImage *src = cvLoadImage("t1.jpg");
    IplImage *h_src = NULL ,*s_src = NULL;
    GetHSV(src,&h_src,&s_src,NULL);
    IplImage *images[] = {h_src,s_src};
    CvHistogram *hist_src;
    {//计算二维直方图
        int dims = 2;
        int size[] = {30,32}; // 这个地方不要取的太大!
        float range_h[] = {0,180} 
//再用cvCvtColor转换时h已经归一化到180了
        ,range_s[] = {0,256};
        float *ranges[] = {range_h,range_s};
        hist_src = cvCreateHist(dims,size,CV_HIST_ARRAY,ranges);
        cvCalcHist(images,hist_src);
        cvNormalizeHist(hist_src,1);
    }

    IplImage *dst = cvLoadImage("t2.jpg");
    IplImage *h_dst = NULL,*s_dst = NULL;
    GetHSV(dst,&h_dst,&s_dst,NULL);
    images[0] = h_dst ,images[1] = s_dst; 

    CvSize patch_size = cvSize(src->width,src->height);
    IplImage *result = cvCreateImage(cvSize(h_dst->width - patch_size.width +1,h_dst->height - patch_size.height +1)
        ,IPL_DEPTH_32F,1);//块搜索时处理边缘是直接舍去,故result的大小比dst小path_size大小
    //32F类型,取值为0~1最亮为1,可直接显示
    //CV_COMP_CORREL相关度,1时最匹配,0时最不匹配
    cvCalcBackProjectPatch(images,result,patch_size,hist_src,CV_COMP_CORREL,1);
    cvShowImage("result",result);
    //找出最大值位置,可得到此位置即为杯子所在位置
    CvPoint max_location;
    cvMinMaxLoc(result,NULL,NULL,NULL,&max_location,NULL);
    //加上边缘,得到在原始图像中的实际位置    
    max_location.x += cvRound(patch_size.width/2);
    max_location.y += cvRound(patch_size.height/2);
    //在dst图像中用红色小圆点标出位置——小圆点就表示杯子所在区域
    cvCircle(dst,max_location,3,CV_RGB(255,0,0),-1);

    cvShowImage("dst",dst);
    cvWaitKey();

    cvReleaseImage(&src);
    cvReleaseImage(&dst);
    cvReleaseImage(&h_src);
    cvReleaseImage(&h_dst);
    cvReleaseImage(&s_dst);
    cvReleaseImage(&s_src);
    cvReleaseHist(&hist_src);
    cvReleaseImage(&result);
    cvDestroyAllWindows();
}

void GetHSV(const IplImage *image , IplImage **h,IplImage **s,IplImage **v)
{
    IplImage *hsv = cvCreateImage(cvGetSize(image),8,3);
    cvCvtColor(image,hsv,CV_BGR2HSV);

    if((h != NULL) && (*h == NULL))
        *h = cvCreateImage(cvGetSize(image),8,1);
    if((s != NULL) && (*s == NULL))
        *s = cvCreateImage(cvGetSize(image),8,1);
    if((v != NULL) && (*v == NULL))
        *v = cvCreateImage(cvGetSize(image),8,1);


    cvSplit(hsv,*h,(s == NULL)?NULL:*s,(v==NULL)?NULL:*v,NULL);
    cvReleaseImage(&hsv);
}

运行结果
用到的图片和上一个实验一样,就不传了。最终结果是用红色的小圆点标记出杯子的位置。

猜你喜欢

转载自blog.csdn.net/u014751607/article/details/60866308