0 votes
in Python Imaging Library by

Extract all Pitch, Yaw and Roll EXIF information from JPEG using Python PIL

I have a series of JPEGS captured during an aerial patrol. These JPEGS have metadata stored within JPEG, this metadata includes the GPSInfo and other data.
I am trying to extract this information into a format I can use (csv etc.). I am also going to try and implement this in a Python script that will run on a shared virtual machine, possibly in FME.
I am able to run the Python PIL library and extract out much of the information I need. See below:
import PIL.Image
import PIL.ExifTags
from PIL import Image, ExifTags
from PIL.ExifTags import GPSTAGS
from PIL.ExifTags import TAGS
from os import walk
import os
import pandas as pd
import os
from datetime import datetime
def get_exif(filepath):
    image = Image.open(filepath)
    image.verify()
    return image._getexif()
The following falls under a Main() method
    for filename in os.listdir(direct):
    if filename.endswith(".jpg"):
        print (i)
        filepath = os.path.join(direct, filename)#
        attribs = []
        exif = get_exif(filepath)
        fields = ['GPSInfo', 'Model', 'ExposureTime', 'FocalLength', 'Software', 'DateTime', 'DateTimeDigitised']
        exifData = {}
        for f in fields:
            for tag, value in exif.items():
                decodedTag = ExifTags.TAGS.get(tag, tag)
                if decodedTag == f:
                    exifData["File"] = filename
                    if decodedTag == 'GPSInfo':
                        exifData["Y"] = value[2]
                        exifData["X"] = value[4]
                        exifData["Z"] = value[6]
                        continue
                    else:
                        exifData[decodedTag] = value
                        continue
        df = df.append(exifData, ignore_index = True)
        i +=1
Extract all Pitch, Yaw and Roll EXIF information from JPEG using Python PIL
Is there a way to have the PIL library return these values for Yaw, Pitch and Roll?
I cannot use the commandline on the machine I want to deploy this and I cannot add any new transformers to my FME Installation on this machine.

1 Answer

0 votes
by
I think it is a matter of the python implementation. If you have a look at the ExifTags.py the tags are not listed. May that's because the tags are not standardized. If you have a look in the exiv2 GPSInfo Group, the tags are also not listed.

I had a look into the Image::ExifTool source code, there are about 100 data formats addressed or handled:

PhotoMechanic Exif GeoTiff CanonRaw KyoceraRaw Lytro MinoltaRaw PanasonicRaw

SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions

PICT PNG MNG FLIF DjVu DPX OpenEXR MIFF PGF PSP PhotoCD Radiance PDF

PostScript Photoshop::Header Photoshop::Layers Photoshop::ImageData

FujiFilm::RAF FujiFilm::IFD Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD

Sony::PMP ITC ID3 FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible

MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime QuickTime::ImageFile

QuickTime::Stream Matroska MOI MXF DV Flash Flash::FLV Real::Media

Real::Audio Real::Metafile Red RIFF AIFF ASF DICOM MIE JSON HTML XMP::SVG

Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString

EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard

VCard::VCalendar RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR RTF OOXML iWork ISO

FLIR::AFF FLIR::FPF MacOS::MDItem MacOS::XAttr

When I filter the modules for the GPSRoll tag, I find advices like:

/usr/share/perl5/Image/ExifTool$ grep GPSRoll *.pm

Geotag.pm:            # Note: GPSPitch and GPSRoll are non-standard, and must be user-defined

Geotag.pm:            @r = $et->SetNewValue(GPSRoll => $$tFix{roll}, %opts);

Geotag.pm:                    GPSImgDirection GPSImgDirectionRef GPSPitch GPSRoll))

Geotag.pm:user-defined tags, GPSPitch and GPSRoll, must be active.

So it seems that the attitude data tagging is made on a "Thin Ice" standard and you have to enable some user defined tag capabilities. When I made a test against image with Roll, Pitch and Yaw tags from a PhaseOne Camera image (which I often use), the library Image::ExifTool can read the tags with complete different names (GPSIMURoll ...). At the moment I don't know how it works.

According to the FME constraints, is it possible to use the either exiftool or the Image::ExifTool library either by a shell-out and parse the resulting code like:

# Pseudo code

with Popen(["exiftool", jpgFileName ], stdout=PIPE) as proc:

    parseExifTool(proc.stdout.read())

or tailor a IPC specific call in Perl to get the info's.

Test dataset

