尝试用OpenCV的模板匹配来定位和检测

1.OpenCV的模板匹配函数:

CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ, OutputArray result, int method );

模板匹配的工作方式:
跟直方图的反向投影基本一样,大致过程是这样的:通过在输入图像image上滑动图像块,对实际的图像块和模板图像templ进行匹配。
假设我们有一张100x100的输入图像image,有一张10x10的模板图像templ,查找的过程是这样的:
(1)从输入图像image的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)用临时图像和模板图像templ进行对比,对比结果记为c,存储在结果图像result的(0,0)处,即result在(0,0)处的像素值;
(3)向右滑动切割图像块,重复(1)~(2)的步骤,并记录到结果图像result中;直到输入图像image的右下角。
可见,直方图反向投影对比的是直方图,而模板匹配对比的是图像的像素值;模板匹配比直方图反向投影速度要快一些,但是有人认为直方图反向投影的鲁棒性会更好。
模板匹配的匹配方式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 归一化相关系数匹配法

enum { TM_SQDIFF=0, TM_SQDIFF_NORMED=1, TM_CCORR=2, TM_CCORR_NORMED=3, TM_CCOEFF=4, TM_CCOEFF_NORMED=5 };

2.OpenCV的定位极值的函数:

CV_EXPORTS_W 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());

简要说明:
(1)minMaxLoc寻找矩阵src中最小值minVal及其位置minLoc;最大值maxVal及其位置maxLoc。
(2)以上参数,若不需要求解,可置为NULL或者0即可。
(3)参数mask不晓得用法,可以忽略不管。

3.示例程序:

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

using namespace cv;
using namespace std;

vector<float> Match(const Mat& src, const Mat& obj, vector<Rect>& rect, int type, int num = 1);

void main()
{
    Mat src = imread("F:\\Test\\LaLa.png");
    Mat obj = imread("F:\\Test\\LaLa0.png");
    namedWindow("Match");   imshow("Match", obj);

    Mat src0 = src.clone(), dst;
    //cvtColor(src, src, CV_BGR2GRAY);
    //cvtColor(obj, obj, CV_BGR2GRAY);
    //normalize(src, src, 0, 255, NORM_MINMAX);
    //normalize(obj, obj, 0, 255, NORM_MINMAX);

    namedWindow("Result");  int type = 0, num = 1;
    createTrackbar("Type", "Result", &type, 5);
    createTrackbar("Number", "Result", &num, 5);

    vector<Rect> rect;  vector<float> pro;
    while ((waitKey(500) & 255) != 13)
    {
        dst = src0.clone();
        pro = Match(src, obj, rect, type, num);
        for (int i = 0; i < num; ++i)
        {
            rectangle(dst, rect[i], Scalar(0,255,0), 2);
            cout << i << "\t" << rect[i] << "\t" << pro[i] << endl;
            Point center(rect[i].x + rect[i].width/2, rect[i].y + rect[i].height/2);
            circle(dst, center, 4, Scalar(0, 255, 0), -1);
        }//end for
        imshow("Result", dst);  cout << endl;
    }//end while
}//end main

vector<float> Match(const Mat& src, const Mat& obj, vector<Rect>& rect, int type, int num)
{
    Mat dst;
    matchTemplate(src, obj, dst, type);
    normalize(dst, dst, 0, 255, NORM_MINMAX);

    vector<float> pro;  rect.clear();
    double mx = 0;  Point loc, pre(-1, -1);
    for (int i = 0; i < num;)
    {
        minMaxLoc(dst, NULL, &mx, NULL, &loc);
        if (abs(loc.x - pre.x) > 10 && abs(loc.y - pre.y) > 10)
        {
            rect.push_back(Rect(loc.x, loc.y, obj.cols, obj.rows));
            pro.push_back(mx/255);  pre = loc;  ++i;
        }//end if
        dst.at<float>(loc.y, loc.x) = 0;    mx = 0;
    }//end for
    return pro;
}//end Match

这里写图片描述

猜你喜欢

转载自blog.csdn.net/CosmosHua/article/details/72829779