5

SOには、現在の質問に対する回答を提供する質問がたくさんありますが、出力は期待されていません。

目標は、2つのRGBA画像をマージすることです。各画像のアルファチャネルに関する情報は同じではありません。

現在の(簡略化された)コードは次のとおりです。

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

2つの画像は次のとおりです。

バックグラウンド

バックグラウンド

前景

前景

期待される出力

期待される出力

実結果

実結果

違いがわからない場合は、最終バージョンのアルファチャネル(視覚化を向上させるために反転)を次に示します。

期待される結果-アルファチャネル

期待される結果-アルファチャネル

実際の結果-アルファチャネル

実際の結果-アルファチャネル

そうは言っても、これを行う方法はありますか、それとも私は何か間違ったことをしていますか?

編集-@zenpoyコメントに続く説明:

前景画像にある程度の不透明度がある場合は、両方の画像を重ね合わせるときにそれを考慮に入れたいのですが、2番目の画像のアルファチャネルを最初の画像に追加したくありません。紙の画像(背景)の前にガラス(前景の画像)を置くのと同じです。

つまり、背景画像がRGBAではなくRGBである場合、最終的な画像にはアルファ情報が含まれていないはずです。

4

1 に答える 1

3

最初の説明から、次のアイデアは同等のようです。X、Yを2つの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 に答える