75

matplotlibのpythonスクリプトで生成したフレームからh264またはdivxムービーを作成したいと思います。この映画には約10万フレームあります。

ウェブ上の例では[例:1]、私は各フレームをpngとして保存し、これらのファイルでmencoderまたはffmpegを実行する方法を見ただけです。私の場合、各フレームを保存することは実用的ではありません。matplotlibから生成されたプロットを取得し、それを直接ffmpegにパイプして、中間ファイルを生成しない方法はありますか?

ffmpegのC-apiを使用したプログラミングは私には難しすぎます[例:2]。また、ムービーファイルは次のステップでは大きすぎるため、x264などの圧縮率の高いエンコーディングが必要です。したがって、mencoder / ffmpeg/x264に固執するのは素晴らしいことです。

パイプでできることはありますか[3]?

[1] http://matplotlib.sourceforge.net/examples/animation/movie_demo.html

[2] x264 C APIを使用して一連の画像をH264にエンコードするにはどうすればよいですか?

[3] http://www.ffmpeg.org/ffmpeg-doc.html#SEC41

4

6 に答える 6

57

この機能は現在 (少なくとも 1.2.0、おそらく 1.1 の時点で) クラスを介して matplotlib に焼き付けられており、モジュールMovieWriter内のサブクラスです。また、事前animationにインストールする必要があります。ffmpeg

import matplotlib.animation as animation
import numpy as np
from pylab import *


dpi = 100

def ani_frame():
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.set_aspect('equal')
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    im = ax.imshow(rand(300,300),cmap='gray',interpolation='nearest')
    im.set_clim([0,1])
    fig.set_size_inches([5,5])


    tight_layout()


    def update_img(n):
        tmp = rand(300,300)
        im.set_data(tmp)
        return im

    #legend(loc=0)
    ani = animation.FuncAnimation(fig,update_img,300,interval=30)
    writer = animation.writers['ffmpeg'](fps=30)

    ani.save('demo.mp4',writer=writer,dpi=dpi)
    return ani

のドキュメントanimation

于 2012-12-21T03:13:37.680 に答える
23

ffmpeg にパッチを適用した後 (私の質問に対する Joe Kington のコメントを参照)、次のように png を ffmpeg にパイプすることができました。

import subprocess
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

outf = 'test.avi'
rate = 1

cmdstring = ('local/bin/ffmpeg',
             '-r', '%d' % rate,
             '-f','image2pipe',
             '-vcodec', 'png',
             '-i', 'pipe:', outf
             )
p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE)

plt.figure()
frames = 10
for i in range(frames):
    plt.imshow(np.random.randn(100,100))
    plt.savefig(p.stdin, format='png')

2 つのファイルを単純に変更して追加するパッチなしでは機能しませんlibavcodec/png_parser.c。にパッチを手動で適用する必要がありましたlibavcodec/MakefileMakefile最後に、ビルドするマニュアル ページを取得するために「-number」を削除しました。コンパイルオプションで、

FFmpeg version 0.6.1, Copyright (c) 2000-2010 the FFmpeg developers
  built on Nov 30 2010 20:42:02 with gcc 4.2.1 (Apple Inc. build 5664)
  configuration: --prefix=/Users/paul/local_test --enable-gpl --enable-postproc --enable-swscale --enable-libxvid --enable-libx264 --enable-nonfree --mandir=/Users/paul/local_test/share/man --enable-shared --enable-pthreads --disable-indevs --cc=/usr/bin/gcc-4.2 --arch=x86_64 --extra-cflags=-I/opt/local/include --extra-ldflags=-L/opt/local/lib
  libavutil     50.15. 1 / 50.15. 1
  libavcodec    52.72. 2 / 52.72. 2
  libavformat   52.64. 2 / 52.64. 2
  libavdevice   52. 2. 0 / 52. 2. 0
  libswscale     0.11. 0 /  0.11. 0
  libpostproc   51. 2. 0 / 51. 2. 0
于 2010-11-07T01:39:32.073 に答える
16

画像形式への変換は非常に遅く、依存関係が追加されます。これらのページと他のページを見た後、mencoderを使用して生のコード化されていないバッファを使用して動作するようになりました(ffmpegソリューションはまだ必要です)。

詳細: http://vokicodder.blogspot.com/2011/02/numpy-arrays-to-video.html

import subprocess

import numpy as np

class VideoSink(object) :

    def __init__( self, size, filename="output", rate=10, byteorder="bgra" ) :
            self.size = size
            cmdstring  = ('mencoder',
                    '/dev/stdin',
                    '-demuxer', 'rawvideo',
                    '-rawvideo', 'w=%i:h=%i'%size[::-1]+":fps=%i:format=%s"%(rate,byteorder),
                    '-o', filename+'.avi',
                    '-ovc', 'lavc',
                    )
            self.p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE, shell=False)

    def run(self, image) :
            assert image.shape == self.size
            self.p.stdin.write(image.tostring())
    def close(self) :
            self.p.stdin.close()

私はいくつかの素晴らしいスピードアップを得ました。

于 2011-02-17T13:26:56.500 に答える
6

これは素晴らしい!私も同じことをしたかった。しかし、パッチを適用した ffmpeg ソース (0.6.1) を Vista で MingW32+MSYS+pr 環境でコンパイルすることはできませんでした... png_parser.c はコンパイル中に Error1 を生成しました。

そこで、PILを使用してこれに対するjpegソリューションを思いつきました。ffmpeg.exe をこのスクリプトと同じフォルダーに置くだけです。これは、Windows でパッチが適用されていない ffmpeg で動作するはずです。サブプロセスに関する公式ドキュメントで推奨されているcommunicationメソッドではなく、stdin.writeメソッドを使用する必要がありました。2 番目の -vcodec オプションは、エンコーディング コーデックを指定することに注意してください。パイプは p.stdin.close() によって閉じられます。

import subprocess
import numpy as np
from PIL import Image

rate = 1
outf = 'test.avi'

cmdstring = ('ffmpeg.exe',
             '-y',
             '-r', '%d' % rate,
             '-f','image2pipe',
             '-vcodec', 'mjpeg',
             '-i', 'pipe:', 
             '-vcodec', 'libxvid',
             outf
             )
p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE, shell=False)

for i in range(10):
    im = Image.fromarray(np.uint8(np.random.randn(100,100)))
    p.stdin.write(im.tostring('jpeg','L'))
    #p.communicate(im.tostring('jpeg','L'))

p.stdin.close()
于 2011-01-06T20:37:19.757 に答える