Trong Python, làm cách nào để đọc dữ liệu exif cho một hình ảnh?


131

Tôi đang sử dụng PIL. Làm cách nào để biến dữ liệu EXIF ​​thành một từ điển về nội dung?


1
Xem câu trả lời tại đây: stackoverflow.com/questions/765396/…
David Wolever

đếnoy.net/dev/pyexiv2/tutorial.html Đây là cách dễ nhất và toàn diện nhất.
Kumar Deepak,

Câu trả lời:


183

Thử cái này:

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

Điều này sẽ cung cấp cho bạn một từ điển được lập chỉ mục bởi các thẻ số EXIF. Nếu bạn muốn từ điển được lập chỉ mục bởi các chuỗi tên thẻ EXIF ​​thực tế, hãy thử một cái gì đó như:

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

10
Bất kỳ thay thế Python 3 nào?
Santosh Kumar,

2
@ 2rs2ts: Hãy thử import ExifTags(không có PILtiền tố).
Florian Brucker

12
Đối với python3 sử dụng Gối. Nó là một ngã ba của PIL, mà vẫn đang được phát triển, và có một tương thích phiên bản python3
Mzzl

1
Bạn có thể kiểm tra điều này trên Câu hỏi này không, tải hình ảnh xuống và thử lấy Mô tả hình ảnh. stackoverflow.com/questions/22173902/…
AJ

3
Chỉ dành cho mã exif tham khảo: Recogsystems.be/imaging/tiff/tifftags/privateifd/exif.html
Deus777

30

Bạn cũng có thể sử dụng mô-đun ExifRead :

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

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

1
Bạn có thể kiểm tra điều này trên Câu hỏi này không, tải hình ảnh xuống và thử lấy Mô tả hình ảnh. stackoverflow.com/questions/22173902/…
AJ

2
@Clayton cho cả hai hình ảnh, exifread trả về từ điển trống. Nhưng tôi đã thử nghiệm trên ảnh của mình và nó hoạt động tốt.
tnq177,

Tôi cũng nhận được một từ điển trống cho một bộ hình ảnh. Bất cứ ai có thể bình luận về lý do tại sao trường hợp này? Exifread.process_file () hoạt động với loại hình ảnh nào?
Momchill

17

Tôi sử dụng cái này:

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)

hoặc để lấy một trường cụ thể:

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
Tốt hơn, bạn có thể đảo ngược TAGS với name2tagnum = dict((name, num) for num, name in TAGS.iteritems())và sau đó làm name2tagnum['ExposureTime'].
Ben

7
Đối với Python 3, hãy đổi exif.iteritems()thànhexif.items()
SPRBRN

14

Đối với Python3.x và bắt đầu Pillow==6.0.0, Imagecác đối tượng hiện cung cấp một getexif()phương thức trả về <class 'PIL.Image.Exif'>hoặc Nonenếu hình ảnh không có dữ liệu EXIF.

Từ ghi chú phát hành Pillow 6.0.0 :

getexif()đã được thêm vào, trả về một Exifthể hiện. Các giá trị có thể được truy xuất và đặt giống như một từ điển. Khi lưu JPEG, PNG hoặc WEBP, thể hiện có thể được chuyển làm exifđối số để bao gồm bất kỳ thay đổi nào trong hình ảnh đầu ra.

Đầu Exifra có thể đơn giản được chuyển thành a dict, để dữ liệu EXIF ​​sau đó có thể được truy cập dưới dạng các cặp khóa-giá trị thông thường của a dict. Các khóa là các số nguyên 16 bit có thể được ánh xạ tới các tên chuỗi của chúng bằng cách sử dụng ExifTags.TAGSmô-đun.

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

Đã thử nghiệm với Python 3.6.8 và Pillow==6.0.0.


Nó không hoạt động với tôi, tôi chỉ có thể xem dữ liệu exif bằng phương thức .info trong hệ nhị phân
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

Tôi nhận thấy rằng việc sử dụng ._getexifkhông hoạt động trong các phiên bản python cao hơn, hơn nữa, nó là một lớp được bảo vệ và người ta nên tránh sử dụng nó nếu có thể. Sau khi tìm hiểu về trình gỡ lỗi, đây là những gì tôi thấy là cách tốt nhất để lấy dữ liệu EXIF ​​cho một hình ảnh:

from PIL import Image

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

Điều này trả về một từ điển của tất cả dữ liệu EXIF ​​của một hình ảnh.

Lưu ý: Đối với Python3.x, hãy sử dụng Pillow thay vì PIL


2
info['parsed_exif']yêu cầu Pillow 6.0 hoặc mới hơn. info['exif']có sẵn trong 5.4, nhưng đây là một bytestring thô.
Åsmund

1
Không có info['parsed_exif']trong phiên bản 7.0.0; duy nhất info['exif'].
ZF007

7

Đây là cái có thể dễ đọc hơn một chút. Hy vọng điều này là hữu ích.

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

Tôi thường sử dụng pyexiv2 để đặt thông tin exif trong tệp JPG, nhưng khi tôi nhập thư viện trong sự cố tập lệnh QGIS tập lệnh.

Tôi đã tìm thấy một giải pháp bằng cách sử dụng thư viện exif:

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

Nó rất dễ sử dụng và với Qgis I don’t have any problem.

Trong mã này, tôi chèn tọa độ GPS vào ảnh chụp nhanh màn hình:

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())
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.