Image Processing22(Template Matching )

Goal

In this tutorial you will learn how to:

  • Use the OpenCV function matchTemplate() to search for matches between an image patch and an input image
  • 使用OpenCV函数matchTemplate()寻找与输入图像匹配的部分
  • Use the OpenCV function minMaxLoc() to find the maximum and minimum values (as well as their positions) in a given array.
  • 使用OpenCV函数minMaxLoc()来查找给定数组中的最大值和最小值(以及它们的位置)。

Theory

What is template matching?

Template matching is a technique for finding areas of an image that match (are similar) to a template image (patch).

模板匹配是一种用于查找与模板图像匹配(相似)的图像区域的技术。

While the patch must be a rectangle it may be that not all of the rectangle is relevant. In such a case, a mask can be used to isolate the portion of the patch that should be used to find the match.

虽然补丁必须是矩形,但可能并非所有的矩形都是相关的。

How does it work?

We need two primary components:

  1. Source image (I): The image in which we expect to find a match to the template image
  2. 我们期望找到与模板图像匹配的图像
  3. Template image (T): The patch image which will be compared to the template image
  4. 将与模板图像进行比较的补丁图像

our goal is to detect the highest matching area:我们的目标是检测最高的匹配区域:

                                       Template_Matching_Template_Theory_Summary.jpg

To identify the matching area, we have to compare the template image against the source image by sliding it:

为了识别匹配区域,我们必须通过滑动比较模板图像和源图像(很笨蛋的方法)

                                            Template_Matching_Template_Theory_Sliding.jpg

By sliding, we mean moving the patch one pixel at a time (left to right, up to down). At each location, a metric is calculated so it represents how "good" or "bad" the match at that location is (or how similar the patch is to that particular area of the source image).

通过滑动,我们的每次将补丁移动一个像素(从左到右,从上到下)。在每个位置,都会计算度量标准,以表示该位置匹配的“好”或“差”(或者该补丁与源图像的特定区域有多相似)。

For each location of T over I, you store the metric in the result matrix R. Each location (x,y) in R contains the match metric:

对于每个位置T超过I,则存储在该度量结果矩阵 R R中的每个位置包含匹配度量:(x,y)

                                                  Template_Matching_Template_Theory_Result.jpg

the image above is the result R of sliding the patch with a metric TM_CCORR_NORMED. The brightest locations indicate the highest matches. As you can see, the location marked by the red circle is probably the one with the highest value, so that location (the rectangle formed by that point as a corner and width and height equal to the patch image) is considered the match.

以上的图像是结果是补丁滑动,且度量参数采用的是TM_CCORR_NORMED最亮的位置表示最高的匹配。正如你所看到的,由红色圆圈标记的位置可能是具有最高值的位置,所以位置(由该点作为中心形成的矩形,并且宽度和高度等于补丁图像)被认为是最匹配。

In practice, we locate the highest value (or lower, depending of the type of matching method) in the R matrix, using the function minMaxLoc()

