模板匹配就是在整个图像区域发现与给定图像最相似的小块区域,所以模板匹配首先需要一个模板图像,另外需要一个待检测图像:

  • 在待检测图像上,从左到右,从上到下,计算模板图像与重叠子图像的匹配度(相似度),匹配度(相似度)越大,两者相同的可能性越大。
  • 对于每一个位置将计算的相似结果保存在矩阵 R 中。如果输入图像的大小为 WxH 且模板图像的大小为 wxh,则输出矩阵 R 的大小为 (W-w+1)x(H-h+1) 。
  • 获得 R 后,从 R 中找出匹配度最高的位置,那么该位置对应的区域就是最匹配的,区域为以该点为顶点,长宽和模板图像一样大小的矩阵。)

OpenCV函数

matchTemplate

将模板与重叠的图像区域进行比较。

使用指定的方法将大小为 w×h 的重叠矩阵与 templ 进行比较,并将比较结果存储在 result 中。

函数完成比较后,可以使用 minMaxLoc 函数找到最佳匹配项,作为全局最小值(使用TM_SQDIFF时)或最大值(使用TM_CCORR或TM_CCOEFF时)。 在彩色图像的情况下,分子的模板求和和分母中的每个和在所有通道上进行,每个通道使用单独的平均值。 即,该函数可以获取彩色模板和彩色图像。 结果仍然是单通道图像,更易于分析。

enum  cv::TemplateMatchModes {
	  cv::TM_SQDIFF = 0,
	  cv::TM_SQDIFF_NORMED = 1,
	  cv::TM_CCORR = 2,
	  cv::TM_CCORR_NORMED = 3,
	  cv::TM_CCOEFF = 4,
	  cv::TM_CCOEFF_NORMED = 5
	}
void cv::matchTemplate( InputArray		image,
                        InputArray		templ,
                        OutputArray		result,
                        int				method,
                        InputArray		mask = noArray() 
                    	)
//Python:
result = cv.matchTemplate(image, templ, method[, result[, mask]])

参数解释

参数

解释

image

源图像,要搜索的图像,8位或32位浮点。

templ

搜索的模板,不大于源图像并且具有相同的数据类型。

result

比较结果图,单通道32位浮点。 如果 image 为 W×H 并且 templ 为 w×h ,则结果为 (W-w + 1)×(H-h + 1)。

method

比较的方法

mask

搜索模板的掩码。 必须与 templ 具有相同的数据类型和大小。默认情况下未设置。 当前,仅支持TM_SQDIFF 和 TM_CCORR_NORMED 方法。

比较方法:

python opencv对比两张图片相似度 opencv比较图片相似度_归一化

  • TM_SQDIFF:平方差匹配法,该方法采用平方差进行匹配,最好的匹配值为0;匹配越差,匹配值越大
  • TM_SQDIFF_NORMED:归一化平方差匹配法
  • TM_CCORR:相关匹配法,该方法采用乘法操作,数值越大表示匹配程度越好
  • TM_CCORR_NORMED:归一化相关匹配法
  • TM_CCOEFF:相关系数匹配法,1表示完美的匹配,-1表示最差的匹配
  • TM_CCOEFF_NORMED:归一化相关系数匹配法

在 OpenCV 的实现中采用了傅里叶变换,速度会快很多。OpenCV 源码路径:modules/imgproc/src/templmatch.cpp

简单说一下 OpenCV 源码的方法:

对于 TM_CCORR 方法,
python opencv对比两张图片相似度 opencv比较图片相似度_OpenCV_02
对于 TM_SQDIFF:
python opencv对比两张图片相似度 opencv比较图片相似度_搜索_03
对于 TM_CCOEFF:
python opencv对比两张图片相似度 opencv比较图片相似度_归一化_04
其中 python opencv对比两张图片相似度 opencv比较图片相似度_归一化_05 为源图像中模板图像对应区域的和,python opencv对比两张图片相似度 opencv比较图片相似度_归一化_06

而对于以上三个公式中的 python opencv对比两张图片相似度 opencv比较图片相似度_搜索_07

对于 python opencv对比两张图片相似度 opencv比较图片相似度_归一化_08

对于 TM_SQDIFF_NORMED,TM_CCORR_NORMED 的分母部分都可以通过图像的(平方)积分来实现。

对于 TM_CCOEFF_NORMED 的分母:
python opencv对比两张图片相似度 opencv比较图片相似度_opencv_09

python opencv对比两张图片相似度 opencv比较图片相似度_OpenCV_10

其中 python opencv对比两张图片相似度 opencv比较图片相似度_搜索_11 为模板图像的方差,python opencv对比两张图片相似度 opencv比较图片相似度_OpenCV_12

通过以上的分析,使用不同的方法计算,可以加快模板匹配的速度。

C++示例

string srcWindow = "src";
string temWindow = "tem";
string matchWindow = "match";
string resultWindow = "result";

int matchMethod = 5;

int main()
{
    string outDir = "./";
    Mat src = imread("src.jpg");
    Mat tem = imread("tem.jpg");
    
    Mat result;
    Mat matchResult;
    // 模板匹配
    matchTemplate(src, tem, result, matchMethod);
    // 获取最大值,最小值,以及对应的点
    Point minLoc, maxLoc, temLoc;
    double minVal, maxVal;
    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
    if(matchMethod == 0 || matchMethod == 1)
    {
        temLoc = minLoc;
    }
    else
    {
        temLoc = maxLoc;
    }
    // 获取匹配到的图像
    matchResult = src(Range(temLoc.y, temLoc.y+tem.rows), Range(temLoc.x, temLoc.x+tem.cols));
    // 在原图画矩形
    rectangle(src, Rect(temLoc.x, temLoc.y, tem.cols, tem.rows), Scalar(0, 0, 255), 2);
    imshow(resultWindow, result);
    imshow(srcWindow, src);
    imshow(matchWindow, matchResult);
    imshow(temWindow, tem);
    imwrite(outDir+"src.jpg", src);
    imwrite(outDir+"result.jpg", matchResult);
    waitKey(0);
    return 0;
}

效果

python opencv对比两张图片相似度 opencv比较图片相似度_归一化_13