LibRaw 0.14.0 (Release)

После трех месяцев разработки и тестирования вышла LibRaw 0.14.

По уже сложившейся традиции, помещу тут несколько отредактированный Changelog.

В этой версии одно принципиальное изменение, влекущее за собой множество мелких:

Разрешены повторные вызовы постобработки (LibRaw::dcraw_process) без переоткрытия файла парой вызовов open()/unpack(). При этом, постобработку можно повторять меняя любые параметры обработки (за исключением выбора кадра через shot_select).

В сочетании с повышением скорости обработки, на (очень) приличной современной машине можно получить:

  • "Почти realtime" показ изменений изображения при смене параметров RAW-конвертации в режиме половинного разрешения. На 40-мегапиксельное изображение уходит примерно 250 мсек (т.к. half-mode, то выдается 10 мегапикселей, что сильно больше любого современного монитора).
  • "Совсем realtime" показ изменений небольшого окошка (например, вокруг курсора) в полном разрешениии с настоящей демозаикой (получается 30-50 кадров/сек для окошка 450x300)
Осталось дождаться, пока это подопрут разработчики конверторов. digiKam обещал, но пока еще не сделал... Более формальный Changelog:
  • Новый пример samples/multirender_test.cpp показывает как использовать новые возможности.
  • Необработанные RAW-данные сохраняются в отдельном буфере (2 байта на пиксель для Байеровских изображений, 8 байт на пиксель для Foveon, sRAW и других полноцветных RAW). Как следствие, для байеровских изображений LibRaw требует на 25% больше памяти чем ранее.
  • Новый вызов LibRaw::raw2image() преобразует RAW-данные в старый формат imgdata.image Если вы используете LibRaw::dcraw_process или LibRaw::document_mode_processing(), вызывать raw2image() не нужно (и даже вредно), все будет сделано внутри функции постпроцессинга.
  • Новый вызов LibRaw::get_decoder_info() позволяет определить формат хранения RAW-данных (если вам нужен к ним доступ). См. samples/unprocessed_raw.cpp как пример использования.
  • LibRaw::adjust_sizes_info_only() может вызываться произвольное количество раз, втч. и вместе с dcraw_process()
  • Новый вызов LibRaw::free_image() Освобождает память, выделенную для imgdata.image. Может быть использован в случае, если обработанный битмэп более не нужен вызывающему приложению, однако время для уничтожения или recycle() объекта LibRaw еще не наступило, например может повторно быть вызвана функция постобработки dcraw_process()
  • Новые вызовы добавлены в C-API: libraw_raw2image() - аналог LibRaw::raw2image() libraw_free_image() - аналог LibRaw::free_image() libraw_get_decoder_info() - аналог LibRaw::get_decoder_info()
Если ваша программа использует обычный порядок вызовов open()/unpack()/dcraw_process(), то можно в ней ничего не менять и все будет работать как раньше. Однако для интерактивных программ, где параметры обработки меняются пользователем, можно пропустить вызовы open()/unpack() при повторной отрисовке и показать пользователю результат гораздо быстрее.

Если ваш код использует RAW-данные (open()+unpack(), а обработка своя), то вам нужно или переключиться на новый формат данных, или использовать вызов LibRaw::raw2image() для конверсии из нового формата в старый.

Если ваш код использовал доступ к маскированной ("черной") рамке, то вам нужно использовать новый RAW-буфер. См. samples/unprocessed_raw.cpp в качестве примера.

