如何使用Python从图像中提取元数据?

33

我该如何使用Python从图像中提取元数据?


Python没有一个用于访问图像元数据的标准模块。您需要寻找一个模块,为您感兴趣的格式提供这样的功能。 - lanzz
你需要哪些元数据? - Slater Victoroff
我认为答案可以在以下网址找到: https://dev59.com/G3RA5IYBdhLWcg3w9y10 - Avinash Garg
答案已经存在,但有点过时了,而且由于你链接的主题已关闭,所以无法更新。那个主题中提到的几个项目已经死亡或濒临死亡。 - Mzzl
这个回答解决了你的问题吗?在Python中,我如何读取图像的exif数据? - Gino Mempin
5个回答

40

使用Pillow,它是PIL的一个分支版本,仍在积极开发中,并支持Python3。 这里我使用字典生成器将exif数据映射到字典中。

from PIL import Image, ExifTags
img = Image.open("/path/to/file.jpg")
exif = { ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in ExifTags.TAGS }

对于PNG图像,您可以通过读取_img_变量的_info_字典来访问元数据。我在这里发布了相同的答案:https://dev59.com/sFYM5IYBdhLWcg3wlQ_I#62456315 - codingmonkey87
3
它给我这个错误:metadata = { ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in ExifTags.TAGS } builtins.AttributeError: 'NoneType' object has no attribute 'items'。 - Leonardo Scotti
有可能您具有没有exif数据的图像。 - Mzzl
@Mzzl 这种方法是可行的,但它不能提供像焦距这样的所有元数据。当您通过右键单击图像查看其属性时,可以看到所有细节,但使用此方法,您只能获得以下输出:ImageWidth:4128 ImageLength:3096 ResolutionUnit:2 ExifOffset:225 Make:mchn Model:yyy Software:xxx Orientation:6 YCbCrPositioning:1 DateTime:ddtt XResolution:72.0 YResolution:72.0 - pentanol
@pentanol 相机记录不同的元数据标签。您确定焦距是相机捕获的元数据之一吗? - Graham Monkman

19

有几种方法可以从文件中获取数据。

1. 使用Exif工具:

对于Windows和Mac,它可以在ExifTool上找到。 对于Linux: 您可以使用apt实用程序在Ubuntu上安装ExifTool sudo apt install libimage-exiftool-perl

现在,您可以在终端的任何位置输入exiftool来运行ExifTool。 这是获取元数据的推荐方法,因为它提供比其他任何方法更多的标签。它是一个命令行工具,要在Python中使用它,用户必须创建一个子进程并将工具和图像文件路径作为参数传递。请参考下面的代码片段以使用Exif工具获取元数据。()

infoDict = {} #Creating the dict to get the metadata tags
exifToolPath = 'D:/ExifTool/exifTool.exe' #for Windows user have to specify the Exif tool exe path for metadata extraction. 
#For mac and linux user it is just 
 """exifToolPath = exiftool"""
imgPath = 'D:/Images/12.jpg'

''' use Exif tool to get the metadata '''
process = subprocess.Popen([exifToolPath,imgPath],stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True) 
''' get the tags in dict '''
for tag in process.stdout:
    line = tag.strip().split(':')
    infoDict[line[0].strip()] = line[-1].strip()

for k,v in infoDict.items():
    print(k,':', v)

以下是以下图片的元数据结果:

输入图像描述

输入图像描述

完整的标签列表在此处:

