有没有办法使用 numpy 数组函数来获得同样的效果?

Is there a way to use numpy array functions to get this same effect?

我正在尝试使用以下代码过滤掉给定公差范围内的所有非灰度值。它给出了预期的结果,但运行速度太慢而无法在实践中使用。有没有办法使用 numpy 操作来执行以下操作?

for i in range(height):
        for j in range(width):
            r, g, b = im_arr[i][j]

            r = (r + 150) / 2
            g = (g + 150) / 2
            b = (b + 150) / 2

            mean = (r + g + b) / 3
            diffr = abs(mean - r)
            diffg = abs(mean - g)
            diffb = abs(mean - b)

            maxdev = 2

            if (diffr + diffg + diffb) > maxdev:
                im_arr[i][j][0] = 0
                im_arr[i][j][1] = 0
                im_arr[i][j][2] = 0

这可以在没有任何循环的情况下完成。我会尽量把每一步都打成专线

import numpy as np
im_arr = np.random.rand(300,400,3) # Assuming this how you image looks like
img_shifted = (im_arr + 15) / 2 # This can be done in one go
mean_v = np.mean(img_shifted, axis=2) # Compute the mean along the channel axis
diff_img = np.abs(mean_v[:,:,None] - img_shifted) # Broadcasting to subtract n x m from n x m x k
maxdev = 2
selection = np.sum(diff_img, axis=2) > maxdev
im_arr[selection] = 0 # Using fancy indexing with booleans 

普通循环 Python 很慢:numpy 的优点之一是 遍历数组是高度优化的。不评论算法,只用numpy就可以得到相同的结果,这样会快很多

由于im_arr是一张图片,所以dtype很可能是np.uint8。 那只有 8 位,所以你必须小心溢出。在您的代码中,当您将 150 添加到一个数字时,结果将是 np.int64 类型。但是,如果将 150 加到 8 位 np.ndarray,结果仍然是 np.uint8 类型并且它可能会溢出。 您可以更改数组类型(使用 astype)或添加浮点数,这会自动将数组提升为 float

mod_img = (im_arr + 150.)/2  # the point of "150." is important
signed_dif = mod_img - np.mean(mod_img, axis=2, keepdims=True)
collapsed_dif = np.sum(np.abs(signed_dif), axis=2)
maxdev = 2
im_arr[collapsed_dif > maxdev] = 0