¿Cuáles son las diferencias prácticas cuando se trabaja con colores en un espacio RGB lineal frente a uno no lineal?

88

¿Cuál es la propiedad básica de un espacio RGB lineal y cuál es la propiedad fundamental de uno no lineal? Cuando se habla de los valores dentro de cada canal en esos 8 (o más) bits, ¿qué cambia?

En OpenGL, los colores son valores 3 + 1, y con esto me refiero a RGB + alfa, con 8 bits reservados para cada canal, y esta es la parte que entiendo claramente.

Pero cuando se trata de la corrección de gamma, no entiendo cuál es el efecto de trabajar en un espacio RGB no lineal.

Como sé cómo usar una curva en un software gráfico para la edición de fotos, mi explicación es que en un espacio RGB lineal se toman los valores como están, sin manipulación y sin función matemática adjunta, en lugar de eso cuando no es lineal cada uno El canal generalmente evoluciona siguiendo un comportamiento clásico de función de potencia.

Incluso si tomo esta explicación como la real, todavía no entiendo qué es un espacio lineal real, porque después del cálculo, todos los espacios RGB no lineales se vuelven lineales y, lo más importante de todo, no obtengo la parte donde no -El espacio de color lineal es más adecuado para el ojo humano porque al final todos los espacios RGB son lineales para lo que entiendo.

Conocido
fuente
En una nota práctica, puede especificar RGB lineal o estándar como su espacio de color en SVG y no tengo idea de cuál es el efecto, aparte del hecho de que esto parece ser importante :-)
Michael Mullany
@MichaelMullany, esta cosa lineal parece más una pista para el usuario que una cualidad distintiva real.
Ken
Algo que me ayudó: creo que fue un profesor de matemáticas el que me dijo "piensa en línea cuando escuches lineal". No estoy seguro de si esto ayuda a algo, pero para mí, fue un "¡Oh, sí!" momento
Joe Plante
Lectura relacionada sobre Gamma: ¿Necesito corregir gamma en la salida de color final?
legends2k

Respuestas:

229

Digamos que está trabajando con colores RGB: cada color se representa con tres intensidades o brillos. Tienes que elegir entre "RGB lineal" y "sRGB". Por ahora, simplificaremos las cosas ignorando las tres intensidades diferentes y asumiremos que solo tiene una intensidad: es decir, solo se trata de tonos de gris.

En un espacio de color lineal, la relación entre los números que almacena y las intensidades que representan es lineal. Prácticamente, esto significa que si duplicas el número, duplicas la intensidad (la claridad del gris). Si desea agregar dos intensidades juntas (porque está calculando una intensidad basada en las contribuciones de dos fuentes de luz, o porque está agregando un objeto transparente encima de un objeto opaco), puede hacerlo simplemente agregando el dos números juntos. Si está haciendo cualquier tipo de mezcla 2D o sombreado 3D, o casi cualquier procesamiento de imagen, entonces desea sus intensidades en un espacio de color lineal., por lo que puede sumar, restar, multiplicar y dividir números para tener el mismo efecto en las intensidades. La mayoría de los algoritmos de procesamiento y reproducción del color solo dan resultados correctos con RGB lineal, a menos que agregue pesos adicionales a todo.

Suena muy fácil, pero hay un problema. La sensibilidad del ojo humano a la luz es más fina a bajas intensidades que a altas intensidades. Es decir, si haces una lista de todas las intensidades que puedes distinguir, hay más oscuras que claras. Para decirlo de otra manera, puede distinguir los tonos oscuros de gris mejor que con los tonos claros de gris. En particular, si está usando 8 bits para representar su intensidad, y lo hace en un espacio de color lineal, terminará con demasiados tonos claros y no suficientes tonos oscuros. Obtienes bandas en tus áreas oscuras, mientras que en tus áreas claras, estás desperdiciando partes en diferentes tonos de casi blanco que el usuario no puede distinguir.

Para evitar este problema y aprovechar al máximo esos 8 bits, solemos utilizar sRGB . El estándar sRGB le indica una curva que debe usar para que sus colores no sean lineales. La curva es menos profunda en la parte inferior, por lo que puede tener más grises oscuros y más pronunciada en la parte superior, por lo que tiene menos grises claros. Si duplica el número, más del doble de intensidad. Esto significa que si suma colores sRGB, obtendrá un resultado más claro de lo que debería ser. En estos días, la mayoría de los monitores interpretan sus colores de entrada como sRGB. Por lo tanto, cuando coloque un color en la pantalla o lo almacene en una textura de 8 bits por canal, guárdelo como sRGB para aprovechar al máximo esos 8 bits.

Notarás que ahora tenemos un problema: queremos que nuestros colores se procesen en un espacio lineal, pero se almacenen en sRGB. Esto significa que termina haciendo conversión de sRGB a lineal en lectura y conversión de lineal a sRGB en escritura. Como ya dijimos que las intensidades lineales de 8 bits no tienen suficientes sombras, esto causaría problemas, por lo que hay una regla práctica más: no use colores lineales de 8 bits si puede evitarlo. Se está volviendo convencional seguir la regla de que los colores de 8 bits son siempre sRGB, por lo que hace su conversión de sRGB a lineal al mismo tiempo que amplía su intensidad de 8 a 16 bits, o de entero a punto flotante; de manera similar, cuando haya terminado su procesamiento de punto flotante, se reducirá a 8 bits al mismo tiempo que convierte a sRGB. Si sigue estas reglas,

