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