代码之家  ›  专栏  ›  技术社区  ›  Sindri Ingolfsson

快速将自定义函数应用于图像中的每个像素

  •  2
  • Sindri Ingolfsson  · 技术社区  · 6 年前

    我正在寻找一种更快的方法,将自定义函数应用到我用来移除蓝色背景的图像。我有一个函数,计算每个像素与背景中蓝色的距离。带有循环的原始代码如下所示:

    def dist_to_blue(pix):
        rdist = 76 - pix[0]
        gdist = 150 - pix[1]
        bdist = 240 - pix[2]
        return rdist*rdist + gdist*gdist + bdist*bdist
    
    imgage.shape #outputs (576, 720, 3)
    for i, row in enumerate(image):
        for j, pix in enumerate(row):
            if dist_to_blue(pix) < 12000: image[i,j] = [255,255,255]
    

    我所做的唯一改进是将for循环替换为以下内容:

    m = np.apply_along_axis(lambda pix: (255,255,255) if dist_to_blue(pix) < 12000 else pix, 2, image)

    大约7秒钟,速度还是很慢。有没有什么我遗漏了的东西可以加速到一个合理的执行时间

    5 回复  |  直到 6 年前
        1
  •  1
  •   Deepak Saini    6 年前

    一种结合“dash tom bang”和“kevinkayaks”答案的方法

    # Assume the image is of shape (h, w, 3)
    # Precompute some data
    RDIST = np.array([(76 - r)**2 for r in range(256)])
    GDIST = np.array([(150 - g)**2 for g in range(256)])
    BDIST = np.array([(240 - b)**2 for b in range(256)])
    
    # Calculate and apply mask
    mask = (RDIST[image[:,:,0]] + GDIST[image[:,:,1]] + BDIST[image[:,:,2]]) < 12000
    image[mask] = [255,255,255]
    
        2
  •  2
  •   kevinkayaks    6 年前

    这应该快一点。。。;)

    import numpy as np 
    blue = np.full_like(image, [76,150,250])
    mask = np.sum((image-blue)**2,axis=-1) < 12000
    image[mask] = [255,0,255]
    

    在这里,生成理想的蓝色图像,逐像素将图像的差异平方,然后在生成遮罩之前对最后一个轴(rgb向量)求和,并使用它修改原始图像中的值。

        3
  •  1
  •   dash-tom-bang    6 年前

    这只是一个暗中拍摄,但也许预先计算一些数据会有帮助?我不确定,但是查表可能比加法和乘法快?

    def square(x): # maybe there's a library function for this?
        return x*x
    
    RDIST = [square(76 - r) for r in range(256)]
    GDIST = [square(150 - g) for g in range(256)]
    BDIST = [square(240 - b) for b in range(256)]
    
    def dist_to_blue(pix):
        return RDIST[pix[0]] + GDIST[pix[1]] + BDIST[pix[2]]
    

    我也怀疑,如果你有一种方法来获得每行像素的数组,可能会更快,而不是索引每一个单独的像素,但我不知道在发挥库。

        4
  •  1
  •   yann    6 年前

    有一些方法可以通过利用 for loops ,就像使用Numpy的ufuncs( + , - , * ** , < …),聚合( sum max , min , mean …),广播,掩蔽,花哨的索引。 下面的代码可能会给您一些提示:

    dist = np.expand_dims(np.array([76, 150, 240]), axis=0)
    image[np.where(np.sum((image-dist)**2, axis=2) < 12000)]=255
    
        5
  •  1
  •   Daniel F    6 年前
    from scipy.spatial.distance import cdist
    
    blue = np.array([76, 150, 250])
    
    def crush_color(image, color, thr = np.sqrt(12000), new = np.array([255, 255, 255]));
        dist_to_color = cdist(image.reshape(-1, 3), color, 'sqeuclidean').reshape(image.shape[:-1])
        image[dist_to_color[..., None] < thr**2] = new
    
    crush_color(image, blue)
    

    cdist 它将计算距离(在本例中为ueclidean的平方),甚至比 numpy 广播。