""" ExifTool Version Number : 11.63
File Name : imgMeta.jpg
Directory : /Projects/ImageMetaData/Images
File Size : 32 kB
File Modification Date/Time : 30
File Access Date/Time : 30
File Creation Date/Time : 30
File Permissions : rw-rw-rw-
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Exif Byte Order : Little-endian (Intel, II)
Make : Canon
Camera Model Name : Canon PowerShot S40
Orientation : Horizontal (normal)
X Resolution : 180
Y Resolution : 180
Resolution Unit : inches
Modify Date : 44
Y Cb Cr Positioning : Centered
Exposure Time : 1/500
F Number : 4.9
Exif Version : 0220
Date/Time Original : 44
Create Date : 44
Components Configuration : Y, Cb, Cr, -
Compressed Bits Per Pixel : 5
Shutter Speed Value : 1/501
Aperture Value : 5.0
Max Aperture Value : 2.8
Flash : Auto, Did not fire
Focal Length : 103.7 mm)
Macro Mode : Normal
Self Timer : Off
Quality : Superfine
Canon Flash Mode : Auto
Continuous Drive : Single
Focus Mode : Single
Record Mode : JPEG
Canon Image Size : Large
Easy Mode : Manual
Digital Zoom : None
Contrast : Normal
Saturation : Normal
Sharpness : 0
Camera ISO : 100
Metering Mode : Center-weighted average
Focus Range : Auto
AF Point : Center
Canon Exposure Mode : Program AE
Lens Type : n/a
Max Focal Length : 21.3125 mm
Min Focal Length : 7.09375 mm
Focal Units : 32/mm
Max Aperture : 5
Min Aperture : 8
Flash Activity : 0
Flash Bits : (none)
Focus Continuous : Single
AE Setting : Normal AE
Display Aperture : 4.9
Zoom Source Width : 2272
Zoom Target Width : 2272
Spot Metering Mode : AF Point
Focal Type : Zoom
Focal Plane X Size : 7.26 mm
Focal Plane Y Size : 5.46 mm
Auto ISO : 100
Base ISO : 100
Measured EV : 13.63
Target Aperture : 5
Target Exposure Time : 1/501
Exposure Compensation : 0
White Balance : Auto
Slow Shutter : Off
Shot Number In Continuous Burst : 0
Optical Zoom Code : 6
Flash Guide Number : 0
AF Points In Focus : Center
Flash Exposure Compensation : 0
Auto Exposure Bracketing : Off
AEB Bracket Value : 0
Control Mode : Camera Local Control
Focus Distance Upper : 7.82 m
Focus Distance Lower : 0 m
Bulb Duration : 0
Camera Type : Compact
Canon Image Type : PowerShot S40 JPEG
Canon Firmware Version : Firmware Version 1.10
File Number : 117-1771
Owner Name : Andreas Huggel
Canon Model ID : PowerShot S40
User Comment : 
Flashpix Version : 0100
Color Space : sRGB
Exif Image Width : 2272
Exif Image Height : 1704
Interoperability Index : R98 - DCF basic file (sRGB)
Interoperability Version : 0100
Related Image Width : 2272
Related Image Height : 1704
Focal Plane X Resolution : 8114.285714
Focal Plane Y Resolution : 8114.285714
Focal Plane Resolution Unit : inches
Sensing Method : One-chip color area
File Source : Digital Camera
Custom Rendered : Normal
Exposure Mode : Auto
Digital Zoom Ratio : 1
Scene Capture Type : Standard
Compression : JPEG (old-style)
Thumbnail Offset : 2066
Thumbnail Length : 5448
Image Width : 480
Image Height : 360
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : 0 (2 2)
Drive Mode : Single-frame Shooting
ISO : 100
Lens : 34.5 - 103.7 mm)
Shooting Mode : Program AE
Aperture : 4.9
Image Size : 480x360
Lens ID : Unknown 7-21mm
Megapixels : 0.173
Scale Factor To 35 mm Equivalent : 4.9
Shutter Speed : 1/500
Thumbnail Image : (Binary data 5448 bytes, use -b option to extract)
Circle Of Confusion : 0.006 mm
Depth Of Field : 2.17 m (3.11 - 5.28 m)
Field Of View : 19.7 deg
Hyperfocal Distance : 15.02 m
Light Value : 13.6 """

2. 使用PIL包:

参考其他文章以获取此方法。然而,使用此方法的缺点是它无法处理所有图像。

3. 使用hachoir包: 与exif工具类似,它也是一个命令行工具,不同之处在于它是一个Python包,并且用户可以使用pip install hachoir进行安装。它可以为大多数文件格式提供元数据,但提供的信息比Exif工具少。

imgPath = 'D:/Images/12.jpg'
exeProcess = "hachoir-metadata"
process = subprocess.Popen([exeProcess,imgPath],
                                           stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                                           universal_newlines=True)

for tag in process.stdout:
        line = tag.strip().split(':')
        infoDict[line[0].strip()] = line[-1].strip()

for k,v in infoDict.items():
    print(k,':', v)

"""for same image : only 31 tags are identified by hachoir Method however Exif method is giving 131 tags """

enter image description here

hachoir 提取的完整标签列表如下:

