PythonでGIFアニメを作る(PILでファイルをつなげる編)

PythonでGIFアニメを作ります。今回は、Pillow(PIL)を使って連番の画像ファイルからGIFファイルを作ります。

目次

  1. PillowでGIFアニメを作る
  2. Pillowで画像を開く
  3. Pillowで画像を保存する
  4. PillowでアニメーションGIFを出力する
  5. アニメーションGIFの出力例

PillowでGIFアニメを作る

以前の投稿 で、matplotlibを使ってリサジュー図形のGIFアニメを作りました。その際にはmatplotlibがimagemagickを必要としたのですが、imagemagickも進化してますしWindowsとの相性的にどうかということもありますので、Pythonで完結してみました。

具体的には、Pillow(PIL)のGIFファイルの書き出し機能を利用します。

ということで、事前にPillowのインストールが必要です。(pipでインストールできます。)

Pillowで画像を開く

Pillowで画像を開くには、Imageクラスのopenメソッドを使います。

ret = PIL.Image.open(fp, [mode])
変数 内容
fp str,Path,file 画像ファイル名、またはPathオブジェクトかopen済みのファイルオブジェクト。
mode str 省略可。既定値はr。
ret Image 画像のオブジェクト。

modeはrしかないようですので、指定する必要はなさそうです。

Pillowで画像を保存する

保存はsaveメソッドを使います。

from PIL import Image

im.save(fp, [format], [params])
変数 内容
im Image Imageオブジェクト。
fp str,Path,file 画像ファイル名、またはPathオブジェクトかopen済みのファイルオブジェクト。
format str 省略可。既定値はNone。ファイル形式。Noneの場合は、拡張子から推定される。
params   省略可。writerに渡す個別の指定。

PillowでアニメーションGIFを出力する

ファイルフォーマットがGIFの場合だけparamsに指定できる引数があります。つまり、アニメーションGIFを出力したいときは次のようになります。

from PIL import Image

im.save(fp, save_all, append_images, [include_color_table], [interlace], [disposal], [palette], [optimize], [transparency], duration, loop, [comment])
変数 内容
im Image 1フレーム目になるImageオブジェクト。
fp str 画像ファイル名。拡張子をgifにする。
save_all bool 全てのフレームを保存するか。静止画像ならFalse、アニメーションならTrue。
append_images list 2フレーム目以降のImageオブジェクトのリスト。
duration int フレームの表示間隔。ミリ秒で指定。
loop int ループ回数の指定。無限ループの場合は0。ループしない場合は1。

上表以外の項目については、 Pillowの公式ドキュメント を参照してください。

アニメーションGIFの出力例

試しに 以前の投稿 と同じリサジュー図形のアニメーションを作ってみます。

まずは連番画像の作成です。

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

theta = np.linspace(0, 2*np.pi, 201)
delta_theta = np.linspace(0, 2*np.pi, 201)

b = 1.0
muki = True
counter = 0

for i in delta_theta:
    x = np.cos(theta)
    y1 = np.sin(theta + i)
    y2 = np.sin(b*theta)
    y3 = np.sin(2*theta + i)
    fig = plt.figure(figsize=(3,3))
    plt.plot(x, y1, 'b', x, y2, 'g', x, y3, 'r')
    plt.savefig(str(counter) + '.png')
    counter = counter + 1
    if muki is True:
        b = b + 0.05
        if b > 6:
            muki = False
    else:
        b = b - 0.05

プロットする毎にmatplotlibのsavefigメソッドを使って画像ファイルを書き出します。

画像ファイルを1枚書き出す毎にfigureメソッドを呼び出さないと、キャンバスが初期化されないので前に描いた図形が残ったまま次の画像が描かれることに注意が必要です。

これを実行すると、0から200までの番号がついたpngファイルが出力されます。

ではこの連番pngファイルから、gifアニメーションを作ってみます。

from PIL import Image

images = []

for i in range(201):
    file_name = str(i)+'.png'
    im = Image.open(file_name)
    images.append(im)

images[0].save('out.gif', save_all=True, append_images=images[1:], loop=0, duration=30)

シンプルですね。

連番画像を1枚ずつ読み込んで、リストにImageオブジェクトを追加していきます。

1枚目の画像、すなわちリストのインデックスが0のオブジェクトに対してsaveメソッドを呼び出して、append_imagesで2枚目以降のリストを指定しています。

これを実行すると、このようなGIF画像が出力されます。

リサジュー図形

広告

Pythonで画像処理カテゴリの投稿