Skip to content

模板匹配

本教程中你将学到如何:

  • 使用 OpenCV 函数 matchTemplate() 在一个图像块与一幅输入图像之间搜索匹配
  • 使用 OpenCV 函数 minMaxLoc() 在给定数组中寻找最大值与最小值(及其位置)。

模板匹配(template matching)是一种在一幅图像中寻找与模板图像(图像块 patch)匹配(相似)区域的技术。

虽然图像块必须是矩形,但矩形的某些部分可能并不相关。在这种情况下,可以使用一个掩膜来隔离图像块中应当用于匹配的那一部分。

  • 我们需要两个主要组件:

    1. 源图像(I): 我们期望在其中找到与模板图像匹配的图像
    2. 模板图像(T): 将与源图像进行比较的图像块

    我们的目标是检测匹配度最高的区域:

  • 为识别匹配区域,我们需要通过滑动的方式将模板图像与源图像进行比较:

  • 所谓滑动,是指每次将图像块移动一个像素(从左到右、从上到下)。在每个位置都计算一个度量,用以表示该位置处匹配“好”还是“坏”(或者说图像块与源图像该特定区域的相似程度)。

  • 对于 T 在 I 上的每个位置,你将该度量存储在结果矩阵 R 中。R 中的每个位置 (x,y)(x,y) 都包含匹配度量:

    上图是用度量 TM_CCORR_NORMED 滑动图像块所得的结果 R。最亮的位置表示最高匹配。可以看到,红圈标记的位置很可能是取值最高的位置,因此该位置(以该点为一个角、宽高等于图像块的矩形)被视为匹配。

  • 实际中,我们使用函数 minMaxLoc() 在 R 矩阵中定位最高值(或根据匹配方法类型,定位最低值)

Template_Matching_Template_Theory_Summary.jpg Template_Matching_Template_Theory_Sliding.jpg Template_Matching_Template_Theory_Result.jpg

  • 如果匹配需要使用掩膜,则需要三个组件:

    1. 源图像(I): 我们期望在其中找到与模板图像匹配的图像
    2. 模板图像(T): 将与源图像进行比较的图像块
    3. 掩膜图像(M): 掩膜,一幅对模板进行遮罩的灰度图像
  • 目前只有两种匹配方法接受掩膜:TM_SQDIFF 与 TM_CCORR_NORMED(关于 opencv 中可用的所有匹配方法,见下文说明)。

  • 掩膜必须与模板具有相同的尺寸

  • 掩膜的深度应为 CV_8U 或 CV_32F,且通道数与模板图像相同。在 CV_8U 情况下,掩膜的值被视为二值(即零与非零)。在 CV_32F 情况下,值应落在 [0..1] 范围内,模板像素将与对应的掩膜像素值相乘。由于示例中的输入图像类型为 CV_8UC3,掩膜也作为彩色图像读入。

OpenCV 中有哪些可用的匹配方法?

Section titled “OpenCV 中有哪些可用的匹配方法?”

好问题。OpenCV 在函数 matchTemplate() 中实现了模板匹配。可用方法共 6 种:

  1. method=TM_SQDIFF

    R(x,y)=∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2

  2. method=TM_SQDIFF_NORMED

    R(x,y)=∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

  3. method=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'))

  4. method=TM_CCORR_NORMED

    R(x,y)=∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′))∑x′,y′T(x′,y′)2⋅∑x′,y′I(x+x′,y+y′)2R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}

  5. method=TM_CCOEFF

    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'))

    其中

    T′(x′,y′)=T(x′,y′)−1/(w⋅h)⋅∑x′′,y′′T(x′′,y′′)I′(x+x′,y+y′)=I(x+x′,y+y′)−1/(w⋅h)⋅∑x′′,y′′I(x+x′′,y+y′′)\begin{array}{l} 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'') \end{array}

  6. method=TM_CCOEFF_NORMED

    R(x,y)=∑x′,y′(T′(x′,y′)⋅I′(x+x′,y+y′))∑x′,y′T′(x′,y′)2⋅∑x′,y′I′(x+x′,y+y′)2R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }

  • 这个程序做什么?

    • 载入一幅输入图像、一个图像块(模板),以及可选的一个掩膜
    • 使用 OpenCV 函数 matchTemplate() 配合前述 6 种匹配方法中的任意一种执行模板匹配。用户可通过在 Trackbar 中输入选择来选用方法。若提供了掩膜,则它只会用于支持掩膜的方法
    • 对匹配过程的输出进行归一化
    • 定位匹配概率最高的位置
    • 在最高匹配对应的区域周围绘制一个矩形
  • 可下载代码:点击 这里

  • 代码一览: 代码见下方示例

  • 可下载代码:点击 这里

  • 代码一览: 代码见下方示例

  • 可下载代码:点击 这里

  • 代码一览: 代码见下方示例

  • 声明一些全局变量,例如图像、模板与结果矩阵,以及匹配方法和窗口名称:
  • 载入源图像、模板,并在匹配方法支持的情况下,可选地载入一个掩膜:
  • 创建 Trackbar 以输入要使用的匹配方法种类。检测到变化时即调用回调函数。

Template_Matching_Mask_Example.jpg

  • 我们来看回调函数。首先,它拷贝源图像:
  • 执行模板匹配操作。参数自然是输入图像 I、模板 T、结果 R 以及匹配方法(由 Trackbar 给出),以及可选的掩膜图像 M。
  • 我们对结果进行归一化:
  • 我们使用 minMaxLoc() 定位结果矩阵 R 中的最小值与最大值。
  • 对于前两种方法(TM_SQDIFF 与 TM_SQDIFF_NORMED),最佳匹配是最低值。对于其余所有方法,值越高表示匹配越好。因此,我们将对应的值保存到 matchLoc 变量中:
  • 显示源图像与结果矩阵。在最高可能匹配区域周围绘制一个矩形:

Template_Matching_Original_Image.jpg Template_Matching_Template_Image.jpg Template_Matching_Correl_Result_0.jpg Template_Matching_Correl_Result_1.jpg Template_Matching_Correl_Result_2.jpg Template_Matching_Correl_Result_3.jpg Template_Matching_Correl_Result_4.jpg Template_Matching_Correl_Result_5.jpg Template_Matching_Image_Result.jpg

  1. 用如下输入图像测试我们的程序:

    以及一个模板图像:

  2. 生成如下结果矩阵(第一行是标准方法 SQDIFF、CCORR 与 CCOEFF,第二行是同样方法的归一化版本)。在第一列中,越暗表示匹配越好;对于另外两列,位置越亮则匹配度越高。

  3. 正确匹配如下图所示(右侧那个人脸部周围的黑色矩形)。注意 CCORR 与 CCOEFF 给出了错误的最佳匹配,然而它们的归一化版本却匹配正确。这可能是因为我们只考虑了“最高匹配”,而没有考虑其他可能的高匹配。