Хабрахабр

[Перевод] Преобразование цветовой температуры (K) в RGB: алгоритм и пример кода

Если вы не знаете, что такое цветовая температура, начните отсюда.

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

Пример экрана камеры с установкой баланса белого. Работая над инструментом «Цветовая температура» для PhotoDemon, я целый вечер пытался определить простой и понятный алгоритм преобразования между значениями температуры (в Кельвинах) и RGB. Источник

Конечно, есть некоторые алгоритмы, но большинство из них работают путём преобразования температуры в цветовое пространство XYZ, к которому вы потом можете добавить преобразование RGB. Оказалось, найти надёжную формулу преобразования температуры в RGB практически невозможно. Такие алгоритмы, похоже, основаны на методе Робертсона, одна реализация которого здесь, а другая здесь.

Это может быть разумно при определённых обстоятельствах, но если учесть дополнительное преобразование XYZ → RGB, то получается слишком медленно для простой регулировки цветовой температуры в реальном времени. К сожалению, такой подход не даёт чисто математической формулы — это просто интерполяция по таблице преобразования.

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

Предупреждение 1: мой алгоритм обеспечивает высококачественное приближение, но он недостаточно точен для серьёзного научного использования. Он предназначен в основном для манипуляций с фотографиями — так что не пытайтесь использовать его для астрономии или в медицине.

Я показываю алгоритм без математических оптимизаций, чтобы не усложнять его. Предупреждение 2: из-за своей относительной простоты этот алгоритм достаточно быстр для работы в реальном времени на изображениях разумного размера (я тестировал его на 12-мегапиксельных снимках), но для достижения наилучших результатов следует применить математические оптимизации, характерные для вашего языка программирования.

(На самом деле он намного больше, чем может потребоваться в большинстве ситуаций). Предупреждение 3: алгоритм предназначен только для использования в диапазоне от 1000 K до 40000 K, что является хорошим диапазоном для фотографии. Хотя он работает для температур и за пределами этого диапазона, но качество будет снижаться.

Во-первых, должен отдать большой долг и поблагодарить Митчелла Чарити за исходные данные, которые использовал для создания этих алгоритмов: необработанный файл чёрного тела. Чарити предоставляет два набора данных, и мой алгоритм использует 10-градусную функцию сопоставления цветов CIE 1964. Обсуждение 2-градусной функции CIE 1931 с исправлениями Джадда Воса по сравнению с 10-градусным набором выходит за рамки этой статьи, но если вам интересно, можете начать всесторонний анализ с этой страницы.
Вот выдача алгоритма в диапазоне от 1000 К до 40000 К:

Белая точка находится на 6500−6600 К, что идеально подходит для обработки фотографий на современном ЖК-мониторе
Выдача моего алгоритма от 1000 К до 40000 К.

Вот более подробный снимок алгоритма в интересном для фотографии диапазоне от 1500 К до 15000 К:


Тот же алгоритм, но от 1500 K до 15000 K

Алгоритм также делает большую работу по сохранению светло-жёлтого оттенка возле белой точки, что важно для имитации дневного света в постобработке фотографий. Как можно заметить, бандажирование полосами минимально, что является большим улучшением по сравнению с вышеупомянутыми таблицами соответствия.

Первым шагом к выведению надёжной формулы было построить график оригинальных значений чёрного тела от Чарити. Вы можете скачать всю электронную таблицу в формате LibreOffice/OpenOffice .ods (430 КБ).

Вот данные после построения графика:

Опять же, преобразование основано на 10-градусной CMF-функции CIE 1964.
Данные оригинальной температуры (K) в RGB (sRGB), график LibreOffice Calc. Источник Белая точка, как и требовалось, находится между 6500 K и 6600 K (пик в левой части графика).

В частности: Легко заметить, что есть несколько участков, которые упрощают наш алгоритм.

  • Красные значения ниже 6600 K всегда 255
  • Синие значения ниже 2000 K всегда 0
  • Синие значения выше 6500 K всегда 255

Ещё важно отметить, что для подгонки кривой под данные зелёный цвет лучше всего рассматривать как две отдельные кривые — одна для температур ниже 6600 K, а другая для температур выше этой точки.

В идеальном мире кривую можно подогнать к каждому набору точек, но, к сожалению, в реальности это не так просто. С этого момента я разделил данные (без сегментов «всегда 0» и «всегда 255») на отдельные цветовые компоненты. В целях оптимизации я сначала разделил значение x (температура) на 100 для каждого цвета, а затем вычел сколько нужно, если это значительно помогало в подгонке к графику. Поскольку на графике сильное несоответствие между значениями X и Y — все значения x больше 1000 и отображаются в 100 точечных сегментах, в то время как значения y находятся между 255 и 0 — пришлось транспонировать данные x, чтобы получить лучшее соответствие. Вот результирующие диаграммы для каждой кривой, а также наиболее подходящая кривая и соответствующее значение коэффициента детерминации (R-квадрат):

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

Я мог бы потратить больше времени на подгонку кривых, но для обработки фотографиями этого достаточно. Как видите, все кривые достаточно хорошо выровнены, со значениями коэффициента детерминации выше 0,987. Ни один обыватель не скажет, что кривые неточно соответствуют исходным идеализированным наблюдениям чёрного тела, верно?

Вот алгоритм во всей красе.

Во-первых, псевдокод:

