Delving into Delusion

Geotagging Photos with Exiftool

 June 12, 2020      Stardate: 73912.5     Tagged as: Ubuntu Exiftool

I use the Mapillary android app for taking “street-level” images, especially while driving. There is a library of CLI-tools available for processing these images if you want/need to do anything customized or above what the mobile app does. It uses the power of one of my favorite tools, Exiftool, and I wanted to dive under the hood to understand Exiftool more. This post is essentially some random information that I want to document for my future use as well as information that the reader can use to build their own photo processing workflow.

Reading Tags

You can list all the metadata for a photo:

exiftool -a -s -G file.jpg
  • -a means to show all tags, even if they are duplicated, like in a different group.
  • -s means instead of showing the “friendly” names like “Create Date”, show the names you need to use when you write ExifTool commands. So instead of “Create Date” you see “CreateDate”.
  • -G means also show the metadata Group to which the metadata tag belongs.
In [1]:
!exiftool -a -s -G photo.jpg
[ExifTool]      ExifToolVersion                 : 11.88
[File]          FileName                        : photo.jpg
[File]          Directory                       : .
[File]          FileSize                        : 1789 kB
[File]          FileModifyDate                  : 2020:06:07 22:15:00+05:30
[File]          FileAccessDate                  : 2020:06:07 22:15:05+05:30
[File]          FileInodeChangeDate             : 2020:06:07 22:15:00+05:30
[File]          FilePermissions                 : rwxr-----
[File]          FileType                        : JPEG
[File]          FileTypeExtension               : jpg
[File]          MIMEType                        : image/jpeg
[File]          ExifByteOrder                   : Big-endian (Motorola, MM)
[File]          ImageWidth                      : 4032
[File]          ImageHeight                     : 2268
[File]          EncodingProcess                 : Baseline DCT, Huffman coding
[File]          BitsPerSample                   : 8
[File]          ColorComponents                 : 3
[File]          YCbCrSubSampling                : YCbCr4:2:0 (2 2)
[EXIF]          Make                            : samsung
[EXIF]          Model                           : SM-G955U
[EXIF]          Orientation                     : Rotate 180
[EXIF]          XResolution                     : 72
[EXIF]          YResolution                     : 72
[EXIF]          ResolutionUnit                  : inches
[EXIF]          Software                        : G955USQS6DSG4
[EXIF]          ModifyDate                      : 2020:06:06 14:06:41
[EXIF]          YCbCrPositioning                : Centered
[EXIF]          ExposureTime                    : 1/1723
[EXIF]          FNumber                         : 1.7
[EXIF]          ExposureProgram                 : Not Defined
[EXIF]          ISO                             : 56
[EXIF]          ExifVersion                     : 0220
[EXIF]          DateTimeOriginal                : 2020:06:06 14:06:41
[EXIF]          CreateDate                      : 2020:06:06 14:06:41
[EXIF]          ComponentsConfiguration         : Y, Cb, Cr, -
[EXIF]          ShutterSpeedValue               : 1/1722
[EXIF]          ApertureValue                   : 1.7
[EXIF]          BrightnessValue                 : 0
[EXIF]          ExposureCompensation            : 0
[EXIF]          MaxApertureValue                : 1.7
[EXIF]          MeteringMode                    : Unknown
[EXIF]          Flash                           : No Flash
[EXIF]          FocalLength                     : 4.2 mm
[EXIF]          SubSecTime                      : 907093
[EXIF]          SubSecTimeOriginal              : 907093
[EXIF]          SubSecTimeDigitized             : 907093
[EXIF]          FlashpixVersion                 : 0100
[EXIF]          ColorSpace                      : sRGB
[EXIF]          ExifImageWidth                  : 4032
[EXIF]          ExifImageHeight                 : 2268
[EXIF]          InteropIndex                    : R98 - DCF basic file (sRGB)
[EXIF]          InteropVersion                  : 0100
[EXIF]          SensingMethod                   : Unknown (0)
[EXIF]          SceneType                       : Unknown (0)
[EXIF]          ExposureMode                    : Auto
[EXIF]          WhiteBalance                    : Manual
[EXIF]          SceneCaptureType                : Standard
[EXIF]          GPSLatitudeRef                  : North
[EXIF]          GPSLatitude                     : 18 deg 33' 53.03"
[EXIF]          GPSLongitudeRef                 : East
[EXIF]          GPSLongitude                    : 73 deg 46' 31.66"
[EXIF]          GPSAltitudeRef                  : Above Sea Level
[EXIF]          GPSAltitude                     : 508.1000061 m
[EXIF]          GPSTimeStamp                    : 08:36:41.90709
[EXIF]          GPSImgDirection                 : 76
[EXIF]          GPSDateStamp                    : 2020:06:06
[XMP]           XMPToolkit                      : Image::ExifTool 11.88
[XMP]           Creator                         : Joe
[XMP]           Description                     : This is a sunset taken on lookout hill
[Composite]     Aperture                        : 1.7
[Composite]     ImageSize                       : 4032x2268
[Composite]     Megapixels                      : 9.1
[Composite]     ShutterSpeed                    : 1/1723
[Composite]     SubSecCreateDate                : 2020:06:06 14:06:41.907093
[Composite]     SubSecDateTimeOriginal          : 2020:06:06 14:06:41.907093
[Composite]     SubSecModifyDate                : 2020:06:06 14:06:41.907093
[Composite]     GPSAltitude                     : 508.1 m Above Sea Level
[Composite]     GPSDateTime                     : 2020:06:06 08:36:41.90708999Z
[Composite]     GPSLatitude                     : 18 deg 33' 53.03" N
[Composite]     GPSLongitude                    : 73 deg 46' 31.66" E
[Composite]     FocalLength35efl                : 4.2 mm
[Composite]     GPSPosition                     : 18 deg 33' 53.03" N, 73 deg 46' 31.66" E
[Composite]     LightValue                      : 13.1

