简单的一线解决方案
您可以像这样在一行中完成所需的操作:
new_img = (((image - color)**2).sum(axis=2)**.5 <= 10) * 255
优化的两线解决方案
上一行不是执行OP所需的所有操作的最有效方式.这是一种明显更快的方法(感谢Paul Panzer在注释中提出优化建议,但不能保证可读性):
d = image - color
new_img = (np.einsum('...i, ...i', d, d) <= 100) * 255
时间:
给定一些100×100像素的测试数据:
import numpy as np
color = np.array([30, 70, 130])
# random data within [20,60,120]-[40,80,140] for demo purposes
image = np.random.randint(10*2 + 1, size=[100,100,3]) + color - 10
这是OP方法的时序与该答案的解决方案的比较.一站式解决方案比OP解决方案快约100倍,而完全优化的版本则比OP快约300倍:
%%timeit
# OP's code
img_dim = image.shape
new_img = np.zeros((img_dim[0],img_dim[1])) # no alpha channel replica
for c in range(img_dim[0]):
for r in range(img_dim[1]):
pixel = image[r,c,:3]
new_img[r,c] = L2_dist(color,pixel)
43.8 ms ± 502 ?s per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
# one line solution
new_img = (((image - color)**2).sum(axis=2)**.5 <= 10) * 255
439 ?s ± 13.7 ?s per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
# fully optimized solution
d = image - color
new_img = (np.einsum('...i, ...i', d, d) <= 100) * 255
145 ?s ± 2.29 ?s per loop (mean ± std. dev. of 7 runs, 10000 loops each)
简单的一线解决方案的说明
作为第一个解决方案提供的简单的单线将:
>查找图像中每个像素(将是形状(m,n,3)的数组)和颜色(将被形状(3)的数组)之间的欧几里得距离.
>检查这些距离中的任何一个是否在10之内,并在满足条件的任何地方返回一个布尔数组,该数组为True,否则为False.
>布尔数组实际上只是0和1的数组,因此我们将布尔数组乘以255,以获得所需的最终结果.
优化解决方案的说明
以下是使用的优化列表:
>使用einsum来计算距离计算所需的平方和.在后台,einsum利用Numpy包装的BLAS库来计算所需的求和积,因此它应该更快.
>通过比较距离的平方与阈值的平方来跳过平方根.
>我试图找到一种最小化数组分配/复制的方法,但这实际上使事情变慢了.这是优化解决方案的一个版本,该版本恰好分配两个数组(一个分配给中间结果,一个分配给最终结果),并且不进行其他复制:
%%timeit
# fully optimized solution, makes as few array copies as possible
scr = image.astype(np.double)
new_img = np.zeros(image.shape[:2], dtype=np.uint8)
np.multiply(np.less_equal(np.einsum('...i,...i', np.subtract(image, color, out=scr), scr, out=scr[:,:,0]), 100, out=new_img), 255, out=new_img)
232 ?s ± 7.72 ?s per loop (mean ± std. dev. of 7 runs, 1000 loops each)