Начнём с температуры в Кельвинах где-то между 1000 и 40000. (Другие значения могут работать, но я не могу дать никаких обещаний о качестве оценок алгоритма выше 40000 K). Обратите внимание, что переменные температуры и цвета должны быть объявлены как переменные с плавающей точкой. Set Temperature = Temperature \ 100 Вычисление красного: If Temperature <= 66 Then Red = 255 Else Red = Temperature - 60 Red = 329.698727446 * (Red ^ -0.1332047592) If Red < 0 Then Red = 0 If Red > 255 Then Red = 255 End If Вычисление зелёного: If Temperature <= 66 Then Green = Temperature Green = 99.4708025861 * Ln(Green) - 161.1195681661 If Green < 0 Then Green = 0 If Green > 255 Then Green = 255 Else Green = Temperature - 60 Green = 288.1221695283 * (Green ^ -0.0755148492) If Green < 0 Then Green = 0 If Green > 255 Then Green = 255 End If Вычисление синего: If Temperature >= 66 Then Blue = 255 Else If Temperature <= 19 Then Blue = 0 Else Blue = Temperature - 10 Blue = 138.5177312231 * Ln(Blue) - 305.0447927307 If Blue < 0 Then Blue = 0 If Blue > 255 Then Blue = 255 End If End If

Обратите внимание, что в приведённом псевдокоде Ln() означает натуральный логарифм. Также обратите внимание, что можно опустить проверки «если цвет меньше 0», если температуры всегда в рекомендуемом диапазоне. (Однако всё равно нужно оставить проверки «если цвет больше 255»).

Она ещё не оптимизирована (например, логарифмы стианут намного быстрее с таблицами соответствия), но хотя бы код краткий и читаемый: Что касается фактического кода, вот точная функция Visual Basic, которую я использую в PhotoDemon.

'Для данной температуры (в Кельвинах) вычисляем RGB-эквивалент Private Sub getRGBfromTemperature(ByRef r As Long, ByRef g As Long, ByRef b As Long, ByVal tmpKelvin As Long) Static tmpCalc As Double 'Температура должна быть в диапазоне от 1000 до 40000 градусов If tmpKelvin < 1000 Then tmpKelvin = 1000 If tmpKelvin > 40000 Then tmpKelvin = 40000 'Все вычисления требуют tmpKelvin \ 100, так что можно обойтись однократным преобразованием tmpKelvin = tmpKelvin \ 100 'Вычисляем все цвета по очереди 'Сначала красный If tmpKelvin <= 66 Then r = 255 Else 'Примечание: значение R-квадрата для этого приближения 0,988 tmpCalc = tmpKelvin - 60 tmpCalc = 329.698727446 * (tmpCalc ^ -0.1332047592) r = tmpCalc If r < 0 Then r = 0 If r > 255 Then r = 255 End If 'Затем зелёный If tmpKelvin <= 66 Then 'Примечание: значение R-квадрата для этого приближения 0,996 tmpCalc = tmpKelvin tmpCalc = 99.4708025861 * Log(tmpCalc) - 161.1195681661 g = tmpCalc If g < 0 Then g = 0 If g > 255 Then g = 255 Else 'Примечание: значение R-квадрата для этого приближения 0,987 tmpCalc = tmpKelvin - 60 tmpCalc = 288.1221695283 * (tmpCalc ^ -0.0755148492) g = tmpCalc If g < 0 Then g = 0 If g > 255 Then g = 255 End If 'Наконец, синий If tmpKelvin >= 66 Then b = 255 ElseIf tmpKelvin <= 19 Then b = 0 Else 'Примечание: значение R-квадрата для этого приближения 0,998 tmpCalc = tmpKelvin - 10 tmpCalc = 138.5177312231 * Log(tmpCalc) - 305.0447927307 b = tmpCalc If b < 0 Then b = 0 If b > 255 Then b = 255 End If End Sub

Функция использовалась для генерации образца выдачи в начале этой статьи, поэтому я могу гарантировать, что она работает.
Вот отличный пример того, что могут сделать регулировки цветовой температуры. Изображение ниже — рекламный плакат для сериала HBO «Настоящая кровь» — зрелищно демонстрирует потенциал регулировки цветовой температуры. Слева — исходный кадр; справа — регулировка цветовой температуры с помощью кода выше. Одним щелчком мыши ночную сцену можно переделать для дневного света.


Регулировка цветовой температуры в действии

Реальный инструмент цветовой температуры в моей программе PhotoDemon выглядит следующим образом:


Инструмент цветовой температуры PhotoDemon

Скачайте программу и посмотрите его в действии.

Рено Бедар сделал отличное онлайн-демо для этого алгоритма. Спасибо, Рено!
Спасибо всем, кто предложил улучшения оригинального алгоритма. Я знаю, что у статьи много комментариев, но их стоит прочитать, если вы планируете реализовать собственную версию.

Во-первых, Neil B любезно предоставил лучшую версию для исходных функций подгонки кривой, что слегка меняет температурные коэффициенты. Хочу выделить два конкретных улучшения. Изменения подробно описаны в его превосходной статье.

Его модификации производят гораздо более детальное изображение, что видно на примерах. Затем Фрэнсис Лох добавил некоторые комментарии и примеры изображений, которые очень полезны, если вы хотите применить эти преобразования к фотографиям.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть