Quais são as diferenças práticas ao trabalhar com cores em um espaço RGB linear vs. não linear?

88

Qual é a propriedade básica de um espaço RGB linear e qual é a propriedade fundamental de um espaço não linear? Ao falar sobre os valores dentro de cada canal nesses 8 (ou mais) bits, o que muda?

Em OpenGL, as cores são 3 + 1 valores, e com isso quero dizer RGB + alpha, com 8 bits reservados para cada canal, e essa é a parte que entendo claramente.

Mas quando se trata de correção de gama, não entendo qual é o efeito de trabalhar em um espaço RGB não linear.

Como eu sei como usar uma curva em um software gráfico para edição de fotos, minha explicação é que em um espaço RGB linear você pega os valores como eles são, sem manipulação e sem função matemática anexada, em vez de quando é não linear cada o canal geralmente evolui seguindo um comportamento clássico de função de potência.

Mesmo se eu tomar esta explicação como a real, eu ainda não entendo o que é um espaço linear real, porque após a computação todos os espaços RGB não lineares se tornam lineares e o mais importante de tudo, eu não entendo a parte onde um não - O espaço de cor linear é mais adequado para o olho humano porque no final todos os espaços RGB são lineares, pelo que eu entendo.

Ken
fonte
Em uma nota prática, você pode especificar RGB linear ou padrão como seu espaço de cor em SVG e eu não tenho ideia de qual é o efeito, além do fato de que isso parece ser importante :-)
Michael Mullany
@MichaelMullany essa coisa linear parece mais uma dica para o usuário do que uma qualidade realmente distinta.
Ken,
Algo que me ajudou: acho que foi um professor de matemática que me disse "pense linha quando ouvir linear". Não tenho certeza se isso ajuda, mas para mim, foi um "Oh sim!" momento
Joe Plante
Leitura relacionada no Gamma: Preciso corrigir o gamma na saída de cores final?
legends2k

Respostas:

229

Digamos que você esteja trabalhando com cores RGB: cada cor é representada com três intensidades ou brilhos. Você tem que escolher entre "RGB linear" e "sRGB". Por enquanto, vamos simplificar as coisas ignorando as três diferentes intensidades e assumir que você tem apenas uma intensidade: ou seja, você está lidando apenas com tons de cinza.

Em um espaço de cores linear, a relação entre os números que você armazena e as intensidades que eles representam é linear. Praticamente, isso significa que se você dobrar o número, dobrará a intensidade (a claridade do cinza). Se você quiser adicionar duas intensidades juntas (porque está calculando uma intensidade com base nas contribuições de duas fontes de luz ou porque está adicionando um objeto transparente em cima de um objeto opaco), você pode fazer isso apenas adicionando o dois números juntos. Se você está fazendo qualquer tipo de combinação 2D ou sombreamento 3D, ou quase qualquer processamento de imagem, então você quer suas intensidades em um espaço de cor linear, então você pode apenas adicionar, subtrair, multiplicar e dividir os números para ter o mesmo efeito nas intensidades. A maioria dos algoritmos de processamento de cores e renderização só fornecem resultados corretos com RGB linear, a menos que você adicione pesos extras a tudo.

Parece muito fácil, mas há um problema. A sensibilidade do olho humano à luz é melhor em baixas intensidades do que em altas intensidades. Ou seja, se você fizer uma lista de todas as intensidades que consegue distinguir, há mais intensidades escuras do que claras. Em outras palavras, você pode diferenciar os tons escuros de cinza melhor do que os tons de cinza claros. Em particular, se você estiver usando 8 bits para representar sua intensidade, e fizer isso em um espaço de cor linear, você acabará com muitos tons claros e poucos tons escuros. Você obtém faixas nas áreas escuras, enquanto nas áreas claras, você está desperdiçando pedaços em diferentes tons de quase branco que o usuário não consegue distinguir.

Para evitar esse problema e fazer o melhor uso desses 8 bits, costumamos usar sRGB . O padrão sRGB indica uma curva a ser usada para tornar as cores não lineares. A curva é mais rasa na parte inferior, então você pode ter mais cinzas escuros e mais íngreme na parte superior, então você tem menos cinza claro. Se você dobrar o número, mais do que dobrará a intensidade. Isso significa que, se você adicionar cores sRGB, obterá um resultado mais claro do que deveria. Atualmente, a maioria dos monitores interpreta suas cores de entrada como sRGB. Portanto, ao colocar uma cor na tela ou armazená-la em uma textura de 8 bits por canal, armazene-a como sRGB , para que você faça o melhor uso desses 8 bits.

Você notará que agora temos um problema: queremos nossas cores processadas no espaço linear, mas armazenadas em sRGB. Isso significa que você acaba fazendo a conversão de sRGB em linear na leitura e a conversão de linear em sRGB na gravação. Como já dissemos, as intensidades lineares de 8 bits não têm escurecimento suficiente, isso causaria problemas, então há mais uma regra prática: não use cores lineares de 8 bits se puder evitar. Está se tornando convencional seguir a regra de que cores de 8 bits são sempre sRGB, então você faz sua conversão sRGB em linear ao mesmo tempo que amplia sua intensidade de 8 para 16 bits, ou de inteiro para ponto flutuante; da mesma forma, ao terminar o processamento de ponto flutuante, você reduz para 8 bits ao mesmo tempo que converte para sRGB. Se você seguir essas regras,

