使用 Python 检索图像描述(不通过 PIL 或 exifread 在 EXIF 数据中返回)

Retrieve Image description with Python (not returned in EXIF data via PIL or exifread)

我想获取 .jpg 图片的描述。它显示在 Mac OSx Info (cmd +i) window.

我想阅读“描述”(德语的 Beschreibung)字段。用 PIL 和 exifread 尝试这个没有成功。

我可以获得这些 exif 标签,但它们不包含描述或关键字。

Key: Image ImageWidth
Key: Image ImageLength
Key: Image Compression
Key: Image Make
Key: Image Model
Key: Image XResolution
Key: Image YResolution
Key: Image PlanarConfiguration
Key: Image ResolutionUnit
Key: Image Software
Key: Image DateTime
Key: Image YCbCrPositioning
Key: Image ExifOffset
Key: Thumbnail Compression
Key: Thumbnail Orientation
Key: Thumbnail XResolution
Key: Thumbnail YResolution
Key: Thumbnail ResolutionUnit
Key: Thumbnail DateTime
Key: Thumbnail JPEGInterchangeFormat
Key: Thumbnail JPEGInterchangeFormatLength
Key: EXIF ExposureTime
Key: EXIF FNumber
Key: EXIF ExposureProgram
Key: EXIF ISOSpeedRatings
Key: EXIF SensitivityType
Key: EXIF ExifVersion
Key: EXIF DateTimeOriginal
Key: EXIF DateTimeDigitized
Key: EXIF ComponentsConfiguration
Key: EXIF ShutterSpeedValue
Key: EXIF ApertureValue
Key: EXIF ExposureBiasValue
Key: EXIF MaxApertureValue
Key: EXIF MeteringMode
Key: EXIF LightSource
Key: EXIF Flash
Key: EXIF FocalLength
Key: EXIF SubSecTimeOriginal
Key: EXIF SubSecTimeDigitized
Key: EXIF ColorSpace
Key: EXIF ExifImageWidth
Key: EXIF ExifImageLength
Key: EXIF FocalPlaneXResolution
Key: EXIF FocalPlaneYResolution
Key: EXIF FocalPlaneResolutionUnit
Key: EXIF SensingMethod
Key: EXIF FileSource
Key: EXIF SceneType
Key: EXIF CVAPattern
Key: EXIF CustomRendered
Key: EXIF ExposureMode
Key: EXIF WhiteBalance
Key: EXIF DigitalZoomRatio
Key: EXIF FocalLengthIn35mmFilm
Key: EXIF SceneCaptureType
Key: EXIF GainControl
Key: EXIF Contrast
Key: EXIF Saturation
Key: EXIF Sharpness
Key: EXIF SubjectDistanceRange
Key: EXIF BodySerialNumber
Key: EXIF LensSpecification
Key: EXIF LensModel

我假设这些字段不是 EXIF 数据?我需要寻找什么才能获得描述?

一般来说,元数据可能隐藏在许多地方,您可以使用一些技术来查找它。我会在我的回答的不同部分写几句话。


您查找的数据可能在您文件的 “扩展属性” 中,或者 xattr。如果您在终端中 运行 以下内容,您可以看到这一点:

ls -l image.jpg

-rw-r--r--@ 1 mark  staff  214557  2 Jan 15:47 image.jpg

和任何具有 “扩展属性” 的文件将在其权限后具有 @。然后你可以看到扩展属性:

ls -@l image.jpg

-rw-r--r--@ 1 mark  staff  2219100  3 Jan 18:07 image.jpg
    com.apple.lastuseddate#PS        16 
    com.apple.quarantine         22 

参见 man xattr 的手册页。


数据可能位于文件的 EXIF 部分。 EXIF 数据最好的工具是 exiftool,所以试试:

exiftool -v -v image.jpg 

您可以使用 homebrewmacOS 上安装 exiftool 使用:

brew install exiftool

当您在 Mac 上创建文件时,Apple 会进行各种索引,因此数据可能位于元数据数据库中。您可以像这样使用 mdls 检查:

