【问题标题】:Overlay Blending Mode in Python Efficiently as Possible (Numpy, OpenCV)在 Python 中尽可能高效地覆盖混合模式(Numpy,OpenCV)
【发布时间】:2019-02-08 01:15:42
【问题描述】:

假设我有两个相同尺寸、8 位颜色、RGB 格式的 numpy 图像数组,ab。现在假设我想生成一个新的 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)

这似乎相当快,而且肯定比试图通过逐个像素迭代来实现同样的事情要快得多。但是再一次,这只是 Addition 混合模式,我需要 Overlay 混合模式。

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

【问题讨论】:

    标签: python python-3.x image numpy opencv


    【解决方案1】:
    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 
    

    我认为应该这样做。现在ab 是-1,2 上的浮动图像,是ab 的混合。这将相对较快,因为它使用broadcastingmasking 而不是循环。我很想知道速度差异。


    Mark Setchell 于 2018 年 11 月 16 日添加的以下材料,让你们都知道谁是有罪的一方 :-)

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

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

    如果你把这两张图片分别为a.jpgb.jpg

    如果您选择叠加混合模式,您将在左侧获得结果 - 右侧是您从 Photoshop 获得的结果:

    【讨论】:

    • 当我按照您的代码使用cv2.imwrite('zOutNEW.png', ab) 行时,输出图像似乎很暗,并且与您在 Photoshop 中获得的结果大不相同。我不确定出了什么问题。
    • 我怀疑 imwrite 期望 uint8 在 0-255 范围内。这就是我首先要尝试的。假设ab.min() 约为-1,ab.max() 约为1,请尝试ab = ((ab-ab.min())/2.0*255.0).astype('uint8')。您可能需要min 中的轴参数。我现在在这台计算机上没有 python 可以检查。要进行调试,还请事先尝试使用遮罩和广播复制您之前的加法混合结果。这些原则是快速完成的方法。
    • 有什么更新吗?您的问题可能是 imwrite 的输入数据类型或我对 a 和 b 的解释。
    • 我希望您不介意我在您的代码中添加一些内容 - 如果您这样做,请拒绝或删除它。我想添加它,因为您是如此接近,但我不想添加竞争答案并窃取您应得的分数。希望你能理解。
    猜你喜欢
    • 2012-12-09
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 2017-07-31
    相关资源
    最近更新 更多