FFmpeg Time Lapse
Posted by at 23:05 on 10 May 2009. There are ? Comments

I recently helped a friend of mine film and stream several university graduation ceremonies in Orlando. Most of my job entailed making sure that the stream worked via the CDN, making sure the video looked good and that the audio was working properly. Since that meant I was basically sitting there waiting until something went wrong (which it thankfully never did), I had some extra time on my hands. I had the last minute idea to try to do some time-lapse photography since I had brought my camera with me and bought a USB cable on the way to the shoot. First the result, then a tutorial on how it was done:


Rollins 2009 graduation in 16 seconds | Download 480p 720p 1080p

Equipment

Here is the equipment I used, but remember you can use any camera, lens, etc as long as you can either control the camera from the laptop or take photos at regular intervals with the camera, either by having that feature built-in on by using a remote shutter release that supports such a feature.

  • Canon EOS 50D
  • Tokina 10-17mm f/3.5-4.5 Pro DX fisheye lens
  • USB cable
  • Laptop (I used a Macbook)
  • Canon EOS Utility
  • FFmpeg
  • x264

Setup

I didn't have a tripod with me, so the setup was fairly basic. I set the camera on a windowsill (after securing the neck strap around a pole just in case). I put some paper towels under the camera until it was facing where I wanted. I set the camera to full manual and used the built-in light meter to setup a good exposure. I then connected the camera to the laptop via USB and fired up Canon EOS Utility. I set the timer interval to 30 seconds and told it to take 500 photos, and off it went firing shots every 30 seconds, showing a nice preview of the latest shot in a small window. At this point I just left it alone for the next few hours while it produced images like this:

<p>One of about 400 photos taken of the graduation
</p>

One of about 400 photos taken of the graduation

(~)
CameraCanon Eos 50D
Date10 May 2009 at 10:33
Exposure ModeManual
Exposure Time1/40 seconds
Aperturef/5
ISO Speed320
Focal Length11 mm
MeteringPattern
FlashOff

Creating the Video

To create the video I used FFmpeg and x264, both of which are not only free software but also some of the best video tools on the planet. Before installing FFmpeg you need to make sure you have x264 installed, which depends on yasm. Here is what I did on Mac OS X:

curl -O http://www.tortall.net/projects/yasm/releases/yasm-0.8.0.tar.gz
tar -xzvf yasm-0.8.0.tar.gz
cd yasm*
./configure --prefix=/usr
make
sudo make install
 
curl -O ftp://ftp.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-20090510-2245.tar.bz2
tar -xjvf x264-snapshot-20090510-2245.tar.bz2
cd x264*
./configure --prefix=/usr
make
sudo make install

The next thing I had to do is get and modify FFmpeg to support scaling of such large images. By default at the time of this writing FFmpeg is only able to scale images smaller than 2048 pixels wide or tall. This limitation is done for memory and speed reasons. We need to modify the limit to something larger. I was shooting 8 megapixels, so my photos were 3456 x 2304 and I set the new limit to 4096 pixels in libswscale.

curl -O http://ffmpeg.org/releases/ffmpeg-export-snapshot.tar.bz2
tar -xjvf ffmpeg-export-snapshot.tar.bz2
cd ffmpeg*
sed -i 's/VOFW 2048/VOFW 4096/g' libswscale/swscale_internal.h
./configure --prefix=/usr --enable-gpl --enable-libx264
make
sudo make install

FFmpeg can read in an image sequence if given a template as the input file. This requires that your images be named in increasing order with no gaps (e.g. 001.jpg, 002.jpg, 003.jpg, ...). Since the EOS Utility software will name the files sequentially but can start at a number other than 1, I wrote a quick python script to create symlinks in another directory that follow the proper naming rules for FFmpeg:

#!/usr/bin/env python
 
"""
Create symlinks from a set of paths returned by glob for FFmpeg to read
"""
 
import os
import glob
 
files = sorted(glob.glob("/Users/dan/Pictures/IMG_0*.JPG"))
 
outdir = "/Users/dan/Pictures/rollins_grad"
 
if not os.path.exists(outdir):
os.makedirs(outdir)

for i, f in enumerate(files):
os.symlink(f, os.path.join(outdir, "%03d.jpg" % (i + 1)))

Now that I had the required software install and the files named properly I was ready to create the movie. The output I wanted was H.264 in an MP4 container sized at 480p, 720p, and 1080p at 16:9 resolution. Since my photos weren't 16:9 I had to tell FFmpeg to crop the top and bottom. To find out how much I used this:

crop = height - (width / (16.0 / 9.0))

For my photos this was 2304 - (3456 / (16.0 / 9.0)) = 360 pixels, or 180 pixels from the top and 180 pixels from the bottom. Now using this info I encoded the videos:

cd /path/to/images
ffmpeg -i %03d.jpg -r 15 -croptop 180 -cropbottom 180 -s hd480 -vcodec libx264 -vpre hq -crf 16 rollins_480.mp4
ffmpeg -i %03d.jpg -r 15 -croptop 180 -cropbottom 180 -s hd720 -vcodec libx264 -vpre hq -crf 16 rollins_720.mp4
ffmpeg -i %03d.jpg -r 15 -croptop 180 -cropbottom 180 -s hd1080 -vcodec libx264 -vpre hq -crf 16 rollins_1080.mp4

The above creates three files, one each for 480p, 720p, and 1080p. Each video is 15 frames per second using the high quality H.264 preset with a constant rate factor of 16, which I chose because of the complexity of the video (tons of fast moving very small objects where keeping a lot of detail is a necessity).

Tips for the Future

  • Use a tripod to minimize movement (every picture taken shakes the camera slightly)
  • Use a longer exposure time to reduce blips and flashes as people move around
  • Set white balance to manual to keep colors consistent
  • Take more photos with a shorter interval between them for a better final framerate

Comments

blog comments powered by Disqus