The test dataset is from a PhaseOne iXM-RS150F aerial camara. The IIQ format is a special image format based on 2 page TIF with a overview image TIF coded and the large RAW dataset block. Metadata are embedded Tif specific present in the IFD.

Python Pillow (PIL fork)

Here is my Python test code (I'm not a crack in python coding), which is hopefully similar to the Perl code below. Unfortunatly PIL cannot read or decode the exif directory of my IIQ image. May it works for you with the JPG.

While it in Perl it works (see the test below). May be as mentioned, that's because the library supports a large number of also strange or vendor related (raw) image formats (..see table of images supported).

Python script

#!/usr/bin/env python3

import sys

from PIL import Image

from PIL.ExifTags import TAGS, GPSTAGS

DATA = 'data/example.IIQ';

def printf(format, \*args):

    sys.stdout.write(format % args)

image = Image.open(DATA)

info  = image.info

if info is None:

    print("ERROR: Image info is empty!")

    exit(1)

printf("INFO.TAGS in file %s ARE:\n", DATA);

for k, v in info.items():

    printf(" %16s: %s\n",k, v);

exifInfo = info.get('exif')

if exifInfo is None:

    print("ERROR: Image exif info is empty!")

    exit(1)

printf("EXIF.DATA file %s ARE:\n", DATA);

for k, v in exifInfo.items():

    printf(" %16s %s\n", k, v);

#EOF

Resulting output from the Python script

./Pillow-Exifs.py

INFO.TAGS in file data/example.IIQ ARE:

      compression: raw

              dpi: (292.57142857142856, 292.57142857142856)

ERROR: Image exif info is empty!

Perl Family

Exif Tool

Extract GPS tags with the exiftool (Perl5 related code base). The exiftool inserts some spaces to make the matter better human readable. In the machine prepared dictionary these space disappear.

$ exiftool data/example.IIQ | grep GPS

GPS Date/Time                   : 10:17:41.405459

GPS Latitude                    : 52 deg 8' 57.22" N

GPS Longitude                   : 8 deg 16' 52.81" W

GPS Altitude Ref                : Above Sea Level

GPS Event ID                    : 24

GPSIMU Pitch                    : -0.29

GPSIMU Roll                     : -0.18

GPSIMU Yaw                      : 358.31

GPSIMU Yaw Ref                  : T

GPS Altitude                    : 551.9 m Above Sea Level

GPS Latitude Ref                : North

GPS Longitude Ref               : West

GPS Position                    : 52 deg 8' 57.22" N, 8 deg 16' 52.81" W

Perl script -- library Image::ExifTool

Extract the GPS tags with the perl library Image::ExifTool where the ExifTool belongs to.

#!/usr/bin/env perl

use strict;

use warnings;

use Image::ExifTool qw(:Public);

# The test dataset from a PhaseOne iXM-RS150F.

my $DATA = 'data/example.IIQ';

# Get hash of meta information tag

# The hash is returned as a reference.

my $info = ImageInfo($DATA);

# Filter the GPS Tags and print them

print "TAGS if file $DATA ARE:\n";

for my $tag (sort keys %$info) {

    print "\t$tag\n" if $tag =~ /^GPS/;

}

print "\n";

# Set the filter for tags of interest

my @tagsUse = qw(GPSAltitude GPSLatitude GPSLongitude

                 GPSIMUPitch GPSIMURoll GPSIMUYaw);

# Filter the GPS Tags, get the values and print them.

print "TAGS & VALUES of INTEREST ARE:\n";

for my $tag (@tagsUse) {

    my $value = $info->{$tag};

    $value = 'NA' if not defined $value;

    printf  "%16s: %s\n", $tag, $value;

}

print "\nREADY\n";

Resulting output from the Perl script

TAGS if file data/example.IIQ ARE:

    GPSAltitude

    GPSAltitude (1)

    GPSAltitudeRef

    GPSDateTime

    GPSEventID

    GPSIMUPitch

    GPSIMURoll

    GPSIMUYaw

    GPSIMUYawRef

    GPSLatitude

    GPSLatitudeRef

    GPSLongitude

    GPSLongitudeRef

    GPSPosition

TAGS & VALUES of INTEREST ARE:

     GPSAltitude: 551.9 m Above Sea Level

     GPSLatitude: 52 deg 8' 57.22" N

    GPSLongitude: 8 deg 16' 52.81" W

     GPSIMUPitch: -0.29

      GPSIMURoll: -0.18

       GPSIMUYaw: 358.31
...