我要覆盖除指定颜色(在我的情况下为黑色)以外的两个图像。我已经为此写了一些代码。
def overlay_two_image(image, overlay):
result = image.copy()
mask = np.full(image.shape, False)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if not np.array_equal(overlay[i, j], [0, 0, 0]):
mask[i, j] = True
result[mask] = image[mask] * 0.5 + overlay[mask] * 0.5
return result
确定可以。但是我认为这不是一个好的解决方案。这非常慢,而且似乎不是pythonic。使用(1024、1024、3)图像大约需要5秒钟。
有没有更有效的方法? numpy中是否有array_equal的轴向版本?在OpenCV中是否确实有内部功能?还是有更有效的算法?
编辑:当要忽略的颜色不是黑色时,上面的代码不起作用。
答案 0 :(得分:3)
方法1
这是一个通用的,可以处理通用的ignore-color参数-
def overlay_two_image(image, overlay, ignore_color=[0,0,0]):
ignore_color = np.asarray(ignore_color)
mask = ~(overlay==ignore_color).all(-1)
# Or mask = (overlay!=ignore_color).any(-1)
out = image.copy()
out[mask] = image[mask] * 0.5 + overlay[mask] * 0.5
return out
方法2
使用np.where
使其更具有 pythonic -
def overlay_two_image_v2(image, overlay, ignore_color=[0,0,0]):
ignore_color = np.asarray(ignore_color)
mask = (overlay==ignore_color).all(-1,keepdims=True)
out = np.where(mask,image,(image * 0.5 + overlay * 0.5).astype(image.dtype))
return out
方法3
将views
用于内存,从而提高性能-
# https://stackoverflow.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are arrays
a = np.ascontiguousarray(a)
b = np.ascontiguousarray(b)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
def overlay_two_image_v3(image, overlay, ignore_color=[0,0,0]):
ignore_color = np.asarray(ignore_color)
O,I = view1D(overlay.reshape(-1,overlay.shape[-1]),ignore_color)
mask = (O==I).reshape(overlay.shape[:2])[...,None]
out = np.where(mask,image,(image * 0.5 + overlay * 0.5).astype(image.dtype))
return out
利用numexpr
模块来进一步增强-
import numexpr as ne
def overlay_two_image_v3_numexpr(image, overlay, ignore_color=[0,0,0]):
ignore_color = np.asarray(ignore_color)
O,I = view1D(overlay.reshape(-1,overlay.shape[-1]),ignore_color)
mask = (O==I).reshape(overlay.shape[:2])[...,None]
scaled_vals = ne.evaluate('image * 0.5 + overlay * 0.5').astype(image.dtype)
out = np.where(mask,image,scaled_vals)
return out
大型图像数据集上的时间-
In [250]: np.random.seed(0)
...: image = np.random.randint(0,256,(4000,5000,3))
...: overlay = np.random.randint(0,256,(4000,5000,3))
In [251]: ignore_color = [56,23,90]
In [252]: m,n = image.shape[:2]
...: unq_idx = np.random.choice(m*n,m*n//2,replace=0)
...: overlay.reshape(-1,overlay.shape[-1])[unq_idx] = ignore_color
In [253]: %timeit overlay_two_image(image, overlay, [56,23,90])
...: %timeit overlay_two_image_v2(image, overlay, [56,23,90])
...: %timeit overlay_two_image_v3(image, overlay, [56,23,90])
...: %timeit overlay_two_image_v3_numexpr(image, overlay, [56,23,90])
1.91 s ± 8.57 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1.43 s ± 8.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1.3 s ± 2.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
869 ms ± 3.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
答案 1 :(得分:1)
考虑使用numpy.ma
。它可以更快地完成工作。
根据您的情况,尝试更换
mask = np.full(image.shape, False)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if not np.array_equal(overlay[i, j], [0, 0, 0]):
mask[i, j] = True
使用
mask = np.ma.masked_greater(overlay, 0).mask