Dengan Python, bagaimana cara membaca data exif untuk gambar?

Jawaban:

183

Coba ini:

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

Ini akan memberi Anda kamus yang diindeks oleh tag numerik EXIF. Jika Anda ingin kamus diindeks oleh string nama tag EXIF ​​yang sebenarnya, coba sesuatu seperti:

import PIL.ExifTags
exif = {
    PIL.ExifTags.TAGS[k]: v
    for k, v in img._getexif().items()
    if k in PIL.ExifTags.TAGS
}
payne
sumber
10
Ada alternatif Python 3?
Santosh Kumar
2
@ 2rs2ts: Coba import ExifTags(tanpa PILawalan).
Florian Brucker
12
Untuk python3 gunakan Pillow. Ini adalah cabang dari PIL, yang masih dikembangkan, dan memiliki versi yang kompatibel dengan
python3
1
Bisakah Anda menguji ini pada Pertanyaan ini, mengunduh gambar, dan mencoba mendapatkan ImageDescription. stackoverflow.com/questions/22173902/…
AJ
3
Hanya untuk referensi kode exif: awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html
Deus777
30

Anda juga dapat menggunakan modul ExifRead :

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

# Return Exif tags
tags = exifread.process_file(f)
ianaré
sumber
1
Bisakah Anda mengujinya pada Pertanyaan ini, mendownload gambar, dan mencoba mendapatkan ImageDescription. stackoverflow.com/questions/22173902/…
AJ
2
@Clayton untuk kedua gambar, exifread mengembalikan kamus kosong. Tapi saya menguji pada foto saya dan berfungsi dengan baik.
tnq177
Saya juga menerima kamus kosong untuk sekumpulan gambar. Adakah yang bisa berkomentar mengapa ini terjadi? Jenis gambar apa yang digunakan exifread.process_file ()?
Momchill
17

Saya menggunakan ini:

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)

atau untuk mendapatkan bidang tertentu:

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
sumber
6
Lebih baik, Anda dapat membalik TAGS dengan name2tagnum = dict((name, num) for num, name in TAGS.iteritems())dan kemudian melakukannya name2tagnum['ExposureTime'].
Ben
7
Untuk Python 3, ubah exif.iteritems()keexif.items()
SPRBRN
14

Untuk Python3.x dan awal Pillow==6.0.0, Imageobjek sekarang menyediakan getexif()metode yang mengembalikan <class 'PIL.Image.Exif'>atau Nonejika gambar tidak memiliki data EXIF.

Dari catatan rilis Pillow 6.0.0 :

getexif()telah ditambahkan, yang mengembalikan sebuah Exifinstance. Nilai dapat diambil dan diatur seperti kamus. Saat menyimpan JPEG, PNG atau WEBP, instance dapat diteruskan sebagai exifargumen untuk menyertakan perubahan apa pun pada gambar output.

The Exifkeluaran hanya dapat dicor ke dict, sehingga data EXIF kemudian dapat diakses sebagai pasangan kunci-nilai yang teratur dari dict. Kuncinya adalah bilangan bulat 16-bit yang dapat dipetakan ke nama stringnya menggunakan ExifTags.TAGSmodul.

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

Diuji dengan Python 3.6.8 dan Pillow==6.0.0.

Gino Mempin
sumber
Ini tidak berhasil untuk saya, saya hanya dapat melihat data exif menggunakan metode .info dalam biner
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
sumber
8

Saya telah menemukan bahwa penggunaan ._getexiftidak berfungsi di versi python yang lebih tinggi, terlebih lagi, ini adalah kelas yang dilindungi dan seseorang harus menghindari menggunakannya jika memungkinkan. Setelah menggali di sekitar debugger, inilah yang saya temukan sebagai cara terbaik untuk mendapatkan data EXIF ​​untuk sebuah gambar:

from PIL import Image

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

Ini mengembalikan kamus dari semua data EXIF ​​gambar.

Catatan: Untuk Python3.x gunakan Pillow sebagai ganti PIL

Param Kapur
sumber
2
info['parsed_exif']membutuhkan Pillow 6.0 atau yang lebih baru. info['exif']tersedia dalam 5.4, tapi ini adalah bytestring mentah.
Åsmund
1
Tidak ada info['parsed_exif']di versi 7.0.0; saja info['exif'].
ZF007
7

Ini salah satu yang mungkin sedikit lebih mudah dibaca. Semoga bermanfaat.

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
sumber
0

Saya biasanya menggunakan pyexiv2 untuk mengatur informasi exif dalam file JPG, tetapi ketika saya mengimpor perpustakaan dalam skrip QGIS script crash.

Saya menemukan solusi menggunakan library exif:

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

Sangat mudah digunakan, dan dengan Qgis saya tidak punya masalah.

Dalam kode ini saya memasukkan koordinat GPS ke snapshot layar:

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
sumber