python - cv2.addWeighted 除了一些颜色
问题描述
我想叠加两个图像,除了指定的颜色(在我的情况下是黑色)。我已经为此编写了一些代码。
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中是否有内部函数可以做到这一点?还是有更有效的算法?
编辑:当要忽略的颜色不是黑色时,上面的代码不起作用。
解决方案
方法#1
这是一个通用的忽略颜色参数的通用方法 -
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)