Geotagging Photos


Table of Contents

What is Geotagging a photo?

Geotagging is the act of associating geographical / GPS co-ordinates with a photo, normally by embedding the data in the EXIF information stored in several image formats - for example, alongside the ISO, shutter speed and aperture settings.

There are two ways geotagging is performed: with a suitable camera (such as the Nikon D200) and an adapter for a GPS unit, you can record it straight to EXIF at shooting time. Alternatively, you can replay the the track and align the timestamps to see the nearest point to the time at which you took each photo. I'm doing the latter, because not only is it cheaper, but it looks a whole lot easier than carrying around huge adapter cables.

Why?

Adding location data to photos at source saves me the hassle of browsing around on multimap trying to find exactly where I was at the time; the data is there, accurate to maybe 5s and a few metres. In my photo gallery I present the data as links to multimap, google maps, flickr, panoramio and geourl so people can examine the area, check for photos or other websites in the area. Additionally, any section of my gallery (area, series or keyword search) has its own KML network-link feed for use in Google Earth.

A Geo-tagging Workflow

Background

I have two GPS units, a Garmin GPS V whose output I read using gpstrans(1), and a Garmin Forerunner 301, from which I pull data using gpsbabel(1).

The central repository for my geo-location data is a table in a PostgreSQL database, with this simple schema:

CREATE TABLE whereabouts (
    tstmp timestamp without time zone,
    la double precision,
    lo double precision,
    alt double precision
);
CREATE UNIQUE INDEX whereabouts_location ON whereabouts USING btree (la, lo, alt);

CREATE UNIQUE INDEX whereabouts_tstmp ON whereabouts USING btree (tstmp);

Inputs

The data formats from the GPS V and Forerunner differ; I don't know if the output from gpstrans has a name but the tracks are simply one-point-per-line, I have a perl script, gps2pg.pl that reads this and executes SQL insert statements to populate the whereabouts table above.

From the Forerunner, I use gpsbabel:

gpsbabel -i garmin -f /dev/ttyUSB0 -o gpx -F somefile.gpx

which gives me a file in GPX format.

Given that GPX is just a particular XML schema, I use XSLT to transform this directly into SQL statements, using sablotron or xsltproc and this xslt sheet: gpx2sql.xslt.

sabcmd gpx2sql.xslt foo.gpx | psql

Update: newer GPS devices such as SportsTracker on the nokia n95 output GPX with a small change to the XML namespace; the line xmlns:gpx="http://www.topografix.com/GPX/1/0" has been updated to xmlns:gpx="http://www.topografix.com/GPX/1/1" .

The newer version of this file can be downloaded here: gpx2sql-n95.xslt. No other change is necessary.

Update 2: the GPX output from Google Android's MyTracks uses the 1.0 namespace, so the regular gpx2sql.xslt script works fine with it.

Outputs

KML

For immediately checking where I've been with Google Earth, I find quick export to KML handy. For this I have a perl script, gps-pg2kml.pl that works from the table in postgresql, or an xslt style sheet gpx2kml.xslt that works directly from the GPX file.

Commandline, Ruby & EXIF

It's often useful to be able to run the time-correlation directly on the commandline, before the data's been embedded in the EXIF. For this I have a two-faced script that takes either a timestamp, either specified directly on the commandline or pulls it out of EXIF in a referenced image file, and finds the nearest point. This is nearest2pic.rb.

bash$ ./nearest2pic.rb '2007-04-14 18:55:49'
Found nearest point: 2007-04-14 18:55:49, 55.569197182, -3.820974715

Alternatively:

bash$ nearest2pic.rb 4-perspective.jpg
Time from EXIF info: [2007-03-10 13:44:59]
Found nearest point: 2007-03-10 13:44:59, 57.1478333333333, -2.09375

This script can also output a URL to a map using Multimap:

bash$ nearest2pic.rb 4-perspective.jpg map
http://www.multimap.com/map/browse.cgi?lat=57.1478333333333&lon=-2.09375&scale=25000&icon=x

From here I found a script for embedding GPS in a JPEG image directly, a wrapper around exiftool: exiftool-gps-wrap.sh originally from the KDE project and wrote a simple wrapper to make it use my nearest2pic.rb script as well: pic-ram-exif.zsh.

Probably not the most efficient method, but it works for me, and flickr can extract the results to place the photos on a map automatically, which saves no end of time.