Converter temperatura de cor (K) em RGB: algoritmo e exemplo de código



Se você não sabe o que é a temperatura da cor, comece aqui .

Enquanto trabalhava na ferramenta Temperatura da cor do PhotoDemon , passei a noite inteira tentando determinar um algoritmo simples e claro para a conversão entre valores de temperatura (em Kelvin) e RGB. Eu pensei que esse algoritmo seria fácil de encontrar, porque muitos editores de fotos têm ferramentas para corrigir a temperatura da cor e, em todas as câmeras modernas, incluindo smartphones, há um ajuste de balanço de branco com base nas condições de iluminação.


Um exemplo de tela de câmera com uma configuração de balanço de branco. Fonte

Descobriu-se que encontrar uma fórmula confiável para converter temperatura em RGB é quase impossível. Obviamente, existem alguns algoritmos, mas a maioria deles funciona convertendo a temperatura no espaço de cores XYZ, ao qual você pode adicionar a transformação RGB. Tais algoritmos parecem basear-se no método Robertson, cuja implementação está aqui e a outra está aqui .

Infelizmente, essa abordagem não fornece uma fórmula puramente matemática - é simplesmente interpolação de acordo com a tabela de conversão. Isso pode ser razoável em certas circunstâncias, mas se você levar em consideração a conversão adicional XYZ → RGB, ela ficará muito lenta para um simples ajuste da temperatura da cor em tempo real.

Então, eu escrevi meu próprio algoritmo, e funciona muito bem. É assim que eu entendi.

Avisos sobre este algoritmo


Aviso 1 : meu algoritmo fornece uma aproximação de alta qualidade, mas não é precisa o suficiente para uso científico sério. Destina-se principalmente à manipulação de fotografias - portanto, não tente usá-lo para astronomia ou medicina.

Aviso 2 : devido à sua relativa simplicidade, esse algoritmo é rápido o suficiente para trabalhar em tempo real em imagens de tamanho razoável (testei-o em imagens de 12 megapixels), mas, para obter melhores resultados, use otimizações matemáticas específicas da sua linguagem de programação. Eu mostro o algoritmo sem otimizações matemáticas para não complicá-lo.

Aviso 3 : o algoritmo é apenas para uso no intervalo de 1000 K a 40.000 K, o que é um bom intervalo para fotografia. (De fato, é muito maior do que o necessário na maioria das situações). Embora funcione para temperaturas fora desse intervalo, a qualidade diminuirá.

Agradecimentos especiais a Mitchell Charity


Primeiro, tenho que pagar muita dívida e agradecer a Mitchell Charity pelos dados iniciais que usei para criar esses algoritmos: um arquivo blackbody não processado . O Charity fornece dois conjuntos de dados, e meu algoritmo usa a função de correspondência de cores de 10 graus CIE 1964 . Uma discussão da função CIE 1931 de 2 graus com as correções de Judd Wos em comparação com o conjunto de 10 graus está além do escopo deste artigo, mas se você estiver interessado, poderá iniciar uma análise abrangente a partir desta página .

Algoritmo: saída de exemplo


Aqui está a saída do algoritmo na faixa de 1000 K a 40.000 K:


A saída do meu algoritmo é de 1000 K a 40.000 K. O ponto branco é de 6500 a 6600 K, o que é ideal para processar fotos em um monitor LCD moderno

Aqui está um instantâneo mais detalhado do algoritmo em uma gama interessante para fotografias de 1500 K a 15000 K:


O mesmo algoritmo, mas de 1500 K a 15000 K

Como você pode ver, as faixas são mínimas, o que é uma grande melhoria em relação às tabelas correspondentes acima. O algoritmo também faz um ótimo trabalho em preservar uma tonalidade amarela clara perto do ponto branco, o que é importante para simular a luz do dia nas fotos pós-processamento.

Como cheguei a esse algoritmo


O primeiro passo para obter uma fórmula confiável foi traçar os valores originais do corpo negro de Charity . Você pode baixar a planilha inteira no formato .ods do LibreOffice / OpenOffice (430 KB) .

Aqui estão os dados após a plotagem:


Dados de temperatura original (K) em RGB (sRGB), gráfico do LibreOffice Calc. Novamente, a conversão é baseada na função CMF de 10 graus CIE 1964. O ponto branco, conforme necessário, fica entre 6500 K e 6600 K (pico no lado esquerdo do gráfico). Fonte

