繁体   English   中英

在 OpenCV 中实现加权平均绝对/平方差

[英]Implementing Weighted Mean Absolute/Square difference in OpenCV

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

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

我需要做的等式是:

wmad.png

其中F是图像, T是模板, w是权重 window(与模板大小相同)

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

msd.png

如果有一种方法可以像这样在其中实现重量 function ,这将给出我想要的相似性度量

wmsd.png

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

你可以用小矩阵技巧来做到这一点。 我将尝试用一个例子来解释。
如果您有一个 3x3 kernel,其值为 k_ij 和 3x3 权重 kernel w_ij,您可以通过每次在每个方向移动一次来从原始图像创建 9 个图像。 您最终将获得 9 张图像。
现在,您可以展平 kernel t 并从堆叠的 9 个图像中减去它。 结果将等同于移动 kernel。
取绝对值后,您可以对 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

笔记:

  • 我的实现不处理边界(“有效”),可以通过其他方式实现。
  • 我的实现假设一个正方形 kernel (kxk),但是可以用一个矩形来实现它。
  • 仅当 kernel 尺寸不太大时,该解决方案才会有效。

我将回答受此答案启发的问题计算均方、绝对偏差和自定义相似度度量 - Python/NumPy

我决定使用加权 MSD(均方偏差)的 go,因为我可以扩展方括号并将权重分布在三个术语上。 以下是步骤

1-扩展方括号

[ wmad.png

2-在扩展支架上分配 window kernel 二龙

3-在每个术语上分配两个和运算符,我们将结束三个术语

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

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

3.c-模板平方 T^2 * window (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 快速进行此操作

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM