Python rawkit, как читать значения метаданных из файла RAW?

Я пишу скрипт на 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, это также для затвора, диафрагмы,...

Я взломал libraw и rawkit doc, но не смог найти, как читать / конвертировать такие значения.

Эта часть в документе не очень подробно:

float iso_speed;
ISO sensitivity.

float shutter;
Shutter speed.

Может кто-нибудь помочь мне понять, как читать эти значения?

Спасибо

[Обновить]

Как нео советую, я буду использовать ExifRead. На самом деле это лучший выбор, я пишу скрипт на Python. С ExifRead нет необходимости в дополнительной зависимости от библиотеки C.

Я смог открыть файл Canon Raw и проанализировать 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/) Я решил расшифровать себя и узнать, что происходит.

Эта ссылка отправляет меня на страницу для декодирования необработанного файла 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 легко.

Быстрый способ заключается в поиске непосредственно 0x927c MarkerNote (так в файле 7C 92) флаг, содержащий адрес раздела MakerNote. Если вы не можете найти это, пройдите 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 х тип 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 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

Как мы можем прочитать в гексе: 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 как и ожидалось.

1 ответ

Решение

Я предлагаю вам использовать библиотеку, которая ориентирована на чтение EXIF. Материал, доступный в libraw/rawkit, действительно просто приятный дополнения. Я могу порекомендовать библиотеку ExifRead. Это чистый Python, а также чертовски быстро. И это дает вам лучшее понимание ценностей.

Если совместимость со многими форматами является для вас большей проблемой, чем производительность, вы можете вызвать 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
Другие вопросы по тегам