Add GPS information to pictures

One of the features I enjoy with taking pictures and importing them on to my Mac, is that afterwards the Photo app can show a map of everywhere I have taken a picture. But that only works if the longitude and latitude are included in the picture. With my iPhone, that works great. With my nice (but not too nice) camera, that does not happen. However, since I am a runner, I have a GPS unit that is often keeping track of where I am. With a bit of software and know-how, I can combine the information.

The important thing is to try and get a time synchronization picture. That is a picture of the display of the GPS unit showing it running. Preferably try and get the picture while the time is showing a round number, but with the tools on this page it isn't as important. With this image you can know the difference between the time of the GPS versus the date/time on the camera. I like to keep my time as accurate as possible on the camera, but this will make it absolutely precise.

The tool, ExifTool, used in this documentation makes the assumption that you can see the UTC time on your device. Since I use a runner's GPS unit, it does not tell me that information and I need to use the operations I document here to extract it.

If you can’t get a synchronization picture, then you have to hope your camera has the exact same time as the GPS satellites. You don’t have to get the time synchronization picture at the same time as you are taking the pictures: You can start a new run of the GPS unit and take a picture then and use that to find the offset.

If you are using the Photos.app on a Mac, I have found that doing this operation on both files will destroy the link between a matched JPEG and RAW file. Before this, Photos would just recognize them as the same picture and would treat both files as one picture. After this operation, they are loaded as two separate pictures. In this case, I would recommend just deleting the JPEG, as the RAW one has more information.

Setup

You will need ExifTool to do most of the work. You can download it here. It has a page on Geotagging with ExifTool, but it doesn't give much help with the calculations that are needed. I believe it was written under the impression that the geotagging would be done in the same time zone that the pictures were taken.

Optionally, you can also download jhead which I find conveniently fast for modifying dates and times for files, and doesn't constantly create new files. You can download it here.

Optional

If you have a heightened attention to detail, it may bother you if your pictures have a wrong time embedded within them. The exiftool can help you with this. To change the time you can use the helpful -AllDates feature to shift each pictures time by the appropriate amount. At the same time, you can explicitly set the time zone with the -timezone option. For completeness, you should probably use the "-filemodifydate<datetimeoriginal" option to keep the file time set appropriately.

For example, if you crossed from a -6:00 time zone to a -7:00 time zone (you travelled west), and forgot to set the time and zone on your camera, you would need to run the following commands on the pictures:

exiftool -AllDates-=1 -timezone=-7:00 "-filemodifydate<datetimeoriginal" .

Steps

  1. Get the GPX file
    Since I am using a Garmin device (Garmin Forerunner 310XT) all of my routes are on the Garmin website. Once I am looking at a route, I can click the gear in the upper-right corner and select "Export to GPX".
  2. Get data from the GPX file.
    Since it is an XML file, it is human readable. Use the XPATH to find the information.
    • /gpx/trk/trkseg/trkpt[first()]/time: We will refer to this as the GpxStartTime
    • /gpx/trk/trkseg/trkpt[last()]/time: We will refer to this as the GpxEndTime. It is not actually necessary, but it is convenient for keeping track of which pictures you have that were taken while the GPS unit was running.
  3. Get data from the synchronization picture
    You can open the picture in Preview to get the information. You will also run the command exiftool -h <<time synchronization picture file>> on it.
    • The time displayed in the picture: We will refer to this as the SyncDisplayTime
    • From ExifTool output, /table//tr[td='Date/Time Original']/td[1]: We will refer to this as the SyncCameraTime.
    • From ExifTool output, /table//tr[td='Time Zone']/td[1]: We will refer to this as CameraTimeZone.
  4. Calculate numbers
    Now you need to do some math.
    • TimeZoneOffset
      This is the difference, in seconds between the time zone the picture was taken, and the time zone this tool is operating in. We use this to differentiate between offsets for the camera time being off, and entirely different timezones.
      TimeZoneOffset = (LocalTimeZone - CameraTimeZone) * 60 * 60
    • GpsTime
      This is time in UTC that you took the time synchronization picture.
      GpsTime = GpxStartTime + GpxStartTime
    • Offset
      The offset in seconds of the camera to the GPS unit. We get this by looking at the difference between the GpsTime and the SyncCameraTime, taking into account the time zone difference. (The GpsTime is in UTC, the SyncCameraTime is in the camera's time zone.)
      Offset = GpsTime - SyncCameraTime + CameraTimeZone
    • TotalOffset
      This is the the Offset with the TimeZoneOffset added in. The ExifTool gets confused between the time zone the tool is operating in, and the time zone the picture was taken in. So you need to add the differences in time zones in.
      TotalOffset = Offset + TimeZoneOffset
  5. Run the commands
    • exiftool -geotag <<logfile.gpx>> -geosync=<<TotalOffset>> .
      This will go through every picture in the current directory and set the offset correctly. Unfortunately (or fortunately), it makes duplicate files, so you may have to clean up afterwards.
    • exiftool '-DateTimeOriginal>FileModifyDate' .
      This will go through every picture in the current directory and set its file time to match the time the picture was taken. The previous command would have changed the file time, so this will put it back to what should be expected.
      You can also use the jhead -ft *.JPG to fix these files, but jhead only works on JPEG files.

Calculations

You can input the values you have collected into this form and it will calculate the exact command you will need to run.

LogfileName
GpxStartTime (UTC)
GpxEndTime (UTC)
SyncDisplayTime (H:M:S)::
SyncCameraTime
CameraTimeZone (Hours)
LocalTimeZone (Hours)
TimezoneOffset (Seconds)
GpsTime (UTC)
Offset (Seconds)
TotalOffset (Seconds)
CameraGpxStartTime (Local)
CameraGpxEndTime (Local)

Appendix

Version History

2016-7-13: Inital writing

2016-7-29: After taking a vacation in a different time zone, and taking lots of pictures, I discovered errors with the algorithm.