このページでは、PIL や NumPy、OpenCV 等で扱う画像オブジェクトからアルファチャンネルのみを取得する方法について解説していきたいと思います。
結論としては、他の色(赤や緑や青)のみの成分を取得する時と同じ方法でアルファチャンネルも取得することが可能です。
また、最初にアルファチャンネルそのものについて解説しますが、アルファチャンネルについて既にご存知の方、及び、すぐにアルファチャンネルのみを取得する方法を知りたいという方は アルファチャンネルのみ取得する方法 までスキップしていただければと思います。
アルファチャンネルとは
最初にアルファチャンネルについて簡単に解説しておきます。
画像はピクセル(画素)の集まりであり、通常、画像の各ピクセルは、赤色を示す R、緑色を示す G、青色を示す B の3つのチャンネルの値によって色が決定されます。
さらに、例えば PNG などの特定の画像フォーマットにおいては、4つ目のチャンネルを扱うことができます。この4つ目のチャンネルをアルファチャンネルと呼びます。このアルファチャンネルの用途は様々ですが、透明度の設定に用いられることが多いです。
PNG などでは、アルファチャンネルの値としては 0
〜 255
を設定することができ、値が小さいほど透明度が高くなり、値が大きくなるほど透明度が低くなります。ですので、アルファチャンネルが 0
の画素は完全に透明になり、アルファチャンネルが 255
の画素は完全に不透明になります。
例えば下の画像は白と灰色の市松模様の画像に見えますが、実は違います。白色に見える画素に対してはアルファチャンネルを 0
に設定していますので、実はこの画素は白色ではなく透明な画素になります。
この画像をコピーしてパワポなどに貼り付け、色のついた背景などの上に移動させてみると、白色ではなく透明であることも確認できると思います。
こんな感じで、主に透明度の設定に用いられるのがアルファチャンネルになります。
で、今回は、Python でこの画像のアルファチャンネルのみを取得する方法について解説していきます。
例えば上記でお見せした白と黒の市松模様の画像からアルファチャンネルのみを取得してグレースケール画像として表現したものが下の図になります。
元画像である下の画像と比べると、透明だった画素が黒色に、不透明だったがそが白色に変化していることが分かると思います。
透明な画素のアルファチャンネルの値は 0
ですので、それをグレースケール画像の画素として考えると黒色で表現されることになります。逆に不透明な画素のアルファチャンネルの値は 255
ですので、それをグレースケール画像の画素として考えると白色の画素で表現されることになります。
アルファチャンネルのみ取得する方法
それでは、画像からアルファチャンネルのみを取得する方法について解説していきたいと思います。
アルファチャンネルは4つ目のチャンネルであるものの、画像データの中では他の3つのチャンネルと同様にして管理されています。
ですので、特定のチャンネルのみを取得する(赤色成分のみを取得する・緑色成分のみを取得する・青色成分のみを取得する)のと同様の方法でアルファチャンネルのみを取得することが可能です。
スポンサーリンク
PIL の場合
PIL の場合、Image
クラスの split
メソッドにより各チャネルごとに分離した画像を取得することができますので、これを利用することでアルファチャンネルのみを取得することができます。
実際に PIL の Image
クラスの split
メソッドを利用してアルファチャンネルのみを取得するスクリプトの例は下記のようになります。
from PIL import Image
# 読み込みたい画像のファイルパス
IMAGE_PATH = "hashiru_boy.png"
# アルファチャネルのみの画像を保存するファイルパス
SAVE_PATH = "alpha_hashiru_boy.png"
image = Image.open(IMAGE_PATH)
# 画像をチャネルごとに分離
r, g, b, alpha_image = image.split()
# アルファチャネルのみの画像を保存
alpha_image.save(SAVE_PATH)
IMAGE_PATH
ではアルファチャンネルの取得先となる画像のファイルパスを、SAVE_PATH
では取得したアルファチャンネルをグレースケール画像としたデータの保存先のファイルパスを指定するようにしています。
スクリプトを実行すれば、IMAGE_PATH
の画像のアルファチャンネルのみがグレースケール画像として SAVE_PATH
に保存されます(SAVE_PATH
で指定したパスのファイルは上書きされてしまうので注意してください)。
例えば いらすとや で公開されている下図の画像のファイルパスを IMAGE_PATH
に指定してスクリプトを実行した場合、
転載元:いらすとや
SAVE_PATH
で指定したパスに下の図のような画像が保存されることになります。
黒色の部分は値が 0
の画素ですので、元々の画像では、この黒色の画素のアルファチャンネルの値が 0
であり、透明な画素だったことになります。
少年が存在しない背景の部分だけ真っ黒になっているので、この部分はアルファチャンネルが 0
で透明に設定されていることが確認できます。
上記スクリプトにおいて、アルファチャンネルの取得を行なっているのは下記部分になります。
# 画像をチャネルごとに分離
r, g, b, alpha_image = image.split()
image.split()
を実行することによって、元々の画像のオブジェクト image
をチャネルごとに分離し、分離後の画像オブジェクトを返却値として取得することができます(正確にいうと分離後の画像オブジェクトを要素とするタプルが返却される。上記ではそのタプルのアンパックも同時に行なっている)。
返却される画像オブジェクトの数は元々の画像のチャネル数となります。さらに、RGBα の順で返却されますので、4つ目の返却値がアルファチャンネルのみに分離された画像のオブジェクトとなります。
上記では image.split()
の返却値が4つであることを前提としていますので、アルファチャンネルが設定されていない画像などに対して実行するとエラーになるので注意してください。
NumPy の場合
NumPy の場合でも考え方は同じで、要は特定の色のみを取得するときと同様の方法でアルファチャンネルのみを取得することが可能です。
NumPy の場合は画像の各画素のデータが3次元の配列で管理されています。
この配列の各軸(各次元)はそれぞれ下記を表します
- 第1軸:横方向の座標
- 第2軸:縦方向の座標
- 第3軸:色(チャンネル)
図で表すと下のようになります。
さらに、NumPy 配列に対してスライスを利用すれば、各チャンネル毎にデータを切り出し、画像の特定のチャンネルのみを取得することができます。このスライスを利用する際に、アルファチャンネルのみを取得するように指定すれば、アルファチャンネルのみを取得することができます。
より具体的には、画像から生成した NumPy 配列を array
とすれば、array[:, :, 3]
によりアルファチャンネルのみを取得することができます。
ちなみに array[:, :, 0]
、array[:, :, 1]
、array[:, :, 2]
と指定すれば、それぞれ赤色のチャンネルのみ、緑色のチャンネルのみ、青色のチャンネルのみを取得するようなこともできます。
この辺りの解説は下記ページでも行なっていますので、詳しく知りたい方は下記ページの前半を読んでいただければと思います。
Pythonでの差分画像の作り方【NumPy・PIL】実際にスライスを利用して NumPy 配列からアルファチャンネルのみを取得するスクリプトの例は下記のようになります。
from PIL import Image
import numpy
# 読み込みたい画像のファイルパス
IMAGE_PATH = "hashiru_boy.png"
# アルファチャネルのみの画像を保存するファイルパス
SAVE_PATH = "alpha_hashiru_boy.png"
# 画像を読み込んでNumPy配列を作成
image_array = numpy.array(Image.open(IMAGE_PATH))
# スライスを利用してアルファチャンネルのみを切り出し
alpha_array = image_array[:,:,3]
# アルファチャンネルのみの画像を作成して保存
alpha_image = Image.fromarray(alpha_array)
alpha_image.save(SAVE_PATH)
IMAGE_PATH
や SAVE_PATH
の意味、実行結果は PIL の場合 と全く同じなので説明は省略します。
今回も読み込む画像が4チャンネルであることを前提とした作りになっているので注意してください。
OpenCV の場合
OpenCV では、画像データは結局 NumPy 配列として扱われていますので、NumPy 配列の時と全く同じ処理によりアルファチャンネルのみを取得することが可能です。
NumPy 配列の時と同様の処理により、OpenCV で扱う画像からアルファチャンネルのみを取得するスクリプトの例は下記のようになります。
import cv2
# 読み込みたい画像のファイルパス
IMAGE_PATH = "hashiru_boy.png"
# アルファチャネルのみの画像を保存するファイルパス
SAVE_PATH = "alpha_hashiru_boy.png"
# 画像を読み込んでNumPy配列を作成
image = cv2.imread(IMAGE_PATH, cv2.IMREAD_UNCHANGED)
# スライスを利用してアルファチャンネルのみを切り出し
alpha_image = image[:,:,3]
# 画像ファイルとして保存
cv2.imwrite(SAVE_PATH, alpha_image)
こちらも IMAGE_PATH
や SAVE_PATH
の意味、実行結果は PIL の場合 と全く同じなので説明は省略します。
また、今回も読み込む画像が4チャンネルであることを前提とした作りになっているので注意してください。
OpenCV の場合は追加の注意点があって、どうも cv2.imread
で特にオプション指定しない場合、アルファチャンネル付きの画像であってもアルファチャンネルが除去された状態で画像オブジェクト(NumPy 配列)が生成されるようです。
アルファチャンネルを除去せずに、元の画像のままで画像オブジェクトを生成したい場合は、cv2.imread
の引数で cv2.IMREAD_UNCHANGED
を指定する必要があります。
スポンサーリンク
まとめ
このページでは、Python で画像のアルファチャンネルのみを取得する方法について解説しました!
基本的な考え方は他の色(赤・緑・青)を取得する時と同じで、単に4チャンネル目のデータを取得することでアルファチャンネルを取得することが可能です。
ただ、4チャンネル目のみを取得する方法が、使用するモジュールによって異なるので注意してください。
画像にどんな感じでアルファチャンネルが設定されているかを調べたり、画像と画像とで不透明部分が重なっているかどうかを判断したりしたい際は、このページの内容を参考にしていただければと思います!
ちなみに私は今2Dアクションゲームを作ろうとしていて、キャラクター同士が重なったかどうかの判断(要は当たり判定)に、このページの内容を利用しようと思っています。