Прочие изменения:

  • Импортирована dcraw 9.10 (1.444), добавлена поддержка для камер: ARRIRAW, Canon SX30 IS, Leica D-LUX 5 и V-LUX2, Olympus E-P3, Panasonic G3 и GF3, Sony NEX-C3 и SLT-A35
  • Исправлена ошибка: green_matching несовместим (и не имеет смысла) с вейвлет-фильтрацией, коррекцией аберраций и прочими случаями уменьшения выходного изображения вдвое.
  • Поддержка цифровых кинокамер RedOne (формат R3D). Для использования этой поддержки вам надо:
    • Установить библиотеку libjasper для раскодирования JPEG2000
    • компилировать LibRaw с ключом компилятора -DUSE_JASPER (./configure сделает это сама)
    • Если вы используюете свой LibRaw_datastream, вы должны имплементировать там вызов make_jas_stream(), который вернет указатель на "поток" libjasper. Примеры реализаций этого вызова для потоков LibRaw можно найти в хвосте файла src/libraw_cxx.cpp
  • Оптимизация постпроцессинга, особенно для обрезанных (cropped) изображений.
  • Минимальные косметические изменения в описании интерфейса LibRaw_file_datastream interface
  • OpenMP-ускорение постпроцессинга (до 50% для режима half_size на 4-ядерном CPU)
  • Кроппинг работает и для сенсоров FujiCCD. По ряду причин, позиция верхнего левого угла области кроппинга округляется до ближайшего меньшего целого числа кратного 4.
  • Новый пример samples/postprocessing_benchmark.cpp
    Позволяет оценить скорость этапа постпроцессинга. Поддерживает разные варианты интерполяции, кроппинг, averaged white balance, медианный фильтр, wavelet-фильтрацию и highlight recovery.
  • Отдельных буферов под черную (маскированную) рамку более не существует. Байеровские данные хранятся в буфере вместе с рамкой, а для остальных (полноцветных) форматов данных рамка несущественна. Как следствие, нет больше и отвратительного вызова LibRaw::add_masked_border_to_bitmap()
  • Параметра, управлявшего фильтрацией RAW-данных (params.filtering_mode) тоже больше нет с нами. Тоновая кривая RAW применяется всегда (для тех форматов, где она есть) на стадии распаковки, нулевые пикселы затираются усредненными соседними данными на стадии постпроцессинга (тоже, только для тех форматов, где есть проблема нулевых пикселов).
  • Удален вызов LibRaw::rotate_fuji_raw() и соответствующий ему вызов С API.
  • Примеры unprocessed_raw и 4colors используют новые форматы хранения RAW и новый вызов raw2image.
  • * Новые макросы проверки версий:

    LIBRAW_RUNTIME_CHECK_VERSION_EXACT() - рантайм проверка, что версия библиотеки (DLL, .SO) в точности та же, что была на компиляции приложения.

    LIBRAW_RUNTIME_CHECK_VERSION_NOTLESS() - рантайм проверка, что версия не меньше той, что была на компиляции.

    LIBRAW_COMPILE_CHECK_VERSION_EXACT(major,minor) - Проверка на компиляции, что версия в точности major.minor

    LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(major,minor) - Проверка на шаге компиляции, что версия не меньше чем major.minor

  • Удалены поля данных imgdata.sizes.bottom_margin и right_margin. Если размеры этих полей интересны, используйте для их вычисления raw_width - width - left_margin (и аналогично для нижнего поля).
  • Косметические изменения в ./configure
  • Обновлены файлы для Qmake и проектные файлы Visual Studio.
  • Большинство исходных текстов методов LibRaw*datastream перемещено в отдельный файл с исходными текстами, дабы не захламлять libraw_datastream.h
  • Класс LibRaw_windows_datastream (работа под Win32 с memory-mapped файлами) включен в "основную" библиотеку.

Comments

Собственно, а в RPP v0.14 когда появится?

На сегодняшний день в RPP свой декодер RAW (тоже dcraw-based) и полностью свой постпроцессинг.

Почему Андрею интересно самому возиться с dcraw я не знаю, но это не такие и большие усилия нужны.

А сами прикрутить сможете? Или на линух переходить?..

К чему прикрутить, к RPP?

Автора надо просить, наверное. У меня никакого доступа к исходным текстам RPP нет. Я бы там наслесарил....

Частенько слесарь лучше ювелира. В смысле, хоть какая-то практическая реализация...

Практическая реализация ЧЕГО?

В RPP полностью свой постпроцессинг, прикручивать туда (плохой) целочисленный от LibRaw - только портить.

А в РПП всё насквозь в real???

Лучше у Андрея спрашивать, но насколько я знаю - да.

Я прошу прощения, что вопрос, может, на уровне чайника.

Я скачал LibRaw-0.14.0-demosaic-packs-GPL2-GPL3-Win32.zip

Переписал в папку D:\Projects\LibRaw\

Открыл файл LibRaw.sln, он открылся.

Попробовал построить, и тут оп.

4>LINK : fatal error LNK1181: не удается открыть входной файл "libraw.lib"

Ну, попытался построить второй раз - оно строит, хотя не всё.

У меня такое чувство, что там что-то не то с зависимостями, нет? То есть, к тому моменту когда ему нужно dcraw_emu.exe строить, у него ещё нет lib.

