PythonのPillowのImage.frombytesの使い方: バイト列データを画像に変換する

62, 2020-09-29

目次

PillowのImage.frombytesの使い方

Pythonの画像処理ライブラリであるPillowは画像を処理するImageモジュールを持っています。
Imageモジュールは低レイヤ―なバイト列(bytes)から画像を生成できるfrombytes()関数を持っています。

この関数を使うとバイト列で画像データを編集し、結果を画像に変換することが可能になります。

プログラミング的な画像の編集は、一般的にはnumpyを使ったほうが効率がいいのでよければ↓の記事も参照してみてください。

Image.frombytesの構造

Image.frombytes()は↓のような構造を持っています。

PIL.Image.frombytes(mode, size, data, decoder_name='raw', *args)

引数と返り値の解説は↓の通りです。

mode(第1引数)

modeは生成する画像のモードです。L(8ビット)やRGB等を指定できます。

バイト列(data)のモードとこのmodeは一致させる必要があります。
たとえばバイト列のモードがRGBAで、このmodeRGBだったりすると、生成される画像がおかしくなります。

size(第2引数)

sizeは生成する画像のサイズです。(width, height)のフォーマットのタプルで渡します。

data(第3引数)

datamodeに指定されたモードのバイト列です。

decoder_name(第4引数)

decoder_nameはデコーダーの名前です。デフォルトはrawです。

args(第5引数)

argsはデコーダーの引数です。

返り値

返り値はImageオブジェクトです。

今回使用する画像

今回使用する画像はこちらです。
この画像はRGBA画像です。

【共有】水没する2人

画像をバイト列にする

Imageオブジェクトをバイト列にするにはImage.tobytes関数を使います。

from PIL import Image

im = Image.open('img/a.png')  # RGBAの画像ファイルを開く
bs = im.tobytes()  # 画像をバイト列に変換する

print(type(bs))  # タイプ
print(bs[:4])  # バイト列(先頭4バイトのみ)
<class 'bytes'>
b'\x95\x8e\x8e\xff'

バイト列を画像にする

bytesを画像にするにはImage.frombytes()を使います。

from PIL import Image

im = Image.open('img/a.png')  # 画像を開く
bs = im.tobytes()  # 画像をバイト列に変換する

dst_im = Image.frombytes('RGBA', im.size, bs)  # バイト列から画像を生成
dst_im.save('dst/out0.png')  # 画像を保存

出力結果。

【0062】out0.png

バイト列を編集する

RGBAの画像をバイト列で編集します。
RGBAの場合、RGBA自体の長さは4つです。例えば画像のサイズが横幅(10px)、高さ(10px)だった場合、そのデータの長さは以下の式で求められます。

data_len = 4 (RGBA) * 10 (横幅) * 10 (高さ)

↓のコードでは、横幅x高さの長さだけfor文を回し、そのインデックスを基準にしたRGBAのデータにアクセスしています。
data[4 * i + 0]というのがRへのアクセスで、data[4 * i + 1]Gへのアクセスです。

from PIL import Image

im = Image.open('img/a.png')  # RGBA画像を開く
data = im.tobytes()  # バイト列に変換
arr = bytearray()  # 編集用のバイト配列

print('data len', len(data))  # RGBAの500px(横)* 500px(高さ)の画像だから全体の長さは1000000

for i in range(im.size[0] * im.size[1]):  # 横x高さだけ回す
    r = data[4 * i + 0] * 3 % 255  # Rの編集
    g = data[4 * i + 1] * 3 % 255  # Gの編集
    b = data[4 * i + 2] * 3 % 255  # Bの編集
    a = data[4 * i + 3]  # Aの編集
    arr += bytearray((r, g, b, a))  # 編集したRGBAをバイト配列に追加

print('arr len', len(arr))

dst_im = Image.frombytes('RGBA', im.size, bytes(arr))  # バイト列から画像を生成
dst_im.save('dst/out1.png')  # 画像を保存

出力結果。

data len 1000000
arr len 1000000
【0062】out1.png

関連

Image.frombytes()と関連のある関数の記事は以下があります。

問題

Q1: Image.frombytes()の第1引数として適当なものを答えよ

  1. 'L'

  2. 'RGB'

  3. 'bytes'

Q2: Image.frombytes()の返り値として適当なものを答えよ

  1. bytes

  2. Image

  3. list

Q3: Image.frombytes()の第3引数として適当なものを答えよ

  1. Image

  2. bytes

  3. dict


正解はこちら↓

Q1: 1, 2
Q2: 2
Q3: 2