Wie lese ich in Python die Exif-Daten für ein Bild?


Antworten:


183

Versuche dies:

import PIL.Image
img = PIL.Image.open('img.jpg')
exif_data = img._getexif()

Dies sollte Ihnen ein Wörterbuch geben, das durch numerische EXIF-Tags indiziert ist. Wenn Sie möchten, dass das Wörterbuch durch die tatsächlichen EXIF-Tag-Namenszeichenfolgen indiziert wird, versuchen Sie Folgendes:

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

9
Irgendeine Python 3-Alternative?
Santosh Kumar

2
@ 2rs2ts: Versuchen Sie import ExifTags(ohne das PILPräfix).
Florian Brucker

12
Verwenden Sie für Python3 Pillow. Es ist eine Abzweigung von PIL, die noch in der Entwicklung ist, und hat eine Python3-kompatible Version
Mzzl

1
Können Sie dies anhand dieser Frage testen, die Bilder herunterladen und versuchen, die ImageDescription zu erhalten? stackoverflow.com/questions/22173902/…
AJ


30

Sie können auch das ExifRead- Modul verwenden:

import exifread
# Open image file for reading (binary mode)
f = open(path_name, 'rb')

# Return Exif tags
tags = exifread.process_file(f)

1
Können Sie dies anhand dieser Frage testen, die Bilder herunterladen und versuchen, die ImageDescription zu erhalten? stackoverflow.com/questions/22173902/…
AJ

2
@Clayton für beide Bilder gibt exifread ein leeres Wörterbuch zurück. Aber ich habe meine Fotos getestet und es funktioniert einwandfrei.
tnq177

Ich erhalte auch ein leeres Wörterbuch für eine Reihe von Bildern. Kann jemand sagen, warum dies der Fall ist? Mit welcher Art von Bildern arbeitet exifread.process_file ()?
Momchill

17

Ich benutze das:

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS

for (k,v) in Image.open(sys.argv[1])._getexif().iteritems():
        print '%s = %s' % (TAGS.get(k), v)

oder um ein bestimmtes Feld zu erhalten:

def get_field (exif,field) :
  for (k,v) in exif.iteritems():
     if TAGS.get(k) == field:
        return v

exif = image._getexif()
print get_field(exif,'ExposureTime')

6
Besser, Sie können TAGS mit umkehren name2tagnum = dict((name, num) for num, name in TAGS.iteritems())und dann tun name2tagnum['ExposureTime'].
Ben

7
Für Python 3 ändern Sie exif.iteritems()zuexif.items()
SPRBRN

14

Für Python3.x und beginnen Pillow==6.0.0, Imagebieten Objekte nun ein getexif()Verfahren , dass die Rendite <class 'PIL.Image.Exif'>oder Nonewenn das Bild keine EXIF - Daten.

Ab Pillow 6.0.0 Versionshinweise :

getexif()wurde hinzugefügt, wodurch eine ExifInstanz zurückgegeben wird. Werte können wie ein Wörterbuch abgerufen und festgelegt werden. Beim Speichern von JPEG, PNG oder WEBP kann die Instanz als exifArgument übergeben werden, um Änderungen im Ausgabebild aufzunehmen.

Die ExifAusgabe kann einfach in a umgewandelt werden dict, so dass auf die EXIF-Daten als reguläre Schlüssel-Wert-Paare von a zugegriffen werden kann dict. Die Schlüssel sind 16-Bit-Ganzzahlen, die mithilfe des ExifTags.TAGSModuls ihren Zeichenfolgennamen zugeordnet werden können.

from PIL import Image, ExifTags

img = Image.open("sample.jpg")
img_exif = img.getexif()
print(type(img_exif))
# <class 'PIL.Image.Exif'>

if img_exif is None:
    print("Sorry, image has no exif data.")
else:
    img_exif_dict = dict(img_exif)
    print(img_exif_dict)
    # { ... 42035: 'FUJIFILM', 42036: 'XF23mmF2 R WR', 42037: '75A14188' ... }
    for key, val in img_exif_dict.items():
        if key in ExifTags.TAGS:
            print(f"{ExifTags.TAGS[key]}:{repr(val)}")
            # ExifVersion:b'0230'
            # ...
            # FocalLength:(2300, 100)
            # ColorSpace:1
            # FocalLengthIn35mmFilm:35
            # ...
            # Model:'X-T2'
            # Make:'FUJIFILM'
            # ...
            # DateTime:'2019:12:01 21:30:07'
            # ...

Getestet mit Python 3.6.8 und Pillow==6.0.0.


Es funktioniert nicht für mich, ich kann nur die Exif-Daten mit der .info-Methode in Binär sehen
GM

12
import sys
import PIL
import PIL.Image as PILimage
from PIL import ImageDraw, ImageFont, ImageEnhance
from PIL.ExifTags import TAGS, GPSTAGS



