Time lapse (or stop-motion) video is really cool, and this post explains how to make a simple time lapse style video in Linux using entirely free open source software.
There is more than one way to skin a cat and when I was searching for how to do this I came across many different methods and suggestions but not really anything that suited what I wanted. Andrew Wells suggests making a movie and then processing it with ffmpeg to only store 1 in every n frames. That seems a neat solution but I wanted to take a series of still shots and string those together into a movie. Tim Nugent published a teaser of some nice looking time lapse software he wrote but as yet there is no published source or binary. There were various other suggestions dotted around the web but each one I tried had some problem or other. So here’s how I did it.
First of all, you need a working webcam. Webcam support has really improved recently in Linux and I found the built-in iSight on my MacBook and my cheapo Logitech USB webcam work just fine without any intervention from me.
Next we need some way to save an image from the webcam every x seconds. I found that camstream does the trick just fine despite it’s sucky 1996-looking website and lack of a release since 2006. Under Fedora 10 to install camstream just use yum or your favourite GUI package manager:
yum install camstream
Camstream is pretty easy to use. Really, a child could do it. Just use the “File” menu to open up your webcam device. Then click the little configuration icon (it looks like a spanner) to adjust the file settings you’d like to use for capture. I found that JPG images work much better than PNG.
As the “Basename” enter the full path of the filename you’d like to save your images as, for example if you want to save your images as “/home/yourname/Pictures/Webcam/MyTimeLapse/image001.jpg” (and so on) then set the basename as “/home/yourname/Pictures/Webcam/MyTimeLapse/image” then choose “Number sequence” and set the maximum sequence number to something pretty big (like 100000). Close the settings. Click the icon to “show last snapshot”.
Now click “take snapshot at regular intervals” and set your interval. I chose 3 seconds. Choose whatever you think is appropriate. Now you’re all set. Camstream will take images at the interval chosen and save them into the directory you configured. Sweeeeet.
Ok, so now we have a directory full of images that looks something like this:
$ ls
image000.jpg image003.jpg image006.jpg image009.jpg image012.jpg image015.jpg image018.jpg
image001.jpg image004.jpg image007.jpg image010.jpg image013.jpg image016.jpg
image002.jpg image005.jpg image008.jpg image011.jpg image014.jpg image017.jpg
We’re gonna feed these files to mencoder for it to pull together into a movie. To do this we need a text file containing a list of the files in the order that we want them. You could write this file yourself (boring) but we can create it using something like this:
ls -1tr > files.txt
This provides a listing (ls) of the current working directory outputting 1 file per line (1) sorted by modification time (t) in reverse order (r) and sends the output (>) to a file named files.txt. In the example above my files.txt looks like this:
image000.jpg
image001.jpg
image002.jpg
image003.jpg
image004.jpg
image005.jpg
image006.jpg
image007.jpg
image008.jpg
image009.jpg
image010.jpg
image011.jpg
image012.jpg
image013.jpg
image014.jpg
image015.jpg
image016.jpg
image017.jpg
image018.jpg
Now download and install mencoder. Again it’s available on nearly all modern distros. For Fedora 10 just do “yum install mencoder”. Now all we need do to make our move is issue a command like this:
mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4 -o test.avi -mf type=jpeg:fps=20 mf://@files.txt
This will encode all the files listed in files.txt into a movie called test.avi using the mpeg4 encoder with no sound and a framerate of 20 frames per second. Messing with the fps gives very different results. See “Encoding from multiple input image files” in the mencoder documentation for more info.
Here’s an example video made using this method: