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:

(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.



Comments
Leave a comment Trackback