Quando você está lendo uma imagem sRGB e deseja intensidades lineares, aplique esta fórmula para cada intensidade:

float s = read_channel();
float linear;
if (s <= 0.04045) linear = s / 12.92;
else linear = pow((s + 0.055) / 1.055, 2.4);

Por outro lado, quando você quiser escrever uma imagem como sRGB, aplique esta fórmula para cada intensidade linear:

float linear = do_processing();
float s;
if (linear <= 0.0031308) s = linear * 12.92;
else s = 1.055 * pow(linear, 1.0/2.4) - 0.055; ( Edited: The previous version is -0.55 )

Em ambos os casos, o valor do ponto flutuante varia de 0 a 1, então se você estiver lendo inteiros de 8 bits, você deseja dividir por 255 primeiro, e se estiver escrevendo inteiros de 8 bits, você deseja multiplicar por 255 por último, da mesma forma que você normalmente faria. Isso é tudo que você precisa saber para trabalhar com sRGB.

Até agora, lidei com apenas uma intensidade, mas existem coisas mais inteligentes para fazer com as cores. O olho humano pode distinguir diferentes brilhos melhor do que tons diferentes (mais tecnicamente, tem melhor resolução de luminância do que crominância), então você pode fazer um uso ainda melhor de seus 24 bits, armazenando o brilho separadamente do matiz. Isso é o que as representações YUV, YCrCb etc. tentam fazer. O canal Y é a claridade geral da cor e usa mais bits (ou tem mais resolução espacial) do que os outros dois canais. Dessa forma, você não precisa (sempre) aplicar uma curva como faz com as intensidades RGB. YUV é um espaço de cor linear, então se você dobrar o número no canal Y, você dobra a luminosidade da cor, mas você não pode adicionar ou multiplicar as cores YUV juntas como você pode com as cores RGB, então '

Acho que isso responde à sua pergunta, então vou terminar com uma rápida nota histórica. Antes do sRGB, os CRTs antigos costumavam ter uma não linearidade incorporada. Se você dobrar a voltagem de um pixel, terá mais do que o dobro da intensidade. Quanto mais era diferente para cada monitor, e este parâmetro foi chamado de gama . Esse comportamento era útil porque significava que você poderia obter mais escuros do que luzes, mas também significava que você não poderia dizer o quão brilhantes seriam as cores no CRT do usuário, a menos que você o calibrasse primeiro. Correção de gamasignifica transformar as cores com as quais você começa (provavelmente lineares) e transformá-las para a gama do CRT do usuário. O OpenGL vem dessa era, e é por isso que seu comportamento sRGB às vezes é um pouco confuso. Mas os fornecedores de GPU agora tendem a trabalhar com a convenção que descrevi acima: quando você está armazenando uma intensidade de 8 bits em uma textura ou framebuffer, é sRGB, e quando você está processando cores, é linear. Por exemplo, um OpenGL ES 3.0, cada framebuffer e textura tem um "sinalizador sRGB" que você pode ativar para habilitar a conversão automática ao ler e gravar. Você não precisa fazer explicitamente a conversão de sRGB ou correção de gama.

Dan Hulme
fonte
6
resposta incrível, obrigado, é sempre incrível ver as coisas explicadas, eu só pediria um livro ou um recurso que na sua opinião seja bom o suficiente para este tópico, os espaços de cores, e quais são as fórmulas usadas para fazer a conversão sRGB <-> linear ou qual a função que pode aproximar este comportamento.
Ken,
Receio não saber de nenhum livro ou recurso bom. A página da Wikipedia é abrangente e inclui todo o material sobre o ponto branco e o quão pequena é a gama (que eu não mencionei, já que a maioria das pessoas não precisa saber sobre isso), mas isso a torna um pouco impenetrável .
Dan Hulme,
1

Eu não sou um "especialista em detecção de cores humanas", mas encontrei algo semelhante na conversão YUV-> RGB. Existem diferentes pesos para canais R / G / B, portanto, se você alterar a cor de origem em x, os valores RGB mudam em quantidades diferentes.

Como disse, não sou um especialista, de qualquer forma, acho que se você quiser fazer alguma transformação de cor correta, deve fazê-lo no espaço YUV, depois convertê-lo para RGB (ou fazer a operação matematicamente equivalente em RGB, cuidado de perda de dados). Além disso, não tenho certeza se YUV é a melhor representação nativa de cores, mas as câmeras de vídeo fornecem esse formato, é aí que encontrei o problema.

Aqui está a fórmula mágica YUV-> RGB com números secretos incluídos: http://www.fourcc.org/fccyvrgb.php

ern0
fonte
1
Tenha cuidado com as conversões RGB <-> YUV e vice-versa. Não tenho certeza se isso ocorre em todos os casos, mas o espaço de cores YUV às vezes se converte em um intervalo de 16-235 em vez de 0-255 em RGB de 24 bits. Portanto, você pode perder dados cada vez que fizer uma conversão do espaço de cores. A maioria das pessoas tende a dizer para manter o mesmo espaço de cores, se você puder evitar.
Joe Plante,