QT+opencv学习笔记(6)——模板匹配

开发环境为:win10+QT5.8+opencv3.2 

        把不同传感器或同一传感器在不同时间、不同成像条件下对同一景物获取的两幅或多幅图像在空间上对准,或根据已知模式到另一幅图中寻找相应模式的处理方法叫做模板匹配。

        模板匹配的思想很简单:拿已知的模板,和原图像中同样大小的一块区域去对比。最开始时,模板的左上角点和图像的左上角点是重合的,将模板和原图像中同样大小的一块区域去对比,然后平移到下一个像素,仍然进行相同的操作,所有的位置都对比完后,差别最小的那一块区域就是要找的目标。

        opencv通过matchTemplate()函数实现模板匹配。matchTemplate()函数有六种模板匹配算法。分别为:

        1、平方差匹配 method=CV_TM_SQDIFF
        这种方法利用平方差来进行匹配,最好匹配为0。匹配越差,匹配值越大。

        2、标准平方差匹配 method=CV_TM_SQDIFF_NORMED
        3、相关匹配 method=CV_TM_CCORR
        这种方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果。
        4、标准相关匹配 method=CV_TM_CCORR_NORMED
        5、相关匹配 method=CV_TM_CCOEFF
        这种方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。
        在这里
        6、标准相关匹配 method=CV_TM_CCOEFF_NORMED
        对于平方差匹配和标准平方差匹配,越小的数值代表更好的匹配结果;而对于其他四种方法, 数值越大匹配效果越好。
        通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价)。 最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案。

        matchTemplate()函数的定义如下:

void matchTemplate(InputArray image,   //输入图像,类型为CV_8F或CV_32F
                   InputArray temp,    //模板图像,与输入图像类型相同
                   OutputArray result, //匹配结果,类型为CV_32FC1,如果输入图像大小为W * H,模板大小为w * h , 则结果大小为(W-w+1)*(H-h+1)
                   int method          //匹配算法
                   )
        主要代码如下:
#include <QCoreApplication>
#include"cv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

// 全局变量
Mat img;
Mat templ;
Mat result;
const String image_window = "Source Image";
const String result_window = "Result window";

int match_method;
const int max_Trackbar = 5;

// 函数声明
void MatchingMethod( int, void* );
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 载入原图像和模板
    img = imread("C://document//gray.bmp", IMREAD_GRAYSCALE );
    templ = imread("C://document//template.bmp", IMREAD_GRAYSCALE );
    imshow( "template", templ );
    // 创建窗口
    namedWindow( image_window, CV_WINDOW_AUTOSIZE );
    namedWindow( result_window, CV_WINDOW_AUTOSIZE );
    // 创建滑动条
    const String trackbar_label = "Method";
    createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );

    MatchingMethod( 0, 0 );

    waitKey(0);
    return a.exec();
}

/*Method
0: SQDIFF           平方差匹配
1: SQDIFF NORMED    标准平方差匹配
2: TM CCORR         相关匹配
3: TM CCORR NORMED  标准相关匹配
4: TM COEFF         相关匹配
5: TM COEFF NORMED" 标准相关匹配
*/

//滑动条回调函数
void MatchingMethod( int, void* )
{
  // 将被显示的原图像
  Mat img_display;
  img.copyTo( img_display );
  //cvtColor(img_display,img_display,CV_GRAY2BGR);

  // 创建输出结果的矩阵
  int result_cols =  img.cols - templ.cols + 1;
  int result_rows = img.rows - templ.rows + 1;

  result.create( result_cols, result_rows, CV_32FC1 );

  // 进行匹配和标准化
  matchTemplate( img, templ, result, match_method );
  normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );

  // 通过函数 minMaxLoc 定位最匹配的位置
  double minVal; double maxVal; Point minLoc; Point maxLoc;
  Point matchLoc;

  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );

  // 对于方法 SQDIFF 和 SQDIFF_NORMED, 越小的数值代表更高的匹配结果. 而对于其他方法, 数值越大匹配越好
  if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    { matchLoc = minLoc; }
  else
    { matchLoc = maxLoc; }

  //cvtColor(result,result,CV_GRAY2BGR);
  // 绘制匹配结果
  rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
  rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );

  imshow( image_window, img_display );
  imshow( result_window, result );

}
        匹配结果如下:

        从左至右依次为模板图像,输入图像,和匹配结果图。

        试验了六种方法,其中相关匹配 method=CV_TM_CCORR的匹配结果是错误的,结果如下:

        标准相关匹配 method=CV_TM_CCORR_NORMED的匹配结果是正确的。如下:

         可能是由于我们实际上仅仅考虑 “最匹配” 而没考虑其他可能的高匹配位置,实际做的过程中应该对达到一定阈值的高匹配的匹配结果再次进行筛选,确定最佳匹配位置。

猜你喜欢

转载自blog.csdn.net/minghui_/article/details/80668080