mdls image.jpg

示例输出

_kMDItemDisplayNameWithExtensions      = "image.jpg"
kMDItemAcquisitionMake                 = "Apple"
kMDItemAcquisitionModel                = "iPhone 4"
kMDItemAltitude                        = 1.128681019549616
kMDItemAperture                        = 2.970853573907009
kMDItemBitsPerSample                   = 32
kMDItemColorSpace                      = "RGB"
kMDItemContentCreationDate             = 2013-03-09 08:59:50 +0000
kMDItemContentCreationDate_Ranking     = 2013-03-09 00:00:00 +0000
kMDItemContentModificationDate         = 2013-03-09 08:59:50 +0000
kMDItemContentModificationDate_Ranking = 2013-03-09 00:00:00 +0000
kMDItemContentType                     = "public.jpeg"
kMDItemContentTypeTree                 = (
    "public.jpeg",
    "public.image",
    "public.data",
    "public.item",
    "public.content"
)
kMDItemCreator                         = "6.1.2"
kMDItemDateAdded                       = 2021-01-03 18:07:34 +0000
kMDItemDateAdded_Ranking               = 2021-01-03 00:00:00 +0000
kMDItemDisplayName                     = "image.jpg"
kMDItemDocumentIdentifier              = 0
kMDItemEXIFVersion                     = "2.2.1"
kMDItemExposureMode                    = 0
kMDItemExposureProgram                 = 2
kMDItemExposureTimeSeconds             = 0.001094091903719912
kMDItemFlashOnOff                      = 0
kMDItemFNumber                         = 2.8
kMDItemFocalLength                     = 3.85
kMDItemFocalLength35mm                 = 35
kMDItemFSContentChangeDate             = 2021-01-03 18:07:34 +0000
kMDItemFSCreationDate                  = 2021-01-03 18:07:34 +0000
kMDItemFSCreatorCode                   = ""
kMDItemFSFinderFlags                   = 0
kMDItemFSHasCustomIcon                 = (null)
kMDItemFSInvisible                     = 0
kMDItemFSIsExtensionHidden             = 0
kMDItemFSIsStationery                  = (null)
kMDItemFSLabel                         = 0
kMDItemFSName                          = "image.jpg"
kMDItemFSNodeCount                     = (null)
kMDItemFSOwnerGroupID                  = 20
kMDItemFSOwnerUserID                   = 501
kMDItemFSSize                          = 2219100
kMDItemFSTypeCode                      = ""
kMDItemGPSDateStamp                    = "2013:03:09"
kMDItemHasAlphaChannel                 = 0
kMDItemImageDirection                  = 324.4435483870968
kMDItemInterestingDate_Ranking         = 2019-08-27 00:00:00 +0000
kMDItemISOSpeed                        = 80
kMDItemKind                            = "JPEG image"
kMDItemLastUsedDate                    = 2019-08-27 14:26:14 +0000
kMDItemLastUsedDate_Ranking            = 2019-08-27 00:00:00 +0000
kMDItemLatitude                        = 20.84433333333333
kMDItemLogicalSize                     = 2219100
kMDItemLongitude                       = 107.091
kMDItemMeteringMode                    = 5
kMDItemOrientation                     = 0
kMDItemPhysicalSize                    = 2220032
kMDItemPixelCount                      = 5018112
kMDItemPixelHeight                     = 1936
kMDItemPixelWidth                      = 2592
kMDItemProfileName                     = "sRGB IEC61966-2.1"
kMDItemRedEyeOnOff                     = 0
kMDItemResolutionHeightDPI             = 72
kMDItemResolutionWidthDPI              = 72
kMDItemTimestamp                       = "01:59:48"
kMDItemUseCount                        = 1
kMDItemUsedDates                       = (
    "2019-08-26 23:00:00 +0000"
)
kMDItemWhiteBalance                    = 0

您可以尝试一种老式的“蛮力” 方法。 strings 实用程序会搜索任何二进制文件以查找任何看起来像文本的内容,因此您可以尝试提取任何看起来像一堆字母的内容并搜索一个相对罕见的词 - 在您的示例中我会选择 Wollo,所以你可以这样做来查看字符串 Wollo 是否确实存在于你的文件中 - 否则它可能在其他地方:

