opencv笔记之模板匹配

来源:互联网 发布:当当读书网络连接失败 编辑:程序博客网 时间:2024/05/22 12:23

opencv笔记之模板匹配

原理:即从一幅图像中找出与给定模板最相似的部分,如图:



具体实现

1.以模板大小的框T,从原图左上角开始Z字型遍历,步长为一个像素,得到与原图大小一致的图像S;

2.利用相关匹配等五种方法之一计算原图中S与模板T相似性;

3.将2中计算的值生成一幅大小为(srcImg.width-Template.width+1)*(srcImg.height-Template.height+1)矩阵M。(其类型为浮点型)

4.搜索矩阵M中最大或最小的坐标为在原图上匹配的结果的起始坐标(即上图中白色框的左上角坐标)。

注:在上述中第3步中,我们利用下图来具体描述:


其中第一幅图为原图像S,第二幅图像模板图像T,第三幅图像为匹配结果生成的矩阵Res。

我们通过在原图S中截取与模板图像T大小一致的图像,(即4*4的S1与4*4的T1)通过计算其像素值与模板图像的相关匹配CV_TM_CCORR,得到其Res的第一个值,通过Z字型划窗,步长为1,分别计算相关匹配CV_TM_CCORR的值,即可生成矩阵Res;

算法python实现:

# -*- coding:utf-8 -*-"""@author:Leyon@file:test.py@time:2017/12/1312:22"""import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('lena1.jpg', 0)cv2.imshow('img',img)#cv2.imwrite("img.jpg",img)img2 = img.copy()template = cv2.imread('lena2.jpg', 0)cv2.imshow('template',template)#cv2.imwrite("template.jpg",template)w, h = template.shape[::-1]# All the 6 methods for comparison in a listmethods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']for meth in methods:    img = img2.copy()    method = eval(meth)    # Apply template Matching    res = cv2.matchTemplate(img, template, method)    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:        top_left = min_loc    else:        top_left = max_loc    bottom_right = (top_left[0] + w, top_left[1] + h)    cv2.rectangle(img, top_left, bottom_right, 255, 1)    plt.subplot(121), plt.imshow(res, cmap='gray')    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])    plt.subplot(122), plt.imshow(img, cmap='gray')    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])    plt.suptitle(meth)    plt.show()

五种方法对应的效果图:




C++实现:(其代码在opencv\sources\samples\cpp\tutorial_code\Histograms_Matching文件夹下)

/** * @file MatchTemplate_Demo.cpp * @brief Sample code to use the function MatchTemplate * @author OpenCV team */#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"#include <iostream>#include <stdio.h>using namespace std;using namespace cv;/// Global VariablesMat img; Mat templ; Mat result;const char* image_window = "Source Image";const char* result_window = "Result window";int match_method;int max_Trackbar = 5;/// Function Headersvoid MatchingMethod( int, void* );/** * @function main */int main( int, char** argv ){  /// Load image and template  //img = imread( argv[1], 1 );  //templ = imread( argv[2], 1 );  img = imread("lena.jpg", 1);  templ = imread("lena1.jpg", 1);  /// Create windows  namedWindow( image_window, WINDOW_AUTOSIZE );  namedWindow( result_window, WINDOW_AUTOSIZE );  /// Create Trackbar  const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";  createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );  MatchingMethod( 0, 0 );  waitKey(0);  return 0;}/** * @function MatchingMethod * @brief Trackbar callback */void MatchingMethod( int, void* ){  /// Source image to display  Mat img_display;  img.copyTo( img_display );  /// Create the result matrix  int result_cols =  img.cols - templ.cols + 1;  int result_rows = img.rows - templ.rows + 1;  result.create( result_cols, result_rows, CV_32FC1 );  /// Do the Matching and Normalize  matchTemplate( img, templ, result, match_method );  normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );  /// Localizing the best match with minMaxLoc  double minVal; double maxVal; Point minLoc; Point maxLoc;  Point matchLoc;  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );  /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better  if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )    { matchLoc = minLoc; }  else    { matchLoc = maxLoc; }  /// Show me what you got  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 );  return;}
如果想要单步调试,查看其具体函数实现,可以用Cmake编译Opencv的Sample查看其细节实现

:两个主要函数如下:或在OpenCV API Reference查询


五种计算模板相似性方法:


      总结:使用此类算法有一定的局限性,其用时过长,而且准确率也不高,例如上述效果图中,第一,三种方法匹配结果不准确;对于此类算法,我们也可以利用原图与模板的直方图进行对比,来实现匹配。比如,肤色检测中,我们利用肤色模板的H-S二维直方图,与原图的H-S二维直方图进行匹配。准确率应该会有一定程度的提高。