PythonのPillowのImage.fromarrayの使い方: 配列を画像に変換する
- 作成日: 2020-09-28
- 更新日: 2023-12-24
- カテゴリ: Python
PillowのImage.fromarrayの使い方
Pythonの画像処理ライブラリであるPillownには画像を処理するImage
モジュールがあります。
Image
モジュールは、numpy
の配列から画像を生成するfromarray()
という関数を持っています。
Image.fromarray()
を使えば、加工した配列から画像を生成することが出来ます。
たとえばnumpy
を使って画像の配列を加工し、その結果をImage.fromarray()
に渡して画像にすると言った具合です。
この記事ではImage.fromarray()
について具体的に↓を見ていきます。
- Image.fromarrayの構造
- 画像をnumpyの配列に変換する
- numpyの配列を画像に変換する
- numpyの配列を編集する
今回使用する画像
今回は↓の画像を使用します。
RGBA
のPNG
画像で、横幅500px
高さ500px
の合計250000
ピクセルの画像です。
Image.fromarrayの構造
Image.fromarray()
は↓のような構造を持っています。
Image.fromarray()
は最大で2つの引数を取り、1つの返り値を返します。
PIL.Image.fromarray(obj, mode=None)
obj(第1引数)
obj
には配列のインターフェースを持ったオブジェクトを指定します。
配列のインターフェースとは具体的には属性「__array_interface__
」のことです。
この属性はnumpy
のndarray
などの配列が持っているインターフェースです。
Image.fromarray()
は内部でこの属性を参照します。
そのためobj
がこの__array_interface__
を持っていない場合はエラーになります。
たとえばPythonのlist
をこのobj
に指定すると↓のようなエラーになります。
AttributeError: 'list' object has no attribute '__array_interface__'
mode(第2引数)
mode
は生成する画像のモードを指定します。デフォルトはNone
です。
代表的なモードは↓の通りです。
- 1 ... 1ビットピクセル画像。黒と白
- L ... 8ビットピクセル画像。黒と白
- P ... 8ビットピクセル画像。(8-bit pixels, mapped to any other mode using a color palette)
- RGB ... 3x8ビット画像。トゥルーカラー
- RGBA ... 4x8ビット画像。トゥルーカラー&透過チャンネル
- CMYK ... 4x8ビット画像
- YCbCr ... 3x8ビット画像。カラー・ビデオ・フォーマット
- LAB ... 3x8ビット画像。Labカラースペース
- HSV ... 3x8ビット画像。Hue, Saturation Value カラースペース
- I ... 32ビット符号付き整数画像
- F ... 32ビット浮動小数点画像
よく使われるのはRGB
, RGBA
のモードです。
mode
がNone
の場合、配列が格納しているタイプ情報からモードが決定されます。
返り値
Image.fromarray()
の返り値はPIL.Image
です。
この画像はImage.fromarray()
に渡された配列から新しく作成された画像です。
メモリ的にも新しく領域が確保されています。
画像をnumpyの配列に変換する
Image.fromarray()
でnumpy
の配列を画像に変換するわけですが、Image.fromarray()
の前にnumpy
の使い方を簡単に解説します。
まずImage
をnumpy
の配列に変換するには、numpy.array()
を使います。
from PIL import Image
import numpy as np
# 画像を開く
im = Image.open('img/a.png')
# 画像をnumpyの配列(ndarray)に変換
arr = np.array(im)
print(type(arr)) # タイプ
print(arr.shape) # 形状
出力結果。
<class 'numpy.ndarray'>
(500, 500, 4)
このようにnumpy.array
にPillowのImage
を渡すと、画像をnumpy
の配列(numpy.ndarray
)に変換できます。
arr.shape
を参照すると配列の形状を参照できます。
↑の場合、(500, 500, 4)
なので横幅500
で高さ500
で奥ゆきが4
の3次元配列になっています。
numpyの配列を画像に変換する
numpy
の配列(numpy.ndarray
)をImage
オブジェクトに変換するにはタイトルにあるImage.fromarray()
を使います。
↓のようにnumpy
の配列をImage.fromarray()
の第1引数に渡します。
from PIL import Image
import numpy as np
# 画像を開く
im = Image.open('img/a.png')
# 画像をnumpyの配列(ndarray)に変換
arr = np.array(im)
# numpyの配列から画像を生成
dst_im = Image.fromarray(arr)
print(type(dst_im)) # タイプ
dst_im.save('dst/out0.png') # 画像を保存
出力結果。
<class 'PIL.Image.Image'>
保存した画像は↓のようになります。
特に配列を加工するといったことはしていないので、画像は元の画像と同じものになります。
加工する場合は、Image.fromarray()
に配列を渡す前に配列を加工します。
numpyの配列を編集する
numpy.array()
で作成した配列を編集し、その配列をImage.fromarray()
に渡して画像を生成すれば、結果的にプログラミングで加工された画像を手に入れることが出来ます。
from PIL import Image
import numpy as np
# 画像を開く
im = Image.open('img/a.png')
# 画像をnumpyの配列(ndarray)に変換
arr = np.array(im)
# 以下から編集開始
# 配列をコピー
red = arr.copy()
# すべての画素のG, B成分に0を代入し、Rの成分以外を黒にする
red[:, :, (1, 2)] = 0
# 配列から画像を生成
dst_img = Image.fromarray(red)
# 画像を保存
dst_img.save('dst/out1.png')
保存した画像は↓のようになります。
すべてのG
, B
成分に0
を代入しているので、画像は赤い系統の画像になります。
配列のG
, B
成分への0
の代入は↓のようにnumpy
の配列の機能を使います。
red[:, :, (1, 2)] = 0
↑の式の意味はすべての画素の3
次元目の1
, 2
番目の要素、つまりG
, B
の要素に0
を代入するという意味になります。
出題
Q1: Image.fromarray()
の第1引数として適当なものを答えよ
- numpy.ndarray
- dict
- int
Q2: Image.fromarray()
の戻り値として適当なものを答えよ
- int
- dict
- Image
Q3: Image.fromarray()
の第2引数として適当なものを答えよ
- 'L'
- 'RGB'
- 'color'
正解はこちら↓
Q1: 1
Q2: 3
Q3: 1, 2