strings image.jpg | grep "Wollo"

感谢@Mark Serchells的回答,我发现描述中没有EXIF数据而是IPTC数据(exiftool显示所有字段)

在 Python 中,我现在可以使用 IPTCInfo3:https://pypi.org/project/IPTCInfo3/ 并通过以下方式提取描述:

info = IPTCInfo('img.jpg')
info['caption/abstract']

打印:

b'Gel\xe4ndewagen auf den Salzformationen im Salzsee Ass-Ale in der Danakil-Senke, Danakil-Senke, Hamed Ela, Wollo, \xc4thiopien, Afrika

提取 EXIF 是最简单的部分。最难的部分是解释它们并使它们适用于每个品牌和型号。有些品牌和型号缺少一些标签(例如,Fujifilm 同时具有 LensMake 和 LensModel,而 Canon 只有 LensModel)。简而言之,它可能是这样的。

from PIL import Image
from math import pow
from PIL.ExifTags import TAGS
import datetime

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

    return labeled

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


def get_shutter_speed(shutter_speed):
    print("shutter_speed = {0}, type = {1}".format(
        shutter_speed, type(shutter_speed)))

    ss_val1 = 0.0
    ss_val2 = 0.0

    if type(shutter_speed) != type(list):
        ss_val1 = shutter_speed
        ss_val2 = 0

        ss = (str(ss_val1/1) + "s") if ss_val1 > 0 else str(ss_val1)+"s"

        return ss
    
    ss_val1 = float(shutter_speed[0])
    ss_val2 = float(shutter_speed[1])

    ss = ss_val1/ss_val2

    return str(round(1/pow(2, ss))) + \
        "s" if ss_val1 < 0 else "1/"+str(round(pow(2, ss)))

def get_aperture(aperture):
    print("aperture = {0}, type(aperture) = {1}".format(
        aperture, type(aperture)))
    ap_val1 = 0.0
    ap_val2 = 0.0

    if type(aperture) != type(list):
        ap = float(aperture)
    else:
        ap_val1 = float(aperture[0])
        ap_val2 = float(aperture[1])
        
        ap = ap_val1/ap_val2
    
    print("get_aperture:: ap_val1 = {0}, ap_val2 = {1}, aperture = {2}".format(ap_val1, ap_val2, ap))
    return "f/"+str(ap)

def get_exposure_mode(mode):
    if mode == 0:
        return "Auto"
    elif mode == 1:
        return "Manual"
    else:
        return "Auto Bracket"

def get_light_source(ls_val):
    if ls_val==10:
        return "Cloudy Weather"
    elif ls_val==13:
        return "Cool White Fluorescent"
    elif ls_val==1:
        return "Daylight"
    elif ls_val==12:
        return "Daylight Fluorescent"
    elif ls_val==13:
        return "Day White Fluorescent"
    elif ls_val==9:
        return "Fine Weather"
    elif ls_val==4:
        return "Flash"
    elif ls_val==2:
        return "Fluorescent"
    elif ls_val==11:
        return "Shade"
    elif ls_val==3:
        return "Tungsten (Incandescent Light)"
    elif ls_val==15:
        return "White Fluorescent"
    else:
        return "Other Light Source"


