cv2.addWeighted除了一些颜色

时间:2019-07-19 02:54:11

标签: python performance numpy opencv image-processing

我要覆盖除指定颜色(在我的情况下为黑色)以外的两个图像。我已经为此写了一些代码。

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中是否确实有内部功能?还是有更有效的算法?

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

2 个答案:

答案 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
相关问题