É fácil perceber que existem várias seções que simplificam nosso algoritmo. Em particular:

  • Valores vermelhos abaixo de 6600 K são sempre 255
  • Valores azuis abaixo de 2000 K são sempre 0
  • Valores azuis acima de 6500 K são sempre 255

Também é importante observar que, para ajustar a curva aos dados, o verde é melhor visualizado como duas curvas separadas - uma para temperaturas abaixo de 6600 K e a outra para temperaturas acima deste ponto.

A partir desse momento, dividi os dados (sem os segmentos “sempre 0” e “sempre 255”) em componentes de cores separados. Em um mundo ideal, a curva pode ser ajustada para cada conjunto de pontos, mas, infelizmente, na realidade não é tão simples. Como existe uma forte incompatibilidade entre os valores de X e Y no gráfico - todos os valores de x são maiores que 1000 e são exibidos em 100 segmentos de ponto, enquanto os valores de y estão entre 255 e 0 - eu tive que transpor os dados x para obter o melhor ajuste. Para fins de otimização, primeiro dividi o valor x (temperatura) por 100 para cada cor e subtraí o quanto eu precisava se isso ajudasse muito na adaptação ao gráfico. Aqui estão os diagramas resultantes para cada curva, bem como a curva mais adequada e o valor correspondente do coeficiente de determinação (R ​​ao quadrado):









Peço desculpas pelo terrível kerning de fontes e dicas nos gráficos. O LibreOffice tem muitas vantagens, mas a incapacidade de suavizar fontes nos gráficos é completamente vergonhosa. Também não gosto de extrair diagramas de capturas de tela porque eles não têm opção de exportação, mas é melhor deixá-lo para mais tarde.

Como você pode ver, todas as curvas estão bem alinhadas, com valores do coeficiente de determinação acima de 0,9897. Eu poderia gastar mais tempo ajustando as curvas, mas isso é suficiente para processar fotos. Nem um único habitante dirá que as curvas não correspondem exatamente às observações idealizadas iniciais do corpo negro, certo?

Algoritmo


Aqui está o algoritmo em toda a sua glória.

Primeiro, pseudo-código:

     -  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 

Observe que no pseudo-código acima, Ln () significa o logaritmo natural . Observe também que você pode omitir a verificação se a cor for menor que 0, se a temperatura estiver sempre na faixa recomendada. (No entanto, você ainda precisa sair da seleção "se a cor for maior que 255").

Em relação ao código real, aqui está a função exata do Visual Basic que eu uso no PhotoDemon . Ainda não foi otimizado (por exemplo, os logaritmos serão muito mais rápidos com as tabelas de correspondência), mas pelo menos o código é conciso e legível:

 '   ( )  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 

A função foi usada para gerar a saída de amostra no início deste artigo, para garantir que funcione.

Imagens de exemplo


Aqui está um ótimo exemplo do que os ajustes de temperatura de cor podem fazer. A imagem abaixo - um pôster publicitário do True Blood da HBO - mostra espetacularmente o potencial para ajustar a temperatura da cor. À esquerda está o quadro original; à direita - ajuste a temperatura da cor usando o código acima. Com um clique, a cena noturna pode ser refeita à luz do dia.


Ajuste da temperatura da cor em ação

A ferramenta real de temperatura de cor no meu programa PhotoDemon é a seguinte:


Ferramenta de temperatura de cor PhotoDemon

Baixe o programa e assista-o em ação.

Atualização de outubro de 2014


O Renault Bedar fez uma excelente demonstração online para esse algoritmo. Obrigado Renault!

Atualização de abril de 2015


Obrigado a todos que sugeriram melhorias no algoritmo original. Sei que o artigo tem muitos comentários, mas vale a pena ler se você planeja implementar sua própria versão.

Quero destacar duas melhorias específicas. Primeiro, Neil B gentilmente forneceu a melhor versão para as funções originais de ajuste de curva, o que altera levemente os coeficientes de temperatura. As mudanças são descritas em detalhes em seu excelente artigo .

Em seguida, Francis Loch adicionou alguns comentários e exemplos de imagens, que são muito úteis se você deseja aplicar essas transformações às fotos. Suas modificações produzem uma imagem muito mais detalhada, como visto nos exemplos .

Source: https://habr.com/ru/post/pt427333/


All Articles