Blog from July, 2013

Fun With Time Lapse

Call me silly but I like to see work being done.  There are many times when I've stood back at the end of a large project with visible results and said "man, I wish I had a recording of that".  I keep saying that I wanted to setup a webcam to take pictures for a time lapse and today I finally did.

The What:

  • Logitech Pro 9000
  • Old laptop running Linux
  • Tripod

The How:

Hook up the webcam to your laptop and point it where you want to take the shots.  I recommend using camorama to get things lined up since it will show you the real-time video.  If you only want to take a shot every minute you could also use it to take the pictures as it has a timer built-in.  However, you can't customize your image type or quality.  I chose to use fswebcam to capture my images.  There are at least a dozen different apps out there that will grab images for you so just choose what works best for you.  You can even use FFMPEG to grab images if you'd like.

Once you have your shot framed you'll want to start grabbing images.  I wrote the following simple script to grab images:

/usr/local/sbin/camshot.sh
#!/bin/bash

JPG_PATH="/home/camuser/Pictures/$(date '+%Y.%m.%d-%H:%M:%S').jpg"

fswebcam \
  -q \
  -p YUYV \
  -r 1600x1200 \
  -S 15 \
  --no-banner \
  $JPG_PATH

chown camuser: $JPG_PATH

You may have to adjust the flags to suit your camera. For example, the -p YUYV and -r 1600x1200 flags will only work on higher-end cameras.

Depending on your setup you may not have to run the image capture as root, but I didn't feel like dinking with it and the old laptop I used has nothing on it but these frame grabs.

For my camera the -S 15 was absolutely critical.  That option instructs fswebcam to discard the first 15 frames after initializing the webcam before saving a shot.  This gave the camera time to adjust the focus and levels on the image.  Without this every image I took was washed out.

Make sure that if you modify the scheme for naming the images that you ensure they can be listed in chronological order easily (such as with a simple ls).

Once you have a script that will grab and save an image, schedule it in cron:

# Take webcam snapshots every 10 seconds-ish
* * * * * root /usr/local/sbin/camshot.sh
* * * * * root sleep 10 && /usr/local/sbin/camshot.sh
* * * * * root sleep 20 && /usr/local/sbin/camshot.sh
* * * * * root sleep 30 && /usr/local/sbin/camshot.sh
* * * * * root sleep 40 && /usr/local/sbin/camshot.sh
* * * * * root sleep 50 && /usr/local/sbin/camshot.sh

I chose to take an image every ten seconds.  It's really a matter of preference how often you take images.  My take on it is that you can always discard images but you can't use what you don't have.  So as long as you have the hard drive space, the more the merrier.  Each of my captures was around 250k.

After you've gathered your shots you can convert them into a video.  This is where it can get confusing because you have so many options.  I used FFMPEG (avconv), but many other people have had success with mencoder and various ImageMagick tools (and other tools on Windows and OS X).  If you're going the FFMPEG route you first need to rename your images in a sequential order:

$ cd /home/camuser/Pictures
$ mkdir ffmpeg
$ i=1
$ for a in *.jpg; do
>   mv $a ffmpeg/`printf "%04d" $i`.jpg
>   ((i++))
> done

This will go through each image and move it to a directory called ffmpeg with a zero-padded name (such as 0001.jpg) in sequential order (assuming you followed the note above regarding your file naming scheme).  You can then spit out a movie with a command such as this:

$ cd ffmpeg
$ avconv -f image2 -i %04d.jpg -r 24 -s uxga -vcodec libx264 ~/Videos/lapse.mp4

The command above generates an MPEG4 video using H.264 encoding at 1600x1200 (the same resolution the pictures were taking at) using 24 frames (pictures) for each second.  If your picture resolution is different you will want to alter the -s uxga flag (you can specify a resolution instead of a name).  Avconv is supposed to match the resolution of the output to that of the input by default, but that was not working for me.  If you want to change the frames per second adjust the -r 24 flag.

The position of the arguments is important in avconv. For example, if you move the -r 24 flag so that it preceeds the -i flag then it becomes an input parameter instead of an output parameter.

If you want your video to play slower, decrease your -r value.

The wife doctored up my resulting video in Adobe Premiere, but here's the result of our Saturday:

Avconv is an extremely powerful tool.  You can use a command such as this to resize your video:

avconv -i ~/Videos/lapse.mp4 -c:v libx264 -q:v 5 -vf scale=640:-1 ~/Videos/lapse640.mp4

Or if you want to convert it to Flash Video:

avconv -i ~/Videos/lapse.mp4 -c:v libx264 -q:v 5 -vf scale=640:-1 ~/Videos/lapse.flv

Enjoy!

Modern Linux distributions typically have LVM resting between physical storage devices and the file system.  This is great for your OS and other data drives that are installed in your system or otherwise "permanently" attached.  The ext file system is designed to allow resizing as the underlying block devices are grow (or even shrunk in the right scenario).  But this does require that the file system reserve space to allow what's called the "block group descriptor table" to grow.  USB drives don't magically change in size (outsize of you messing with partitioning) and because of this don't need to reserve that space.

To get the most file system bang for your buck out of your USB drive use the following mke2fs command:

# mke2fs -m 1 -O ^resize_inode -j -t ext4 /dev/sdz1

Replace /dev/sdz1 with the path to the partition on your USB device.

The -m 1 argument reduces the amount of space reserved for the super user to 1%.

The -o ^resize_inode argument disables the reserving of space for resizing the file system.

Check out the defaults in /etc/mke2fs.conf and man mke2fs for more information about how your file system is being sped up.

Searching for "os x wireless connection timed out" will bring up 100's of unique posts about people having issues getting their Mac's wireless card connected to a new (or just different) router.  Most answers start with the typical knee jerk "I wanted to be the first post" responses of reboot your router, reboot your Mac, change the wireless channel, check your SSID and passphrase... Because, you know, when stuff that was working minutes ago breaks it's because you typed your password wrong.

Dig through the replies a bit more and you will find insightful advice such as deleting system preferences, creating new network profiles, and clearing out your key chain.  When my sister's MacBook Pro suddenly wouldn't connect to a new router using the same security settings as the old, I started running through the gauntlet of troubleshooting.  I did all the resetting (including my SMC) and rebooting and whatnot just to make sure I wasn't "that guy".  I set static channels, downgraded the speed from N to G to B, and tried various combinations of WPA, WPA2, TKIP, and AES/CCMP.  I deleted every network preference I could find.  The thing just wouldn't work.

Then I remembered an issue I had with my Raspberry Pi a few weeks earlier.  I could get my Pi to associate with the wireless network but it wouldn't get an address from the gateway's built-in DHCP server.  Setting a static address worked fine.  After a couple days of scratching my head I figured out that a hidden SSID was the culprit.  Interestingly enough, un-hiding my SSID also fixed a digital picture frame that had mysteriously stopped connecting to the wireless (even though it was connecting earlier with a hidden SSID).

But alas, the SSID at my mom's house wasn't hidden.  I fired up the Network Preferences again on the MacBook, set a manual IP for the wireless connection, and ta da!  The laptop connected to the network and I was able to browse the Internet.  Even after reverting the settings to return to using DHCP the connection still worked (with an appropriately assigned address from the pool).  I did find one reference of someone fixing this same error message by setting a static assignment on his router for the Mac.

I can't say for sure if the issue was with the Mac or the router.  I tend to lean in the direction of the Mac as it seems to store information about past connections in so many places, and even when you delete these old connections from your settings they are still there in *.plist files on your system.  That and every other device was working just fine, including the Mac when connected via ethernet cable.