5

There's a bunch of questions here on SO which provide answers to the present question, however the output is not the expected.

The goal is to merge two RGBA images. The information on the alpha channel of each image is not the same.

The current (simplified) code is:

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")

The two images are:

Background

Background

Foreground

Foreground

Expected output

Expected output

Actual result

Actual result

In case you don't see the difference, here are the alpha channels (inverted for better visualization) of the final versions.

Expected result - alpha channel

Expected result - alpha channel

Actual result - alpha channel

Actual result - alpha channel

So with that said, is there any way of doing this or am I doing something wrong?

EDIT - clarification following @zenpoy comment:

If the foreground image has a certain amount of opacity, I want that to be taken into account when superimposing both images, but I don't want the alpha channel of the second image to be added to the first. Much like putting a piece of glass (the foreground image) in front of a paper image (background).

In other words, if the background image was RGB instead of RGBA, the final image should have no alpha information.

4

1 回答 1

3

从您最初的描述来看,以下想法似乎是等效的。设 X, Y 为两个 RGBA 图像。考虑 X 中的 RGB 波段和 Y 中的 RGBA 波段,合并 X 和 Y,生成图像 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')

函数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

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

于 2012-12-08T00:42:23.637 回答