def printFujifilmExif(labeled):
    shutter_speed = get_shutter_speed(labeled['ExposureTime'])

    aperture = get_aperture(labeled['FNumber'])

    format = "%Y:%m:%d %H:%M:%S"
    date_created = datetime.datetime.strptime(labeled['DateTimeOriginal'], format)

    exposure_mode = get_exposure_mode(labeled['ExposureMode'])
    light_source = get_light_source(
        labeled['LightSource'])  # LightSource for Fujifilm

    iso_value = labeled['ISOSpeedRatings']
    camera_make = labeled['Make']
    camera_model = labeled['Model']

    lens_make = labeled['LensMake']  # LensMake for Fujifilm
    lens_model = labeled['LensModel']  # LensModel for Fujifilm
    software = labeled['Software']

    print("\n\nPRINTING PROFILE FOR FUJIFILM***")
    print("Camera Make: {0}".format(camera_make))
    print("Camera Model: {0}".format(camera_model))
    print("Lens Make: {0}".format(lens_make))
    print("Lens Model: {0}".format(lens_model))
    print("Date taken: {0}".format(date_created))
    print("Aperture: {0}".format(aperture))
    print("Shutter speed: {0}".format(shutter_speed))
    print("ISO: {0}".format(iso_value))
    print("Exposure mode: {0}".format(exposure_mode))
    print("Light source: {0}".format(light_source))
    print("Softwawre = {0}".format(software))

def printExifInfo(file_name):
    exif = get_exif(file_name)
    labeled = get_labeled_exif(exif)
    print("EXIF: {0}\n\n".format(labeled))

    if labeled['Make'].upper()=="FUJIFILM":
        printFujifilmExif(labeled)
    else:
        printCanonExif(labeled)


print("****Printing Fujifilm profile****")
printExifInfo('DSCF3846_Lowres.jpg')

示例输出

Printing Fujifilm profile* EXIF: {'ResolutionUnit': 2, 'ExifOffset': 446, 'Make': 'FUJIFILM', 'Model': 'GFX 50S', 'Software': 'GIMP 2.10.18', 'DateTime': '2021:05:14 22:58:13', 'Copyright': '
', 'XResolution': 72.0, 'YResolution': 72.0, 'ExifVersion': b'0230', 'ShutterSpeedValue': 8.965784, 'ApertureValue': 4.970854, 'DateTimeOriginal': '2021:05:14 15:51:42', 'DateTimeDigitized': '2021:05:14 15:51:42', 'BrightnessValue': 9.94, 'ExposureBiasValue': 0.0, 'MaxApertureValue': 5.0, 'MeteringMode': 5, 'LightSource': 1, 'Flash': 0, 'FocalLength': 196.5, 'ColorSpace': 1, 'ExifImageWidth': 7333, 'FocalPlaneXResolution': 914.0, 'FocalPlaneYResolution': 914.0, 'ExifImageHeight': 5500, 'FocalPlaneResolutionUnit': 3, 'Sharpness': 0, 'SubjectDistanceRange': 0, 'SensingMethod': 2, 'FileSource': b'\x03', 'ExposureTime': 0.002, 'FNumber': 5.6, 'SceneType': b'\x01', 'ExposureProgram': 1, 'CustomRendered': 0, 'ISOSpeedRatings': 100, 'ExposureMode': 1, 'SensitivityType': 1, 'StandardOutputSensitivity': 100, 'WhiteBalance': 1, 'BodySerialNumber': '72012151', 'LensSpecification': (196.5, 196.5, 5.656854256854257, 5.656854256854257), 'LensMake': 'FUJIFILM', 'LensModel': 'GF100-200mmF5.6 R LM OIS WR', 'LensSerialNumber': '88A10682', 'FocalLengthIn35mmFilm': 155, 'SceneCaptureType': 0}

shutter_speed = 0.002, type = <class 'PIL.TiffImagePlugin.IFDRational'> The shutter speed is not a list shutter speed value: 0.002, type <class 'PIL.TiffImagePlugin.IFDRational'> get_shutter_speed:: ss_val1 = 0.002, ss = 1/500s aperture = 5.6, type(aperture) = <class 'PIL.TiffImagePlugin.IFDRational'> get_aperture:: ap_val1 = 0.0, ap_val2 = 0.0, aperture = 5.6

PRINTING PROFILE FOR FUJIFILM*** Camera Make: FUJIFILM Camera Model: GFX 50S Lens Make: FUJIFILM Lens Model: GF100-200mmF5.6 R LM OIS WR Date taken: 2021-05-14 15:51:42 Aperture: f/5.6 Shutter speed: 1/500s ISO: 100 Exposure mode: Manual Light source: Daylight Software = GIMP 2.10.18