Python rawkit如何从原始文件读取元数据值?

Python rawkit如何从原始文件读取元数据值?,python,metadata,photo,libraw,Python,Metadata,Photo,Libraw,我正在编写python脚本,需要从原始照片文件(.CR2)获取exif信息 我发现Python提供了这样做的能力 with Raw(filename=image_path) as raw: print raw.metadata Metadata(aperture=-1.2095638073643314e+38, timestamp=4273602232L, shutter=-1.1962713245823862e+38, flash=True, foc

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

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

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)
但我有点困惑,如何读取这些值?。例如,我期望iso100/200/400这样的值,但-1.182978841800441e+38是什么

我的问题不是针对iso的,而是针对快门、光圈

我检查了和rawkit文档,但无法找到如何读取/转换此类值

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

float iso_speed;
ISO sensitivity.

float shutter;
Shutter speed.
有人能帮我理解如何读取这些值吗

谢谢

[更新]

正如neo所建议的,我将使用Exifrad。事实上,这是一个更好的选择,我正在编写一个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)
详细回答(我是如何找到/调试的):

阅读此exelent链接了解佳能RAW
.CR2
文件中存储的内容,如何以及为什么()我决定解码自己,并了解发生了什么

这个链接发送给我一个原始文件的解码 因此,我认为最好的价值似乎是在我的佳能特定MakerNote部分中关于FNumber的价值。(此处提供了所有值的说明)

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

关键事项:

  • 偏移量是文件中包含您的值的地址
  • 读取:文件中的
    C8 05
    应读取
    05C8
    。例如,对于偏移量,地址为
    0x5C8
有了这些,MakeNote部分就很容易了

快速方法是直接搜索包含MakerNote节地址的
0x927c MarkerNote
(因此在文件
7C 92
)标志。 如果找不到,请通过
IFD
部分查找
EXIF小节
。然后在这一小节中,你会找到MakerNote部分

Tag     Type   Count        Value
7C 92   07 00  B8 A0 00 00  84 03 00 00
偏移量:
84 03 00
->
00 03 84
0x384
地址)

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

Tag     Type   Count        Value
03 00   03 00  04 00 00 00  C8 05  00 00
转到偏移量
0x5C8
查找我们的值(计数4 x类型3 ushort,16位)

而且。。。失败了,事实上我的佳能没有填补这一部分

可以在EXIF小节中找到读取FNumber的信息

执行相同的过程以查找EXIF子部分和标记“
0x829d EXIF.Image.FNumber
type5 Rational” 有理类型由64位(分子和分母Ulong)组成

然后读取
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
float,这个值以分数格式存储。所以库不做数学运算,只是简化分数


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

我建议您使用一个专注于EXIF阅读的库。libraw/rawkit中提供的东西真的只是一个不错的额外功能。我可以推荐图书馆。它是纯Python,而且速度非常快。如果与多种格式的兼容性对您来说比性能更重要,那么您可以使用-j选项将exiftool作为子流程调用,以获得一个json字符串,并将其转换为字典

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


你试过从LibRaw运行“原始标识-v”吗?输出是什么?看起来很好:(ISO速度:400快门:1/50.0秒光圈:f/2.8)。我不是一个好的cpp读者,但我会检查。可能是c->python绑定错误,可能是错误的数据类型?您安装了什么版本的libraw和rawkit?没有注意到Exifrad能够读取原始数据。看起来不错,但不幸的是光圈的值是错误的(3而不是2.8)。我将尝试解码我自己,以在Exifrad Github上打开一个bug。我建议您首先尝试ExifTool命令行工具并进行比较。这应该是“参考资料”。我发现了我的错误并更新了我的问题,这是ExifReat thanksGlad的作品。你解决了这个谜团,并且用十六进制编辑器很好地挖掘了二进制数据!
Tag     Type   Count        Value
9D 82   05 00  01 00 00 00  34 03 00 00
1C 00 00 00  0A 00 00 00
EXIF.py 100EOS5D/IMG_8813.CR2 -vv | grep -i 14/5
EXIF FNumber (Ratio): 14/5
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