OpenCV —— 模板匹配

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

  • 在待检测图像上,从左到右,从上到下,计算模板图像与重叠子图像的匹配度(相似度),匹配度(相似度)越大,两者相同的可能性越大。

  • 对于每一个位置将计算的相似结果保存在矩阵 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 方法。

比较方法:

OpenCV —— 模板匹配_第1张图片

  • 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 方法,
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) R(x, y) = \sum_{x',y'}(T(x', y') \cdot I(x+x', y+y')) R(x,y)=x,y(T(x,y)I(x+x,y+y))
对于 TM_SQDIFF:
R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) 2 − 2 ⋅ T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) + I ( x + x ′ , y + y ′ ) 2 ) \begin{aligned} R(x, y) & = \sum_{x',y'}(T(x', y') - I(x+x', y+y'))^2 \\ & = \sum_{x',y'}(T(x', y')^2 - 2\cdot T(x', y') \cdot I(x+x', y+y') + I(x+x', y+y')^2) \end{aligned} R(x,y)=x,y(T(x,y)I(x+x,y+y))2=x,y(T(x,y)22T(x,y)I(x+x,y+y)+I(x+x,y+y)2)
对于 TM_CCOEFF:
R ( x , y ) = ∑ x ′ , y ′ ( T ′ ( x ′ , y ′ ) ⋅ I ′ ( x + x ′ , y + y ′ ) ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) − s u m ( I ) ⋅ m e a n ( T ) \begin{aligned} R(x, y) & = \sum_{x',y'}(T'(x', y') \cdot I'(x+x', y+y')) \\ & = \sum_{x',y'}(T(x', y') \cdot I(x+x', y+y')) - sum(I)\cdot mean(T) \end{aligned} R(x,y)=x,y(T(x,y)I(x+x,y+y))=x,y(T(x,y)I(x+x,y+y))sum(I)mean(T)
其中 s u m ( I ) sum(I) sum(I) 为源图像中模板图像对应区域的和, m e a n ( T ) mean(T) mean(T) 是模板图像的均值。

而对于以上三个公式中的 ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) \sum_{x',y'}(T(x', y') \cdot I(x+x', y+y')) x,y(T(x,y)I(x+x,y+y)) 是在频率域上进行计算的(可以将模板图像看成卷积核在源图像上滑动求卷积,可以在频率域计算,从而加快速度)

对于 I ( x + x ′ , y + y ′ ) 2 , s u m ( I ) I(x+x', y+y')^2, sum(I) I(x+x,y+y)2,sum(I) 可以通过图像的(平方)积分实现。

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

对于 TM_CCOEFF_NORMED 的分母:
∑ x ′ , y ′ T ′ ( x ′ , y ′ ) 2 = N M ⋅ σ 2 \sum_{x',y'}T'(x', y')^2 = NM \cdot \sigma^2 x,yT(x,y)2=NMσ2

∑ x ′ , y ′ I ′ ( x + x ′ , y + y ′ ) 2 = ∑ x ′ , y ′ I ( x + x ′ , y + y ′ ) 2 − s u m ( I ) 2 N M \sum_{x',y'}I'(x+x', y+y')^2 = \sum_{x',y'}I(x+x', y+y')^2 - \frac{sum(I)^2}{NM} x,yI(x+x,y+y)2=x,yI(x+x,y+y)2NMsum(I)2

其中 σ 2 \sigma^2 σ2 为模板图像的方差, N , M N,M N,M 分别是模板图像的宽和高

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

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;
}

效果

OpenCV —— 模板匹配_第2张图片
参考:

https://www.bilibili.com/video/BV18v41117un

你可能感兴趣的:(OpenCV,opencv)