【问题标题】:Implementing Weighted Mean Absolute/Square difference in OpenCV在 OpenCV 中实现加权平均绝对/平方差
【发布时间】:2021-08-10 01:01:23
【问题描述】:

我正在尝试在 Python-OpenCV 中实现模板图像和视频流帧之间的某种相关性跟踪

我正在尝试使用加权平均绝对偏差(加权 MAD)作为模板和视频帧之间的相似性度量(对象应位于最小 MAD 的位置。)。

我需要做的等式是:

其中F是图片,T是模板,w是权重窗口(与模板大小相同)

我知道 open-cv 提供了模板匹配的功能(即:cv2.matchTemplate)。与 MAD 最接近的是 TM_SQDIFF_NORMED,即均方偏差 (MSD),我相信 open-cv 实现了这个方程

如果有办法像这样在其中实现权重函数,这将给出我想要的相似性度量

我的问题是如何在 Open-CV 中实现任何加权 MAD 或加权 MSD 而无需自己实现循环(以免失去速度)利用 cv2.matchTemplate 函数(或类似方法

【问题讨论】:

  • 也许通过使用权重作为掩码图像。有关掩码选项,请参阅docs.opencv.org/4.1.1/df/dfb/…
  • @fmw42 文档说掩码乘以模板,这不是所示的等式。 gregorkovalcik.github.io/opencv_contrib/…
  • 这只是一个想法。否则,我看不到任何方法可以在不重新编程代码的情况下向当前 matchTemplate() 添加权重。因此,您必须编写自己的例程。
  • @fmw42 我试过实现它,但是对于普通的视频文件来说太慢了。如果我能有合理的速度,我执行它没有问题
  • 循环太慢了,我已经使用 numpy.convolve(或 scipy)实现了 TM_CCOEFF。那么你能把方程变成卷积吗?

标签: python numpy opencv image-processing scipy


【解决方案1】:

您可以使用小矩阵技巧来做到这一点。我将尝试用一个例子来解释。
如果您有一个 3x3 内核,其值为 k_ij 和 3x3 权重内核 w_ij,您可以通过在每个方向上每次移动一次来从原始图像创建 9 个图像。您最终将获得 9 张图片。
现在,您可以展平内核 t 并从堆叠的 9 个图像中减去它。结果将等同于移动内核。
取绝对值后,您可以对 w 执行相同的操作(展平和相乘)。
最后,您可以对新轴上的张量求和并得到解决方案。

实现示例:

def stack_image(image, n):
    channels = []
    row, col = image.shape
    for i in range(n):
        for j in range(n):
            channels.append(image[i:row-(n - i)+1, j:col-(n - j)+1])
    return np.stack(channels, axis=-1)

def weighted_mad(f, t, w):
    image_stack = stack_image(image=f, n=t.shape[0])
    image_stack = np.abs(image_stack - t.flatten()) * w.flatten()
    image_stack = image_stack.sum(axis=-1)

    norm = len(image_stack.flatten())
    return 1 / norm * image_stack

注意事项:

  • 我的实现不处理边界(“有效”),可以通过其他方式实现。
  • 我的实现假定使用方形内核 (kxk),但可以使用矩形内核来实现。
  • 只有在内核大小不太大的情况下,该解决方案才会有效。

【讨论】:

  • @TxviLederer 不错的概念。非常聪明。但也许用 np.roll() 替换您的 def stack_image() 以将您的图像移动 9 次。见numpy.org/doc/stable/reference/generated/numpy.roll.html
  • 请您添加更多数学解释,因为我没有很好地理解您的想法。
  • @fmw42 好主意.. 但如果你这样做,无论如何你都需要裁剪边缘(np.roll() 会将行/列的末尾带到开头)。
  • @TzviLederer 对。我忘记了。但是你没有有效地做同样的事情吗?图像的边界像素将没有需要移动到的邻居。可以通过展开操作将输入图像四周填充 2 个像素。然后任何一种方法都会有所需的数据,尽管它可能不相关。但是,这是一个小问题。
  • @MohamedIbrahim 的概念是,在内核的每次迭代中,您可以将原始图像堆叠在三维(移动)以便在每个像素 i、j 中,第三维中的值将与原始内核将“捕获”的值相同。现在,您可以在第三维中进行减法、abs 和权重,而不是在空间上移动内核。我希望它很清楚。
【解决方案2】:

我将根据这个答案Compute mean squared, absolute deviation and custom similarity measure - Python/NumPy来回答我的问题

我决定使用加权 M​​SD(均方偏差),因为我可以扩展方括号并将权重分配到三个项上。以下是步骤

1- 扩大方括号

[

2- 在展开的括号上分发窗口内核

3-在每一项上分配两个和运算符 我们将结束三个任期

3.a- Image square (F^2) 和 Window(W) 之间的卷积

3.b- -2 * Image (F) 和 window*template (T * W, element-wise) 之间的卷积

3.c- 模板平方 T^2 * 窗口 (w) 的总和(逐元素)

最后乘以 (1/(m*n))

这里是如何在 python open-cv 中做到这一点

def wmsd( img, tmp ,W):
    # input: img= image
    # input: tmp= template
    # input: W= weighting window
    # return: msd_map= weighted mean square deviation map

    h,w = img.shape
    th,tw = tmp.shape
    img_sq=np.square(np.uint64(img))
    tmp_sq=np.square(np.uint64(tmp))

    p1=cv2.filter2D(img_sq,-1,cv2.flip(W,-1),0)

    WT=W*tmp
    p2=-2*cv2.filter2D(img,-1,cv2.flip(WT,-1),0)

    p3=np.sum(tmp_sq*W)     
    msd_map=(p1+p2+p3)/(th*tw)

    return msd_map

这样看,可以很容易地利用 open-cv 的力量以良好的 fps 快速进行此操作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2019-07-10
    相关资源
    最近更新 更多