我正在寻找一种将自定义功能应用于图像的更快方法,该图像用于去除蓝色背景。我有一个函数可以计算每个像素与背景中的蓝色近似的距离。带有循环的原始代码如下:
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秒钟仍然很慢。我缺少什么可以将其加速到合理的执行时间
答案 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(+
,-
,*
,**
,<
...),聚合(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
答案 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)进行替换