将自定义功能应用于图像中每个像素的快速方法

时间:2018-08-24 03:27:01

标签: python image numpy

我正在寻找一种将自定义功能应用于图像的更快方法,该图像用于去除蓝色背景。我有一个函数可以计算每个像素与背景中的蓝色近似的距离。带有循环的原始代码如下:

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]

但是,对于此相对较小的图像,此代码大约需要8秒钟才能运行。我一直在尝试使用numpy的“ vectorize”函数,但是该函数分别应用于每个值。但是我想对每个像素也不要扩展z / rgb尺寸

我想出的唯一改进就是用以下内容替换了for循环:

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

运行约7秒钟仍然很慢。我缺少什么可以将其加速到合理的执行时间

5 个答案:

答案 0 :(得分:2)

这应该快一点...;)

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矢量)求和,然后使用其修改原始图像中的值。

答案 1 :(得分:1)

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

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]]

我也怀疑您是否有办法仅获得每行像素数组可能更快,而不是对每个单独的像素编制索引,但是我不知道正在使用的库。

答案 2 :(得分:1)

一种结合了@ 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]

答案 3 :(得分:1)

有一些方法可以通过乘for loops来加速Numpy代码,例如使用Numpy的ufuncs(+-***< ...),聚合(summaxminmean ...),广播,屏蔽,花式索引。 以下代码可能会给您一些提示:

dist = np.expand_dims(np.array([76, 150, 240]), axis=0)
image[np.where(np.sum((image-dist)**2, axis=2) < 12000)]=255

答案 4 :(得分:1)

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)

1)代替手动进行距离计算,使用cdist可以比numpy广播更快地计算距离(在这种情况下,平方欧氏距离)。

2)进行替换