【Python/Pillow(PIL)】画像のビット数、チャンネル数を調べる

画像のビット数(8や24など)やチャンネル数(色の数、Lの場合は1、RGBの場合は3など)は画像処理をするときに、画像データを直接参照する場合などに必要になってきます。

jpegファイル(*.jpg)を開いたときには bits という値が拾え、1画素、1色あたり8bitであることがわかります。

しかしながら、他の形式のファイル(少なくとも bmp, pmg, gif)では、この bits の値がありません。

 

そこで、どのファイルでも画像のビット数やチャンネル数を調べられるようにするには、mode の値を調べるようにします。
modeの取得は、以下のように行います。

from PIL import Image

# Pillow で画像を読み込む
pil_image = Image.open("image_color.bmp")
# modeの表示
print("モード:", pil_image.mode)

モードの種類は以下の通りです。

mode 説明
1 1-bit pixels, black and white, stored with one pixel per byte
L 8-bit pixels, black and white
P 8-bit pixels, mapped to any other mode using a color palette
RGB 3×8-bit pixels, true color
RGBA 4×8-bit pixels, true color with transparency mask
CMYK 4×8-bit pixels, color separation
YCbCr 3×8-bit pixels, color video format
LAB 3×8-bit pixels, the L*a*b color space
HSV 3×8-bit pixels, Hue, Saturation, Value color space
I 32-bit signed integer pixels
F 32-bit floating point pixels

(参考)

https://pillow.readthedocs.io/en/stable/handbook/concepts.html

 

画像のビット数やチャンネル数を調べるのに、この mode を取得して、条件分岐でビット数やチャンネル数を上記の表から取得すると正確に求まります。

ただ、実際に使われるのは L, RGB, RGBA の3つぐらいなので、1画素8bit限定として考えると、チャンネル数が求まればビット数も求まります。

チャンネル数を直接取得できる方法は無さそうなので、 getbands() というメソッドを使って行います。

この getbands() は、例えば mode = ‘RGB’ のとき、各チャンネルの色の名前の(‘R’, ‘G’, ‘B’)というタプルを返すメソッドになります。そのため、このタプルの長さを取得すればチャンネル数も求まります。

 

サンプルプログラム

from PIL import Image

# Pillow でモノクロ画像を読み込む
pil_image_mono = Image.open("image_mono.bmp")
print("■■ モノクロ画像 ■■")
print("モード:\t\t", pil_image_mono.mode)
print("バンド:\t\t", pil_image_mono.getbands())
print("チャンネル数:\t", len(pil_image_mono.getbands()))

# Pillow でカラー画像を読み込む
pil_image_color = Image.open("image_color.bmp")
print("■■ カラー画像 ■■")
print("モード:\t\t", pil_image_color.mode)
print("バンド:\t\t", pil_image_color.getbands())
print("チャンネル数:\t", len(pil_image_color.getbands()))

実行結果

 

参考

https://pillow.readthedocs.io/en/stable/reference/Image.html?highlight=getbands#PIL.Image.Image.getbands

matplotlibで画像データ(OpenCV,pillow,list)を表示する

matplotlibを使って画像を表示すると、下図のように画像の画像の座標軸が表示され、右下にはマウスポインタの座標および、その位置の画像の輝度値が表示されるので便利です。

さらに矢印アイコンで、画像の移動、虫眼鏡アイコンで画像の領域を選択すると、その領域が拡大表示されます。

 

Pillow画像の表示

上図ではPillowで画像を開いて、matplotlibで表示しているのですが、そのプログラムは以下の通りです。

import matplotlib.pyplot as plt
from PIL import Image

# Pillow でカラー画像を読み込む
pil_image_color = Image.open("Parrots.bmp")
# matplotlibで表示
plt.imshow(pil_image_color)    
plt.show()

ただし、モノクロ画像を以下のようなプログラムで画像を表示すると、変な色合いになります。

import matplotlib.pyplot as plt
from PIL import Image

# Pillow でモノクロ画像を読み込む
pil_image_color = Image.open("Text.bmp")
# matplotlibで表示
plt.imshow(pil_image_color)    
plt.show()

 

モノクロのグレースケールで表示するには、imshowの引数にグレースケールの cmap(カラーマップ、カラーパレット) “gray” を指定して、以下のようにします。

import matplotlib.pyplot as plt
from PIL import Image

# Pillow でモノクロ画像を読み込む
pil_image_color = Image.open("Text.bmp", cmap = "gray")
# matplotlibで表示
plt.imshow(pil_image_color)    
plt.show()

 

このカラーマップ(cmap)にはデフォルトで “viridis” というものが設定されていて、下図のような色味になっています。

 

カラーマップは他にも hsv や rainbow, jet など様々用意されており、例えば、rainbowを使うと、下図のようになります。

 

カラーマップは色々用意されているので、モノクロ画像を疑似カラーで表示したい場合は、gray以外のものを使用するのも便利だと思います。

カラーマップの詳細については、以下のページで確認できます。

