在 Python 中尽可能高效地叠加混合模式(Numpy、OpenCV)

Ell*_*ial 3 python opencv numpy image python-3.x

假设我有两个 numpy 图像数组ab,尺寸相同,8 位颜色,RGB 格式。现在假设我想生成一个新的 numpy 数组,其像素值是使用“叠加”混合模式组合的前两个数组的像素值。

它的定义,取自维基百科,如下,其中b是顶层,a是底层:

在此输入图像描述

在公式中,我相信ab是用它们的“白度”来表示的,即全白像素为 1,全黑像素为 0。我不确定色调如何发挥作用。

我不确定除了逐像素迭代两个图像之外是否有更快的方法来做到这一点,这对于 1920x1080 图像来说确实很慢。我需要能够尽快完成这件事。

例如,我设法实现加法混合模式,如下所示:

import numpy as np
import cv2

a = cv2.imread("a.jpg", cv2.IMREAD_UNCHANGED)
b = cv2.imread("b.jpg", cv2.IMREAD_UNCHANGED)

a = a.astype(float)
b = b.astype(float)

ab = a
for i in range(len(ab)):
  ab[i] = a[i] + b[i]

cv2.imwrite('Out.png', ab)
Run Code Online (Sandbox Code Playgroud)

它看起来相当快,并且肯定比尝试通过逐像素迭代来实现相同的事情要快得多。但再次强调,这只是加法混合模式,我需要叠加混合模式。

如果您知道任何以 numpy 数组形式实现两个 RGB 图像之间的叠加混合模式的 Python 实现非常高效,请帮我找到它。如果没有,你能尽可能有效地实施它吗?

kev*_*aks 6

import numpy as np
import cv2

a = cv2.imread("a.jpg", cv2.IMREAD_UNCHANGED)
b = cv2.imread("b.jpg", cv2.IMREAD_UNCHANGED)

a = a.astype(float)/255  
b = b.astype(float)/255 # make float on range 0-1

mask = a >= 0.5 # generate boolean mask of everywhere a > 0.5 
ab = np.zeros_like(a) # generate an output container for the blended image 

# now do the blending 
ab[~mask] = (2*a*b)[~mask] # 2ab everywhere a<0.5
ab[mask] = (1-2*(1-a)*(1-b))[mask] # else this 
Run Code Online (Sandbox Code Playgroud)

我认为应该这样做。现在是 -1,2 上的浮动图像,并且是和ab的混合。这将相对较快,因为它使用and而不是循环。我很好奇听到速度差异。abbroadcastingmasking


以下材料由 Mark Setchell 于 2018 年 11 月 16 日添加,以便大家知道谁是有罪者:-)

Mr Kayaks 的代码计算出的值是 0..1 范围内的浮点数,而imwrite()预期的 uint8 值范围是 0..255。所以你只需要在他的代码底部添加以下内容:

# Scale to range 0..255 and save
x=(ab*255).astype(np.uint8) 
cv2.imwrite('result.png',x) 
Run Code Online (Sandbox Code Playgroud)

如果您将这两个图像作为a.jpgb.jpg

在此输入图像描述 在此输入图像描述

你会得到左边的结果 - 右边的结果是你选择叠加混合模式时从 Photoshop 得到的结果:

在此输入图像描述 在此输入图像描述