En Python, ¿cómo leo los datos exif de una imagen?

Respuestas:

183

Prueba esto:

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

Esto debería darle un diccionario indexado por etiquetas numéricas EXIF. Si desea que el diccionario sea indexado por las cadenas de nombre de etiqueta EXIF ​​reales, intente algo como:

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in img._getexif().items()
    if k in PIL.ExifTags.TAGS
}
Payne
fuente
10
¿Alguna alternativa a Python 3?
Santosh Kumar
2
@ 2rs2ts: Prueba import ExifTags(sin el PILprefijo).
Florian Brucker el
12
Para python3 use Pillow. Se trata de un tenedor de PIL, que todavía se está desarrollando, y tiene una versión compatible python3
Mzzl
1
¿Puede probar esto en esta pregunta, descargar las imágenes e intentar obtener la ImageDescription? stackoverflow.com/questions/22173902/…
AJ
3
Solo para códigos exif de referencia: awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html
Deus777
30

También puede usar el módulo ExifRead :

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

# Return Exif tags
tags = exifread.process_file(f)
ianaré
fuente
1
¿Puede probar esto en esta pregunta, descargar las imágenes e intentar obtener la ImageDescription? stackoverflow.com/questions/22173902/…
AJ
2
@Clayton para ambas imágenes, exifread devuelve un diccionario vacío. Pero probé en mis fotos y funciona bien.
tnq177
También recibo un diccionario vacío para un conjunto de imágenes. ¿Alguien puede comentar por qué este es el caso? ¿Con qué tipo de imágenes funciona exifread.process_file ()?
Momchill
17

Yo uso esto:

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 para obtener un campo específico:

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')
Mike Redrobe
fuente
66
Mejor, puedes revertir TAGS con name2tagnum = dict((name, num) for num, name in TAGS.iteritems())y luego hacerlo name2tagnum['ExposureTime'].
Ben
77
Para Python 3, cambie exif.iteritems()aexif.items()
SPRBRN
14

Para Python3.xy comenzar Pillow==6.0.0, los Imageobjetos ahora proporcionan un getexif()método que devuelve <class 'PIL.Image.Exif'>o Nonesi la imagen no tiene datos EXIF.

De las notas de la versión de Pillow 6.0.0 :

getexif()se ha agregado, lo que devuelve una Exifinstancia. Los valores se pueden recuperar y establecer como un diccionario. Al guardar JPEG, PNG o WEBP, la instancia se puede pasar como exifargumento para incluir cualquier cambio en la imagen de salida.

La Exifsalida simplemente se puede convertir a a dict, de modo que se pueda acceder a los datos EXIF ​​como pares clave-valor regulares de a dict. Las claves son enteros de 16 bits que pueden asignarse a sus nombres de cadena utilizando el ExifTags.TAGSmódulo.

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

Probado con Python 3.6.8 y Pillow==6.0.0.

Gino Mempin
fuente
No me funciona, solo puedo ver los datos exif usando el método .info en 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)
Kirill Vladi
fuente
8

He descubierto que el uso ._getexifno funciona en versiones superiores de Python, además, es una clase protegida y uno debería evitar usarlo si es posible. Después de buscar en el depurador, esta es la mejor forma de obtener los datos EXIF ​​para una imagen:

from PIL import Image

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

Esto devuelve un diccionario de todos los datos EXIF ​​de una imagen.

Nota: Para Python3.x use Pillow en lugar de PIL

Param Kapur
fuente
2
info['parsed_exif']requiere Pillow 6.0 o más reciente. info['exif']está disponible en 5.4, pero esta es una cadena de bytes sin procesar.
Åsmund
1
No hay info['parsed_exif']en la versión 7.0.0; solamente info['exif'].
ZF007
7

Aquí está el que puede ser un poco más fácil de leer. Espero que esto sea útil.

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
Raj Stha
fuente
0

Usualmente uso pyexiv2 para configurar información exif en archivos JPG, pero cuando importo la biblioteca en un script QGIS se bloquea.

Encontré una solución usando la biblioteca exif:

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

Es muy fácil de usar, y con Qgis no tengo ningún problema.

En este código inserto coordenadas GPS en una instantánea de la pantalla:

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())
RBenet
fuente