4

我正在编写 python 脚本,我需要从原始照片文件(例如 .CR2)中获取 exif 信息。

我发现 Python Rawkit提供了这样做的能力。

with Raw(filename=image_path) as raw:
  print raw.metadata

Metadata(aperture=-1.2095638073643314e+38, timestamp=4273602232L,
         shutter=-1.1962713245823862e+38, flash=True, 
         focal_length=-1.2228562901462766e+38, height=3753, 
         iso=-1.182978841800441e+38,
         make='Canon', model='EOS 5D Mark II', 
         orientation=0, width=5634)

但我有点困惑,如何读取这个值?例如,我期望iso值像100/200/400-1.182978841800441e+38是什么?

我的问题不是针对iso的,它也针对快门,光圈,...

我检查了libraw和 rawkit 文档,但无法找到如何读取/转换这种值。

文档中的这部分不是很详细:

float iso_speed;
ISO sensitivity.

float shutter;
Shutter speed.

有人可以帮助我了解如何阅读这些值吗?

谢谢

[更新]

正如新建议的那样,我将使用 ExifRead。事实上这是一个更好的选择,我正在编写一个 python 脚本。使用 ExifRead 不需要额外的 C 库依赖。

我能够打开佳能原始文件并解析 Exif,但不幸的是光圈值错误:

EXIF ApertureValue (Ratio): 3
# My photo was taken in 2.8 (maybe a rounded value on this flag ?)

快速回答:使用 Fnumber 标志

EXIF FNumber (Ratio): 14/5 
14/5 is in fact 2.8 (do the math)

长答案(我是如何发现/调试的):

阅读这个出色的链接了解存储在佳能 RAW.CR2文件中的内容、方式和原因 ( http://lclevy.free.fr/cr2/ ) 我决定自己解码并知道发生了什么。

此链接发送给我以解码原始文件cr2_poster.pdf 从中我认为最佳值似乎在我的佳能特定 MakerNote 部分中的 FNumber 值。(所有值描述都在这里canon_tags

Tag Id : 3 (In fact 0x0003 that you write 0x3) 
Name : FNumber

我用 Hexa 编辑器(hexedit)打开了我的文件,然后……我完全迷失了。

关键事项:

  • 偏移量是文件中包含您的值的地址。
  • 读取:C8 05在文件中应该被读取05C8。偏移量示例,地址为0x5C8

有了这个发现 MakeNote 部分很容易。

快速的方法是直接搜索包含 MakerNote 部分地址的0x927c MarkerNote(所以在文件中)标志。7C 92如果您找不到,请浏览该IFD部分以找到EXIF subsection. 然后在该小节中,您将找到 MakerNote 部分

Tag     Type   Count        Value
7C 92   07 00  B8 A0 00 00  84 03 00 00

偏移量:84 03 00 00-> 00 00 03 840x384地址)

转到此地址并在 MakerNote 部分中搜索FNumber 0x3

Tag     Type   Count        Value
03 00   03 00  04 00 00 00  C8 05  00 00

转到偏移量0x5C8以找到我们的值(计数 4 x 类型 3 ushort,16 位)

0x0x5C8 : 00 00 00 00  00 00 00 00

而且...失败了,实际上我的佳能没有填写此部分。

阅读http://www.exiv2.org/tags.html FNumber 可以在 EXIF 小节中找到。

做同样的过程找到EXIF小节和标签“ 0x829d Exif.Image.FNumbertype 5 Rational” Rational type由64位组成(分子和分母ulongs)Rational_data_type

Tag     Type   Count        Value
9D 82   05 00  01 00 00 00  34 03 00 00

然后读取0x334偏移量

1C 00 00 00  0A 00 00 00

正如我们在 Hexa 中所读到的:0x1C/0XA 十进制,做数学:28/10= 14/5=2.8

验证我在 ExifRead 中有这个值

EXIF.py 100EOS5D/IMG_8813.CR2 -vv | grep -i 14/5
EXIF FNumber (Ratio): 14/5

瞧!

我在寻找2.8浮点数,这个值以分数格式存储。所以图书馆不做数学,只是简化分数。

这就是为什么我们有14/5而不是2.8像预期的那样。

4

2 回答 2

6

我建议您使用专注于 EXIF 阅读的库。libraw/rawkit 中可用的东西真的只是一个不错的附加功能。我可以推荐ExifRead库。它是纯 Python,而且速度极快。它让你更好地理解价值观。

于 2015-11-10T21:12:53.220 回答
1

如果与许多格式的兼容性对您来说比性能更重要,您可以调用 exiftool 作为带有 -j 选项的子进程,为您提供一个 json 字符串,您可以将其转换为字典。

这应该为您设置大多数原始格式,甚至是根本不是图像的东西。它会从文件中挤出最后一点 exif 信息。然而,与其他选项相比,它相当缓慢(比如慢 200 倍):

from PIL import Image
import PIL.ExifTags
import subprocess
import json
import datetime
import exifread
filePath = "someImage.jpg"
filePath = "someRawImage.CR2"
filePath = "someMovie.mov"
filePath = "somePhotoshopImage.psd"


try:
    start = datetime.datetime.now()
    img = Image.open(filePath)
    exif_0 = {
        PIL.ExifTags.TAGS[k]: v
        for k, v in img.getexif().items()
        if k in PIL.ExifTags.TAGS
        }
    end = datetime.datetime.now()

    print("Pillow time:")
    print(end-start)
    print(str(len(exif_0)), "tags retrieved")
    print (exif_0, "\n")
except:
    pass

try:
    start = datetime.datetime.now()
    exif_1 = json.loads(subprocess.run(["/usr/local/bin/exiftool", "-j", filePath], stdout=subprocess.PIPE).stdout.decode("utf-8"))
    end = datetime.datetime.now()

    print("subprocess time:")
    print(end-start)
    print(str(len(exif_1[0])), "tags retrieved")
    print(exif_1, "\n")
except:
    pass

try:
    start = datetime.datetime.now()
    f = open(filePath, "rb")
    exif_2 = exifread.process_file(f)
    end = datetime.datetime.now()

    print("Exifread time:")
    print(end-start)
    print(str(len(exif_2)), "tags retrieved")
    print(exif_2, "\n")
except:
    pass
于 2019-11-10T11:43:58.353 回答