5

I would like to import EXIF & metadatas of JPG images into QGIS. For each image, a vector were created by 'ImportPhotos' pluggin, it adds some EXIF into attributes fields but some importants EXIF informations are missing.

In fact, I need 3 more fields. The XMP tags I need are: GimbalYawDegree, FlightYawDegree, RelativeAltitude value are real. That's why I've created 3 new columns (attributes fields) named: GimbalYawDegree, FlightYawDegree, RelativeAltitude.

I would like to create a python script to run a batch for every feature (img imported by ImportPhotos) of a layer. The task would :

  • import the XMP datas of images stored at the path located into the attribute field named "Path"

    import PIL.ExifTags
    exif = {
        PIL.ExifTags.TAGS[k]: v
        for k, v in img._getexif().items()
        if k in PIL.ExifTags.TAGS
    }
    

This code should read the EXIF but this is my first experience in Python and I'm not able to finish the job.

there few samples of images including GimbalYawDegree, FlightYawDegree, RelativeAltitude tags https://we.tl/t-BjPuzBGMRc

10
  • 1
    This is using only python, but I think this will help you to obtain the information. stackoverflow.com/questions/4764932/… Dec 15 '19 at 12:25
  • @Jhon Galindo thanks for this answer it definitly helps as it resolves the "Reading EXIF" part of the code. Now I have to build the second part: importing these datas into as attributes for every features (image imported by ImportPhotos) in a layer. But with my null knowledge in Python, it is going to be funny xD
    – zlikotp
    Dec 15 '19 at 12:50
  • 2
    For Time field, if you change 'Widget Type' as 'Text Edit' in 'Layer Properties > Attributes Form'. Then you'll see Time value in 'form view'. Dec 15 '19 at 12:58
  • 2
    Your question is too broad. Because exif data has different types (string, date, time, integer, decimal, etc.). And all should be handled one by one. ImportPhotos plugin works in that way for fields which it adds to attribute table. Maybe a solution is proposed for only one or two exif data which is not added by ImportPhotos plugin. And then you customize the script for the others. Dec 15 '19 at 18:02
  • 1
    I've been trying for hours. I can't provide a solution without sample image includes GimbalYawDegree, FlightYawDegree, RelativeAltitude tags. Dec 15 '19 at 19:45
4

PIL Solution

Add three new fields (real type) named "fyd", "gyd", "ra" (fyd: FlightYawDegree, gyd: GimbalYawDegree, ra: RelativeAltitude)

Copy/paste the script to QGIS Python Editor (not to Console), select layer (important) and run.

from xml.etree import ElementTree as ET

layer = iface.activeLayer()
dpr = layer.dataProvider()

fyd_ind = layer.fields().indexFromName("fyd")
gyd_ind = layer.fields().indexFromName("gyd")
ra_ind  = layer.fields().indexFromName("ra")

for feature in layer.getFeatures():
    file_path = feature["Path"] 
    print(file_path)

    with open(file_path, "rb") as f:
        s = str(f.read())

    start = s.find('<x:xmpmeta')
    end   = s.find('</x:xmpmeta')
    xmp   = s[start:end+12].replace("\\n","\n")
    tree  = ET.XML(xmp)

    fyd = tree[0][0].attrib['{http://www.dji.com/drone-dji/1.0/}FlightYawDegree']
    gyd = tree[0][0].attrib['{http://www.dji.com/drone-dji/1.0/}GimbalYawDegree']
    ra  = tree[0][0].attrib['{http://www.dji.com/drone-dji/1.0/}RelativeAltitude']

    dpr.changeAttributeValues({  feature.id():{fyd_ind: fyd,
                                               gyd_ind: gyd,
                                               ra_ind:   ra}  })

#  Other DJI Tags if you need
#  {http://www.dji.com/drone-dji/1.0/}GpsLatitude'
#  {http://www.dji.com/drone-dji/1.0/}GpsLongitude'
#  {http://www.dji.com/drone-dji/1.0/}AbsoluteAltitude'
#  {http://www.dji.com/drone-dji/1.0/}GimbalRollDegree'
#  {http://www.dji.com/drone-dji/1.0/}GimbalPitchDegree'
#  {http://www.dji.com/drone-dji/1.0/}FlightRollDegree'
#  {http://www.dji.com/drone-dji/1.0/}FlightPitchDegree'
#  {http://www.dji.com/drone-dji/1.0/}CamReverse'
#  {http://www.dji.com/drone-dji/1.0/}GimbalReverse'

pyexiv2 Solution

When you run next script, you'll see all metadata includes EXIF, IPTC, XMP .

from pyexiv2 import Image

image = Image("file_path")
metadata = image.read_all() # returns all metadata (EXIF, IPTC, XMP)
print(metadata.keys()) # prints dict_keys(['EXIF', 'IPTC', 'XMP'])
print(metadata["XMP"]) # prints all XMP metadata keys and values

Then, decide tags you want to add, add new fields for them, customize next script, select layer and run the script.

from pyexiv2 import Image

layer = iface.activeLayer()
dpr = layer.dataProvider()

fyd_ind = layer.fields().indexFromName("fyd")
gyd_ind = layer.fields().indexFromName("gyd")
ra_ind  = layer.fields().indexFromName("ra")

for feature in layer.getFeatures():
    file_path = feature["Path"] 
    print(file_path)

    image = Image(file_path)
    metadata = image.read_all()
    xmp = metadata["XMP"]

    fyd = float(xmp["Xmp.drone-dji.FlightYawDegree"])
    gyd = float(xmp["Xmp.drone-dji.GimbalYawDegree"])
    ra  = float(xmp["Xmp.drone-dji.RelativeAltitude"])

    dpr.changeAttributeValues({ feature.id():{fyd_ind: fyd,
                                              gyd_ind: gyd,
                                              ra_ind:   ra} })
8
  • You should use after using Import Photos plugin. Dec 15 '19 at 22:58
  • Perfect I'm going to try but before I'm trying to read the script and my question is about image_folder. Since the path of every file is already stored (because I've used ImportPhotos), could we avoid to have to change the path manually by using the field Path?
    – zlikotp
    Dec 15 '19 at 23:19
  • You're right. I didn't notice that. My mistake. Dec 15 '19 at 23:24
  • another point is the url : dji.com/drone-dji/1.0 does this function requiert any internet connexion ?
    – zlikotp
    Dec 15 '19 at 23:25
  • 1
    No. Just Element Treemodule parses xmp data in that way. Dec 15 '19 at 23:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.