OpenCV 4.10.0
开源计算机视觉
正在加载...
正在搜索...
无匹配
模板匹配

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

原作者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. method=TM_SQDIFF

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

  2. method=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. method=TM_CCORR

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

  4. method=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. method=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. method=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 种任意一种匹配方法进行模板匹配过程。用户可以通过在轨迹条中输入其选择来选择方法。如果提供了遮掩,它将仅用于支持遮掩的方法
    • 对匹配过程的输出进行归一化
    • 定位匹配概率较高的位置
    • 在对应于最高匹配的区域周围绘制一个矩形

说明

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

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

  • 创建轨道栏以输入要使用的匹配方法类型。当检测到更改时,会调用回调函数。

  • 让我们检查一下回调函数。首先,它复制一份源图像

  • 执行模板匹配操作。参数自然地是输入图像I、模板T、结果R和match_method(由轨道栏给出),以及选择性地输入掩模图像M

  • 我们对结果进行归一化

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

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

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

结果

  1. 用一张这样的输入图像测试我们的程序

和一张模板图

  1. 生成以下结果矩阵(第一行是标准方法 SQDIFF、CCORR 和 CCOEFF,第二行是这些方法的归一化版本)。在第一列中,深色表示匹配度越高,对于其他两列,越亮的区域表示匹配度越高。
  2. 正确的匹配如下所示(右边的方框围绕着右边的这个人的面部)。请注意,CCORR 和 CCDEFF 给出了错误的最佳匹配,然而它们的归一化版本给出了正确的匹配,这可能是由于我们仅考虑“最高匹配”而不是其他可能的匹配所致。