In Python, come leggo i dati exif per un'immagine?


Risposte:


183

Prova questo:

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

Questo dovrebbe darti un dizionario indicizzato da tag numerici EXIF. Se vuoi che il dizionario sia indicizzato dalle stringhe del nome del tag EXIF, prova qualcosa come:

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

10
Qualche alternativa a Python 3?
Santosh Kumar

2
@ 2rs2ts: prova import ExifTags(senza PILprefisso).
Florian Brucker

12
Per python3 usa Pillow. È un fork di PIL, che è ancora in fase di sviluppo, e ha una versione compatibile con
python3

1
Puoi testarlo su questa domanda, scaricare le immagini e provare a ottenere la descrizione dell'immagine. stackoverflow.com/questions/22173902/…
AJ

3
Solo per i codici exif di
Deus777

30

Puoi anche usare il modulo ExifRead :

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

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

1
Puoi testarlo su questa domanda, scaricare le immagini e provare a ottenere la descrizione dell'immagine. stackoverflow.com/questions/22173902/…
AJ

2
@Clayton per entrambe le immagini, exifread restituisce un dizionario vuoto. Ma ho provato sulle mie foto e funziona benissimo.
tnq177

Ricevo anche un dizionario vuoto per una serie di immagini. Qualcuno può commentare perché questo è il caso? Con che tipo di immagini funziona exifread.process_file ()?
Momchill

17

Io uso questo:

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)

o per ottenere un campo specifico:

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
Meglio, puoi invertire TAGS con name2tagnum = dict((name, num) for num, name in TAGS.iteritems())e poi farlo name2tagnum['ExposureTime'].
Ben

7
Per Python 3, cambia exif.iteritems()inexif.items()
SPRBRN

14

Per Python3.x e per l'avvio Pillow==6.0.0, gli Imageoggetti ora forniscono un getexif()metodo che restituisce <class 'PIL.Image.Exif'>o Nonese l'immagine non ha dati EXIF.

Dalle note di rilascio di Pillow 6.0.0 :

getexif()è stato aggiunto, che restituisce Exifun'istanza. I valori possono essere recuperati e impostati come un dizionario. Quando si salva JPEG, PNG o WEBP, l'istanza può essere passata come exifargomento per includere eventuali modifiche nell'immagine di output.

L' Exifoutput può essere semplicemente convertito in a dict, in modo che i dati EXIF ​​possano essere quindi accessibili come normali coppie chiave-valore di a dict. Le chiavi sono numeri interi a 16 bit che possono essere mappati ai loro nomi di stringa utilizzando il ExifTags.TAGSmodulo.

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'
            # ...

Testato con Python 3.6.8 e Pillow==6.0.0.


Non funziona per me, posso vedere solo i dati exif usando il metodo .info in binario
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

Ho scoperto che l'utilizzo ._getexifnon funziona nelle versioni superiori di Python, inoltre, è una classe protetta e si dovrebbe evitare di usarla se possibile. Dopo aver esaminato il debugger, questo è quello che ho trovato essere il modo migliore per ottenere i dati EXIF ​​per un'immagine:

from PIL import Image

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

Questo restituisce un dizionario di tutti i dati EXIF ​​di un'immagine.

Nota: per Python3.x usa Pillow invece di PIL


2
info['parsed_exif']richiede Pillow 6.0 o successivo. info['exif']è disponibile in 5.4, ma questa è una stringa secondaria non elaborata.
Åsmund

1
Non c'è info['parsed_exif']nella versione 7.0.0; solo info['exif'].
ZF007

7

Ecco quello che potrebbe essere un po 'più facile da leggere. Spero che questo sia utile.

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

Di solito uso pyexiv2 per impostare le informazioni exif nei file JPG, ma quando importa la libreria in uno script, lo script QGIS si blocca.

Ho trovato una soluzione utilizzando la libreria exif:

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

È così facile da usare e con Qgis non ho alcun problema.

In questo codice inserisco le coordinate GPS su un'istantanea dello schermo:

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())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.