Using the -G flag is useful for seeing groups. One use is if you what to view all tags for a group. For example,

In [2]:
!exiftool -s -G -Composite:all photo.jpg
[Composite]     Aperture                        : 1.7
[Composite]     ImageSize                       : 4032x2268
[Composite]     Megapixels                      : 9.1
[Composite]     ShutterSpeed                    : 1/1723
[Composite]     SubSecCreateDate                : 2020:06:06 14:06:41.907093
[Composite]     SubSecDateTimeOriginal          : 2020:06:06 14:06:41.907093
[Composite]     SubSecModifyDate                : 2020:06:06 14:06:41.907093
[Composite]     GPSAltitude                     : 508.1 m Above Sea Level
[Composite]     GPSDateTime                     : 2020:06:06 08:36:41.90708999Z
[Composite]     GPSLatitude                     : 18 deg 33' 53.03" N
[Composite]     GPSLongitude                    : 73 deg 46' 31.66" E
[Composite]     FocalLength35efl                : 4.2 mm
[Composite]     GPSPosition                     : 18 deg 33' 53.03" N, 73 deg 46' 31.66" E
[Composite]     LightValue                      : 13.1

The -s flag is useful because it shows the real names of the fields and not the “pretty” or “friendly” name. If you want to show a single tag you can call the name.

In [3]:
!exiftool -s -G -CreateDate photo.jpg
[EXIF]          CreateDate                      : 2020:06:06 14:06:41

If there are duplicates and any doubt about which tag you are reading/writing, you can define the group.

In [4]:
!exiftool -s -G -EXIF:CreateDate photo.jpg
[EXIF]          CreateDate                      : 2020:06:06 14:06:41

You can also read multiple tags.

In [5]:
!exiftool -File:FileName -EXIF:CreateDate -Composite:SubSecCreateDate photo.jpg
File Name                       : photo.jpg
Create Date                     : 2020:06:06 14:06:41
Create Date                     : 2020:06:06 14:06:41.907093
In [7]:
!exiftool -s -File:FileName -EXIF:CreateDate -Composite:SubSecCreateDate photo.jpg
FileName                        : photo.jpg
CreateDate                      : 2020:06:06 14:06:41
SubSecCreateDate                : 2020:06:06 14:06:41.907093
In [6]:
!exiftool -s -G -File:FileName -EXIF:CreateDate -Composite:SubSecCreateDate photo.jpg
[File]          FileName                        : photo.jpg
[EXIF]          CreateDate                      : 2020:06:06 14:06:41
[Composite]     SubSecCreateDate                : 2020:06:06 14:06:41.907093

Writing Tags

You can also write tags, or overwrite tags. Let’s say I want to create a new metadata tag named “Creator” and add my name to it. I can also write multiple tags at once.

exiftool -Creator="Joe" -Description="This is a sunset taken on lookout hill" photo.jpg
In [7]:
!exiftool -s -G -XMP:all photo.jpg
[XMP]           XMPToolkit                      : Image::ExifTool 11.88
[XMP]           Creator                         : Joe
[XMP]           Description                     : This is a sunset taken on lookout hill

