微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决在 OpenCV 中实现加权平均绝对/平方差

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

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

我需要做的等式是:

wmad.png

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

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

msd.png

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

wmsd.png

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

解决方法

你可以用小的矩阵技巧来做到这一点。我会试着用一个例子来解释。
如果您有一个具有 k_ij 值和 3x3 权重内核 w_ij 的 3x3 内核,您可以通过在每个方向上每次移动一次,从原始图像创建 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),但也可以使用矩形内核来实现。
  • 只有当内核大小不太大时,解决方案才会有效。
,

我将回答受此答案启发的问题Compute mean squared,absolute deviation and custom similarity measure - Python/NumPy

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

1- 展开方括号

[wmad.png

2- 在扩展括号上分配窗口内核 two.ong

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) (element-wise) 的总和

最后乘以 (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,cv2.flip(WT,0)

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

    return msd_map

这样看,可以很容易地利用 open-cv 功能以良好的 fps 快速完成此操作

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。