Pynote

Python、機械学習、画像処理について

Python - インデックスカラー画像を読み込む方法について

概要

インデックスカラー画像を PIL で読み込み、各画素のインデックスの値及びカラーパレットを参照する方法について紹介する。
Deep Learning のセグメンテーションタスクでは、正解データがインデックスカラー画像で配布されていることが多いので、色ではなく、元のインデックスの値を参照したい場合に利用できる。


インデックスカラー画像

インデックスカラー (indexed color) とはビットマップ画像の一種。画素毎に色を直接指定するのではなく、カラーマップと呼ばれる色定義テーブルの参照番号を指定して画像を表現する形式。
インデックスカラーの色番号と実際の色の対応を定義する表はカラーマップ (color map) 、カラールックアップテーブル (color lookup table) またはカラーパレット (color palette) と呼ばれる。

インデックスカラー (Wikipedia)

インデックスカラー画像をインデックスの値のまま読み込む。

OpenCV の imread() の場合、インデックスの値はそれが参照する色に置き換えられた配列を返すため、元のインデックスの値は参照できない。PIL を使用すると、インデックスの値のまま、読み込むことができる。

サンプル画像

import numpy as np
from PIL import Image

pil_img = Image.open("248ce4167d95fa556e7d9c21aada15d6.png")  # PIL で読み込む。
print('Image.mode', pil_img.mode)  # P インデックスカラーを意味する。

img = np.asarray(pil_img)  # numpy 配列に変換する。
print(img.shape)  # (500, 375)
print(img)
[[  0   0   0 ...   0   0   0]
 [  0   0   0 ...   0   0   0]
 [  0   0   0 ...   0   0   0]
 ...
 [255  11  11 ...   0   0   0]
 [255  11  11 ...   0   0   0]
 [255  11  11 ...   0   0   0]]

カラーパレットを参照する。

カラーパレットには PIL.Image.getpalette() でアクセスできる。
返り値は (256 * 3) の1次元配列で、index=0 から順番に [R, G, B, R, G, B, ...] と値が入っている。

# カラーパレットにアクセスする。
palette = pil_img.getpalette()
# リストの値は index=0 から順番に [R, G, B, R, G, B, ...]
palette = np.array(palette).reshape(-1, 3)
print(palette.shape)  # (256, 3)

# 256個のうち、0~20 だけ表示
fig, ax_list = plt.subplots(21, 1, figsize=(5, 10))
for i, color in enumerate(palette[:21]):
    color_img = np.full((1, 10, 3), color, dtype=np.uint8)

    ax_list[i].imshow(color_img, aspect='auto')
    ax_list[i].set_axis_off()
    ax_list[i].text(-1, 0, i, va='center', ha='right', fontsize=10)

plt.show()