Fixing and Improving Geotagging on with gps_retag, Exiftool, and gpsPhoto
Is gps_retag for you?
What is this?
If you have a camera without GPS and you want to geotag pictures via an external GPS, see my gps geotagging page with GPS Visualizer and gpsPhoto.
Now, things get interesting if you have a camera with built in GPS like the Panasonic DMC TZ30 (ZS20) among several: due to battery constraints, the GPS is not on all the time, and doesn't update position often enough if you are fast moving (mine updates once every 5mn at best. When I fly at 200kts, that's at least 30km of error, that's huge).
But the biggest and most nagging problem is that when you go somewhere and turn your camera on, your first pictures are geotagged with your home address becaue invariably the GPS will not have gotten a lock quickly enough during your first pictures and it'll use the last known location which is usually your home.
Next, what if you go on a trip with a GPS, but your GPS isn't on all the time, so you want to use your GPS data to add a GPS location to your picture, but only if the time delta between the external GPS fix and when the picture was taken, is smaller than the GPS fix taken by the camera itself.
Given these needs, I wrote code that does the following:
- Go through all your pictures in a directory, work on them backwards and if the GPS fix from the next picture has a time delta that is smaller than the delta with the last GPS fix that was available when the picture was taken, then the picture location is updated with the location of the next picture's GPS tag.
If you think about it, it makes sense, because the camera is always using an out of date GPS fix, the fix for picture N is often too old, but it might actually be closer for picture N-1.
Now, this is most useful for fixing the location of your first pictures when they are mistakenly tagged with your home address which is maybe a fix that is days or weeks old. Invariably, your first pictures will get a much beter location by being retagged with the location of the first picture in your series that isn't days or weeks old.
- (new 2014) Do a 2nd forward pass to tag pictures n from n-1 if that makes sense (useful for some cameras, see header below).
- Just to make things interesting, after the step above is done, if you also provided a GPX file from an external GPS (this is optional), my script uses gpsphoto to retag your picture with the nearest point in your GPX but if and only if that location is more precise than the GPS tag that is already in the picture (typically think about pictures taken during an evening dinner or indoors when your GPS was turned off, but your camera is still getting an updated GPS location from time to time).
GPS Retagging backwards and forwards: Panasonic-style vs Canon-style
Now, other GPS cameras like the Canon HX50V actually don't do as good a job. They do not GPS tag a picture at all if the camera doesn't have a recent tag (they could remember the previous tag and time, and use them if time delta is close enough. As a result, plenty of pictures do not have a tag at all.
My original code would only walk pictures backwards and tag picture n-1 from the location on picture n if the location is more precise. With cameras like the Canon, since plenty of pictures had no GPS at all, I modified the code to do a 2nd forward pass: after tagging n-1 with n if the dates are close enough, it goes the other way and tags n with n-1 so that more pictures can be tagged using known GPS fix locations that are close enough in time.
For comparison, the Panasonic will tag a lot of pictures with locations that could be from days ago and totally wrong, but they'll all be tagged. My script will attempt to improve some of those locations but will not delete tags that it can't improve.
With the Canon, my script will not retag pictures it doesn't have any closeby confirmed GPS location for, but on the plus side, pictures that have no GPS location don't end up with a most likely bogus location.
I'm sold, gimme gimme gimme!
Ok, here is my magic gps_retag script. You will need to edit $OFFSET in the script to set it to your local time zone. I recommend you do not change your camera for DST or standard time, use the same time all year and therefore have a consistent offset from GMT for geotagging.
Things to know:
- This page and the perl script assume that you can edit a time offset in a perl script, and generally install linux software (actually it ought to work on Mac and likely even windows if you have a properly installed perl setup and you know what you're doing, just don't ask me for help :).
- It is somewhat slow in normal mode and very slow if you run comparative geotagging using an external GPX file (gpsphoto needs to be run with a max allowable offset for retagging each picture).
- You will need Exiftool to copy GPS location from one picture to another one (case #1 above), and gpsPhoto gpsPhoto to do conditional GPS retagging with an acceptable GPS time delta (exiftool can also do geotagging, but I didn't find a way to force a per picture maximum allowed time offset, hence my use of gpsphoto for geotagging).
Simple Usage example: retagging pictures in a directory
Let's start simple and retag a bunch of pictures, mostly to fix the tagging of the first pictures (last in the list since they are processed backwards):
gandalfthegreat [mc]$ gps_retag --doit *.jpg
GPS tag is for 141_20120721_SJ_History_Park.jpg is 934.0 secs older than the photo
141_20120721_SJ_History_Park.jpg: date 2012072115:11:24 next pict gps: 2999123123:59:59. Diff from next pict: 31160800115.0
Keeping GPS tag because tag from is 31160800115.0 secs offset from the picture time instead of 934.0 secs
GPS tag is for 140_20120721_SJ_History_Park.jpg is 329.0 secs older than the photo
140_20120721_SJ_History_Park.jpg: date 2012072115:01:19 next pict gps: 2012072114:55:50. Diff from next pict: -329.0
141_20120721_SJ_History_Park.jpg has a GPS date older than 140_20120721_SJ_History_Park.jpg by 329 secs
Keeping GPS tag because tag from 141_20120721_SJ_History_Park.jpg is 329 secs offset from the picture time instead of 329.0 secs
GPS tag is for 102_20120721_SJ_History_Park.jpg is 60398.0 secs older than the photo
102_20120721_SJ_History_Park.jpg: date 2012072113:37:13 next pict gps: 2012072113:42:26. Diff from next pict: 313.0
Using GPS tag from 103_20120721_SJ_History_Park.jpg since it is 313.0 secs offset from the picture time instead of 60398.0 secs
1 image files updated
GPS tag is for 101_20120721_SJ_History_Park.jpg is 60364.0 secs older than the photo
101_20120721_SJ_History_Park.jpg: date 2012072113:36:39 next pict gps: 2012072113:42:26. Diff from next pict: 347.0
Using GPS tag from 102_20120721_SJ_History_Park.jpg since it is 347.0 secs offset from the picture time instead of 60364.0 secs
1 image files updated
GPS tag is for 100_20120721_SJ_History_Park.jpg is 60339.0 secs older than the photo
100_20120721_SJ_History_Park.jpg: date 2012072113:36:14 next pict gps: 2012072113:42:26. Diff from next pict: 372.0
Using GPS tag from 101_20120721_SJ_History_Park.jpg since it is 372.0 secs offset from the picture time instead of 60339.0 secs
1 image files updated
Note that the last picture can't get its tagging improved without an external GPX file (and you can ignore the bogus Keeping GPS tag because tag from unset is 31160800115.0 secs offset). The first pictures (shown last), had a GPS location that was 60339 seconds old (16 hours) as was way wrong and now have a much better location after the script has run.
Complex Usage example: retagging pictures in a directory using a GPX file as second location source
The example below shows the more complex run with hand picked examples of 4 pictures.
- The first picture show first has its GPS location improved by usign the next picture's location, and then improved again by using a location from the GPX file
- The 2nd picture has its GPS location also improved by using the next picture's location and that location is more precise than the external GPS' location, so the nearest external GPS location is ignored.
- The 3rd picture actually a better GPS location than the next picture, so it kept that location, but it was replaced by a better location in the GPX file.
gps_retag --doit --gpsfile ~merlin/public_html/perso/gps/data/20120603_Ecuador_Galapagos.gpx *.jpg
GPS tag is for 284_Ecuador_Quito.jpg is 345.0 secs older than the photo
284_Ecuador_Quito.jpg: date 2012060417:28:15 next pict gps: 2012060417:30:31. Diff from next pict: 136.0
Using GPS tag from 285_Ecuador_Quito.jpg since it is 136.0 secs offset from the picture time instead of 345.0 secs
1 image files updated
Running gpsPhoto to improve geotagging if it has an offset smaller than 136 (you will see 'KEEP GEOTAGGING FROM PICTURE' if current gps data was better)
gpsPhoto --gpsfile /home/merlin/public_html/perso/gps/data/20120603_Ecuador_Galapagos.gpx --overwrite-geotagged --timeoffset 25200 --maxtimediff 136 -i '284_Ecuador_Quito.jpg'
/var/www/Pix/new/tmp01/200_Quito/284_Ecuador_Quito.jpg, 2012-06-04T17:28:15Z, timediff=2 to 00:28:13
Lat -0.220063263550401, Lon -78.511824030429125 - Bearing: 0 - Altitude: 2822m
GPS tag is for 283_Ecuador_Quito.jpg is 0.0 secs older than the photo
283_Ecuador_Quito.jpg: date 2012060417:10:32 next pict gps: 2012060417:30:31. Diff from next pict: 1199.0
Keeping GPS tag because tag from 284_Ecuador_Quito.jpg is 1199.0 secs offset from the picture time instead of 0.0 secs
Running gpsPhoto to improve geotagging if it has an offset smaller than 0 (you will see 'KEEP GEOTAGGING FROM PICTURE' if current gps data was better)
gpsPhoto --gpsfile /home/merlin/public_html/perso/gps/data/20120603_Ecuador_Galapagos.gpx --overwrite-geotagged --timeoffset 25200 --maxtimediff 0 -i '283_Ecuador_Quito.jpg'
/var/www/Pix/new/tmp01/200_Quito/283_Ecuador_Quito.jpg, 2012-06-04T17:10:32Z, timediff=276
KEEP GEOTAGGING FROM PICTURE.
Lat -0.219219444444444, Lon -78.5114083333333 - Bearing: 0 - Altitude: 0m
GPS tag is for 273_Ecuador_Quito.jpg is 36.0 secs older than the photo
273_Ecuador_Quito.jpg: date 2012060416:09:49 next pict gps: 2012060416:17:52. Diff from next pict: 483.0
Keeping GPS tag because tag from 274_Ecuador_Quito.jpg is 483.0 secs offset from the picture time instead of 36.0 secs
Running gpsPhoto to improve geotagging if it has an offset smaller than 36 (you will see 'KEEP GEOTAGGING FROM PICTURE' if current gps data was better)
gpsPhoto --gpsfile /home/merlin/public_html/perso/gps/data/20120603_Ecuador_Galapagos.gpx --overwrite-geotagged --timeoffset 25200 --maxtimediff 36 -i '273_Ecuador_Quito.jpg'
/var/www/Pix/new/tmp01/200_Quito/273_Ecuador_Quito.jpg, 2012-06-04T16:09:49Z, timediff=4 to 23:09:45
Lat -0.219303192570806, Lon -78.511458663269877 - Bearing: 0 - Altitude: 2838m
Link to Home Page