Geotagging in the 21st Century

Geotagging Prototype: BridgeIn preparation for my WalkAmerica get-up-early and test-those-sneakers walk, I’ve been playing around with some of my GPS toys. This involves two projects which I hope will converge, but so I don’t confuse you, let me just talk about the geotagging piece.

My Motives

  • I hate asking for donations, in fact up ’til now I have avoided it entirely. But I thought maybe I could use my strengths (geeky and musical) to add a low-cost incentive, so it’s less of a “something for nothing” proposition.
  • It’s no fun having geeky toys and not using them to their fullest. Time to break out the Garmin eTrex Legend that’s been sitting around here.

From this, I decided to try documenting the event using geotagged photographs. Basically, I would provide a map of where I walked, and pictures along the path. Not as exciting as the Grand Canyon or something, but it had potential.

Low-Tech Geotagging: The Theory

Okay, here’s the plan: on my walk, I’m going to bring my GPS receiver (Garmin eTrex Legend), and my digital camera (Canon Powershot A40), then use the combined data to map the digital pictures to a GPS location.

The camera records the date/time each image was shot, inside the EXIF data of the JPEG file.

The GPS receiver records my GPS position, along with the time it was recorded, in its Track Log (eTrex Legend users can see data usage by going to Main Menu -> Tracks).

Caveat #1: GPS Positions seem to be recorded every 15 seconds or so, meaning I won’t know the *EXACT* location a photo was taken at, but this is close enough for me. The frequency might change as my movement vector changes, but I didn’t look into it.

Caveat #2: When you save a GPS track, the eTrex strips the timestamp data. That’s right — if I decide to “Save” my track, I won’t be able to use it to geotag images. Only the “Active Track Log” (the log automatically maintained, where you DON’T save images) maintains the timestamp.

Caveat #3: I’m dealing with two separate clocks: the GPS receiver’s and the camera’s. Since the camera clock is only maintained by an internal battery, and the GPS receiver’s is based on the satellite time, I’m trusting the receiver. This means that I need to either change my camera’s time to match my receiver’s prior to shooting, or I need to specify a time offset as photos are merged.

Coding the Prototype (in Java!)

Yeah, I could write a 10-step process using existing commercial apps, but I’d rather code a solution than bootstrap non-open solutions. Plus I’m curious how it all works. So this led me to use the following:

  • Netbeans 5 IDE – for MacOS X this time, just for fun. Java Runtime 1.4.2 for compatibility, as much as I enjoy 1.5.
  • GPSLib4J – an open library to retrieve Garmin GPS data using Java. It’s structured in the hopes of pulling data from other devices in the future, but such support has yet to be seen. Since I’ve got a Garmin, I’m set, plus if I ever want to support other devices, this is probably the best place to start. With this, I can retrieve my trackpoints (timestamps, latitude, longitude, etc).
  • Drew’s JpegMetadataReader – also known as “jpeg exif / iptc metadata extraction in java”, which doesn’t have a snazzy acronym yet. This lets me read the timestamp each of my images was captured (which is stored as EXIF data), and was very easy to get started with. Mad props to those who published the library and provided simple example code.
  • Some random thumbnailer code by Marco Schmidt. I don’t know if AWT is still “the way to go” for this (I’m no Java expert), but it was great enough for my prototyping session.

With those tools, my code takes a directory of images, and an attached GPS receiver as input. Then it:

  1. Imports trackpoints from the GPS receiver, and sorts them by time.
  2. Iterates through all the images in my directory, reading the normalized capture timestamp (the timestamp, which is synched to the GPS receiver’s time by some offset), and matching this to the nearest two GPS trackpoints.
    • If it matches one trackpoint exactly, we use that trackpoint’s coordinates.
    • If the image time is prior to the first trackpoint, we deem it unmatchable (harsh, I suppose — I could still allow it within N seconds of the first trackpoint)
    • If the image time is after to the last trackpoint, we deem it unmatchable (harsh again; I need to set up a threshold)
    • Otherwise it’s between two points! I interpolate a new point between these two points, and return that new point’s coordinates. In my tests, this was FAR more accurate than simply choosing the nearest (timewise) of the two points.The interpolation is simple, too. Ignoring minute issues about “double” precision:
      • // Determine where on this segment this image was taken (between 0.0 (point A) and 1.0 (point B))
      • double trackpointTimeDiff = trackpointB.time – trackpointA.time;
      • double imageTimeOffset = image.time – trackpointA.time;
      • double normalizedImagePos = imageTimeOffset / trackpointTimeDiff;
      • // Determine actual position
      • double newLat = trackpointA.latitude + (normalizedImagePos * (trackpointB.latitude – trackpointA.latitude));
      • double newLon = trackpointA.longitude + (normalizedImagePos * (trackpointB.longitude – trackpointA.longitude));
    • If the nearest trackpoints were more than N seconds apart (N=20 for me) I warn that the image’s coordinates could have some more error than usual.
  3. Outputs some HTML code that I can use to build my “Google Maps”-indexed page

