Friday, October 26, 2012

Exporting Videos in Mathematica (the hard but nice way)

Have you ever tried to export your sweet looking Mathematica animation only to end up with some crappy quality video that doesn't seem to play anywhere? Well, you're about to leave that behind for good, because I'm going to teach you how to obtain videos of perfect quality out of that accursed IDE. The way we'll do it is we'll export high quality pdf/png frames of your movie, and then stitch them all together into a custom video. First off you'll need some tools. I used ffmpeg and imagemagick, command line utilities, in order to convert pdfs to pngs and stitch frames together. On linux they are easily available from your repositories. For Debian, for example, you just do
apt-get install ffmpeg imagemagick
On OS X it's also relatively simple, provided you're already using macports (or fink, or homebrew). For macports, the command is
sudo port install ffmpeg imagemagick
For Windows you're on your own, since I haven't ran that platform in years and I don't know how you get software for it anymore. I'm sure you can find a tool for the purpose somewhere on Google. Ok, I'll also assume you have Mathematica installed (otherwise you wouldn't be reading this) and a good understanding of how to use it. Then you want some code very similar to what I pasted below, as well as an implementation of the Draw[] function.

(* make sure that the default export path is in the same place as your .nb file *)
(* I actually have this as the first line in pretty much all Mathematica files *)

(* export slides *)
     (* here I export every 5th slide, but they have to be named
     sequentially, hence the Ceiling[] call. *)
     oFile = StringForm["./frames/frame`1`.pdf", Ceiling[i/5]];
     oFile = ToString[oFile];
     (* this call exports a picture to oFile *)
     (* Draw[i] takes the frame number and returns a graphics object *)
     Export[oFile, Graphics[Draw[i], (* extra options for Graphics[] *) ]],     
  (* the do loop counter, picking every 5th frame*)
  {i, 1, Length[tk], 5}
Ok, you need to change the code to suit your needs, but most of the heavy lifting gets done in the Draw[] function, which you already know how to write, right? We're exporting to pdf, which makes for some really good quality. If you do it all right you should have a subfolder called frames filled with pdf files named frame1.pdf, frame2.pdf, and so on. This is awesome, we're halfway done! Next you need to stitch those frames together. If you're in Windows, you best be using cygwin or something equivalent, otherwise you're on your own. In *nix, you open a terminal (don't worry, it won't bite), cd to the frames directory and run ffmpeg :
cd ~/path/to/math/code/file/frames
for f in frame*.pdf do convert -density 300 "$f" "{$f/.pdf}".png done
ffmpeg -q:v 1 -r 25 -i frame%d.png video.mp4
What this does is convert all the pdfs to png, with a 300dpi density and then it merges all the frames into a video, showing 25 frames per second (-r 25) and keeping the video quality of the original images unchanged (-q:v 1). That's it, you're done!

No comments:

Post a Comment