В-принципе, там все зависимости в .sln прописаны и работают. Но прописаны только в .vcproj, но не в .sln (Qmake которым я все генерирую - в .sln не умеет, а при ручном создании проектов оно цепляется к моей структуре дисков и каталогов).
Можно и вручную прописать в свойствах Solution.

Но. На быстрых многоядерных машинах есть другая печаль (возможно, это какой-то конфликт с антивирусами или чем-то подобным): когда VisualStudio считает, что проект libraw уже построен, на самом деле там еще файлы .dll/lib открыты и недописаны и слинковаться с ними все еще нельзя, еще несколько секунд.

В общем, вручную если строить сначала dll, а потом exe - работает, вроде. Так.

Тогда у меня багрепорт, и правка к коду. Сейчас fbdd делает цветные полосы по краям, с 4-го по 6-й пиксель, получается такая "рамка".

Я поправил код, чтобы он просто не трогал изображение в этих областях. По идее, получается что 6 пикселей с каждой стороны не чистятся, (до этого было 3 пикселя). Но это лучше, чем то, что было до этого.

Код тут

http://lj.vladimirovich.net/lj11/fbdd.correction.txt

Ага, спасибо!

Патч, да еще и через правильное место был бы удобнее, но и так восприму.

Ок, сделал.

Ну, попробовать нужно :-) (у меня работает, но, понятно, может какой косяк).

Попробуем, отчего же не попробовал.

А механизм для меня настолько удобнее, что просто ой. Одну кнопку нажал - и все.

А вот такой вопрос. Есть строчка

int FC(int row,int col) { return (imgdata.idata.filters >> (((row << 1 & 14) | (col & 1)) << 1) & 3);}

Зачем тут нужно "& 14"???

В смысле, зачем? Три верхних бита (из четырех) взять.

Эээ

Мы берём row, сдвигаем его на 1 влево, три верхних бита

rrr0

добавляем младший бит от col

rrrc

сдвигаем еще раз влево

rrrc0

и берём старшие 2 бита

c0

Эээ?

два бита берутся от результата сдвига filters влево на rrrc0

вправо!

А как определить зелёный канал, и тот факт что он "в два раза чаще"?

В зависимости от контекста вопроса, ответ может быть разный. Зеленых может быть два, но они при этом могут быть разными.

Но надо посмотреть в cdesc[] и если там RGBG, то он "в два раза чаще". Имена в cdesc[] соответствуют номерам в image[..][c]

Кстати, а зачем по Y оно кратно 8 пикселям?

А посмотрите на паттерн PowerShot Pro70 или A50, там как раз 2x8 (есть в начале dcraw.c)

А зачем нужно LIBRAW_DECODER_USEBAYER2?

USEBAYER - это в одной строке чередуются два цвета. USEBAYER2 - "более чем два"

Для первого случая обработка оптимизирована

Так. У меня такие предложения. Добавить вот это:

unsigned int imagemode;
ushort (*image) [4];
float (*imagef)[4];

LIBRAW_DECODER_FLOAT = 1<<5,
LIBRAW_DECODER_DONOTSUBBLACK = 1<<6,
LIBRAW_DECODER_ALLOWNEGFLOAT = 1<<7,

Ну и переделать код raw2image_ex. Кстати, заодно поправив, чтобы внутри цикла умножения не встречалось, если уж есть желания чтобы оно быстрее работало.

По умолчанию ничего не изменится, а для меня ну и для желающих будет всё, что нужно.

В смысле, я готов это всё переписать, если архитектурных нет противоречий.

Идёт?

В смысле, придумать такой "декодер", который выдает все в float?

Оно как-то выглядит бессмысленно на мой взгляд. На сегодня все камеры - целые. И буфер raw - соответственно.
И плавучка может быть только где-то в постпроцессинге, а не до.

Так постпроцессинг делается на imgdata.image, разве нет?

Ну да. Но я зацепился глазом за флаги декодера - а они описывают то, что в imgdata.rawimage.

На мой взгляд, надо делать вызов *вместо* dcraw_process (назвать его process_fp(), например).
Результат, да, класть в imagef[][4] или что-то подобное.

В этом случае нужно обязательно переписать вычитание черного, scale_colors() /если нужна/, pre_interpolate(), какую-то интерполяцию, convert_to_rgb() ну и какой-то вывод в 16 бит: dcraw_mem_image() или писалку тиффов-PPM. Лучше, конечно, обе.

