30 June 2006

Capturing an image sequence from a webcam

A friend asked me if there was a way (on a Windows XP PC) to capture a sequence of images (e.g. every 5 minutes for a couple of hours) from a webcam on the Internet. An image from a webcam embedded in a web page is no different from any static image (unless it's wrapped inside a Flash or Java container), so a single capture is usually as simple as right-clicking on the image and choosing "Save Image As...". However, for the automated capture of a sequence of images something else is needed.

There are probably cheap shareware tools out there that can do this (there is no shortage of apps that can do the reverse, capturing images from an attached camera and publishing them to the web), but I hate installing new cruft on my PC for simple jobs, and since I'd recently installed cURL (a command line tool for downloading files with a URL) I thought I'd figure out a scripted solution. The installer for the Windows XP version of cURL can be found here (versions for other operating systems are here).

Once cURL is installed, we can invoke it from any folder on our system provided we add it to a Windows environment variable called "Path" (instructions on how to change environment variables can be found here). In my case, cURL is installed to "C:\Program Files\curl-7.15.3" so I appended ";C:\Program Files\curl-7.15.3" to the end of my Path. You can check it's working by opening a DOS shell (Start > Run > cmd) and entering curl at the prompt - you should get a message saying curl: try 'curl --help' or 'curl --manual' for more information
If you get 'curl' is not recognized as an internal or external command, operable program or batch file then cURL is not installed, or the path to it is not in your Path variable.

We can now invoke cURL from a batch file and capture an image: with Notepad you can create a file called "capture.bat" (if you put the name in quotes when saving from Notepad, ".txt" won't get appended to the end of the filename). The file only needs one line:

curl -o test.jpg http://path/to/image/file

The -o test.jpg tells cURL to create an output file called test.jpg (in the current folder), and the remainder of the line is the URL of the image file - you can find this out by right-clicking on the image in your browser and choosing "Copy Image Location" (Firefox) or "Properties" (Internet Explorer). You can run your batch file by double-clicking on it.

After this, I started experimenting with DOS commands to loop for a specified time and rename each captured image file to something time-based and unique, however I soon discovered that this is not as easy as it sounds - I'm sure it is possible with some serious DOS trickery (such as is described here), but I gave up - it was too arcane and kludgy for me.

Any Linux/UNIX enthusiast will tell you that the bash shell is ideal for this kind of scripting. Fortunately, Windows users can also run bash scripts - we just need to install the amazing cygwin (a Linux-like environment for Windows) - click here to install it. Installation instructions for Windows XP can be found here.

Once cygwin is installed, browse to your home directory (which will have the same name as your Windows username - mine is "c:\cygwin\home\Rich Edwards"). Create a new file called "capture" (if you're using Notepad, remember the quotes around the name when saving to prevent Notepad from adding the ".txt") and enter the following script:

#!/bin/bash

# The following three lines are parameters you can change
duration=300
interval=30
url=http://www.ogwen-rescue.org.uk/oggi_cam/bethesdacam.jpg

# Record the start time (this will give us
# the number of seconds elapsed since 01/01/1970)
time_start=$(date +%s)

# Some output
echo
echo Every $interval seconds for the next $duration seconds
echo this script will capture an image from $url
echo

# Start an infinite loop
while [ 1 ]
do

# The time now (number of secs elapsed since 01/01/1970))
time_now=$(date +%s)

# Construct the filename (this will be unique provided
# our interval >= 1 second)
filename=$time_now.$image_format

# Grab the image and store it in the file
echo Creating $filename
curl -o $filename $url

# If the elapsed time is greater than the specified
# duration exit the loop
if [ $(($time_now - $time_start)) -ge $duration ]
then
echo
echo 'Time duration exceeded - exiting!'
break
fi
echo

# Pause for the specified interval
sleep $interval

done

This script will capture an image from Ogwen Mountain Rescue's webcam (donations) every 30 seconds for 5 minutes, but you can customise it for any duration, interval and/or URL. If cURL returns an error but you are sure your URL is correct, have a look at the cURL help (type curl --help) for how to use additional parameters; for example, there is a -A switch that lets you specify additional info that lets cURL pretend to be a web browser asking for the resource (some webservers are configured to prohibit requests which do not appear to come from a browser).

Now to run the script: start Cygwin from the "cygwin.bat" file in your cygwin folder (e.g. "c:\cygwin\cygwin.bat"). This will start a Cygwin shell that looks much like a DOS shell (but fortunately it's way more functional!). Enter pwd (print working directory) to see your current location relative to the cygwin folder ("/home/Rich Edwards" in my case). Now enter chmod +x capture - this changes the "mode" of the capture script to "executable" (this only needs to be done once).

Now all that's needed is to execute the script with ./capture every time we want to capture images from the specified webcam. The preceding dot and slash tells cygwin that the script is in the current folder (otherwise it will search the Windows Path and not find it).

If you've followed me this far then you now also have the benefit of an amazingly useful scripting environment! There are lots of useful intros to bash - see here for a tutorial for absolute beginners. Happy scripting!

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]