""" Metadata : 
Image width : 480 pixels
Image height : 360 pixels
Image orientation : Horizontal (normal)
Bits/pixel : 24
Pixel format : YCbCr
Image DPI width : 72 DPI
Image DPI height : 72 DPI
Creation date : 44
Camera aperture : 2.97
Camera focal : 4.9
Camera exposure : 1/500
Camera model : Canon PowerShot S40
Camera manufacturer : Canon
Compression : JPEG (Baseline)
Thumbnail size : 5448 bytes
EXIF version : 0220
Date-time original : 44
Date-time digitized : 44
Compressed bits per pixel : 5
Shutter speed : 8.97
Aperture : 4.66
Exposure bias : 0
Focal length : 21.3
Flashpix version : 0100
Focal plane width : 8.11e+03
Focal plane height : 8.11e+03
Comment : 75%
Format version : JFIF 1.01
MIME type : image/jpeg
Endianness : Big endian
"""

3
您所提到的基于PIL的方法存在的缺陷是它仅适用于图像,并且不会为所有图像提供元数据信息。这意味着该方法只能处理图像本身,而无法提供有关图像的其他信息,例如拍摄时间、地点或者相机设置等元数据。 - Febin Sunny
我该如何从中提取缩略图? - user11840960
使用PIL进行标签提取并不适用于所有图像。 - Vaibhav K
选项1(exif-tool)是唯一一个具有我需要的标签的工具。但在Windows上,该工具会挂起等待我按回车键。我能够通过使用此处顶部答案中的自定义exif工具类来克服这个问题:https://dev59.com/h2kw5IYBdhLWcg3wMHkY - Rivers Cuomo
@FebinSunny PIL基于的方法无法从png图像中提取信息。 - undefined
显示剩余2条评论

8
您可以使用Python的PIL Exif库提取元数据:
from PIL import Image
from PIL.ExifTags import TAGS

你可以将图片文件路径传递给程序,然后读取相应的exif标签数据:

# path to the image or video
imagename = "IMG_20220306_095310.jpg"

# read the image data using PIL
image = Image.open(imagename)

# extract EXIF data
exifdata = image.getexif()

# iterating over all EXIF data fields
for tag_id in exifdata:
    # get the tag name, instead of human unreadable tag id
    tag = TAGS.get(tag_id, tag_id)
    data = exifdata.get(tag_id).decode("utf-16")
    print(f"{tag:25}: {data}")  

1
你的方法返回utf-16编码。我能够使用以下方式进行解码:https://stackoverflow.com/a/48826207/13434875 - bonzoon
谢谢,@bonzoon,没错。我明白为什么在某些情况和某些标签中需要编码 :) 我已经在我的代码中添加了解码函数,再次感谢。 - iD_Sgh

4
您可以使用以下Python代码实现此功能。
#!/bin/python
import os
import sys
from PIL import Image
from PIL.ExifTags import TAGS

image = sys.argv[1]

for (tag,value) in Image.open(image)._getexif().iteritems():
        print '%s = %s' % (TAGS.get(tag), value)

以下是样例输出。 enter image description here

这实际上是另一个答案的复制。 - Mzzl
我该如何提取缩略图信息并将其保存为图像? - user11840960
我不知道为什么,也许是我的问题,但它适用于 .JPG 文件,而不是 .jpg 文件。 - Klaus Maria

1
一些相机制造商在图像中添加了XMP数据,而这些数据可以通过libxmp(pip install python-xmp-toolkit)轻松读取。 我编写了一个从DJI无人机图像中提取数据的函数:
from libxmp.utils import file_to_dict

def read_xmp_data(image_path: Path):
    xmp_dict = file_to_dict(str(image_path))
    exif_dict = {}
    dji_data = {}

    # debug printout - helped me to find tag keywords in 'purl.org' 
    print(k)         

    for k in xmp_dict.keys():
        if 'drone-dji' in k:
            for element in xmp_dict[k]:
                dji_data[element[0].replace('drone-dji:', '')] = element[1]
        if 'exif' in k:
            for element in xmp_dict[k]:
                exif_dict[element[0].replace('exif:', '')] = element[1]
    return dji_data, exif_dict

read_xmp_data("image.jpg")

编辑的评论: python-xmp-toolkit 在2014年发布,所有者在2023年2月20日将其存档于github(https://github.com/python-xmp-toolkit/python-xmp-toolkit)。我使用fstop(在安卓上)给图像打标签,geeqie可以看到关键字。这个解决方案正在揭示它们。

谢谢assaf-ge。


加号: pip安装指南 减号:不完整的示例 - jaromrax
抱歉,在编辑您的帖子时,我发现导入行已经存在,只是没有显示出来。 - jaromrax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接