Generating movie from python without saving individual frames to files Generating movie from python without saving individual frames to files python python

Generating movie from python without saving individual frames to files


This functionality is now (at least as of 1.2.0, maybe 1.1) baked into matplotlib via the MovieWriter class and it's sub-classes in the animation module. You also need to install ffmpeg in advance.

import matplotlib.animation as animationimport numpy as npfrom pylab import *dpi = 100def 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

Documentation for animation


After patching ffmpeg (see Joe Kington comments to my question), I was able to get piping png's to ffmpeg as follows:

import subprocessimport numpy as npimport matplotlibmatplotlib.use('Agg')import matplotlib.pyplot as pltoutf = 'test.avi'rate = 1cmdstring = ('local/bin/ffmpeg',             '-r', '%d' % rate,             '-f','image2pipe',             '-vcodec', 'png',             '-i', 'pipe:', outf             )p = subprocess.Popen(cmdstring, stdin=subprocess.PIPE)plt.figure()frames = 10for i in range(frames):    plt.imshow(np.random.randn(100,100))    plt.savefig(p.stdin, format='png')

It would not work without the patch, which trivially modifies two files and adds libavcodec/png_parser.c. I had to manually apply the patch to libavcodec/Makefile. Lastly, I removed '-number' from Makefile to get the man pages to build. With compile options,

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


Converting to image formats is quite slow and adds dependencies. After looking at these page and other I got it working using raw uncoded buffers using mencoder (ffmpeg solution still wanted).

Details at: http://vokicodder.blogspot.com/2011/02/numpy-arrays-to-video.html

import subprocessimport numpy as npclass 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()

I got some nice speedups.