OpenCV 4.13.0
开源计算机视觉库 (Open Source Computer Vision)
正在加载...
正在搜索...
未找到匹配项
模板匹配

上一个教程: 反向投影
下一个教程: 查找图像中的轮廓

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,你将学习如何:

  • 使用 OpenCV 函数 matchTemplate() 搜索图像块和输入图像之间的匹配项
  • 使用 OpenCV 函数 minMaxLoc() 查找给定数组中的最大值和最小值(以及它们的位置)。

理论

什么是模板匹配?

模板匹配是一种在图像中查找与模板图像(补丁)匹配(相似)区域的技术。

虽然补丁必须是矩形,但可能并非所有矩形都相关。在这种情况下,可以使用掩码来隔离应用于查找匹配项的补丁部分。

它是如何工作的?

  • 我们需要两个主要组件

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

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

  • 为了识别匹配区域,我们必须通过滑动模板图像与源图像进行比较
  • 通过滑动,我们指的是一次移动一个像素的补丁(从左到右,从上到下)。在每个位置,都会计算一个度量,以表示该位置的匹配有多“好”或多“坏”(或者补丁与源图像的该特定区域有多相似)。
  • 对于 TI 上的每个位置,您将度量存储结果矩阵 R 中。R 中的每个位置 \((x,y)\) 都包含匹配度量

上图是使用度量 TM_CCORR_NORMED 滑动补丁的结果 R。最亮的位置表示最高的匹配项。正如您所看到的,红色圆圈标记的位置可能是具有最高值的位置,因此该位置(由该点作为角以及等于补丁图像的宽度和高度形成的矩形)被认为是匹配项。

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

掩码是如何工作的?

  • 如果匹配需要掩码,则需要三个组件
    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 中有哪些可用的匹配方法?

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

  1. 方法=TM_SQDIFF

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

  2. 方法=TM_SQDIFF_NORMED

    \[R(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. 方法=TM_CCORR

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

  4. 方法=TM_CCORR_NORMED

    \[R(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. 方法=TM_CCOEFF

    \[R(x,y)= \sum _{x',y'} (T'(x',y') \cdot 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. 方法=TM_CCOEFF_NORMED

    \[R(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 中输入选择来选择方法。如果提供了掩码,则仅将其用于支持掩码的方法
    • 标准化匹配过程的输出
    • 定位匹配概率较高的位置
    • 在与最高匹配项对应的区域周围绘制一个矩形

解释

  • 声明一些全局变量,例如图像、模板和结果矩阵,以及匹配方法和窗口名称

  • 加载源图像、模板,以及可选地(如果匹配方法支持)掩码

  • 创建轨迹条以输入要使用的匹配方法。当检测到更改时,将调用回调函数。

  • 让我们看看回调函数。首先,它创建源图像的副本

  • 执行模板匹配操作。参数自然是输入图像 I、模板 T、结果 R 和匹配方法(由轨迹条给出),以及可选的掩码图像 M

  • 我们标准化结果

  • 我们通过使用 minMaxLoc() 在结果矩阵 R 中定位最小值和最大值。

  • 对于前两种方法(TM_SQDIFF 和 MT_SQDIFF_NORMED),最佳匹配是最低值。对于所有其他方法,值越高表示匹配越好。因此,我们将相应的值保存在 matchLoc 变量中

  • 显示源图像和结果矩阵。在最高可能的匹配区域周围绘制一个矩形

结果

  1. 使用输入图像测试我们的程序,例如

和模板图像

  1. 生成以下结果矩阵(第一行是标准方法 SQDIFF、CCORR 和 CCOEFF,第二行是其归一化版本中的相同方法)。在第一列中,越暗表示匹配越好,对于其他两列,位置越亮表示匹配度越高。

  1. 正确的匹配显示在下方(右边那个人的脸周围的黑色矩形)。请注意,CCORR 和 CCDEFF 提供了错误的最佳匹配,但它们的归一化版本做得很好,这可能是因为我们只考虑“最高匹配”而不是其他可能的较高匹配。