python - 在 Python 中使用 OpenCV 的 matchTemplate 方法进行二维互相关的奇怪结果

标签 python matlab opencv scipy octave

在以下示例中,使用 cv2.matchTemplate 方法计算 A、B 数组的互相关。结果存储在C数组中:

import cv2
import numpy as np
A=np.ones((3,3), dtype=np.uint8)
B=np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=np.uint8)
C=cv2.matchTemplate( A, B, cv2.TM_CCORR )

>>> A
    array([[1, 1, 1],
           [1, 1, 1],
           [1, 1, 1]], dtype=uint8)
>>> B
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]], dtype=uint8)
>>> C
    array([[ 45.]], dtype=float32)

让我们使用 scipy 实现相同的示例:

import cv2
import numpy as np
import scipy
import scipy.signal

A = np.ones((3,3), dtype=np.uint8)
B = np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=np.uint8)
C = scipy.signal.correlate2d(A,B)

>>> C
array([[ 9, 17, 24, 15,  7],
       [15, 28, 39, 24, 11],
       [18, 33, 45, 27, 12],
       [ 9, 16, 21, 12,  5],
       [ 3,  5,  6,  3,  1]], dtype=uint8)

现在让我们使用 Octave 实现相同的示例:

octave:4> A=ones(3,3)
A =

   1   1   1
   1   1   1
   1   1   1

octave:5> B=[1 2 3; 4 5 6; 7 8 9]
B =

   1   2   3
   4   5   6
   7   8   9

octave:6> C=xco
xcorr   xcorr2  xcov    
octave:6> C=xcorr2(A,B)
C =
    9   17   24   15    7
   15   28   39   24   11
   18   33   45   27   12
    9   16   21   12    5
    3    5    6    3    1

通过比较结果我们可以看到opencv的方法产生了明显不同的结果。

有人可以解释一下 2D 互相关的各种实现之间的区别吗?

为了正确计算 2D 互相关,我应该对我的 opencv 代码进行哪些更改?

谢谢大家

放克

最佳答案

好吧,首先我们需要引用 OpenCV 文档:

Matlab/OpenCV

cv2.matchTemplate(image, templ, method[, result]) → result
  • result – 比较结果图。必须是单 channel 32位 float 。如果图像是 W x H 并且 templw x h ,那么结果是 (W-w+1) x (H-h +1)

使用 3x3 图像和 3x3 模板,您的结果将是一个 (3-3+1)x(3-3+1) = (1x1) 矩阵,这就是方法实际上确实返回了。

TM_CCORR方法使用的公式如下:

OpenCV implementation

现在让我们看看这个实现与其他实现之间的区别。

科学

scipy.signal.correlate2d(in1, in2, mode='full', boundary='fill', fillvalue=0)[source]

结果大小由 mode 参数决定。使用默认参数 full 意味着结果大小将为 (W+w-1) x (H+h-1)。但是,将模式更改为 valid 将导致 (W-w+1) x (H-h+1) 结果,这与通过以下方式实现的结果相同OpenCV.

Octave

C = xcorr2(A,B)

结果矩阵的大小为:

  • C_rows = A_rows + B_rows - 1
  • C_cols = A_cols + B_cols - 1

使用 3x3 图像和 3x3 模板,您的结果将是一个 (3+3-1)x(3+3-1)=(5x5) 矩阵。

该方法使用的公式看起来与 OpenCV 使用的公式不同,但实际上只是同一方程的不同形式。

Octave

结论

所有三个实现中使用的公式似乎是相同的。这些方法之间存在差异的原因在于处理边界条件的方式。互相关是通过在图像矩阵上“滑动”模板矩阵并将给定单元格的结果总和设置为图像和模板中重叠单元格的乘积之和来实现的。但是,对于图像中的边缘情况,除非模板是 1x1 矩阵,否则它将与图像的边缘重叠(示例见下图)。这种情况可以通过填充或环绕图像来处理。在第一种情况下,图像被放大并用零填充以确保模板不会超出图像。

Overlap

在 SciPy 和 Octave 中,默认方法是填充图像,这将生成比输入图像大的图像(实际上,在两个 3x3 矩阵的情况下,结果是 5x5,因为模板悬在当以图像的边缘单元格为中心时,图像总共有 2 行和 2 列)。在 OpenCV 中,默认方法是删除模板悬在图像上方的边缘情况,在这种情况下,这意味着模板的唯一有效位置恰好位于图像的中心。这解释了值为 45 的单个结果单元格:模板所有元素的总和乘以 1。

要回答有关如何使用 OpenCV 的 Matlab 实现获得相同结果的问题:只需扩大输入矩阵,使其大小为 (W+w-1) x (H+h-1),将图像置于新矩阵的中心,并用 0 填充图像外部的区域:

A=padarray(np.ones((3,3), dtype=np.uint8), [1, 1])

关于python - 在 Python 中使用 OpenCV 的 matchTemplate 方法进行二维互相关的奇怪结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31561513/

相关文章:

python - 在 App Engine 应用程序初始化时执行代码

python - 使用 Python 计算数据框中唯一单词的数量

python - 使用 OpenCV 为 Tesseract OCR 预处理七段图像

matlab - 在 windows 中运行 STIP(时空兴趣点)的问题

c++ - 训练图像在openCV中意味着什么?

python - 如何将XYZ颜色空间更改为RGB 0-255

python - 使用python制作气泡图动画

Python Pandas print() 和 .to_csv() 截断结果

matlab arctanh 函数

matlab - 如何在 MATLAB 中找到三个相互交叉的圆锥体的共同体积?