首页 > 解决方案 > 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中是否有内部函数可以做到这一点?还是有更有效的算法?

编辑:当要忽略的颜色不是黑色时,上面的代码不起作用。

标签: pythonperformancenumpyopencvimage-processing

解决方案


方法#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)

推荐阅读