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

时间:2015-11-09 15:14:48

标签: python metadata photo libraw

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

我发现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,而是针对快门,光圈,...

我ckecked libraw和rawkit doc但是无法找到读取/转换此类值的方法。

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

float iso_speed;
ISO sensitivity.

float shutter;
Shutter speed.

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

由于

[更新]

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

我能够打开Canon原始文件并解析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链接了解Canon RAW .CR2文件中存储的内容,How and Why(http://lclevy.free.fr/cr2/)我决定解码自己并知道发生了什么。

此链接向我发送graal以解码原始文件cr2_poster.pdf 从那以后,我认为最好的值似乎是在我的canon特定的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.FNumber类型5 Rational" Rational类型由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 float,这个值以小数格式存储。所以图书馆不做数学计算,只是简化了分数。

这就是为什么我们按预期14/5而不是2.8

2 个答案:

答案 0 :(得分:3)

我建议您使用专注于EXIF阅读的库。 libraw / rawkit中提供的东西真的只是一个很好的额外功能。我可以推荐ExifRead库。这是纯粹的Python,也快死了。它让您更好地理解价值观。

答案 1 :(得分:1)

如果与多种格式的兼容性对您而言不是性能问题,那么您可以使用-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