class Worker(object):
    def __init__(self, img):
        self.img = img
        self.exif_data = self.get_exif_data()
        self.lat = self.get_lat()
        self.lon = self.get_lon()
        self.date =self.get_date_time()
        super(Worker, self).__init__()

    @staticmethod
    def get_if_exist(data, key):
        if key in data:
            return data[key]
        return None

    @staticmethod
    def convert_to_degress(value):
        """Helper function to convert the GPS coordinates
        stored in the EXIF to degress in float format"""
        d0 = value[0][0]
        d1 = value[0][1]
        d = float(d0) / float(d1)
        m0 = value[1][0]
        m1 = value[1][1]
        m = float(m0) / float(m1)

        s0 = value[2][0]
        s1 = value[2][1]
        s = float(s0) / float(s1)

        return d + (m / 60.0) + (s / 3600.0)

    def get_exif_data(self):
        """Returns a dictionary from the exif data of an PIL Image item. Also
        converts the GPS Tags"""
        exif_data = {}
        info = self.img._getexif()
        if info:
            for tag, value in info.items():
                decoded = TAGS.get(tag, tag)
                if decoded == "GPSInfo":
                    gps_data = {}
                    for t in value:
                        sub_decoded = GPSTAGS.get(t, t)
                        gps_data[sub_decoded] = value[t]

                    exif_data[decoded] = gps_data
                else:
                    exif_data[decoded] = value
        return exif_data

    def get_lat(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_latitude = self.get_if_exist(gps_info, "GPSLatitude")
            gps_latitude_ref = self.get_if_exist(gps_info, 'GPSLatitudeRef')
            if gps_latitude and gps_latitude_ref:
                lat = self.convert_to_degress(gps_latitude)
                if gps_latitude_ref != "N":
                    lat = 0 - lat
                lat = str(f"{lat:.{5}f}")
                return lat
        else:
            return None

    def get_lon(self):
        """Returns the latitude and longitude, if available, from the 
        provided exif_data (obtained through get_exif_data above)"""
        # print(exif_data)
        if 'GPSInfo' in self.exif_data:
            gps_info = self.exif_data["GPSInfo"]
            gps_longitude = self.get_if_exist(gps_info, 'GPSLongitude')
            gps_longitude_ref = self.get_if_exist(gps_info, 'GPSLongitudeRef')
            if gps_longitude and gps_longitude_ref:
                lon = self.convert_to_degress(gps_longitude)
                if gps_longitude_ref != "E":
                    lon = 0 - lon
                lon = str(f"{lon:.{5}f}")
                return lon
        else:
            return None

    def get_date_time(self):
        if 'DateTime' in self.exif_data:
            date_and_time = self.exif_data['DateTime']
            return date_and_time 

if __name__ == '__main__':
    try:
        img = PILimage.open(sys.argv[1])
        image = Worker(img)
        lat = image.lat
        lon = image.lon
        date = image.date
        print(date, lat, lon)

    except Exception as e:
        print(e)

8

Ich habe festgestellt, dass die Verwendung ._getexifin höheren Python-Versionen nicht funktioniert. Außerdem ist sie eine geschützte Klasse und sollte nach Möglichkeit vermieden werden. Nachdem ich mich im Debugger umgesehen hatte, stellte ich fest, dass dies der beste Weg ist, um die EXIF-Daten für ein Bild zu erhalten:

from PIL import Image

def get_exif(path):
    return Image.open(path).info['parsed_exif']

Dies gibt ein Wörterbuch aller EXIF-Daten eines Bildes zurück.

Hinweis: Verwenden Sie für Python3.x Pillow anstelle von PIL


2
info['parsed_exif']erfordert Pillow 6.0 oder neuer. info['exif']ist in 5.4 verfügbar, dies ist jedoch ein roher Bytestring.
Åsmund

1
Es gibt keine info['parsed_exif']in Version 7.0.0; nur info['exif'].
ZF007

7

Hier ist die, die vielleicht etwas einfacher zu lesen ist. Hoffe das ist hilfreich.

from PIL import Image
from PIL import ExifTags

exifData = {}
img = Image.open(picture.jpg)
exifDataRaw = img._getexif()
for tag, value in exifDataRaw.items():
    decodedTag = ExifTags.TAGS.get(tag, tag)
    exifData[decodedTag] = value

0

Normalerweise verwende ich pyexiv2, um Exif-Informationen in JPG-Dateien festzulegen, aber wenn ich die Bibliothek in ein Skript importiere, stürzt das QGIS-Skript ab.

Ich habe eine Lösung mit der Bibliothek exif gefunden:

https://pypi.org/project/exif/

Es ist so einfach zu bedienen und mit Qgis habe ich kein Problem.

In diesem Code füge ich GPS-Koordinaten in eine Momentaufnahme des Bildschirms ein:

from exif import Image
with open(file_name, 'rb') as image_file:
    my_image = Image(image_file)

my_image.make = "Python"
my_image.gps_latitude_ref=exif_lat_ref
my_image.gps_latitude=exif_lat
my_image.gps_longitude_ref= exif_lon_ref
my_image.gps_longitude= exif_lon

with open(file_name, 'wb') as new_image_file:
    new_image_file.write(my_image.get_file())
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.