Как правильно извлечь яркость из изображения JPEG (гамма-коррекция и т. Д.)? - PullRequest
3 голосов
/ 20 января 2012

в двух словах: я не могу извлечь значимые значения интенсивности света из значений RGB из фотографий JPEG, и попытка учесть гамма-коррекцию или sRGB только ухудшает ситуацию.

Я занимаюсь игрушечным проектом, который включает обработку множества фотоизображений, снятых с помощью интервометра. По сути, я хочу сделать из них промежуток времени с некоторыми исправлениями, чтобы клипы были более аккуратными. Я использую Canon dSLR.

Мне нужна функция, которая, учитывая файл JPEG, вычисляет «среднюю яркость сцены». Результат должен быть простым числом; Не нужно выражать какие-либо абсолютные фотометрические единицы, я делаю только относительные сравнения. Так, например, вы делаете снимок какой-то комнаты, и функция возвращает, скажем, «5.0». Затем вы добавляете вторую лампочку к источнику, точно такого же типа, как и первая, расположенную рядом с ней, и снова снимаете. Функция должна теперь дать вам «10.0».

Итак, моя текущая реализация этой функции сочетает в себе несколько вещей: чувствительность ISO, выдержку, диафрагму (извлеченную из EXIF) и среднюю яркость изображения. Материал Exif, очевидно, важнее, потому что в автоматических режимах камера будет пытаться использовать такие-то и такие-то настройки, поэтому яркость изображения приближается к средней серой точке. Тем не менее, все настройки ISO / Затвора / Апертуры имеют разрешение 1/3 ступени или меньше, поэтому определение яркости изображения важно для «тонкой настройки».

Пока я делал это, я получал некоторые явно фиктивные результаты, и чем больше я копался, тем больше удивлялся. В итоге я поставил «почти серьезный» эксперимент:

Тестовая настройка: Простая стена в комнате, освещенная лампой накаливания, освещенность довольно ровная. Для сравнения результатов использовали две камеры: 5D с 50-миллиметровым основным, 350D с 35-миллиметровым основным. Расстояние до стены: около 3 метров. Все фотографии сняты с выдержкой 1/10 с. Настройки камеры: ручной, «точный режим» (без улучшений, без насыщенности или контрастности), Tungsten WB, без пользовательских функций, JPEG-Fine, цветовое пространство sRGB. Линзы не имеют фильтров. Подсветка не меняется, меняются только настройки ISO и диафрагмы. Вот результаты, которые я получил:

     Avg   Spd   ISO  Aperture
1. 0.3507, 0.10, 100, f/2.8
2. 0.5382, 0.10, 200, f/2.8
3. 0.3557, 0.10, 200, f/4.0
4. 0.2709, 0.10, 200, f/5.0
5. 0.2118, 0.10, 200, f/5.6
6. 0.1718, 0.10, 200, f/6.3
7. 0.1459, 0.10, 200, f/7.1
8. 0.1112, 0.10, 200, f/8.0
9. 0.0883, 0.10, 200, f/9.0

Первый столбец - это среднее значение пикселя (прямо из JPEG), усредненное по всему изображению, с преобразованием в оттенки серого как (R + G + B) / 3. Цвета нормализуются в диапазоне [0..1] путем деления диапазона [0..255] на 255. Таким образом, между 1) и 2) я только меняю настройки ISO, изображение должно стать в два раза ярче, но среднее значение пикселя увеличивается только на 53% (переэкспонированных областей нет).

2..3: диафрагма на одну ступень вниз, поэтому изображение должно стать наполовину менее ярким, поэтому 1) и 3) согласуются (дополнительная яркость, вероятно, связана с уменьшением виньетирования)

3..5: Опять же, один стоп вниз, 5) должен быть наполовину таким же ярким, как 3)

5..8: То же самое, должно быть наполовину (хотя в принципе это нормально).

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

Это без применения гамма-коррекции. Код для чтения JPEG написан на C ++ и в основном соответствует примеру кода IJG (утилита djpeg). Теперь JPEG сохраняет значения с гамма-коррекцией, поэтому значения пикселей следует рассматривать как значения в цветовом пространстве sRGB (получить исходные пиксели, преобразовать в [0..1] и применить sRGB-> линейное преобразование RGB . Давайте попробуем это:

     Avg   Spd   ISO  Aperture
1. 0.1140, 0.10, 100, f/2.8
2. 0.2746, 0.10, 200, f/2.8
3. 0.1175, 0.10, 200, f/4.0
4. 0.0682, 0.10, 200, f/5.0
5. 0.0424, 0.10, 200, f/5.6
6. 0.0287, 0.10, 200, f/6.3
7. 0.0213, 0.10, 200, f/7.1
8. 0.0133, 0.10, 200, f/8.0
9. 0.0092, 0.10, 200, f/9.0

Я также попробовал «простую» гамма-коррекцию (гамма = 2,2), результаты очень похожи на случай коррекции sRGB.

Так что я очень, очень озадачен. Может кто-нибудь объяснить, как интенсивность RGB от JPEG с камеры должна действительно интерпретироваться как, так как у меня нет идей:)

1 Ответ

8 голосов
/ 27 января 2012

Итак, тайна медленно раскрывалась, когда я читал дальше.

Хотя датчик камеры теоретически способен измерять линейную интенсивность света, он, очевидно, этого не делает, но вместо этого имитирует поведение фотопленки,который имеет хорошо известный нелинейный отклик (например, см. this , рисунок 3).Таким образом, кривая отклика dSLR далеко не линейна, а больше похожа на это:

exposure response on a digital camera

Поэтому получение абсолютной яркости сцены из значений пикселей нецелесообразно без точной калибровки.

Однако я только хотел отрегулировать яркость фотографий, и приблизительно правильная оценка яркости помогает мне, поэтому я продолжил реконструкцию передаточной функции моей камеры (Canon 350D):

log-linear response curve of Canon 350D's sensor

Точки данных белого цвета соответствуют различным значениям экспозиции при различных значениях диафрагмы (f / 22, f / 20, f / 18, f / 16 и т. Д. С шагом 1/3 ступени).Как и на предыдущем графике, ось X является логарифмической по входящей яркости, а ось Y является линейной по значениям пикселей (после гамма-коррекции).Предполагая, что график находится в единичном квадрате, я также рассчитал приближенную аппроксимирующую кривую с помощью полинома пятого порядка:

(((((- 6.76219 * x) + 12.0459) * x - 5.8683) * x + 1.72338) * x - 0.148753) * x + 0.0105364;

для x в [0,05, 1] ​​

Итак, если выПолучив необработанную («реальную») яркость, получаем значение пикселя, которое будет выглядеть следующим образом:

  1. Получите логарифм входной яркости и линейно преобразуйте его, чтобы у вас было 7⅓ ступеней экспозиции винтервал [0..1],
  2. Примените приведенный выше полином (хотя для интервала [0..0.05) вам потребуется специальная обработка).
  3. Примените сжатие sRGB.

Назовите это преобразование T , и весь рабочий процесс в моем приложении теперь работает следующим образом:

  1. Обрабатывайте входные изображения JPEG с помощью T -1 ,
  2. Результирующие значения хранятся в формате с плавающей запятой и обрабатываются как линейные значения RGB,
  3. Применить T непосредственно перед сохранениемрезультаты обратно в формате JPEG.
...