在实践中,我们使用函数minMaxLoc()定位R矩阵中的最高值(或更低,取决于匹配方法的类型

How does the mask work?

  • If masking is needed for the match, three components are required:
    1. Source image (I): The image in which we expect to find a match to the template image
    2. 我们期望找到与模板图像匹配的图像
    3. Template image (T): The patch image which will be compared to the template image
    4. 将与模板图像进行比较的补丁图像
    5. Mask image (M): The mask, a grayscale image that masks the template
    6. 掩码模板的灰度图像

Only two matching methods currently accept a mask: CV_TM_SQDIFF and CV_TM_CCORR_NORMED (see below for explanation of all the matching methods available in opencv).

目前只有两个匹配的方法接受掩码:CV_TM_SQDIFF和CV_TM_CCORR_NORMED(有关opencv中所有可用匹配方法的说明,请参见下文)

The mask must have the same dimensions as the template

MASK必须与模板具有相同的尺寸

The mask should have a CV_8U or CV_32F depth and the same number of channels as the template image. In CV_8U case, the mask values are treated as binary, i.e. zero and non-zero. In CV_32F case, the values should fall into [0..1] range and the template pixels will be multiplied by the corresponding mask pixel values. Since the input images in the sample have the CV_8UC3 type, the mask is also read as color image.

掩模应具有CV_8U或CV_32F深度,并且与模板图像具有相同数量的通道。在CV_8U情况下,掩码值被视为二进制,即零和非零。在CV_32F情况下,值应该落入[0..1]范围内,并且模板像素将乘以相应的MASK像素值。由于样本中的输入图像具有CV_8UC3类型,因此掩码也会被读取为彩色图像。

应注意区别tpye和depth.


                                         Template_Matching_Mask_Example.jpg


Which are the matching methods available in OpenCV?

Good question. OpenCV implements Template matching in the function matchTemplate(). The available methods are 6:

匹配方法如下:

  1. method=CV_TM_SQDIFF

    R(x,y)=x,y(T(x,y)I(x+x,y+y))2
  2. method=CV_TM_SQDIFF_NORMED

    R(x,y)=x,y(T(x,y)I(x+x,y+y))2x,yT(x,y)2x,yI(x+x,y+y)2
  3. method=CV_TM_CCORR

    R(x,y)=x,y(T(x,y)I(x+x,y+y))
  4. method=CV_TM_CCORR_NORMED

    R(x,y)=x,y(T(x,y)I(x+x,y+y))x,yT(x,y)2x,yI(x+x,y+y)2
  5. method=CV_TM_CCOEFF

    R(x,y)=x,y(T(x,y)I(x+x,y+y))

    where

    T(x,y)=T(x,y)1/(wh)x′′,y′′T(x′′,y′′)I(x+x,y+y)=I(x+x,y+y)1/(wh)x′′,y′′I(x+x′′,y+y′′)
  6. method=CV_TM_CCOEFF_NORMED

    R(x,y)=x,y(T(x,y)I(x+x,y+y))x,yT(x,y)2x,yI(x+x,y+y)2


Code

  • What does this program do?
    • Loads an input image, an image patch (template), and optionally a mask
    • 加载输入图像,模板以及可选MASK
    • Perform a template matching procedure by using the OpenCV function matchTemplate() with any of the 6 matching methods described before. The user can choose the method by entering its selection in the Trackbar. If a mask is supplied, it will only be used for the methods that support masking
    • 通过使用OpenCV函数matchTemplate()和之前描述的6种匹配方法中的任何一种来执行模板匹配过程用户可以通过在轨迹栏中输入它的选择来选择该方法。如果提供了MASK,它将仅用于支持MASK的方法
    • Normalize the output of the matching procedure
    • 归一化匹配过程的输出
    • Localize the location with higher matching probability
    • 找到匹配概率更高的位置
    • Draw a rectangle around the area corresponding to the highest match
    • 围绕与最高匹配对应的区域绘制矩形
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
bool use_mask;
Mat img; Mat templ; Mat mask; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";
int match_method;
int max_Trackbar = 5;
void MatchingMethod( int, void* );
int main( int argc, char** argv )
{
//   if (argc < 3)
//   {
//     cout << "Not enough parameters" << endl;
//     cout << "Usage:\n./MatchTemplate_Demo <image_name> <template_name> [<mask_name>]" << endl;
//     return -1;
//   }

  img = imread( "1.jpg", IMREAD_COLOR );
  templ = imread( "2.jpg", IMREAD_COLOR );
//   if(argc > 3) {
//     use_mask = true;
//     mask = imread( argv[3], IMREAD_COLOR );
//   }

  if(img.empty() || templ.empty() || (use_mask && mask.empty()))
  {
    cout << "Can't read one of the images" << endl;
    return -1;
  }
  namedWindow( image_window, WINDOW_AUTOSIZE );
  namedWindow( result_window, WINDOW_AUTOSIZE );
  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;
}
void MatchingMethod( int, void* )
{
  Mat img_display;
  img.copyTo( img_display );
  int result_cols =  img.cols - templ.cols + 1; //边界问题
  int result_rows = img.rows - templ.rows + 1; //边界问题
  result.create( result_rows, result_cols, CV_32FC1 );
  bool method_accepts_mask = (TM_SQDIFF == match_method || match_method == TM_CCORR_NORMED);
  if (use_mask && method_accepts_mask)
    { matchTemplate( img, templ, result, match_method, mask); }
  else
    { matchTemplate( img, templ, result, match_method); } //输入,输出,结果,MASK
    
  normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); //归一化输出结果
  double minVal; double maxVal; Point minLoc; Point maxLoc;
  Point matchLoc;
  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); //输入,最小值指针,最大值指针,最小位置指针,最大位置指针
 
  if( match_method  == TM_SQDIFF || match_method == TM_SQDIFF_NORMED )
    { matchLoc = minLoc; }
  else
    { matchLoc = maxLoc; }
    
  //感觉绘制的两个矩形中心并不是最明亮的点。
  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;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

set(CMAKE_CXX_FLAGS "-std=c++11")
project( DisplayImage )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( DisplayImage main.cpp )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )


install(TARGETS DisplayImage RUNTIME DESTINATION bin

Results


猜你喜欢

转载自blog.csdn.net/qq_27806947/article/details/80315022
今日推荐