Since GPS latitude and longitude can be stored in the EXIF data, I would have rather done that, but I couldn’t quickly find a free Java library to save EXIF data. If you know one, please buzz me.

Then I just uploaded the HTML page and images to my Web site, and had a crude map of images! Yay!

I could take this a step further and try uploading the images to Flickr, or upload straight to my site, etc, but this was enough to prove I wasn’t too crazy.

Don’t applications do this already?

I didn’t think so at the time, but as I was troubleshooting I ran into two big give-away URLs:

  • Julian blogged about a similiar project in early 2005. I can’t find the original article anymore — only in the Google cache. He ran into most of the same issues I did: Garmin’s track log not saving the timestamp, RXTX (serial Java interface stuff) not working properly without me belonging to group uucp, etc. Apparently I’ve been living in his shadow.
  • JetPhoto Studio does nearly everything I wanted — it imports the GPS points, correlates them to the images based on times, etc, but version 2.1.3 has two flaws as far as I can tell:
    • I haven’t found a way to specify a camera clock offset, so if I forget to sync my camera clock to the GPS receiver’s, I might suffer worse accuracy issues.
    • When JetPhoto matches a photo to a GPS position, it only picks the nearest point, as far as I can tell. I would much prefer that it interpolates a point as described earlier in my post.
    • I see no mention of open licensing, though it’s a free download. I’m afraid of it becoming pay-to-play, or that I want to add a feature that they don’t support. Open frameworks are neat.

Screenshots

Because reading about it can be pretty boring if you’re not me! My wife and I took a car trip downtown, snapping along the way.

Geotagging Prototype: Points OverviewHere’s how the points got mapped; these points are pretty darn accurate considering the potential margin of error.

Geotagging Prototype: BridgeWhen you click a point on the map, a thumbnail of the image pops up, which you can then click to view a full-size image. The info bubble is a bit, uh, malformed at the moment, but it’s good enough. Look at how this thumbnail matches up really well with the bridge. The picture is facing north, so you can see the highway below us. This interpolated point matched up tons better, I think, than the point JetPhoto Studio chose.

Conclusion

The prototype’s interface is pretty awful, but it’ll be swell enough for my walk, for sure. If I can find a way to save the EXIF data, that’d streamline most of my plans too. Or at least, maybe I can convince JetPhoto folks to add interpolation to their tool. Then I can move onto my second project! (More GPS adventures coming soon)

Please don’t slam the door in my face!

As much as I enjoy the smell of painted birch through my broken nose, I confess to a greater joy. That joy is walkin’ and runnin’ for non-profit causes.

In the past, I’ve just donated and kept quiet about it, but I’m hoping with a little prodding you wouldn’t mind helping out either.

The walk in question? WalkAmerica. The goal? $200. But unless you’re my mom and dad, you probably won’t consider donating without some perks. Here are my gimmicks:

First, I’m writing a bunch of simple, short songs between now and the event, and I’m open to suggestions (which, if you’re waving money, I’m almost sure to do). I am your monkey. Post here or wherever I can see it!

Second, I’m also documenting the event using geocoded pictures. Assuming we don’t have any technical difficulties, you’ll get to see mapped pictures of our walkstravaganza and exactly how yummy the food was, within a few hours of the end of the event. But not if I don’t see donations!

Third, take a look at my WalkAmerica profile. See how pink it is? The closer we get to my goal, the pinker it gets! As easily as I can make myself look girly, now you can too!

Fourth — and this really isn’t my gimmick — know that your donation is going toward helping out babies, to prevent birth defects and the like. Which is something anyone babying it up can appreciate.

So thanks in advance, either for the taste of birch, or the pink explosion.

Donatearoo! They even take PayPal!

Nice Box! (Turtle)

Hah! Yeah. Tawny designed a fancy-pants painted-box-turtle shirt for members of the Internets to enjoy. Have a peek! And don’t forget to sing him the turtle song.

Cows in Hot Pants

It’s getting hot in here, you drank up all the sauce. I am, getting so hot, I’m gonna blow my nose now.

For whatever reason, The Cow Exchange won the Capsaicin fight over on Songfight (reviews here).

It’s a sonically dense tune which prepares listeners for the upcoming alien invasion. It also explains why Taco Bell is open so late.

“Mel” helped me out last-minute by adding female vocals. What a gal. And Enstrim drove her. What a guy. Thanks :-)

Have a listen! I’m not comfortable with the mix, so I’ll probably retake/remix some pieces before it shows up “officially” in Dillfrog land.

Copyright, Acknowledgement, and other Legal Sedatives