【Pillow】PythonでアニメーションWebPを作る
60fpsで画像を動かしたいと思ってアニメーションGIFを作ったのですが、仕様的にできずスローになるようですね。
アニメーションWebPなら実現できそうだったので、備忘録に。
そもそもWebPとは
WebP(ウェッピー)はGoogleが開発した画像形式です。
他の画像形式をいいとこ取りしたような、以下の特徴があります。
画質を保ちつつ容量が軽い
透過処理が可能
アニメーションに対応
新しめの規格なので古いアプリやブラウザでは見られないことも
ライブラリのインストール
Pythonで画像処理をするためのライブラリが必要で、今回はPillowとImageioを使います。
なお、記事投稿時点の以下最新バージョンで実装します。
Pillow:11.0.0
imageio:2.36.0
pip install pillow
pip install imageio
実装方法
アニメーションWebPへの変換処理は、複数の画像を読み込んでWebPとして保存するだけなので数行で済みます。
保存時の処理にて後述の「表示時間 (duration)」のパラメータをミリ秒で設定するのですが、今回の私の目的である60fpsで表示するためには、
なので、16.66ミリ秒で実装します。
ちなみにこの設定で作った各フレームの表示時間は、以下のような感じで16ミリ秒と17ミリ秒が混ざって生成されました。
Frame 1: 150 ms
Frame 2: 17 ms
Frame 3: 16 ms
Frame 4: 17 ms
Frame 5: 17 ms
Frame 6: 16 ms
Frame 7: 17 ms
Frame 8: 17 ms
Frame 9: 16 ms
……
また、Frame 1は容量の削減か、生成時に同じ画像と見なされて長めに設定されたようです。
パラメータ
良く使うと思われるパラメータを箇条書きで。
duration
(Integer, Float, List, Tuple) 各フレームの表示時間をミリ秒単位で指定します。各フレームで個別に設定する場合はリストまたはタプルを渡します。loop
(Integer) アニメーションのループ回数を指定します。0は無限ループ、1は1回のみ再生して停止します。デフォルトは0。quality
(Integer) 0(最低品質)から100(最高品質)までの範囲で設定が可能。デフォルトは80。
その他のパラメータは以下公式ドキュメントを参照してください。
コード
from PIL import Image
import imageio
# 読み込む画像ファイルのリスト
image_files = ["image1.png", "image2.png", "image3.png"]
# 画像を開き、リストに追加
images = [Image.open(image_file) for image_file in image_files]
# 出力ファイル名
output_file = "output_animation.webp"
# WebPとして保存
imageio.mimwrite(output_file, images, format="webp", duration=16.66, loop=1)
ちなみに、ライブラリのインストールでPillowを入れましたが、インポートするパッケージの名前はPillowではなくPILなので注意してください。
おまけコード
複数の画像からアニメーションを作る場合は大抵連番のファイル名だと思うので、連番ファイルを読み込みやすそうなコードを作りました。
from PIL import Image
import imageio
# 読み込む画像ファイルのリスト
image_files = []
# 共通連番ファイル名
file_name = "image{0}.png"
# ファイル名生成
start_num = 0 # 最初の連番ファイルの数値
end_num = 179 # 最後の連番ファイルの数値
for file in range(start_num, end_num + 1):
image_files.append(file_name.format(str(file)))
# ゼロパディングしてるなら下
# image_files.append(file_name.format(str(file).zfill(3)))
# 画像を開き、リストに追加
images = [Image.open(image_file) for image_file in image_files]
# 出力ファイル名
output_file = "output_animation.webp"
# WebPとして保存
imageio.mimwrite(output_file, images, format="webp", duration=16.66, loop=1)