Как работает Lytro, или ещё один обзор

в 5:16, , рубрики: lytro, raw, гаджет, Гаджеты. Устройства для гиков, обработка изображений, фотография, Фототехника, хипстеры, метки: , , , ,

Как работает Lytro, или ещё один обзор
Lytro – пленоптическая камера, не требующая фокусировки, выпускаемая компанией Lytro (стартап Ren Ng – выпускника Стенфорда). Камера работает методом световых полей, о принципе работы которых я и постараюсь рассказать (под катом трафик!).
Картинки, где есть фотографии с lytro, кликабельны (но сайт lytro последнее время, бывает, лежит — наверное, ляжет и сейчас).

Камера

Полные спеки вы можете найти на сайте Lytro, про внешний вид рассказано в предыдущем обзоре. Сама камера сделана в Китае, подключается и заряжается через USB:
Как работает Lytro, или ещё один обзор

Дисплей сенсорный, обычного разрешения, вот тут он показывает, что камера заряжается:
Как работает Lytro, или ещё один обзор

Принцип работы прост: сверху зум (надо провести пальцем по резинке), сверху же кнопка затвора. Зум похож на 24-105mm.

Макро

Если камеру поднести близко к объекту, она не сфокусируется (да-да, и после съёмки тоже не фокусируется):
Как работает Lytro, или ещё один обзор

Чтобы это преодолеть, можно включить режим «creative mode». Он включается нажатием на белый квадратик:
Как работает Lytro, или ещё один обзор

В creative mode можно сфокусировать камеру нажатием на тач-скрин. Тыкнул на объект, камера подумала и сфокусировалась (автофокус, судя по всему, контрастный):
Как работает Lytro, или ещё один обзор

Сфокусироваться можно довольно-таки близко:
Как работает Lytro, или ещё один обзор

Ограничение creative mode в том, что после съёмки диапазон фокусировки будет ограничен.
Когда-то производитель обещали сделать встроенный focus stacking для макро. Сейчас такой фичи в камере нет, но это легко выполнить в фотошопе, достав картинки из lfp — как видим, ГРИП здесь значительно больше, чем до обработки:
Как работает Lytro, или ещё один обзор

Настройки

Никаких настроек в камере больше нет. Экспозицию камера устанавливает самостоятельно, повлиять на этот процесс нельзя (я заметил, что в EverydayMode экспозамер матричный, в CreativeMode центровзвешенный — но тоже как-то не всегда). Вот пара примеров:
Как работает Lytro, или ещё один обзор

В наиболее плохих условиях это будет ISO 3200, 1/15 (хотя странно: при наличии акселерометра можно было бы определить, что камера на штативе и поставить увеличить выдержку):
Как работает Lytro, или ещё один обзор

Софт

При подключении камеры копирует фотографии, позволяет повернуть их и залить на lytro.com.
Написан на Qt, хранит информацию в SQLite-базе, формат которой описан тут.
Совсем недавно вышел софт под win, что не может не радовать:
Как работает Lytro, или ещё один обзор

Формат

У 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 данные с матрицы. Открывается так:
    Как работает Lytro, или ещё один обзор
  • Depth lookup table: присутствует только в web-оптимизированном файле. Карта глубины. Отвечает на вопрос: если я тыкнул сюда, какую из картинок мне надо показать?
    Как работает Lytro, или ещё один обзор
  • Prerendered λ = %lambda%: присутствует только в web-оптимизированном файле. Это изображение, показываемое пользователю, когда он «фокусируется» на каком-либо участке кликом. В файле от 1 до 12 (может быть, бывает больше, я не встречал) таких секций.

Размер RAW-файла 16МБ, web-оптимизированного 1МБ. Последний отличается тем, что хранит в себе набор картинок с картой, ставящей в соответствие координаты клика и номер картинки. Полное побайтовое описание формата можно найти здесь.

RAW

Сам RAW-файл представляет собой данные с матрицы. Мы видим фильтр Байера матрицы, перед которыми расположены микролизны:
Как работает Lytro, или ещё один обзор

Обработка

Самое интересное – это обработка. Процесс полностью описан в работах Ren Ng, я изобразил его схематически:
Как работает Lytro, или ещё один обзор

Сначала происходит демозаик RAW-файла традиционными методами. После этого световое поле приводится к такому состоянию, чтобы «соты» (микролизны) попадали на целое число пикселей, для этого надо слегка повернуть и смасштабировать картинку (это самый трудный этап, требующий кропотливой настройки: у меня пока что так и не получилось его выполнить).
Затем световое поле интегрируется с определёнными параметрами и на выходе получается набор картинок с разным расстоянием фокусировки. Замечу, что софт сам выбирает, куда сфокусироваться и сколько изображений надо получить: пока нет возможности настроить это.
Полученный файл упаковывается и заливается в Интернет. При клике пользователя на одном из участков файла («фокусировка») приложение смотрит по карте, какое это изображение, и показывает его. Это карта глубины, но она очень грубая, в практических целях с таким разрешением, скорее всего, она вам покажется слишком маленькой.

Постобработка

