# R@ndom Curve

Rediscover your travel steps (using Photo EXIFs)
Andres C. Rodriguez 2016-04-07

## Problem

So I have a bunch of photos taken with my iPhone, mainly shot in the mountains, and I would like to extract a GPS Path in the form of a GPX file. Once I have the GPX file I can load it into any mapping tool that supports it. For example here is an image of an intermediate result in the MAC OS X app GPS Tracks:

## Extracting Latitude and Longitude

I wanted to keep the solution as lightweight as possible, so to do that I used a node.js script in conjunction with a utility (that I did not know existed) in Mac OS X: mdls (short for MetaData LS). The latitude and longitude are “hidden” inside the photo(s) in what is called the EXIF (EXchangeable Image Format) segment. It is basically a set of properties and values inside the JPEG or TIFF format.

So, since IMG_3190.JPG is the first image I want to analyze, let’s try the following command:

mdls IMG_3190.JPG


The result:

Note the properties kMDItemLatitude and kMDItemLongitude.

So all that remains is go over the files, extract the properties and list them. I am lucky in that the files are in the same lexicographic order as the chronological order, so no need no muck with dates.

## Extracting Script

The following script receives a directory as the first parameter (or uses the current directory as default) and prints out the list of coordinates one by one.

/**
* Script to extract GPS coordinates from a set of photos. You can pass the name of the directory as
* first parameter, otherwise it will assume
*/

var _ = require("./lodash.js");
var fs = require("fs");
var childProcess = require("child_process");

var dir = process.argv[2] || "/Users/andres/Dropbox/Photos/2015/2015-07 Dolomites";

// Vector to store all EXIF structures
var exifs = [];

// List of all files ending in 'JPG' (i.e. images)
return file.endsWith(".JPG");
});

// Iterate over all files extracting EXIF
for (var i = 0; i < files.length; i++) {
var file = dir+"/"+files[i];
var data = childProcess.execSync("mdls '"+file+"'").toString().trim();
var exif = {};
// Regular expression extract key and value (v2 is with quotes, v3 is bare)
data.replace(/(\w+) *= *("(.+)"|(.+))/g, function(m, k, v1, v2, v3) {
exif[k] = (v2 || v3);
});
// Only add if the photo has latitude and longitude
if (exif.kMDItemLatitude && exif.kMDItemLongitude) exifs.push(exif);
}

var gpx = 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" version="1.1">
<name>Photo Trail</name>
<rte>
<% _.forEach(exifs, function(exif) { %>
<rtept lat="<%= exif.kMDItemLatitude %>" lon="<%= exif.kMDItemLongitude %>"><name><%= exif.kMDItemDisplayName %></name></rtept>
<% }); %>
</rte>
</gpx>
;

// Making sure the XML is trimmed, otherwise it will not work because of the empty line
console.log(_.template(gpx.trim())({ exifs: exifs }));


I then open the track in Google Earth but I discover that a couple of pictures have the wrong GPS location, which completely screws the track.

I actually did not know that the GPS on the phone could get the location so wrong. Especially when not inside a building. I fixed the track by removing those three pictures from it, and then I created a route on Strava that follows the hiking path more closely (because the photos are scattered around with big gaps in between them).

Pretty cool. The video still had some quirks. I omitted adding altitude to the GPX track because when I did I was either flying 50 meters above earth or underground. So I left Google Earth map the altitude to whatever their 3D model of earth says it should be. I suspect that is behind the “jittery” track on screen.