https://matplotlib.org/stable/gallery/color/colormap_reference.html

 

OpenCV画像の表示

matplotlibのimshow関数に指定する画像データはPillowの画像以外にも、OpenCVの画像データ(実態はnumpyのndarray)も指定可能です。

以下のようなプログラムを実行すると

import matplotlib.pyplot as plt

import cv2

# OpenCVでモノクロ画像を読み込む
cv_image_mono = cv2.imread("Text.bmp", cv2.IMREAD_UNCHANGED)
print(type(cv_image_mono))
print(cv_image_mono.shape)
# matplotlibで表示
plt.imshow(cv_image_mono, cmap = "gray")    
plt.show()

下図のようにモノクロ画像が表示されます。

さらにコマンドライン上には、OpenCVで読み込んだ画像の型が <class ‘numpy.ndarray>と表示されていることが確認でき、OpenCVの画像データがnumpyのndarrayそのものだという事がわかります。

画像データのサイズを shapeで表示していますが、モノクロ画像データの時は、二次元配列となっています。

 

同様にして、OpenCVのカラー画像を表示すると、

import matplotlib.pyplot as plt

import cv2

# OpenCVでカラー画像を読み込む
cv_image_color = cv2.imread("Parrots.bmp", cv2.IMREAD_UNCHANGED)
print(type(cv_image_color))
print(cv_image_color.shape)
# matplotlibで表示
plt.imshow(cv_image_color)    
plt.show()

プログラムの実行結果は下図のようになります。

OpenCVのカラー画像をmatplotlibで表示すると、モノクロの時のように、また、変な色になってしまいます。

これは、OpenCVのカラー画像のデータの並びが B, G, R, B, G, R ・・・となっているのですが、matplotlibへは R, G, B, R, G, B ・・・の並びのデータで渡す必要があり、OpenCVのカラー画像をmatplotlibで表示するには、RGBのデータの並びを逆にする必要があります。

また、 shapeの結果が (256, 256, 3) と表示されているように、カラー画像の場合、三次元配列である事が確認できます。

 

BGRのデータをRGBのデータへ変換するには、OpenCVのcvtColor関数を使い

cv_image_color = cv2.cvtColor(cv_image_color, cv2.COLOR_BGR2RGB)

のように、2番目の引数にcv2.COLOR_BGR2RGBを指定し、RGBの並びを逆にします。

import matplotlib.pyplot as plt

import cv2

# OpenCVでカラー画像を読み込む
cv_image_color = cv2.imread("Parrots.bmp", cv2.IMREAD_UNCHANGED)

# BGR から RGB へ変換
cv_image_color = cv2.cvtColor(cv_image_color, cv2.COLOR_BGR2RGB)
#cv_image_color = cv_image_color[:, :, ::-1] # numpyのndarrayに対してスライスを使って反転
# matplotlibで表示
plt.imshow(cv_image_color, cmap = "gray")    
plt.show()

 

OpenCVの画像データはnumpyのndarrayなので、スライスを使って、BGRからRGBへ変換することも可能です。

cv_image_color = cv_image_color[:, :, ::-1]

ただし、この場合、カラー画像データが32bitの場合、OpenCVのカラーデータの並びはB, G, R, A となっているため、このまま並びを反転すると A, R, G, B となり、matplotlibで表示すると、変な色になってしまいます。

32bitのカラー画像をmatplotlibへ渡すには、R, G, B, A の順になっている必要があるため、numpyで並びを逆にしたい場合は

cv_image_color = cv_image_color[:, :, [2, 1, 0, 3]]

とする必要があり面倒なので、OpenCVを使っている場合、cvtColorを使った方がよさそうです。

ちなみに、OpenCVで32bitのカラー画像の並びを反転させるには、本来であれば、

cv_image_color = cv2.cvtColor(cv_image_color, cv2.COLOR_BGRA2RGBA)

もしくは

cv_image_color = cv2.cvtColor(cv_image_color, cv2.COLOR_BGRA2RGB)

とすべきなのですが、

cv_image_color = cv2.cvtColor(cv_image_color, cv2.COLOR_BGR2RGB)

としても、 cv2.COLOR_BGRA2RGBと同じ動き(32bitBGRAから24bitRGBへの変換)となっていました。

 

listデータの表示

matplotlibのimshowで表示する画像データは、ここ↓のページ

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html

を見ても分かるように、配列かPIL Imageを渡す事ができます。

この配列の値は 0~1のfloatの値か、もしくは 0~255のintの値であれば、表示することが可能です。

という事は、Deep Learningでは画像データの0~255を0~1へ変換することが多いので、便利そうです。

また、配列はnumpyのndarrayだけでなく、Pythonのlistも渡す事ができ、以下にサンプルを示します。

import matplotlib.pyplot as plt

list_data = [list(range(256)) for i in range(256)]
plt.imshow(list_data, cmap = "gray")    
plt.show()

 

参考

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html

https://matplotlib.org/stable/gallery/color/colormap_reference.html