在 Python 中,如何读取图像的 exif 数据?

我正在使用 PIL。如何将图片的 EXIF 数据转换成字典?

230087 次浏览

可以使用 PIL 图像的 _getexif()保护方法。

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

这将为您提供一个由 EXIF 数字标记索引的字典。如果您希望通过实际的 EXIF 标记名称字符串来索引字典,可以尝试这样的操作:

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

你也可以使用 ExifRead模块:

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


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

我用这个:

import os,sys
from PIL import Image
from PIL.ExifTags import TAGS


for (k,v) in Image.open(sys.argv[1])._getexif().items():
print('%s = %s' % (TAGS.get(k), v))

或者得到一个特定的领域:

def get_field (exif,field) :
for (k,v) in exif.items():
if TAGS.get(k) == field:
return v


exif = image._getexif()
print get_field(exif,'ExposureTime')
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)

这里有一个可能更容易阅读。希望这是有帮助的。

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

我发现使用 ._getexif在更高的 Python 版本中不起作用,此外,它是一个受保护的类,如果可能的话应该避免使用它。 在深入研究了调试器之后,我发现这是获取图像 EXIF 数据的最佳方法:

from PIL import Image


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

这将返回一个图像的所有 EXIF 数据的字典。

注意: 对于 Python 3.x,使用枕头代替 PIL

对于 Python3.x 和启动 Pillow==6.0.0Image对象现在提供了一个“公共”/官方 getexif()方法,如果图像没有 EXIF 数据,该方法返回 <class 'PIL.Image.Exif'>实例或 None

来自 枕头6.0.0发布说明:

已经添加了 getexif(),它返回一个 Exif实例 当储存 JPEG、 PNG 或 WEBP 时, 实例可以作为 exif参数传递,以包含任何更改 在输出图像中。

如前所述,您可以像常规字典一样迭代 Exif实例的键-值对。这些键是16位整数,可以使用 ExifTags.TAGS模块映射到它们的字符串名称。

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:
for key, val in img_exif.items():
if key in ExifTags.TAGS:
print(f'{ExifTags.TAGS[key]}:{val}')
# ExifVersion:b'0230'
# ...
# FocalLength:(2300, 100)
# ColorSpace:1
# ...
# Model:'X-T2'
# Make:'FUJIFILM'
# LensSpecification:(18.0, 55.0, 2.8, 4.0)
# ...
# DateTime:'2019:12:01 21:30:07'
# ...

使用 Python 3.8.8和 Pillow==8.1.0进行测试。

我通常使用 pyexiv2在 JPG 文件中设置 exif 信息,但是当我在一个脚本 QGIS 脚本崩溃导入库时。

我找到了一个使用库 exif 的解决方案:

Https://pypi.org/project/exif/

它是如此容易使用,并与 Qgis,我没有任何问题。

在这段代码中,我将 GPS 坐标插入到屏幕快照中:

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

读取 图像网址并获取标签

from PIL import Image
from urllib.request import urlopen
from PIL.ExifTags import TAGS




def get_exif(filename):
image = Image.open(filename)
image.verify()
return image._getexif()


def get_labeled_exif(exif):
labeled = {}
for (key, val) in exif.items():
labeled[TAGS.get(key)] = val


return labeled


my_image= urlopen(url)


exif = get_exif(my_image)
labeled = get_labeled_exif(exif)
print(labeled)

为了得到 GPS 坐标,杰森 · 德兰西有很好的博客文章。