LoginSignup
18
20

More than 5 years have passed since last update.

【matplotlib基本】動的グラフを書いてみる♬~動画出力;Gifアニメーション

Last updated at Posted at 2019-01-29

簡単に考えていたが、難解でした。
ということで、Gifアニメーションに出力できました。

やったこと

・animation.ArtistAnimation(fig, ims, interval=100)もanimation.FuncAnimation(fig, plot, interval=100)
・mp4やaviで動画出力
・PILを使ってGifアニメーションとして出力させる

・animation.ArtistAnimation(fig, ims, interval=100)もanimation.FuncAnimation(fig, plot, interval=100)

はっきり言って使いたくない。

コードは簡単で、以下のとおり
性能を見たいので、4分割のグラフに表示している。
※もちろん、一か所であればそれなりに使える
【参考】
matplotlib でアニメーションを作る
matplotlibで簡単にアニメーションをつくる(mp4, gif)

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

# プロット領域(Figure, Axes)の初期化
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.axis([-1.2, 1.2, -1.2, 1.2])
ax2.axis([0, 100, -2, 2]) 

# 棒グラフの作成
s = 1
ims = []

for i in range(10):
        rand = np.random.randn(100)     # 100個の乱数を生成
        im = ax1.plot(rand)             # 乱数をグラフにする
        ims.append(im)                  # グラフを配列 ims に追加
        im = ax2.plot(rand)             # 乱数をグラフにする
        ims.append(im)
        im = ax3.plot(rand)             # 乱数をグラフにする
        ims.append(im)
        im = ax4.plot(rand)             # 乱数をグラフにする
        ims.append(im)

ani = animation.ArtistAnimation(fig, ims, interval=100)
ani.save('anim.gif', writer="imagemagick")
#ani.save('anim.mp4', writer="ffmpeg")
plt.show()

そして、コードの最後に記載しているが、imagemagick、ffmpeg、どちらもうまく動かなかった。
一時的なものかも知れないが、imagemagickはリンクにとべずインストールできなかった。⇒なんと本日はダウンロードできた⇒そして無事にanim.gifが保存できました
※ffmpegは動きませんでした。
ダウンロードページ@imagemagick
anim.gif

・mp4やaviで動画出力

これはこれまでも利用したOpenCVで出力する方法。ただし、Gifアニメーションには対応していない。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import cv2
from PIL import Image, ImageDraw

def cv_fourcc(c1, c2, c3, c4):
        return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
            ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)


OUT_FILE_NAME = "output_video.mp4"
#OUT_FILE_NAME = "output_video.avi"
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
dst = cv2.imread('image.png') #一度、savefigしてから再読み込み
rows,cols,channels = dst.shape
out = cv2.VideoWriter(OUT_FILE_NAME, int(fourcc), int(10), (int(cols), int(rows)))
#out = cv2.VideoWriter(OUT_FILE_NAME, cv_fourcc('X', 'V', 'I', 'D'), 30, (cols, rows), True)  #avi

x = np.arange(0, 10, 0.1)
fig=plt.figure(figsize=(12, 8))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(224)
ax4 = fig.add_subplot(223)
ax1.axis([0, 10,-1.2, 1.2])
ax2.axis([0, 100, 0, 100]) 
ax3.axis([-1.2, 1.2,0, 10]) 
ax4.axis([0, 100, 0, 100]) 

def f(x, y):
    return np.sin(x) + np.cos(y)

x1 = np.linspace(0, 2 * np.pi, 100)
y1 = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
ims = []
images=[]
for a in range(10):
    fig.delaxes(ax1)
    fig.delaxes(ax3)
    ax1 = fig.add_subplot(221)
    ax3 = fig.add_subplot(224)
    y = np.sin(x - a)
    line, = ax1.plot(x, y, "r")
    ims.append([line])
    line, = ax3.plot(y, x, "r")
    ims.append([line])

    x1 += np.pi / 15.
    y1 += np.pi / 20.
    im = ax2.imshow(f(x1, y1), animated=True)
    ims.append([im])
    im = ax4.pcolormesh(f(x1, y1), cmap='hsv')
    ims.append([im])

    fig1=plt.pause(0.001)
    #Gifアニメーションのために画像をためます
    plt.savefig("output/image"+str(a)+".png")
    dst = cv2.imread('output/image'+str(a)+'.png')
    out.write(dst) #mp4やaviに出力します

【matplotlib基本】動的グラフを書いてみる♬

※画像をクリックするとYouTube動画につながります

・PILを使ってGifアニメーションとして出力させる

やっとたどり着いた感じ。。
【参考】
Python, PillowでアニメーションGIFを作成、保存@note.nkmk.me
Python PillowでPNGからGIFを作る

コードは以下のとおり、上記の動画出力の最後に以下を追加するだけで実現できました。

import glob

files = sorted(glob.glob('output/*.png'))
images = list(map(lambda file: Image.open(file), files))
images[0].save('out.gif', save_all=True, append_images=images[1:], duration=100, loop=0)    

画像50枚を使って、gifアニメーションしてみると、以下のとおり。なお、100枚もやってみたが、それなりに動いた。しかし、ファイルが大きすぎてアップできなかった。
out.gif
※どうもがくがくしている??

なお、環境はPillowのバージョンは以下のとおり、3.4以上で対応している。
【参考】
Creating a multiframe image object #2401@python-pillow/Pillow

This makes sense, as append_images was added in Pillow 3.4. So I recommend that you upgrade.

ということで、windows10でも、以下のコマンドで...一応Pillowのバージョンは3.3.1からUpgradeできたようです。

>pip install -U Pillow
>python
>>> import PIL
>>> print(PIL.__version__)
5.4.1

まとめ

・PILとimagemagickでGifアニメーションに出力できた
・PILの方が使い勝手は良い
・matplotlibのanimationは単独程度の低負荷な場合は使えるが、普通にアニメーションさせた方が性能は良い

・よくよく見ると、mp4などでの出力(元画像のパラパラ動画)に比較して、Gifアニメーションの動画は途中余分に変な動作をしているが、原因は不明である
 ⇒おまけに追記した。
・いよいよ、次回はFFT,STFT,そしてWavelet変換のアプリを作ろう

おまけ

以下、ちゃんと出力できなかったが、ダウンロードして動きそうな気配もあるので、記載しておく

images2gif/images2gif.py
使い方は、
python3で3dのgifを作成
Animated 3-D Plots in Python

追記(30/1/2019)

どうもガクガクする理由が正しくソートされていないことが原因だったので、スマートなコードはあきらめて、以下のように明示的に読み込んだ。
⇒スムーズに100枚読込んで表示できた!

from PIL import Image, ImageDraw

images = []
for i in range(40):
    im = Image.open('output/image' + str(i)+ '.jpg') 
    images.append(im)

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

100枚、50枚も綺麗に動いたが、40枚しかアップできないのでそれを貼っておく。
out_original40.gif
もともとの動画もほとんど同じコードでGifアニメーション作成できたので貼っておく
※こちらは100枚貼れました

from PIL import Image, ImageDraw

images = []
for i in range(100):
    im = Image.open('output_ori/image' + str(i)+ '.png') 
    images.append(im)

images[0].save('out_original_ori100.gif', save_all=True, append_images=images[1:100], duration=40, loop=0)    

out_original_ori100.gif
これで、ほんとにすっきり!

18
20
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
20