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

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


Пример экрана камеры с установкой баланса белого. Источник

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

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

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

Предупреждения относительно этого алгоритма


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

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

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

Особая благодарность Митчеллу Чарити


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

Алгоритм: пример выдачи


Вот выдача алгоритма в диапазоне от 1000 К до 40000 К:


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

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


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

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

Как я пришёл к этому алгоритму


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

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


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

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

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

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

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

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

Дополнение, октябрь 2014


Рено Бедар сделал отличное онлайн-демо для этого алгоритма. Спасибо, Рено!

Дополнение, апрель 2015


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

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

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

Комментарии (26)


  1. GeMir
    22.10.2018 20:28

    не пытайтесь использовать его для астрономии или в медицине.
    Чем интересна цветовая температура астрономам примерно понятно, а вот про медицину не напишет ли кто-нибудь?


    1. BD9
      22.10.2018 21:25
      +2

      Навскидку: диагностика кожных заболеваний (особенно — рака) по состоянию кожных покровов. Нужны методы определения степени красноты (ну и других цветов) для передачи изображения между врачами. Телемедицина и пр. (нужно получить одинаковое изображение на разных устройствах).
      Плюс — машинное обучение (диагностика по снимкам).
      Вопрос «при какой степени покраснения горла (которое и так всегда красное) имеется воспаление» пока что решается обучением нейронной сети в мозге врача с помощью другого врача.


      1. nae
        23.10.2018 13:44

        А может просто тепловизором глянуть?


      1. vics001
        23.10.2018 15:40

        Но ведь цвета зависят (точка белого) от освещения в помещении, неужели они каждый раз калибруют мониторы?


  1. Moskus
    22.10.2018 22:06

    Сюда стоит посылать тех студентов и школьников-двоечников с Тостера, которые постоянно задают там вопросы «нужна ли программисту математика», пытаясь найти оправдание своей лени.
    Или тех, кто просит «простую формулу» для вычислений из предметной области, которую они совершенно не понимают.


    1. AngReload
      23.10.2018 11:14

      Где тут математика-то? Самое сложное в статье — возведение в степень. Всё о чём шла речь — это приближение графика формулой a * x ^ b + c.


      1. Kirhgoff
        24.10.2018 01:32

        Ну а чем это не математика?


  1. kAIST
    22.10.2018 22:08

    Спасибо за полезную статью. В фоторедакторах, кстати, это очень редкий инструмент. Даже в фотошопе его нет (вернее есть, но запрятан в очень не очевидное место).


  1. CKOPOCTb
    22.10.2018 23:18
    -2

    Ах как лайкнуть хочется, да кармы нет((


    1. CKOPOCTb
      23.10.2018 01:54
      -1

      эээ, я серьезно. Давно эта тема интересовала.


  1. AEP
    23.10.2018 00:05

    Вообще-то существует два распространенных стандарта на цветовую температуру (blackbody и daylight). Было бы неплохо явно указать, и поближе к началу статьи, какой именно стандарт используется. Или реализовать оба.

    Упс, стандартов целых три, не знал про TM-30.

    www.waveformlighting.com/tech/calculate-cie-1931-xy-coordinates-from-cct


  1. Refridgerator
    23.10.2018 07:06

    Непонятно, как собственно коррекция изображения происходит. Ну, преобразовали температуру в RGB, а что с ним дальше делать — складывать, умножать?
    Или надо сначала RGB в температуру преобразовать, сдвинуть, и обратно температуру в RGB. Но в статье преобразование RGB в температуру не рассматривается, или я что-то пропустил?


    1. yurisv3
      23.10.2018 08:12

      В статье и НЕ рассматривается алгоритм КОРРЕКЦИИ. Ее предмет — получение RGB БЕЛОЙ точки для заданной цветовой температуры.

      Как ее использовать — по ссылкам, там исходники. При этом коррекция по понятным (вроде как, мне так точно) причинам идет не в RGB, а в HSL. В RGB можно, если исходное изображение камерный RAW, тогда RGB белой точки — напрямую коэффициенты для камерных RGB.


  1. huginn
    23.10.2018 08:55
    +1

    Кхм, RGB — величина относительная, она не имеет физической привязки.
    Значения RGB показывают процент (ок. не процент про256) от диапазона измерения датчиков измеряющего устройства, в цветовых координатах конкретного измеряющего устройства.
    Абсолютный физический смысл имеют значения в цветовых координатах CIE Lab.
    Соответственно могу порекомендовать прочитать про CIE Lab, про спектрофотометры, в частности Gretag Macbeth (Xrite) iOne и про icc цветовые профиля устройств.
    В данный момент, МНЕ КАЖЕТСЯ, вы изобретаете велосипед, давным давно изобретенный и лет пятнадцать используемый в полиграфии.


    1. yurisv3
      23.10.2018 09:13
      -1

      А мне кажется — чукча не читатель. От слова «совсем».
      «вы изобретаете велосипед» — это к кому вы вот сейчас обращаетесь, на секундочку?


      1. katzen
        23.10.2018 11:30
        +1

        huginn вообще-то абсолютно прав. RGB — профилезависимое пространство, цветов RGB вне описываемой системы координат, то есть профилируемых излучателей, не существует.


        1. yurisv3
          23.10.2018 12:09
          -1

          Если человек не в состоянии увидеть значок «Перевод» — что вообще обсуждать, он там ничего не понял и не факт, что вообще прочитал (как и вы, кстати)?

          Статья не о RGB значениях пикселей, а о коэффициентах для каналов R, G и B.

          Которые и есть собственно «Баланс Белого». Но поскольку в нашей жизни пользоваться «2.573242 1.000000 1.267578» не так удобно, как «6285(К) 1.011(Тинт)», человек подобрал аппроксимирующий полином, чтобы в своей программе обойтись одним движком «Температура».

          Все. Что непонятно? Что у цветового сдвига относительно «потолочного» 6500, как он делает, неизбежна погрешность — тем больше, чем насыщенней цвет — ну так начинает с этого, «он недостаточно точен для серьёзного научного использования». Как инструмент в фоторедакторе, где коррекция делается «на глаз» с получением приемлемого на вид результата — никаких проблем.


          1. katzen
            24.10.2018 02:41

            … что вообще прочитал (как и вы, кстати)?

            Я как раз прочитал ровно до тех пор, как стал искать слово «профиль» в статье. Вот только переводить плохо написанное или неполностью понятое не стоит.

            … относительно «потолочного» 6500

            Что вы сейчас имели в виду? 6500 на потолке или 6500 как максимальное?

            Все. Что непонятно?

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


    1. JewelFox
      23.10.2018 10:47
      -1

      Абсолютный физический смысл имеют значения в цветовых координатах CIE Lab

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


      1. yurisv3
        23.10.2018 11:08

        Объясняю.

        Одинаковые приборно измеренные значения цвета мотков пряжи, произведенных на разных заводах (или одним заводом, но разное время), глаз (независимо чей) видит одного цвета, и связанный из них свитер не демонстрирует границ — где закончилось одно и началось другое.

        Таких миллион примеров.


        1. JewelFox
          23.10.2018 12:54

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


      1. huginn
        24.10.2018 01:23

        Когда вы разберетесь с тем, что такое свет и цвет, что такое субтрактивная и аддитивная цветовые модели, что такое спектр излучения и спектр поглощения, то вам сразу станет легче.
        Когда вы прочитаете про стандартные излучатели (A, B, C, D50, D65 и тд) вам полегчает ещё больше.
        Потом уже можно будет порассуждать в чем разница между белым листом освещенным желтым светом и желтым листом освещенным белым светом.
        А ещё там есть такая штука как дельта Е…


        1. JewelFox
          24.10.2018 19:49

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

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


          1. huginn
            25.10.2018 03:05

            >И именно поэтому коробит от приписывания физического смысла цвету.

            Если вас от чего то коробит то это повод сходить к психологу или попить успокаивающих препаратов. Спектр излучения и спектр поглощения однако же никуда не делись и вполне позволяют производить математические и аналитические операции со столь коробящим вас понятием «цвет».

            >А менторским тоном писать комментарии не надо, а то возникает ощущение, что у вас большущее такое чувство собственной компетентности в данном вопросе.

            Я не нуждаюсь в ваших оценках своей компетентности и своего тона. Если я сделал ошибку — исправьте, покажите где ошибка и объясните почему ошибка. Я же вам первым спасибо и скажу. Ваши же личные обиды и проекции оставьте при себе, я в них не нуждаюсь. Ну и фразы типа «ты неправ потому что мне не нравится» тоже оставьте при себе.

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


    1. katzen
      23.10.2018 11:34
      +1

      Абсолютный физический смысл имеют значения в цветовых координатах CIE Lab.

      Я бы уточнил: психофизиологический, а не физический.

      Статья на самом деле страдает от того, что автор не ознакомился в должном объёме с теорией цвета.


      1. arabesc
        23.10.2018 16:29

        Конечно, есть некоторые алгоритмы, но большинство из них работают путём преобразования температуры в цветовое пространство XYZ, к которому вы потом можете добавить преобразование RGB.
        Автор пытался, но не осилил. В общем, понятно, что от ФотоДемона и его магии цвета нужно держаться подальше.
        Статья — говно, такой мусор нужно выпиливать из интернета, чтобы никто не тратил время попусту. А тут кто-то рейтнг даже накручивает мракобесию, печаль…