代码之家  ›  专栏  ›  技术社区  ›  juvian

Numpy-计算指标的更高效代码

  •  0
  • juvian  · 技术社区  · 4 年前

    我正试图实现这个指标 enter image description here

    我已经设法用numpy操作计算了NUBN,所以速度很快,但我找不到一种方法来逃避python的慢循环来计算DRD部分。以下是我目前对DRD的计算:

    def drd(im, im_gt):
        height, width = im.shape
        W = np.array([[1/math.sqrt(x**2+y**2) if x != 0 or y != 0 else 0 for x in range(-2, 3)] for y in range(-2, 3)])
        W /= W.sum()
        drd = 0
        s = []
        for y, x in zip(*np.where(im_gt != im)):
            if x > 1 and y > 1 and x + 2 < width and y + 2 < height:
                s.append(im_gt[y-2:y+3, x-2:x+3] == im_gt[y, x])
            else:
                for yy in range(y-2, y+3):
                    for xx in range(x-2, x+3):
                        if xx > 1 and yy > 1 and xx < width - 1 and yy < height - 1:
                            drd += abs(im_gt[yy, xx] - im[y, x]) * W[yy-y+2, xx-x+2]
        return drd + np.sum(s * W)
    
    drd(np.random.choice([0, 1], size=(100, 100)), np.random.choice([0, 1], size=(100, 100)))
    

    有人能想到一种更快的方法来做到这一点吗?1000x1000的计时:

    enter image description here

    0 回复  |  直到 4 年前
        1
  •  3
  •   Mad Physicist    4 年前

    使用numpy加快速度的第一步是将操作序列分解为可以应用于整个数组的内容。让我们从一个简单的开始:消除计算中的理解 W :

    W = np.hypot(np.arange(-2, 3), np.arange(-2, 3)[:, None])
    np.reciprocal(W, where=W.astype(bool), out=W)
    W /= W.sum()
    

    下一件事(如上所述 where=W.astype(bool) )是在适当的情况下使用掩码将条件应用于整个数组。您的算法如下:

    对于不匹配的每个位置 im im_gt ,计算以下元素的总和 W 以它们不匹配的位置为中心。

    你可以用卷积来计算这个 W .地点 im == im_gt 只是被丢弃了。地点 im_gt == 1 需要通过减去来翻转 W.sum() ,因为你需要对零求和,而不是对这些元素求和。卷积在 scipy.signal.convolve2d 。通过使用,您可以获得相同的边缘效果 mode='same' 并仔细调整边缘像素。你可以通过与一个1数组卷积来获得边和:

    from scipy.signal import convolve2d
    
    # Compute this once outside the function
    W = np.hypot(np.arange(-2, 3), np.arange(-2, 3)[:, None])
    np.reciprocal(W, where=W.astype(bool), out=W)
    W /= W.sum()
    
    def drd(im, im_gt):
        m0 = im != im_gt
        m1 = im_gt == 0
        m2 = im_gt == 1
        s1 = convolve2d(m1, W, mode='same')[m0 & m1].sum()
        s2 = convolve2d(m2, W, mode='same')[m0 & m2].sum()
        return s1 + s2