Cuando esté leyendo una imagen sRGB y desee intensidades lineales, aplique esta fórmula a cada intensidad:

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

En el sentido contrario, cuando desee escribir una imagen como sRGB, aplique esta fórmula a cada intensidad lineal:

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 )

En ambos casos, el valor del punto flotante varía de 0 a 1, por lo que si está leyendo números enteros de 8 bits, primero desea dividirlos por 255, y si está escribiendo números enteros de 8 bits, desea multiplicarlos por 255. por último, de la misma manera que lo haría normalmente. Eso es todo lo que necesita saber para trabajar con sRGB.

Hasta ahora, me he ocupado de una sola intensidad, pero hay cosas más inteligentes que hacer con los colores. El ojo humano puede diferenciar los diferentes brillos mejor que los diferentes tintes (más técnicamente, tiene una mejor resolución de luminancia que la crominancia), por lo que puede hacer un uso aún mejor de sus 24 bits almacenando el brillo por separado del tinte. Esto es lo que intentan hacer las representaciones YUV, YCrCb, etc. El canal Y es la luminosidad general del color y utiliza más bits (o tiene más resolución espacial) que los otros dos canales. De esta manera, no es necesario (siempre) aplicar una curva como lo hace con las intensidades RGB. YUV es un espacio de color lineal, por lo que si duplica el número en el canal Y, duplica la luminosidad del color, pero no puede agregar o multiplicar los colores YUV juntos como puede hacerlo con los colores RGB, así que '

Creo que eso responde a tu pregunta, así que terminaré con una breve nota histórica. Antes de sRGB, los CRT antiguos solían tener una no linealidad incorporada. Si duplicara el voltaje de un píxel, duplicaría la intensidad. Cuánto más fue diferente para cada monitor, y este parámetro se llamó gamma . Este comportamiento fue útil porque significaba que podía obtener más sombras que luces, pero también significaba que no podía saber qué tan brillantes serían sus colores en el CRT del usuario, a menos que lo calibrara primero. Corrección gammasignifica transformar los colores con los que comienza (probablemente lineales) y transformarlos para la gamma del CRT del usuario. OpenGL proviene de esta era, por lo que su comportamiento sRGB a veces es un poco confuso. Pero los proveedores de GPU ahora tienden a trabajar con la convención que describí anteriormente: que cuando estás almacenando una intensidad de 8 bits en una textura o framebuffer, es sRGB, y cuando estás procesando colores, es lineal. Por ejemplo, un OpenGL ES 3.0, cada framebuffer y textura tiene un "indicador sRGB" que puede activar para habilitar la conversión automática al leer y escribir. No es necesario que realice una conversión sRGB o una corrección gamma de forma explícita.

Dan Hulme
fuente
6
respuesta increíble, gracias, siempre es increíble ver las cosas explicadas, solo pediría un libro o un recurso que en su opinión sea lo suficientemente bueno para este tema, los espacios de color y cuáles son las fórmulas que se usan para hacer la conversión sRGB <-> lineal o cuál es la función que puede aproximar este comportamiento.
Ken
Me temo que no conozco ningún buen libro o recurso. La página de Wikipedia es completa e incluye todas las cosas sobre el punto blanco y lo pequeña que es la gama (que no he mencionado, ya que la mayoría de la gente no necesita saberlo), pero eso la hace un poco impenetrable. .
Dan Hulme
1

No soy un "experto en detección de color humana", pero he encontrado algo similar en la conversión YUV-> RGB. Hay diferentes pesos para los canales R / G / B, por lo que si cambia el color de origen en x, los valores RGB cambian en cantidades diferentes.

Como dije, no soy un experto, de todos modos, creo que, si desea hacer una transformación de color correcto, debe hacerlo en el espacio YUV, luego convertirlo a RGB (o hacer la operación matemáticamente equivalente en RGB, tenga cuidado de pérdida de datos). Además, no estoy seguro de que YUV sea la mejor representación nativa de colores, pero las cámaras de video proporcionan ese formato, ahí es donde encontré el problema.

Aquí está la fórmula mágica YUV-> RGB con números secretos incluidos: http://www.fourcc.org/fccyvrgb.php

ern0
fuente
1
Tenga cuidado con las conversiones RGB <-> YUV y viceversa. No estoy seguro de si esto es así en todos los casos, pero el espacio de color YUV a veces se convierte en un rango de 16-235 en lugar del 0-255 en RGB de 24 bits. Por lo tanto, puede perder datos cada vez que realiza una conversión de espacio de color. La mayoría de la gente tiende a decir que se mantenga dentro del mismo espacio de color si puede evitarlo.
Joe Plante