• Home
  • About
    • Something About Me photo

      Something About Me

      The shortest answer is doing.

    • Learn More
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

利用OpenCV实现模板匹配

20 Mar 2019

Reading time ~1 minute

模板匹配就是在整个图像区域找出与给定模板匹配的小块区域。匹配过程中需要源图像(I)和模板图像(T),将模板图像在原图像上滑动并一一比对,得到结果图(R),值最大(或最小,依算法而定)的点表明这里的匹配度最高。

1 matchTemplate()函数

void matchTemplate(InputArray img, InputArray temp, OutputArray result, int method)

其中,img为源图像,temp为模板图像,result为结果图,结果图的尺寸为(img.row-temp.row+1)*(img.col-temp.col+1)。

这里OpenCV提供了六种常见的匹配算法:

1 TM_SQDIFF

计算平方差,结果值越小越相关

\[R(x,y)=\sum\limits_{x',y'}(T(x',y')-I(x+x',y+y'))^2\]
2 TM_SQDIFF_NORMED

计算归一化的平方差,结果值越接近0越相关

\[R(x,y)=\frac{\sum\limits_{x',y'}(T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum\limits_{x',y'}T(x',y')^2\cdot\sum\limits_{x',y'}I(x+x',y+y')^2}}\]
3 TM_CCORR

计算相关性,结果值越大越相关

\[R(x,y)=\sum\limits_{x',y'}(T(x',y')\cdot I(x+x',y+y'))\]
4 TM_CCORR_NORMED

计算归一化相关性,结果值越接近1越相关

\[R(x,y)=\frac{\sum\limits_{x',y'}(T(x',y')\cdot I(x+x',y+y'))}{\sqrt{\sum\limits_{x',y'}T(x',y')^2\cdot\sum\limits_{x',y'}I(x+x',y+y')^2}}\]
5 TM_CCOEFF

计算相关系数,结果值越大越相关

\[R(x,y)=\sum\limits_{x',y'}(T'(x',y')\cdot I'(x+x',y+y'))\]

where

\[T'(x',y')=T(x',y')-1/(w\cdot h)\cdot\sum_{x'',y''}T(x'',y'')\] \[I'(x+x',y+y')=I(x+x',y+y')-1/(w\cdot h)\cdot\sum_{x'',y''}I(x+x'',y+y'')\]
6 TM_CCOEFF_NORMED

计算归一化相关系数,结果值越接近1越相关

\[R(x,y)=\frac{\sum\limits_{x',y'}(T'(x',y')\cdot I'(x+x',y+y'))}{\sqrt{\sum\limits_{x',y'}T'(x',y')^2\cdot\sum\limits_{x',y'}I'(x+x',y+y')^2}}\]

2 minMaxLoc()函数

使用上述函数得到结果图后,使用minMaxLoc()函数可以找到图像中最大值和最小值的位置,具体使用方法如下:

void minMaxLoc(InputArray img, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())

其中,img为输入图像,minVal为最小值,maxVal为最大值,minLoc为最小值的位置,maxLoc为最大值的位置,mask为掩膜。

如果matchTemplate()函数中定义的方法为平方差或归一化的平方差,结果图中值越小的地方匹配度越好,这时候就需要找矩阵中的最小值及其位置,也就是minVal和minLoc。如果使用了其它四种方法,则需要找结果图中的最大值及其位置,也就是maxVal和maxLoc。

3 示例

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main()
{
    Mat img, templ, result;
    img = imread("F://OpenCV//img//image_origin.jpg"); //读取源图像
    templ = imread("F://OpenCV//img//temp_origin.jpg"); //读取模板图像
    result.create(img.rows - templ.rows + 1, img.cols - templ.cols + 1, CV_32FC1); //创建结果图
matchTemplate(img, templ, result, TM_SQDIFF_NORMED);  
//模板匹配,这里使用的是归一化平方差方法,这里只对归一化的三种方法TM_SQDIFF_NORMED, TM_CCORR_NORMED, TM_CCOEFF_NORMED进行测试
    double minVal;
    double maxVal;
    Point minLoc;
    Point maxLoc;
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); //寻找最大最小值的位置
    rectangle(img, maxLoc, Point(maxLoc.x + templ.cols, maxLoc.y + templ.rows), Scalar::all(0), 3); //画出匹配后的矩形框
    imshow("img", img);
    imshow("result", result);
    waitKey(0);
    return 0;
}


Computer VisionTemplate Matching Share Tweet +1