Sunday, February 26, 2017

Make a Video from a Processing Sketch

I needed to do this and found the steps challenging enough I wanted to keep them here, and maybe they will be helpful to others. I needed to take the words in a static wordle-type presentation and animate them, so they move around a bit. Then I needed to add that animation to a video of a dance.
Here's my Processing sketch:
 PFont myFont;  
 String words[] = {"anxious", "embarrassment",   
  "awkward", "pressure", "worried", "uncomfortable",   
  "differences", "thoughtful", "different", "judgemental",   
  "stress", "OK", "distant", "weird", "shame", "hope", "doing", "handled",   
  "crazy", "stressful", "unique", "damage", "mediocre", "fearful",   
  "determination", "right", "stressed", "defeated",   
  "scared", "fine", "horrible", "unhappy", "mad",   
  "loneliness", "unsure", "Am I doing the \"right thing\"?", "confidence",   
  "angerfied", "confused", "nervous"};  
 int sizes[] = {5, 1,   
  5, 2, 1, 1,   
  1, 1, 1, 1,   
  2, 2, 1, 2, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1,   
  1, 1, 7, 1,   
  1, 1, 1, 1, 1,   
  1, 1, 1, 1,   
  1, 5, 6};  
 float xPos[] = new float[words.length];  
 float yPos[] = new float[words.length];  
 int r[] = new int[words.length];  
 int g[] = new int[words.length];  
 int b[] = new int[words.length];  
 void setup() {  
  size(displayWidth, displayHeight);  
  for (int i = 0; i<sizes.length; i++) {  
   xPos[i] = int(random(width/2))+width/4;  
   yPos[i] = int(random(height/2))+height/4;  
   r[i]= int(random(150, 200));  
   g[i]=int(random(150, 250));  
   b[i]=int(random(100, 150));  
  }  
  smooth();  
  textAlign(CENTER);  
  myFont = createFont("Superclarendon-Bold", 32);  
  textFont(myFont);  
 }  
 void draw() {  
  background(0);  
  for (int i = 0; i<words.length; i++) {  
   fill(r[i], g[i], b[i]);  
   textSize((sizes[i]+1)*10);  
   text(words[i], xPos[i], yPos[i]);  
   float speed = 0.5;  
   if (xPos[i]<width/2) {  
    xPos[i]-=random(speed);  
   }   
   if (xPos[i]>width/2) {  
    xPos[i]+=random(speed);  
   }  
   if (yPos[i]<height/2) {  
    yPos[i]-=random(speed);  
   }   
   if (yPos[i]>height/2) {  
    yPos[i]+=random(speed);  
   }  
  }  
  saveFrame();  
 }  

At the end of the draw loop I'm using saveFrame() to save an image of every frame as it loops. I ran it for about 3 seconds and stopped it, and ended up with about 200 images sequentially labelled.

To compress those into a video I needed ffmpeg, which I found out about on this forum post (dimkir's answer). The wiki linked there for how to do it was a little unclear but this was much better to help me understand how to use ffmpeg. Here is what I ran in Terminal:

ffmpeg -framerate 60 -i /Users/enauman/Documents/Processing3/wordwall/screen-%04d.tif -pix_fmt yuv420p video.mp4
The -pix_fmt flag was important for getting a compatible format I could use in my iMovie project. The video was in the folder where I ran ffmpeg, and I dropped it right into iMovie. Here's what I got:

Addendum

I just tried to use this on a Processing sketch and kept getting the error that ffmpeg could not find the file "and index in the range 0-4." The difference was that the image sequence did not start at 0 but at 991, and by default ffmpeg will look for an image to start at in sequence 0-4. So I had to add a -start_number 991  flag with the number it should start on. So for this case where the frames do not start at 0 the full ffmpeg call is this:

ffmpeg -start_number 991 -framerate 60 -i /Users/enauman/Documents/Processing/kinectPopolVuh/frames/screen-%04d.tif -pix_fmt yuv420p video.mp4

No comments :