12
$\begingroup$

I have a sequence of graphs that are being created within Mathematica which I'm exporting to create an animated plot of the graph, as follows.

animation example

startTime = 0;
endTime = 5;
secondsPerFrame = 1/30;

sampleData = {#, #^3 - 5*#^2 + #} & /@ Range[startTime, endTime, secondsPerFrame];
{tList, xList} = sampleData\[Transpose];

timeInformationLocation = {0.2 + Min@tList, 0.9*Max@xList};
timeInformation = 
   Graphics[Text[
      "Time: " <> ToString[NumberForm[N[#1], {10, 2}]] <> " s", 
      timeInformationLocation, {-1, 0}, BaseStyle -> {Black, 16}]] &;

 evaluationInitialTime = AbsoluteTime[];

 graphListForExport = 
   ParallelTable[
    Show[ListPlot[Select[Transpose[{tList, xList}], #[[1]] < tdummy &],
       PlotRange -> {1.1*{0, Max@tList}, 1.1*{Min@xList, Max@xList}}, 
      AxesOrigin -> {0, 0}, AxesLabel -> {"time / s", "position / m"}, 
      LabelStyle -> {Black, 16}, ImageSize -> 440, 
      PlotMarkers -> {Automatic, 6}], 
     timeInformation[tdummy]], {tdummy, startTime + secondsPerFrame, 
     endTime, secondsPerFrame}];
 Print[Row[{"List of graphs completed at ", AbsoluteTime[] - evaluationInitialTime}]];

 SetDirectory[NotebookDirectory[]];
 Export["sample.mov", graphListForExport];

 Print[Row[{"Export completed at ", AbsoluteTime[] - evaluationInitialTime}]];

Unfortunately, exporting the images is very slow; for the sample code above to export 150 frames, my system takes ~9s to generate the list of graphs, but another ~90s to export the list into the .mov format.

The question is, how can I optimize exporting a list of Graphics as a video?

There are several things which possibly could be done to improve the code. Firstly, when making the list of graphs, I could have chosen to use Graphics instead, which is likely to be faster. However, as most of the time seems to be taken up in the export step, I would like to focus on that first.

Since I would be processing the video in other software afterwards, I considered encoding the video in another format. However, while saving the video as .avi leads to some performance improvements (~60s for export versus ~90s), it is still rather slow. Other formats seem to be even slower than .mov, although I don't have the hard numbers for this specific example.

I also attempted to export the graphs immediately as a list of images that I could string together again via ffmpeg. Again, there was no significant performance improvement, and considering the additional work that has to be done to produce the final video, I'm not sure whether it is worth it.

Halirutan suggested in chat to rasterize the images first, and YvesKlett added to that by pointing out that the process of rasterization could in fact be parallelized. However, when I attempt to rasterize the images in my system my system crashed. The two approaches I used to try to rasterize the image were inserting a Rasterize within my ParallelTable and inserting the code graphListForExport=Rasterize\@graphListForExport.

For my final application, I will be exporting about 30s worth of graphs at 60fps, which means a total of 1800s. Each export takes about an hour, meaning that modifying elements in the video is very time-consuming.

I'm running Mathematica 9.0 on a system with a Dual Core 1.86 Ghz CPU, and 2.50 GB of RAM.

$\endgroup$
8
  • 2
    $\begingroup$ Did you adjust $HistoryLength=0? That will help you RAM-wise. $\endgroup$
    – Yves Klett
    Commented Jun 27, 2013 at 5:41
  • 2
    $\begingroup$ I've found some advantages to the ffmpeg method: you can fix errors/regenerate single frames, there's more control over output formats, if you get a powercut or a crash you can start again from where you left off, you can more easily monitor progress, and so on. But video is so processor-intensive anyway; just fire it up and go for lunch! (Some individual frames for Toy Story took 30 hours to render...) $\endgroup$
    – cormullion
    Commented Jun 27, 2013 at 7:00
  • $\begingroup$ @YvesKlett nope, I didn't - and I should have! let me try again with that. $\endgroup$ Commented Jun 27, 2013 at 7:46
  • 1
    $\begingroup$ @VincentTjeng So far my record for generating a movie was 27 hours for about 5 minutes of output... :) $\endgroup$
    – cormullion
    Commented Jun 27, 2013 at 7:53
  • 1
    $\begingroup$ @VincentTjeng "A watched export never completes" as my grandmother would have said... In hindsight I needn't have generated each frame at 6000 pixels resolution.:) $\endgroup$
    – cormullion
    Commented Jun 27, 2013 at 8:18

1 Answer 1

5
$\begingroup$

Here's one thing that might ease the pain a little: calculate and save the images in the movie one by one, saving them all to a directory. Once done, read them all back in and export to the movie. The first step is something like:

Do[thisImg = (* define your images here *);
    Export[path ~~ folder ~~ ToString[PaddedForm[r, {4, 2}]] ~~ ".jpg", 
    thisImg];, {r, 1, 500, 1}];

As jens points out, if you have already generated all the plots, you can simplify some of the book-keeping by using the VideoFrames option, which automatically labels the file names sequentially

Export["plot001.png", plots, "VideoFrames"];

Of course you might prefer to save to a .png file and you may need to Rasterize (depending on what your graphics are). Once all the individual frames are stored in one folder, you can read them all in and make the movie:

path = "/Users/Desktop/folderName/" ~~ folder ~~ "/";
fileNames = FileNames["*.jpg", path];
graphics = Table[Import[fileNames[[num]]], {num, 1, Length[fileNames]}];
Export["/Users/Desktop/" ~~ folder ~~ ".mov", graphics];

Dividing the process this way allows you to catch mistakes at intermediate points where they can be mor easily fixed.

$\endgroup$
4
  • $\begingroup$ For this purpose it's better to use the VideoFrames format. $\endgroup$
    – Jens
    Commented Jun 27, 2013 at 17:58
  • $\begingroup$ Thanks for the answer, bill. Offhand, I would expect that re-importing the graphics as a video would introduce an additional overhead and make the process slower, although it is definitely better from the perspective of catching mistakes first at the intermediate points. Let me do some benchmarks when I have the time so I can share them here. $\endgroup$ Commented Jun 28, 2013 at 3:57
  • $\begingroup$ Have you tried it? If you clear the kernel before doing the import (to wipe out memory of the creation of the plots) you may be surprised. $\endgroup$
    – bill s
    Commented Jun 28, 2013 at 16:33
  • $\begingroup$ @bills Sorry for the late reply - I missed this somehow. I will try the suggestion that you made, and hopefully post the benchmarks soon. $\endgroup$ Commented Jul 5, 2013 at 6:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.