带有 alpha 通道的两个图像的 PIL 合并 - 未按预期工作

uno*_*ode 5 python python-imaging-library

这里有一堆关于 SO 的问题,它们提供了当前问题的答案,但是输出不是预期的。

目标是合并两个 RGBA 图像。每张图像的 alpha 通道上的信息是不一样的。

当前(简化)代码是:

from PIL import Image

image = '1.png'
watermark = '2.png'

wmark = Image.open(watermark)
img = Image.open(image)

img.paste(wmark, (0, 0), wmark)
img.save("result.png", "PNG")
Run Code Online (Sandbox Code Playgroud)

两张图分别是:

背景

背景

前景

前景

预期输出

预期输出

实际结果

实际结果

如果您没有看到差异,这里是最终版本的 alpha 通道(为了更好的可视化而反转)。

预期结果 - alpha 通道

预期结果 - alpha 通道

实际结果 - alpha 通道

实际结果 - alpha 通道

话虽如此,有什么办法可以做到这一点,还是我做错了什么?

编辑 - 在@zenpoy 评论后澄清:

如果前景图像具有一定的不透明度,我希望在叠加两个图像时考虑到这一点,但我不希望将第二个图像的 alpha 通道添加到第一个图像中。就像在纸图像(背景)前面放一块玻璃(前景图像)一样。

换句话说,如果背景图像是 RGB 而不是 RGBA,则最终图像应该没有 alpha 信息。

mmg*_*mgp 3

从您最初的描述来看,以下想法似乎是等效的。令 X、Y 为两个 RGBA 图像。合并 X 和 Y,考虑 X 中的 RGB 波段和 Y 中的 RGBA 波段,生成图像 Z。将 Z 中的波段 A 设置为 X 中的波段 A。这与您的最终陈述相矛盾,但它似乎给出了预期的结果这种情况下的输出。

所以,这是代码:

image = '1.png'
watermark = '2.png'

wmark = Image.open(watermark)
img = Image.open(image)

ia, wa = None, None
if len(img.getbands()) == 4:
    ir, ig, ib, ia = img.split()
    img = Image.merge('RGB', (ir, ig, ib))
if len(wmark.getbands()) == 4:
    wa = wmark.split()[-1]

img.paste(wmark, (0, 0), wmark)
if ia:
    if wa:
        # XXX This seems to solve the contradiction, discard if unwanted.
        ia = max_alpha(wa, ia)
    img.putalpha(ia)

img.save('result.png')
Run Code Online (Sandbox Code Playgroud)

其中函数max_alpha是:

def max_alpha(a, b):
    # Assumption: 'a' and 'b' are of same size
    im_a = a.load()
    im_b = b.load()
    width, height = a.size

    alpha = Image.new('L', (width, height))
    im = alpha.load()
    for x in xrange(width):
        for y in xrange(height):
            im[x, y] = max(im_a[x, y], im_b[x, y])
    return alpha
Run Code Online (Sandbox Code Playgroud)

这个新功能似乎考虑到了提到的矛盾。