Хорошо, когда можно что-то подправить в Фотошопе. Можно и тут, но с оговоркой.
Т.к. формат lytro описан, несложно написать скрипт, который будет уметь экспортировать все части lfp-файла. Workflow таков:

  1. Разбираем lfp;
  2. Редактируем картинки. Да, Ивана Говнова придётся убирать не один раз, а ровно столько, сколько картинок в контейнере;
  3. Собираем lfp обратно. Тут надо учесть, что необходимо посчитать все sha1-хеши, в том числе и обновить их в TableOfContents-секции, после чего пересчитать хеш от неё самой;
  4. Запускаем приложение Lytro, которое при клике на этот файл понимает, что он изменился, и обновляет его превьюшку.

Вуаля, Lytro+Instagram-овский фильтр: Как работает Lytro, или ещё один обзор

О световых полях и пленоптической фотографии

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

Каждая микролинза распределяет пришедшие в неё световые лучи в разные участки матрицы:
Как работает Lytro, или ещё один обзор

Диафрагма f/2 выбрана не случайно. Она позволяет наиболее экономно расходовать матрицу. Если взять меньше, на матрице будут неиспользуемые пиксели, если больше – проецируемые изображения будут пересекаться, что недопустимо:
Как работает Lytro, или ещё один обзор

Световое поле в пространстве описывается функцией в пятимерном пространстве:
Как работает Lytro, или ещё один обзор

Как видим, световое поле описывает энергетическую яркость (radiance) для каждой точки пространства и для каждого направления луча из этой точки.
Эта функция может быть задана несколькими способами:
На плоскости:
Как работает Lytro, или ещё один обзор Как работает Lytro, или ещё один обзор

На сфере:
Как работает Lytro, или ещё один обзор

Между двумя плоскостями:
Как работает Lytro, или ещё один обзор

Как раз последний способ описания светового поля и применяется в lytro: две плоскости – это плоскость задней стенки объектива и плоскость матрицы.
Световое поле можно получить при помощи массива камер:
Как работает Lytro, или ещё один обзор

Пленоптическую камеру можно представить как частный случай массива камер: роль камеры выполняет микролинза.
Для получения фотографии необходимо проинтегрировать данные с камер (или в случае lytro, данные с участков микролинз):
Как работает Lytro, или ещё один обзор

В зависимости от способа выбора точек в пределах окна, есть два преобразования:

Смещение наблюдателя – это выбор конкретной точки внутри микролинзы:
Как работает Lytro, или ещё один обзор
Как работает Lytro, или ещё один обзор

Цифровая рефокусировка – выбор способа суммируемых точек с участков каждой микролинзы. Так как под микролинзой мало пикселей, в случае lytro возможности рефокусировки весьма ограничены:
Как работает Lytro, или ещё один обзор
Как работает Lytro, или ещё один обзор

Теорема

Имея пленоптическую камеру с апертурой f/N, у которой каждой микролизне соответствует PxP пикселей, можно получить изображение, эквивалентное по резкости полученному на классическую камеру с апертурой f/(N*P). Для Lytro это около f/14.

Другая интерпретация этой же теоремы:

Описанная в теореме пленоптическая камера позволяет получить изображения с глубиной резкости f/N, сфокусированные в любом месте в пределах ГРИП классической камеры с апертурой f/(N*P).

Трудности обработки

При обработке встречается несколько преград, осложняющих написание визуализатора светового поля:

  1. Микролинзы расположены неровно. Надо калибровать алгоритм;
  2. Надо исключать влияние виньетирования. Но вспоминая, что под микролинзой всего-то порядка 50 пикселей, становится понятным, что эта операция может выдать большую погрешность;
  3. Битые пиксели. Как и в любой другой камере, здесь они тоже есть. Их нужно определять статистически, чтобы они не портили карту глубины;
  4. Производительность. Вычисления необходимо производить в частотном домене, используя 4D-преобразование Фурье.

Боке

Размытие в камере вот такое (это картинки из одного снимка, вытянутые из lfp):
Как работает Lytro, или ещё один обзор

Для сравнения сделал ещё одинаковый кадр на lytro (слева) и на зеркалку на f/2 (справа):
Как работает Lytro, или ещё один обзор

Артефакты

Практически на всех снимках вылезают неестественные артефакты разного рода. Например, такие:
Как работает Lytro, или ещё один обзор

Или такие:
Как работает Lytro, или ещё один обзор

Душераздирающее зрелище.

Инструменты для работы с lytro

Lytro.Net: умеет открывать lfp и экспортировать их части, есть и консольная версия:
Как работает Lytro, или ещё один обзор

Lytro compatible viewer: открывает файлы, позволяет сфокусироваться по клику, есть слайдер расстояния фокусировки:
Как работает Lytro, или ещё один обзор

Размышления

Инструментов, умеющих работать со световыми полями, я не нашёл. Всё, что есть – работа с .lfp-форматом: отображение, экспорт в jpeg.
После прочтения работ Ren Ng технология уже не кажется такой мистической и нереальной, как казалась в начале.
Один и тот же формат файлов с одним и тем же magic-ом – определённо зло. Не понимаю, зачем так сделали.
Если вы желаете поработать с raw-ом, я могу прислать его вам (а могу и камеру продать чуть попозже).

Картинки

Все «живые» фотки из статьи доступны на lytro.com:
Как работает Lytro, или ещё один обзор
Уже второй день сайт 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

* - обязательные к заполнению поля