2つの画像のシンプルなオーバーレイ

これは、ある画像が別の画像にどのようにオーバーレイするかについての面白い話です。 ラスターグラフィックスに携わっている場合、ゲームやグラフィックエディターを書いている場合は、この記事で何かを見つけることはまずありません。 私は、このタスクが一見したほど簡単ではないことを知りたいと思っています。



したがって、RGBA形式の2つの画像(つまり、3色+アルファチャネル)があります。



画像 画像

ご注意 1:画像を選択する基準は、透明、不透明、半透明の領域の存在です。 それらに描かれているものはそれほど重要ではありません。

ご注意 2:写真はPhotoshopで表示されているように見え、リンクは実際の写真につながります。



タスクは、正しいRGBA形式で、正しい透明度と色で、それらの3分の1を組み立てることです。 これは、Photoshopがこれを処理する方法です。この画像を参考にしてください。



画像



PILを使用してPythonの例を示します。

したがって、最も単純なコードは次のとおりです。



im1 = Image.open('im1.png') im2 = Image.open('im2.png') im1.paste(im2, (0,0), im2) #   — ,    im1.save('r1.png')
      
      







2番目のアルファチャネルを使用して両方の画像をミックスします。 この場合、結果のイメージの各ピクセルの各コンポーネント(アルファチャネルを含む)は、X 2 ×a + X 1 ×(1-a)として計算されます。ここで、aは、送信されたアルファチャネルim2からのこのピクセルのアルファ値です。



コードはこの結果を与えます:



画像

不一致はすぐに表示されます-赤いチェックマークが2番目の画像と重なっている場所では、元のものよりもさらに透明になりましたが、ロジックは、1つの半透明のオブジェクトが他のオブジェクトを隠すと、結果は両方のオブジェクトよりも不透明になるはずであることを示唆しています。 これは、色の混合に加えて、アルファチャンネルが混合されたために発生しました。 2番目のアルファチャネルの強度は約0.25で、最初のアルファチャネルの強度は0.5でした。 それらを2番目の強度と混合しました:0.25×0.25 + 0.5×(1-0.25)= 0.44。



背景(最初の)画像が一般的に不透明である場合、そのような混合半透明のスポットがその上に表示され、物理学のすべての法則と矛盾します。



ミキシングの前に2番目の画像のアルファチャンネルをクリアして、この効果を排除してみましょう。

 im1 = Image.open('im1.png') im2 = Image.open('im2.png') im1.paste(im2.convert('RGB'), (0,0), im2) im1.save('r2.png')
      
      







結果は次のようになります。



画像

オーバーレイでの透明度は正常になりましたが、オリジナルではほとんど目立たなかった図形の影が、はっきりとした黒い縞に変わりました。 これは、色を計算するときに、オーバーレイアルゴリズムがこの場所の2番目の画像が最初の画像よりも強いという事実を考慮しないためです(2番目の画像にはアルファチャネルがないため、このデータを取得する必要があります)。 2番目の画像のアルファチャネル。 そして、この場所のアルファチャネルでは、強度は約0.5です。 したがって、実際にはかなり多い黒色は、青色と同じ割合で参加します。



しかし、推測するために、そのようなプロパティを持つ実際のオブジェクトがどのように見えるかを考えた方が良いでしょう。



2つの半透明のガラスを想像してください。1つは青、もう1つは赤です。 青は赤よりも近い。 次に、両方のグラスの全体的な不透明度は、最も近いグラスの不透明度と近い方の透明度(つまり1-A C )の合計に、遠方の不透明度を掛けた値になります:A C +(1-A C )×AK。



色はどうですか? より正確には、関心のあるのは色そのものではなく、浸漬ガラスの色の割合です。 これは、浸漬ガラスの不透明度を合計不透明度で割ったものに等しくなります。 つまり 一般に、色の計算に使用される不透明度の値は、結果のピクセルの不透明度と等しくありません。



このモデルでは、各ガラスは画像の1ピクセルです。 それらから画像を収集すると、より一般的な結論が得られます-結果のピクセルの色の計算に使用されるアルファチャネルは、結果の画像のアルファチャネルと等しくありません。



Pythonを使用して「正しい」透明度を実装すると、次のようになります。



 def alpha_composite(background, image): # get alphachanels alpha = image.split()[-1] background_alpha = background.split()[-1] new_alpha = list(background_alpha.getdata()) new_blending = list(alpha.getdata()) for i in xrange(len(new_alpha)): alpha_pixel = new_blending[i] if alpha_pixel == 0: new_alpha[i] = 0 else: new_alpha[i] = alpha_pixel + (255 - alpha_pixel) * new_alpha[i] / 255 new_blending[i] = alpha_pixel * 255 / new_alpha[i] alpha.putdata(new_alpha) background_alpha.putdata(new_blending) del new_alpha del new_blending result = background.copy() result.paste(image, (0, 0), background_alpha) result.putalpha(alpha) return result im1 = Image.open('im1.png') im2 = Image.open('im2.png') alpha_composite(im1, im2).save('r3.png')
      
      







そして、実際には、結果:



画像

Photoshopで作成された結果とほとんど変わりません。 ちなみに、PILを使用して画像をピクセル単位で処理しなくても同じ結果を得ることができるかどうかを誰かが知っている場合は、お知らせください。



All Articles