En Python, comment lire les données exif d'une image?

Réponses:

183

Essaye ça:

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

Cela devrait vous donner un dictionnaire indexé par des balises numériques EXIF. Si vous voulez que le dictionnaire soit indexé par les chaînes de nom de balise EXIF ​​réelles, essayez quelque chose comme:

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in img._getexif().items()
    if k in PIL.ExifTags.TAGS
}
payne
la source
10
Une alternative à Python 3?
Santosh Kumar
2
@ 2rs2ts: Essayez import ExifTags(sans le PILpréfixe).
Florian Brucker
12
Pour python3, utilisez Pillow. C'est un fork de PIL, qui est encore en cours de développement, et a une version compatible python3
Mzzl
1
Pouvez-vous tester cela sur cette question, télécharger les images et essayer d'obtenir l'ImageDescription. stackoverflow.com/questions/22173902/…
AJ
3
Juste pour les codes exif de référence: awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html
Deus777
30

Vous pouvez également utiliser le module ExifRead :

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

# Return Exif tags
tags = exifread.process_file(f)
ianaré
la source
1
Pouvez-vous tester cela sur cette question, télécharger les images et essayer d'obtenir l'ImageDescription. stackoverflow.com/questions/22173902/…
AJ
2
@Clayton pour les deux images, exifread renvoie un dictionnaire vide. Mais j'ai testé sur mes photos et cela fonctionne très bien.
tnq177
Je reçois également un dictionnaire vide pour un ensemble d'images. Quelqu'un peut-il expliquer pourquoi c'est le cas? Avec quel type d'images fonctionne exifread.process_file ()?
Momchill
17

J'utilise ceci:

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)

ou pour obtenir un champ spécifique:

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
la source
6
Mieux, vous pouvez inverser les TAGS avec name2tagnum = dict((name, num) for num, name in TAGS.iteritems()), puis le faire name2tagnum['ExposureTime'].
Ben
7
Pour Python 3, exif.iteritems()exif.items()
passez
14

Pour Python3.x et le démarrage Pillow==6.0.0, les Imageobjets fournissent désormais une getexif()méthode qui renvoie <class 'PIL.Image.Exif'>ou Nonesi l'image ne contient pas de données EXIF.

À partir des notes de version de Pillow 6.0.0 :

getexif()a été ajouté, qui renvoie une Exifinstance. Les valeurs peuvent être récupérées et définies comme un dictionnaire. Lors de l'enregistrement JPEG, PNG ou WEBP, l'instance peut être transmise en tant exifqu'argument pour inclure toutes les modifications dans l'image de sortie.

La Exifsortie peut simplement être convertie en a dict, de sorte que les données EXIF ​​puissent ensuite être accédées sous forme de paires clé-valeur régulières de a dict. Les clés sont des entiers 16 bits qui peuvent être mappés à leurs noms de chaîne à l'aide du ExifTags.TAGSmodule.

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

Testé avec Python 3.6.8 et Pillow==6.0.0.

Gino Mempin
la source
Cela ne fonctionne pas pour moi, je ne peux voir que les données exif en utilisant la méthode .info en binaire
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
la source
8

J'ai trouvé que l'utilisation ._getexifne fonctionne pas dans les versions python supérieures, de plus, c'est une classe protégée et il faut éviter de l'utiliser si possible. Après avoir fouillé dans le débogueur, c'est ce que j'ai trouvé être le meilleur moyen d'obtenir les données EXIF ​​pour une image:

from PIL import Image

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

Cela renvoie un dictionnaire de toutes les données EXIF ​​d'une image.

Remarque: pour Python3.x, utilisez Pillow au lieu de PIL

Param Kapur
la source
2
info['parsed_exif']nécessite Pillow 6.0 ou plus récent. info['exif']est disponible dans la version 5.4, mais il s'agit d'un bytestring brut.
Åsmund
1
Il n'y info['parsed_exif']en a pas dans la version 7.0.0; seulement info['exif'].
ZF007
7

Voici celui qui peut être un peu plus facile à lire. J'espère que cela est 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
Raj Stha
la source
0

J'utilise généralement pyexiv2 pour définir les informations exif dans les fichiers JPG, mais lorsque j'importe la bibliothèque dans un script, le script de QGIS plante.

J'ai trouvé une solution en utilisant la bibliothèque exif:

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

C'est tellement facile à utiliser, et avec Qgis je n'ai aucun problème.

Dans ce code, j'insère les coordonnées GPS dans un instantané de l'écran:

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
la source