Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save austinhappel/6238576 to your computer and use it in GitHub Desktop.
Save austinhappel/6238576 to your computer and use it in GitHub Desktop.

Adding geolocation to photos with Python

Introduction

I like to hike. On these hikes, I take photographs:

Photo

I am a nerd, and use my iPhone as a GPS while hiking.

It tracks my every move and outputs useful data:

screenie1 screenie2

The Problem: My camera is not equipped with a GPS unit

The solution: Link the photo's timestamp with a timestamp in my GPS track.

Most GPS devices output data in a format called GPX (GPS Exchange Format) or KML (Google's Keyhole Markup Language)

GPX looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" creator="GPS Kit iOS App by Garafa" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
 <metadata>
  <name>Sun Jul 15 2012</name>
 </metadata>
 <trk>
  <name>7/15/12 12:49:13</name>
  <trkseg>
   <trkpt lat="47.724010" lon="-121.266878">
    <ele>827</ele>
    <time>2012-07-15T19:49:13.0980Z</time>
   </trkpt>
   <trkpt lat="47.724065" lon="-121.266835">
    <ele>831</ele>
    <time>2012-07-15T19:49:53.9880Z</time>
   </trkpt>
   <trkpt lat="47.724113" lon="-121.266840">
    <ele>838</ele>
    <time>2012-07-15T19:51:21.0600Z</time>
   </trkpt>
   <trkpt lat="47.724161" lon="-121.266838">
    <ele>837</ele>
    <time>2012-07-15T19:51:25.1110Z</time>
   </trkpt>
   <trkpt lat="47.724207" lon="-121.266816">
    <ele>833</ele>
    <time>2012-07-15T19:52:30.0850Z</time>
   </trkpt>
   <trkpt lat="47.724252" lon="-121.266782">
    <ele>837</ele>
    <time>2012-07-15T19:52:36.1230Z</time>
   </trkpt>

* 1000…

There's a good chance that when the photo is taken, a GPS reading was taken around the same time.

Python is the glue

I wrote a python command-line tool that reads and parses these GPX files, takes a folder of images, and links a GPX trackpoint to each image.

In its current state, it generates a GPX (or geojson) file with trackpoints that link to the photo's filename.

Example time

$ pip install GpxImageLinkifier
	
// Checkout that sweet help (thanks to argparse):
$ gil --help

$ cd ~/Dropbox/work/Smashing\ Ideas/GpxImageLinkifier-example/

$ gil GPSKitData.gpx . --offset-gpx=1h13m --tz-images=US/Pacific --accuracy=20m

// Output looks like:

{
"type": "FeatureCollection", 
"features": [
    {
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -121.479383, 
                48.054684, 
                1020.0
            ]
        }, 
        "type": "Feature", 
        "properties": {
            "content": "IMG_7177.JPG"
        }
    }, 
    {
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -121.479584, 
                48.05951, 
                1254.0
            ]
        }, 
        "type": "Feature", 
        "properties": {
            "content": "IMG_7182.JPG"
        }
    }, 
    {
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -121.479584, 
                48.05951, 
                1254.0
            ]
        }, 
        "type": "Feature", 
        "properties": {
            "content": "IMG_7185.JPG"
        }
    }, 
    {
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -121.471116, 
                48.068929, 
                1743.0
            ]
        }, 
        "type": "Feature", 
        "properties": {
            "content": "IMG_7233.JPG"
        }
    }, 
    {
        "geometry": {
            "type": "Point", 
            "coordinates": [
                -121.471157, 
                48.068906, 
                1743.0
            ]
        }, 
        "type": "Feature", 
        "properties": {
            "content": "IMG_7241.JPG"
        }
    }
]

Paste that output into geojsonlint.com and see the result.

This module is seriously just a mashup of other modules people have made. I just put them all together:

  • PIL (for photo exif reading)
  • gpxpy (parses GPX files)
  • argparse (for argument parsing)
  • json + my code (generates geojson)
  • pytz (timezone conversions if necessary)
  • datetime (for timestamp comparisons)
  • nose (for testing)

Creating a Python package

Creating a python package is probably the least intuitive thing about Python.

The basics (folder structure, etc) are fairly straightforward: Here's a nice starter guide

Distutils, setuptools, distribute, or distutils2?

There are way too many tools for package creation/management in python, and it was really not clear to me at all what I should do.

From http://stackoverflow.com/questions/6344076/differences-between-distribute-distutils-setuptools-and-distutils2

  • Distutils is the standard tool used for packaging. It works rather well for simple needs, but is limited and not trivial to extend.

  • Setuptools is a project born from the desire to fill missing distutils functionality and explore new directions. In some subcommunities, it’s a de facto standard. It uses monkey-patching and magic that is frowned upon by Python core developers.

  • Distribute is a fork of Setuptools that was started by developers feeling that its development pace was too slow and that it was not possible to evolve it. Its development was considerably slowed when distutils2 was started by the same group. 2013-August update: distribute is merged back into setuptools and discontinued.

  • Distutils2 is a new distutils library, started as a fork of the distutils codebase, with good ideas taken from setup tools (of which some were thoroughly discussed in PEPs), and a basic installer inspired by pip. The actual name you use to import Distutils2 is packaging in the Python 3.3+ standard library, or distutils2 in 2.4+ and 3.1–3.2. (A backport will be available soon.) Distutils2 did not make the Python 3.3 release, and it was put on hold.

future of python package management

Problem: distribute is planned to be phased out. But it does things that distutils can't.

The main one is installing external dependencies along with your module.

See this. Only with distribute am I able to add a "install_requires" which will be automatically installed along with my module.

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment