🐍

【Python】RGB配列からGIF画像を作成して、Jupyter Notebookに表示する方法

3 min read

0. はじめに

先日書いたPyBullet調査記事の中で利用したGIF画像の作成・表示の方法をまとめておきます。

https://zenn.dev/ymd_h/articles/381fa7cc4070e8

1. RGB配列からGIF画像を作成する方法

RGB配列をGIF画像にするのに、Pillowを利用します。
多くのライブラリで利用されているので、環境によってはインストール済みであることもあると思いますが、もし未インストールであれば、PyPIにホストされているので、pip で簡単にインストールできます。

pip install Pillow

少しややこしいですが、Pillow は PIL (Python Image Library) を forkしているため、プログラム内で利用するパッケージ名は PIL になっています。

少し検索してみましたが、オリジナルのPILを見つけられませんでした。基本的にはPILとして利用されているものは、Pillowだと考えて良いと思いますが、何かご存じの方がいれば、コメント欄などで教えていただけると嬉しいです。

GIFにしたい画像の各フレームに対して Imageクラスの静的メソッドのImage.fromarrayを利用することで、RGB配列から画像を構築します。

RGB配列の形式は、Image.fromarrayがよしなに検出してくれますが、正しく解釈されない場合は明示的にモードを指定することもできます。
https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.fromarray
https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes

少し不思議かもしれませんが、最初のフレーム画像に対して、Image.saveメソッドを実行し、残りのフレームは引数append_imagesに渡します。
引数loopによって繰り返し回数を指定できます。(loop=0は無限ループ)
保存したいファイル名の拡張子を .gif にすることで、GIF形式だと認識してくれますが、format="gif"と明確に指定することもできます。

from PIL import Image

gif = []

for _ in range():
    rgb = ... # なにかの処理でRGB配列を作成
    gif.append(Image.fromarray(rgb))

gif[0].save("mygif.gif", save_all=True, append_images=gif[1:], loop=0)

2. Jupyter Notebookに表示する方法

Jupyter Notebook (およびGoogle Colaboratory 等の類似の環境) で、GIF画像を表示するには、画像情報をBase64エンコーディングしてHTMLコンポーネントとして表示します。

import base64
from IPython import display as dd # display関数と名前が被るので別名にしておきます。

with open("mygif.gif", "rb") as f
    b64 = base64.b64encode(f.read()).decode("ascii")
    
display(dd.HTML(f'<img src="data:image/gif;base64,{b64}" />'))

3. ファイルに書き出さない方法

作成したファイルをすぐ読み出すだけにしか利用しないのであれば、そもそもファイルに書き出さなくても良いのでは?というニーズがあると思います。
Image.savestr型のファイル名を渡しましたが、file-likeオブジェクト(厳密には、writetellseekを持つ)を代わりに渡すことができるので、io.BytesIOクラスを利用することができます。

基本的には同じですが、書き出した後にディスク位置が最後尾のままなので、読み出す前にseek(0)で先頭に持ってこないと、readしても何も読みだせません。

import base64
import io
from PIL import Image
from IPython import display as dd

gif = []

for _ in range():
    rgb = ... # なにかの処理でRGB配列を作成
    gif.append(Image.fromarray(rgb))

f = io.BytesIO()
gif[0].save(f, save_all=True, append_images=gif[1:],format="gif", loop=0)

f.seek(0)
b64 = base64.b64encode(f.read()).decode('ascii')
f.close()

display(dd.HTML(f'<img src="data:image/gif;base64,{b64}" />'))

4. おわりに

Pythonで、RGB配列からGIFを作成して、Jupyter Notebookに表示する方法をまとめました。

リストとして画像配列を全部保持せずに、ファイルに逐次書き出していく方式もあるのじゃないだろうかと思いますが、今回はそこまでは調べませんでした。GIFぐらいの短い長さであれば、リストとして保持していてもそこまで問題は無いと感じたからです。

Discussion

ログインするとコメントできます