Python rawkit如何从RAW文件中读取元数据值



我正在编写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 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.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

相关内容

  • 没有找到相关文章