Geotag

When you geotag, Exiftool will take the date/time of a photo, find the nearest gps points within a provided log, and then interpolate the position based on the photo’s date/time. If you have a hihg-quality gps receiver and can save a log I think geotagging photo coordinates will improve the location accuracy of the photos.

exiftool -geotag log.gpx *jpg

The above command is telling the tool to perform this position interpolation on all the files mathcing “jpg” in the current directory, using the gps trace “log.gpx” also in the current directory.

From this post it was clarified that the subsecond date/time should be use (if available) for more accurate results.

How to find an appropriate tag? Do a search!

In [8]:
!exiftool -s -G -SubSec* photo.jpg
[EXIF]          SubSecTime                      : 907093
[EXIF]          SubSecTimeOriginal              : 907093
[EXIF]          SubSecTimeDigitized             : 907093
[Composite]     SubSecCreateDate                : 2020:06:06 14:06:41.907093
[Composite]     SubSecDateTimeOriginal          : 2020:06:06 14:06:41.907093
[Composite]     SubSecModifyDate                : 2020:06:06 14:06:41.907093

For this photo it looks like we can use several of composite group tags.

exiftool -geotag log.gpx "-GeoTime<Composite:SubSecCreateDate" *jpg

The tool will update the latitude and longitude positions as well as add a handful of other EXIF and Composite tags.

For example:

In [9]:
!exiftool -s -G1 -GPS:all photo.jpg
[GPS]           GPSLatitudeRef                  : North
[GPS]           GPSLongitudeRef                 : East
[GPS]           GPSAltitudeRef                  : Above Sea Level
[GPS]           GPSTimeStamp                    : 08:36:41.90709
[GPS]           GPSImgDirection                 : 76
[GPS]           GPSDateStamp                    : 2020:06:06

Inverse Geotag

If the photos have GPS information, you can create a gps track from a series of photos. This is as simple as:

exiftool -p ./gpx.fmt *jpg > phototrace.gpx

The above command is telling the tool to go through all files matching “*jpg” in the current directory and pull out the gps data for each one. Then write that data in the output file “phototrace.gpx” using the format “gpx.fmt”. The format is completely customizable and is just a template for how to parse the data. The format files are located here or you can make your own. Note that in this example the location of the file is in the current directory.

If you want to export a Google Earth friendy kml file:

exiftool -p ./kml.fmt *jpg > phototrace.kml

Mapillary Notes

On an Android the photos taken from the Mapillary app are stored in the app data directory. Most likely you are storing the photos on an external SD Card, if so the storage location is:

SAMSUNG Android/Card/Android/data/app.mapillary/files/CAMERA2_0/<dirs>/

Otherwise the storage location is:

SAMSUNG Android/Phone/Android/data/app.mapillary/files/CAMERA2_0/<dirs>/

Another interesting note is that a gpx file is also created and stored in the corresponding directory. Photos are named by Mapillary in this format:

2020_06_06_14_06_41_856_+0530.jpg which translates to YYY\_MM\_DD\_HH\_MM\_SS\_xxx\_UTCOffset

I’m not sure what “xxx” is. I thought it was the subseconds but it doesn’t look like it. Another theory is that it was the subseconds at time of initial file creation and then the field SubSecTime is at the time the metadata was created. The difference is the processing delay or time it took to write the file. At least that is my theory…

In [10]:
!exiftool -s -G \
    -File:FileName -EXIF:CreateDate -EXIF:DateTimeOriginal \
    -EXIF:SubSecTime -EXIF:SubSecTimeOriginal -Composite:SubSecCreateDate \
    photo.jpg
[File]          FileName                        : photo.jpg
[EXIF]          CreateDate                      : 2020:06:06 14:06:41
[EXIF]          DateTimeOriginal                : 2020:06:06 14:06:41
[EXIF]          SubSecTime                      : 907093
[EXIF]          SubSecTimeOriginal              : 907093
[Composite]     SubSecCreateDate                : 2020:06:06 14:06:41.907093
In [11]:
%load_ext version_information
%version_information
Out[11]:
SoftwareVersion
Python3.7.4 64bit [GCC 7.3.0]
IPython7.11.1
OSLinux 5.4.0 33 generic x86_64 with debian bullseye sid
Sun Jun 07 21:56:58 2020 IST

Software Versions

This is an automated list of software versions used during the writing of this article.

SoftwareVersion
OS Ubuntu 20.04 LTS
Exiftool 11.88