我正在编写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.182788841800441e+38?
我的问题不是针对iso的,它也针对快门、光圈。。。
我查了libraw和rawkit文档,但找不到如何读取/转换这种值。
文档中的这一部分不是很详细:
float iso_speed;
ISO sensitivity.
float shutter;
Shutter speed.
有人能帮我理解如何解读这些价值观吗?
感谢
[更新]
正如neo所建议的,我将使用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)
长答案(我是如何发现/调试的):
阅读此链接了解Canon RAW .CR2
文件中存储的内容,如何以及为什么(http://lclevy.free.fr/cr2/)我决定解码自己,知道发生了什么
这个链接让我在graal上解码一个原始文件cr2_poster.pdf从那以后,我认为最好的值似乎是在我关于FNumber值的特定于佳能的MakerNote部分。(此处为所有值的描述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 84
(0x384
地址)
转到该地址并在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.htmlFNumber可在EXIF小节中找到。
执行相同的过程来查找EXIF子部分和标签"0x829d Exif.Image.FNumber
type 5 Rational"有理类型由64位(分子和分母ulong)组成Ratinal_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
正如我们在十六进制中所读到的: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
。
我建议您使用一个专注于EXIF阅读的库。libraw/rawkit中提供的东西真的只是一个不错的额外功能。我可以推荐ExifRead库。它是纯粹的Python,而且速度非常快。它让你更好地理解价值观。
如果与许多格式的兼容性比性能更重要,那么可以使用-j选项将exiftool作为子进程调用,为您提供一个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