Posted by & filed under QGIS.

I recently acquired a Blackberry Bold. The device has a built in GPS and Camera and supports ‘GeoTagging’ images taken with the camera. Its pretty easy to get at the positional information under Ubuntu Linux. First I installed the exiftags package:

sudo apt-get install exiftags

To simply see a list of file names and the location each image was taken at, you can do something like:

for FILE in *; do echo $FILE >> geo.txt; exiftags $FILE | grep "Long\|Lat" >> geo.txt; done; cat geo.txt

Wanting a little more control over the process I decided to write a little python app to pull out the position info. To do that I used the excellent python-pyexiv2 package:

sudo apt-get install python-pyexiv2

From there I could write a script to snag the info I wanted. The script is quite well commented below so just read the source to understand what it does.

NoteThis article was updated 17 June 2009, 10pm GMT+2.

#!/usr/bin/python
#
# Read the lat / lon from a geotagged image
#
#         (c)Tim Sutton 2009
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# Import the pyexiv2 library for reading exif tags from images
import pyexiv2
# Now load the regular expressions library
import re # regexp
# Needed for traversing the dirs
import os

myOutput = file('/tmp/photos.txt',"wt")
myOutput.write("Filename,Lon,Lat\n")

# shamelessly hard coded for now...
mInputDir = '/home/timlinux/Photos/2009/'

myCount = 0
if not os.path.isdir(mInputDir):
    print "Input dir does note exist...quitting"
    sys.exit(0);

for myRoot, myDirs, myFiles in os.walk(mInputDir):
  for myFile in myFiles:
    myPath = myRoot + "/" + myFile

    # This is the image I will be getting the geotagging info from
    myImage = None 

    try:
      myImage = pyexiv2.Image(myPath)
    except:
      continue

    # Use exiv2 to get the metadata from the image
    myImage.readMetadata()

    # For debugging you can do:
    #print exifKeys()
    #myImage.exifKeys()

    # Get the position info as reported by exiv2

    myLonDirection = None
    myLonDegrees = None
    myLonMinutes = None
    myLatDirection = None
    myLatDegrees = None
    myLatMinutes = None
    try:
      # Will be either 'E' or 'W'
      myLonDirection = myImage['Exif.GPSInfo.GPSLongitudeRef']
      # Will return a rational number like : '27/1'
      myLonDegrees = myImage['Exif.GPSInfo.GPSLongitude'][0]
      # Will return a rational number like : '53295/1000'
      myLonMinutes = myImage['Exif.GPSInfo.GPSLongitude'][1]
      # Will be either 'N' or 'S'
      myLatDirection = myImage['Exif.GPSInfo.GPSLatitudeRef']
      # Will return a rational number like : '27/1'
      myLatDegrees = myImage['Exif.GPSInfo.GPSLatitude'][0]
      # Will return a rational number like : '56101/1000'
      myLatMinutes = myImage['Exif.GPSInfo.GPSLatitude'][1]
    except:
      continue

    # Get the degree and minute values

    myRegexp = re.compile( '^[0-9]*' )
    myLonDegreesFloat = float(myRegexp.search( str(myLonDegrees) ).group())
    myLatDegreesFloat = float(myRegexp.search( str(myLatDegrees) ).group())
    myLonMinutesFloat = float(myRegexp.search( str(myLonMinutes) ).group())
    myLatMinutesFloat = float(myRegexp.search( str(myLatMinutes) ).group())

    # Divide the values by the divisor 

    myRegexp = re.compile( '[0-9]*$' )
    myLon = myLonDegreesFloat / float(myRegexp.search( str(myLonDegrees) ).group())
    myLat = myLatDegreesFloat / float(myRegexp.search( str(myLatDegrees) ).group())
    myLonMin = myLonMinutesFloat / float(myRegexp.search( str(myLonMinutes) ).group())
    myLatMin = myLatMinutesFloat / float(myRegexp.search( str(myLatMinutes) ).group())

    # We now have degrees and decimal minutes, so convert to decimal degrees...

    myLon = myLon + (myLonMin / 60)
    myLat = myLat + (myLatMin / 60)

    # Use a negative sign as needed

    if myLonDirection == 'W': myLon = 0 - myLon
    if myLatDirection == 'S': myLat = 0 - myLat

    # Lets see what we got

    myOutput.write( myPath + "," + str(myLon) + "," + str(myLat) + "\n" )

Now you can save the script (I called it showlonlat.py) and then run it to get the Lon/Lat out in decimal degrees…e.g.

chmod +x showlatlong.py
./showlonlat.py

The file generated by his script (hard coded to /tmp/photos.txt) can now be opened with QGIS using the delimited text plugin. From there its a simple matter to create an action in the layer properties dialog so that the image for each point is shown when you click on it. Here is what the end result is like:

Blackberry Images visualised in QGIS
(click the image for a larger view)

In a future article I will do an integration of this script into a QGIS python plugin so that it scans a whole directory structure and builds a spatial lite or shape file with the geometries for all the images, as well as their full path names.

pixelstats trackingpixel

Leave a Reply

You must be logged in to post a comment.