Более того, можно вообще начинать только с интересных вам видов байера (самых простых, как у canon), а на неинтересные честно говорить "не поддерживаем, извини".

А все что вам лично не нужно - не переносить в новый пайплайн. Пущай волонтеры поработают, если кому надо.

Да, кстати, что делает pre_interpolate()?

Там же написано :)
Если заказано половинное разрешение - делает его.
Если не установлено four_color_rgb - копирует второй зеленый канал в первый там где надо.

Ну хочется какую-то стройность соблюдать, иначае для float так, для этого эдак, короче, жесть.

Скажем, есть raw2image_ex - его не планируется сейчас исключать из кода?

В таком случае, либо сделать копию raw2image_ex_f, либо сделать параметр.

То есть, в идеале, вот есть libraw, он как должен данные выдавать? В хелпе написано "в том варианте, как попросит пользователь, один бауер, 4 канала, 4 плоскости, но сейчас только так.

Ну так сейчас в imgdata.rawimage[] - "как оно у камеры", а после raw2image() (не _ex) - 4 плоскости с заполненным одним элементом. Как нравится, так и кушай.

Реально идея что кому-то нужны RAW-данные оказалась очень оптимистичной. Да, нужны, но таких программ мало. Почти все пользователи - используют постпроцессинг (и огорчают этим меня)

А зачем raw2image и raw2image_ex отдельно?

raw2image - именно для тех, кто хочет raw-данные в старом (4 слоя, 3 элемента в каждом пикселе - нули) формате.

Вот например в примере 4channels именно оно, чтобы переписывать этот пример поменьше :)

А raw2image_ex выдаёт разве не так?

raw2image_ex делает сразу
- распихивание в image[]
- вычитание черного (кроме PhaseOne)
- поворот для Fuju (если Fuji)
- кроп.

Но выходной формат такой же, да?

Короче, если туда сделать параметр входной, который будет устанавливать режим работы - ок?

raw2image_ex и так перетяжелена, не надо бы туда больше ничего добавлять.....

Ох. Ну хорошо, предлагаю так: туда добавить флаг, отвечающий за "удалять нули или не". Это вообще на код никак не повлияет, по сути, просто вычитать нужно будет не черный, а "0".

Не нужен для этого флаг.

Сохраните в карман imgdata.rawdata.color.black/cblack, а эти поля - обнулите.
Вот вам и невычитание.
А потом - восстановите. в imgdata.color - по желанию, в imgdata.rawdata - обязательно

Я же писал вчера про это.

Но сама идея сначала сделать 4-компонентное целое, чтобы потом из него сделать 4-компонентное float - пугающая немножко :)

Да не, я бы там сделал копию кода, конечно.

Ну а как сделать вычитание нулей после дебауризации, если вот например, хочется?

А то, допустим, есть пиксель -2, сосед +2. Логично, что между ними должен быть "0". А если вычитать сначала - будет "1".

Так у вас значения черного будут сохранены в кармане - вычитай не хочу

В смысле - "вычитай не хочу"? Ну да, там есть, насколько я понял, вся плоскость raw файла.

Просто, ну честно, получается что встроится и изменить существующий стек до каких-то вещей нельзя, а можно только сделать "свой стек с блекждеком и шлюхами".

Ну, тоже вариант - склонировать текущий dcraw_emu, и поменять там всё.

Просто, ну честно, получается что встроится и изменить существующий стек до каких-то вещей нельзя, а можно только сделать "свой стек с блекждеком и шлюхами".

Для float - очевидно так, ибо надо весь стек переписать.

Не для float - ну это ровно то, про что я говорил вам же недавно - сделать полностью гибкий и при этом эффективный пайплайн - нельзя, т.к. объединение нескольких шагов нельзя сделать, вдруг между ними кому-то захочется, вот прямо как вам.
raw2image_ex() - это про эффективность.

Комбинация raw2image() + subtract_black() + rotate_fuji() + crop() (последние два из 14.x удалены за полной невостребованностью народом, но можно и вернуть, взять из 0/13) - неэффективна в случае использования стандартной функциональноести.

Такой вот парадокс. Можно, если хочется, написать что-то в духе
if(O.wf_debanding)
{
raw2image();
rotate_fuji_raw();
wf_debanging();
subtract_black()
}
else
raw2image_ex();

