Lytro – пленоптическая камера, не требующая фокусировки, выпускаемая компанией Lytro (стартап Ren Ng – выпускника Стенфорда). Камера работает методом световых полей, о принципе работы которых я и постараюсь рассказать (под катом трафик!).
Картинки, где есть фотографии с lytro, кликабельны (но сайт lytro последнее время, бывает, лежит — наверное, ляжет и сейчас).
Камера
Полные спеки вы можете найти на сайте Lytro, про внешний вид рассказано в предыдущем обзоре. Сама камера сделана в Китае, подключается и заряжается через USB:
Дисплей сенсорный, обычного разрешения, вот тут он показывает, что камера заряжается:
Принцип работы прост: сверху зум (надо провести пальцем по резинке), сверху же кнопка затвора. Зум похож на 24-105mm.
Макро
Если камеру поднести близко к объекту, она не сфокусируется (да-да, и после съёмки тоже не фокусируется):
Чтобы это преодолеть, можно включить режим «creative mode». Он включается нажатием на белый квадратик:
В creative mode можно сфокусировать камеру нажатием на тач-скрин. Тыкнул на объект, камера подумала и сфокусировалась (автофокус, судя по всему, контрастный):
Сфокусироваться можно довольно-таки близко:
Ограничение creative mode в том, что после съёмки диапазон фокусировки будет ограничен.
Когда-то производитель обещали сделать встроенный focus stacking для макро. Сейчас такой фичи в камере нет, но это легко выполнить в фотошопе, достав картинки из lfp — как видим, ГРИП здесь значительно больше, чем до обработки:
Настройки
Никаких настроек в камере больше нет. Экспозицию камера устанавливает самостоятельно, повлиять на этот процесс нельзя (я заметил, что в EverydayMode экспозамер матричный, в CreativeMode центровзвешенный — но тоже как-то не всегда). Вот пара примеров:
В наиболее плохих условиях это будет ISO 3200, 1/15 (хотя странно: при наличии акселерометра можно было бы определить, что камера на штативе и поставить увеличить выдержку):
Софт
При подключении камеры копирует фотографии, позволяет повернуть их и залить на lytro.com.
Написан на Qt, хранит информацию в SQLite-базе, формат которой описан тут.
Совсем недавно вышел софт под win, что не может не радовать:
Формат
У Lytro один формат .lfp, используемый и для raw, и для web-оптимизированных файлов. Рассмотрим его подробнее.
Итак, .lfp представляет собой контейнер, разделённый на секции. Секции бывают нескольких типов:
- Метаданные о файле: присутствует всегда, описывает секции файла и содержит их SHA-1 хеши, формат json.
Пример
{ "picture" : { "frameArray" : [ { "frame" : { "metadataRef" : "sha1-079f3465638687275008d656c408c9c91d1bc6ee", "privateMetadataRef" : "sha1-44cdec4d744eae5c06dbef8f086fd7905bd8f55a", "imageRef" : "sha1-2f429e42bef0dc3fa0351dd2d55404c351e3beca" }, "parameters" : { "vendorContent" : { "com.lytro.tags" : { "darkFrame" : false, "modulationFrame" : false } } } } ], "viewArray" : [ { "type" : "com.lytro.stars", "vendorContent" : { "starred" : false } } ], "accelerationArray" : [ { "type" : "com.lytro.acceleration.refocusStack", "generator" : "Lytro Lightfield Engine 1.000000", "vendorContent" : { "viewParameters" : {}, "displayParameters" : { "displayDimensions" : { "mode" : "fixedToValue", "value" : { "width" : 1080, "height" : 1080 } } }, "defaultLambda" : 0, "depthLut" : { "width" : 20, "height" : 20, "representation" : "raw", "imageRef" : "sha1-3797be865adeaf3d28b372a2dca0aa8e3ef79b6f" }, "imageArray" : [ { "representation" : "jpeg", "width" : 1080, "height" : 1080, "lambda" : 4.8976802825927734, "imageRef" : "sha1-6e268b48ced0b5c38e39d477a3100f00bb9c188b" }, { "representation" : "jpeg", "width" : 1080, "height" : 1080, "lambda" : 5.886573314666748, "imageRef" : "sha1-80b19c4365465e63e623d5cc1fb9d345dfab7ce0" }, { "representation" : "jpeg", "width" : 1080, "height" : 1080, "lambda" : 6.8429036140441895, "imageRef" : "sha1-5f7c28a7b4aad7d06fcea230293aadb700ad27ef" } ] } } ], "derivationArray" : [ "sha1-f408b48df6a6c09e40e60585a655e8d81415b789" ] }, "thumbnailArray" : [], "version" : { "major" : 1, "minor" : 0, "provisionalDate" : "2011-08-03" } }
- Метаданные о кадре: присутствует только в RAW-файле, это показания со всех сенсоров на момент съёмки в json.
Пример
{ "type" : "lightField", "image" : { "width" : 3280, "height" : 3280, "orientation" : 1, "representation" : "rawPacked", "rawDetails" : { "pixelFormat" : { "rightShift" : 0, "black" : { "r" : 168, "gr" : 168, "gb" : 168, "b" : 168 }, "white" : { "r" : 4095, "gr" : 4095, "gb" : 4095, "b" : 4095 } }, "pixelPacking" : { "endianness" : "big", "bitsPerPixel" : 12 }, "mosaic" : { "tile" : "r,gr:gb,b", "upperLeftPixel" : "b" } }, "color" : { "ccmRgbToSrgbArray" : [ 3.1115827560424805, -1.9393929243087769, -0.172189861536026, -0.3629055917263031, 1.6408803462982178, -0.27797481417655945, 0.078967012465000153, -1.1558042764663696, 2.0768373012542725 ], "gamma" : 0.41666001081466675, "applied" : {}, "whiteBalanceGain" : { "r" : 1.07421875, "gr" : 1, "gb" : 1, "b" : 1.26953125 } }, "modulationExposureBias" : -1.1193209886550903, "limitExposureBias" : 0 }, "devices" : { "clock" : { "zuluTime" : "2012-07-25T14:05:20.000Z" }, "sensor" : { "bitsPerPixel" : 12, "mosaic" : { "tile" : "r,gr:gb,b", "upperLeftPixel" : "b" }, "iso" : 205, "analogGain" : { "r" : 5.5625, "gr" : 4.0625, "gb" : 4.0625, "b" : 4.6875 }, "pixelPitch" : 1.3999999761581417e-006 }, "lens" : { "infinityLambda" : 123.91555023193359, "focalLength" : 0.011369999885559081, "zoomStep" : 661, "focusStep" : 1271, "fNumber" : 2.0399999618530273, "temperature" : 38.670684814453125, "temperatureAdc" : 2501, "zoomStepperOffset" : 2, "focusStepperOffset" : 22, "exitPupilOffset" : { "z" : 0.039666198730468748 } }, "ndfilter" : { "exposureBias" : 0 }, "shutter" : { "mechanism" : "sensorOpenApertureClose", "frameExposureDuration" : 0.015281426720321178, "pixelExposureDuration" : 0.015281426720321178 }, "soc" : { "temperature" : 47.337005615234375, "temperatureAdc" : 2632 }, "accelerometer" : { "sampleArray" : [ { "x" : -0.066666670143604279, "y" : 1.0392156839370728, "z" : 0.08235294371843338, "time" : 0 } ] }, "mla" : { "tiling" : "hexUniformRowMajor", "lensPitch" : 1.3898614883422851e-005, "rotation" : 0.0020797469187527895, "defectArray" : [], "scaleFactor" : { "x" : 1, "y" : 1.0005592107772827 }, "sensorOffset" : { "x" : -1.0190916061401367e-005, "y" : -2.3611826896667481e-006, "z" : 2.5000000000000001e-005 } } }, "modes" : { "creative" : "tap", "regionOfInterestArray" : [ { "type" : "exposure", "x" : 0.7625085711479187, "y" : 0.21875333786010742 }, { "type" : "creative", "x" : 0.7625085711479187, "y" : 0.21875333786010742 } ] }, "camera" : { "make" : "Lytro, Inc.", "model" : "F01", "firmware" : "v1.0a60, vv1.0.0, Thu Feb 23 15:02:57 PST 2012, e10fcca0668db3dbf94ae347248db3da070d21e9, mods=0, ofw=0" } }
- Private metadata: серийник камеры и матрицы в json.
Пример
{ "devices" : { "sensor" : { "sensorSerial" : "0x5086D178DEADBEEF" } }, "camera" : { "serialNumber" : "A20B00B1E3" } }
- Raw sensor data: присутствует только в RAW-файле, представляет собой RAW данные с матрицы. Открывается так:
- Depth lookup table: присутствует только в web-оптимизированном файле. Карта глубины. Отвечает на вопрос: если я тыкнул сюда, какую из картинок мне надо показать?
- Prerendered λ = %lambda%: присутствует только в web-оптимизированном файле. Это изображение, показываемое пользователю, когда он «фокусируется» на каком-либо участке кликом. В файле от 1 до 12 (может быть, бывает больше, я не встречал) таких секций.
Размер RAW-файла 16МБ, web-оптимизированного 1МБ. Последний отличается тем, что хранит в себе набор картинок с картой, ставящей в соответствие координаты клика и номер картинки. Полное побайтовое описание формата можно найти здесь.
RAW
Сам RAW-файл представляет собой данные с матрицы. Мы видим фильтр Байера матрицы, перед которыми расположены микролизны:
Обработка
Самое интересное – это обработка. Процесс полностью описан в работах Ren Ng, я изобразил его схематически:
Сначала происходит демозаик RAW-файла традиционными методами. После этого световое поле приводится к такому состоянию, чтобы «соты» (микролизны) попадали на целое число пикселей, для этого надо слегка повернуть и смасштабировать картинку (это самый трудный этап, требующий кропотливой настройки: у меня пока что так и не получилось его выполнить).
Затем световое поле интегрируется с определёнными параметрами и на выходе получается набор картинок с разным расстоянием фокусировки. Замечу, что софт сам выбирает, куда сфокусироваться и сколько изображений надо получить: пока нет возможности настроить это.
Полученный файл упаковывается и заливается в Интернет. При клике пользователя на одном из участков файла («фокусировка») приложение смотрит по карте, какое это изображение, и показывает его. Это карта глубины, но она очень грубая, в практических целях с таким разрешением, скорее всего, она вам покажется слишком маленькой.
Постобработка
Хорошо, когда можно что-то подправить в Фотошопе. Можно и тут, но с оговоркой.
Т.к. формат lytro описан, несложно написать скрипт, который будет уметь экспортировать все части lfp-файла. Workflow таков:
- Разбираем lfp;
- Редактируем картинки. Да, Ивана Говнова придётся убирать не один раз, а ровно столько, сколько картинок в контейнере;
- Собираем lfp обратно. Тут надо учесть, что необходимо посчитать все sha1-хеши, в том числе и обновить их в TableOfContents-секции, после чего пересчитать хеш от неё самой;
- Запускаем приложение Lytro, которое при клике на этот файл понимает, что он изменился, и обновляет его превьюшку.
Вуаля, Lytro+Instagram-овский фильтр:
О световых полях и пленоптической фотографии
В классической камере свет, приходящий с разных точек линзы в одну точку матрицы, интегрируется и сохраняется как значение яркости пикселя в этой точке. В пленоптической же камере перед матрицей стоит массив микролинз:
Каждая микролинза распределяет пришедшие в неё световые лучи в разные участки матрицы:
Диафрагма f/2 выбрана не случайно. Она позволяет наиболее экономно расходовать матрицу. Если взять меньше, на матрице будут неиспользуемые пиксели, если больше – проецируемые изображения будут пересекаться, что недопустимо:
Световое поле в пространстве описывается функцией в пятимерном пространстве:
Как видим, световое поле описывает энергетическую яркость (radiance) для каждой точки пространства и для каждого направления луча из этой точки.
Эта функция может быть задана несколькими способами:
На плоскости:
На сфере:
Между двумя плоскостями:
Как раз последний способ описания светового поля и применяется в lytro: две плоскости – это плоскость задней стенки объектива и плоскость матрицы.
Световое поле можно получить при помощи массива камер:
Пленоптическую камеру можно представить как частный случай массива камер: роль камеры выполняет микролинза.
Для получения фотографии необходимо проинтегрировать данные с камер (или в случае lytro, данные с участков микролинз):
В зависимости от способа выбора точек в пределах окна, есть два преобразования:
Смещение наблюдателя – это выбор конкретной точки внутри микролинзы:
Цифровая рефокусировка – выбор способа суммируемых точек с участков каждой микролинзы. Так как под микролинзой мало пикселей, в случае lytro возможности рефокусировки весьма ограничены:
Теорема
Имея пленоптическую камеру с апертурой f/N, у которой каждой микролизне соответствует PxP пикселей, можно получить изображение, эквивалентное по резкости полученному на классическую камеру с апертурой f/(N*P). Для Lytro это около f/14.
Другая интерпретация этой же теоремы:
Описанная в теореме пленоптическая камера позволяет получить изображения с глубиной резкости f/N, сфокусированные в любом месте в пределах ГРИП классической камеры с апертурой f/(N*P).
Трудности обработки
При обработке встречается несколько преград, осложняющих написание визуализатора светового поля:
- Микролинзы расположены неровно. Надо калибровать алгоритм;
- Надо исключать влияние виньетирования. Но вспоминая, что под микролинзой всего-то порядка 50 пикселей, становится понятным, что эта операция может выдать большую погрешность;
- Битые пиксели. Как и в любой другой камере, здесь они тоже есть. Их нужно определять статистически, чтобы они не портили карту глубины;
- Производительность. Вычисления необходимо производить в частотном домене, используя 4D-преобразование Фурье.
Боке
Размытие в камере вот такое (это картинки из одного снимка, вытянутые из lfp):
Для сравнения сделал ещё одинаковый кадр на lytro (слева) и на зеркалку на f/2 (справа):
Артефакты
Практически на всех снимках вылезают неестественные артефакты разного рода. Например, такие:
Душераздирающее зрелище.
Инструменты для работы с lytro
Lytro.Net: умеет открывать lfp и экспортировать их части, есть и консольная версия:
Lytro compatible viewer: открывает файлы, позволяет сфокусироваться по клику, есть слайдер расстояния фокусировки:
Размышления
Инструментов, умеющих работать со световыми полями, я не нашёл. Всё, что есть – работа с .lfp-форматом: отображение, экспорт в jpeg.
После прочтения работ Ren Ng технология уже не кажется такой мистической и нереальной, как казалась в начале.
Один и тот же формат файлов с одним и тем же magic-ом – определённо зло. Не понимаю, зачем так сделали.
Если вы желаете поработать с raw-ом, я могу прислать его вам (а могу и камеру продать чуть попозже).
Картинки
Все «живые» фотки из статьи доступны на lytro.com:
Уже второй день сайт lytro вечером лежит. На всякий случай залил lfp на файл-хостинг, они открываются этим.
Ссылки
Про lytro:
Reverse Engineering the Lytro .LFP File Format — простое понятное описание how-to-hack
lfptools — утилита для работы с файлами lytro на C
Lytro.Net — порт lfptools на C#
Lytro meltdown — няшный gui для работы с файлами lytro на c#, структура SQLite-овской базы lytro, формат файлов
The (New) Stanford Light Field Archive — примеры световых полей, полученные с нескольких камер, можно поиграться online
Lytro Teardown — тут разбирают Lytro, можно посмотреть всю электронику
Работы Ren Ng о световых полях:
Light Field Sensing — световые поля в картинках; не понять это описание сложно
Fourier Slice Photography — теоретическое описание техники световых полей
Light Field Photography with a Hand-held Plenoptic Camera — как применить технику световых полей в фотографии
LightShop: Interactive Light Field Manipulation and Rendering — немного о том, как представить информацию светового поля визуально
Автор: Antelle