Ну, если хочется чтобы на int всё-таки был дебандинг, то придётся пока так. Кстати, на фуджи я вообще не рассчитывал, как его отсечь?

Впрочем, если уж говорить об эффективности, то программа станет сильно эффективнее, если оптимизировать циклы. Скажем, я замерял: моя версия обхода по изображению в два раза эффективнее текущей реализации, хотя код несколько менее читаем, конечно.

Да, станет.

Но в реальной жизни процедура распаковки вообще парит мало, все уходит в демозаику.

Ок, открыл проект.

Во-первых, файл wf_filtering.cpp не включен в проект. Во вторых, у него там не прописан инклуд libraw.h

Ну и в третьих, не получается слинковать из-за странной ошибки

1>wf_filtering.obj : error LNK2005: "public: int __thiscall LibRaw::wf_remove_banding(void)" (?wf_remove_banding@LibRaw@@QAEHXZ) уже определен в demosaic_packs.obj
1>wf_filtering.obj : error LNK2005: "private: double __thiscall LibRaw::wf_filter_energy(int,int,int,int)" (?wf_filter_energy@LibRaw@@AAENHHHH@Z) уже определен в demosaic_packs.obj
1>wf_filtering.obj : error LNK2005: "private: void __thiscall LibRaw::wf_bayer4_green_blur(int,void *,int,void *,int)" (?wf_bayer4_green_blur@LibRaw@@AAEXHPAXH0H@Z) уже определен в demosaic_packs.obj
1>wf_filtering.obj : error LNK2005: "private: void __thiscall LibRaw::wf_bayer4_igauss_filter(int,void *,int,void *,int)" (?wf_bayer4_igauss_filter@LibRaw@@AAEXHPAXH0H@Z) уже определен в demosaic_packs.obj
1>wf_filtering.obj : error LNK2005: "private: void __thiscall LibRaw::wf_bayer4_block_filter(int *,void *,int,void *,int)" (?wf_bayer4_block_filter@LibRaw@@AAEXPAHPAXH1H@Z) уже определен в demosaic_packs.obj

Ну так и не надо его включать в проект.

Потому что, из demosaic_packs.cpp:
#include "./wf_filtering.cpp"

И все 3rd-party включено так же, мне так удобнее.

Уффф. У меня, собственно, очень простой вопрос. Как сделать так, чтобы при редактировании в VS2010 вот такого

не было?

Ну если очень хочется включить туда libraw.h, включите его под #ifndef LIBRAW_LIBRARY_BUILD

Редактор это увидит, а компилятор - нет.

Спасибо, часть проблем пропала, остались проблемы с wf_bayer4_green_blur и др. функциями

Они, почему-то, не члены LibRaw сейчас

Потому что они в internal/libraw_internal_func.h
Как и прочие служебные, коим даже в derived class не нужно пользоваться.

Мешает - перенесите в libraw_h, если надо.

Стоп, насколько я понял самый экстрим - вот тут-же выше по треду, 2х8
Т.е. как может в одной строке больше чем 2 цвета?

Fuji: там в строке все 4 цвета, если я правильно помню.

Существует какой-нибудь флаг, чтобы проверить что это "бауер 2х2"?

1) Через флаги декодера
libraw_decoder_info_t decoder_info;
tmp_metadata->raw_processor.get_decoder_info(&decoder_info);
if((decoder_info.decoder_flags & LIBRAW_DECODER_FLATFIELD)
&& !(decoder_info.decoder_flags & LIBRAW_DECODER_USEBAYER2)
)

2) Через реальный подсчет в реальном файле: пройтись по любой паре строк эдак на 8 пикселов и посчитать цвета через COLOR(0,i) и COLOR(1,i) - если в обоих случаях их по 2, то вы в хопре.

Второй способ какбэ надежнее т.к. USEBAYER2 - это флаг декодера unpacked_load_raw() /больше никаких таких не бывает/, а этот декодер покрывает очень много камер, втч Фуджи (ради которых весь этот геморой и происходит).

А вы смотрели на boost::gil?
http://stlab.adobe.com/gil/presentation/index.htm

Да мне как-то без надобности. Нет, не смотрел.

Кроме этого, меня беспокоит, что она обновлена в 2007-м и все. ... Впрочем, нет, вот у нее гнездо оказывается: http://stlab.adobe.com/

Лучше уж Intel IPP тогда. Или OpenCV