graphics - what - ¿Cuáles son las diferencias prácticas cuando se trabaja con colores en un espacio RGB lineal vs. no lineal?
rgb image (2)
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 supongamos 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 doblas el número, doblas 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 hacer esto simplemente agregando el dos números juntos. Si está realizando cualquier tipo de combinación en 2D o sombreado 3D, o casi cualquier procesamiento de imagen, entonces quiere sus intensidades en un espacio de color lineal , por lo que puede simplemente sumar, restar, multiplicar y dividir números para tener el mismo efecto. en las intensidades. La mayoría de los algoritmos de procesamiento y procesamiento de color solo dan resultados correctos con RGB lineal, a menos que agregue pesos adicionales a todo.
Eso suena muy fácil, pero hay un problema. La sensibilidad del ojo humano a la luz es más fina a intensidades bajas que altas intensidades. Es decir, si haces una lista de todas las intensidades que puedes distinguir, hay más oscuras que ligeras. Para decirlo de otra manera, puedes diferenciar los tonos oscuros de gris mejor que con tonos de gris claro. En particular, si usa 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 las áreas claras, estás desperdiciando bits en diferentes tonos de casi blanco que el usuario no puede diferenciar.
Para evitar este problema, y hacer el mejor uso de esos 8 bits, tendemos a usar sRGB . El estándar sRGB te dice una curva para usar, para hacer que tus 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 doblas el número, tienes más del doble de la intensidad. Esto significa que si agrega colores sRGB juntos, terminará con un resultado que es más claro de lo que debería ser. Actualmente, 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, almacénelo como sRGB , de modo que haga el mejor uso de esos 8 bits.
Notarás que ahora tenemos un problema: queremos que nuestros colores se procesen en espacio lineal, pero almacenados en sRGB. Esto significa que terminará haciendo conversión sRGB a lineal en lectura, y conversión lineal a sRGB en escritura. Como ya hemos dicho que las intensidades lineales de 8 bits no tienen suficientes sombras, esto causaría problemas, por lo que hay una regla más práctica: no use colores lineales de 8 bits si puede evitarlo. Se está convirtiendo en convencional seguir la regla de que los colores de 8 bits siempre son sRGB, por lo que realiza su conversión de sRGB a lineal al mismo tiempo que amplía su intensidad de 8 a 16 bits, o de un número entero a uno flotante; de manera similar, cuando haya terminado su procesamiento de punto flotante, reducirá a 8 bits al mismo tiempo que convierte a sRGB. Si sigues estas reglas, nunca tendrás que preocuparte por la corrección gamma.
Cuando estés leyendo una imagen sRGB y quieras intensidades lineales, aplica 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);
Yendo para otro lado, cuando quiera 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 va de 0 a 1, por lo que si está leyendo números enteros de 8 bits, primero debe dividir entre 255, y si está escribiendo números enteros de 8 bits, quiere multiplicar por 255 último, de la misma manera que usualmente lo harías Eso es todo lo que necesita saber para trabajar con sRGB.
Hasta ahora, he tratado con una sola intensidad, pero hay cosas más inteligentes que hacer con los colores. El ojo humano puede diferenciar diferentes brillos mejor que los diferentes tintes (más técnicamente, tiene una resolución de luminancia mejor que la crominancia), por lo que puede hacer un mejor uso de sus 24 bits almacenando el brillo por separado del tono. Esto es lo que las representaciones de YUV, YCrCb, etc. intentan hacer. El canal Y es la claridad general del color y utiliza más bits (o tiene más resolución espacial) que los otros dos canales. De esta manera, no (siempre) necesita aplicar una curva como lo hace con las intensidades RGB. YUV es un espacio de color lineal, así que si doblas el número en el canal Y, doblas la luminosidad del color, pero no puedes agregar o multiplicar los colores YUV juntos como lo haces con los colores RGB, por lo que no se usa para procesamiento de imágenes, solo para almacenamiento y transmisión.
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 en ellos. Si duplicó el voltaje de un píxel, aumentaría más del doble la intensidad. Cuánto más era diferente para cada monitor, y este parámetro se llamaba gamma . Este comportamiento fue útil porque significaba que podía obtener más luces oscuras que luces, pero también significaba que no podía decir qué tan brillantes serían sus colores en la CRT del usuario, a menos que lo haya calibrado primero. La corrección Gamma significa transformar los colores con los que comienzas (probablemente lineales) y transformarlos para la gama del CRT del usuario. OpenGL proviene de esta época, por lo que su comportamiento sRGB a veces es un poco confuso. Pero los vendedores de GPU ahora tienden a trabajar con la convención que describí arriba: que cuando estás almacenando una intensidad de 8 bits en una textura o framebuffer, es sRGB, y cuando procesas 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 necesita realizar explícitamente conversión sRGB o corrección gamma.
¿Cuál es la propiedad básica de un espacio RGB lineal y cuál es la propiedad fundamental de un espacio 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 + alpha, con 8 bits reservados para cada canal, y esta es la parte que obtengo claramente.
Pero cuando se trata de la corrección 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 ni función matemática, en cambio, cuando no es lineal. el canal generalmente evoluciona siguiendo un comportamiento de función de potencia clásico.
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 es que 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.
No soy un "experto en detección de color humano", 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 por x, los valores RGB cambian en diferentes cantidades.
Como dije, no soy un experto, de todos modos, creo, si quieres hacer una transformación de color correcto, debes hacerlo en el espacio YUV, luego convertirlo a RGB (o hacer la operación matemáticamente equivalente en RGB, ten 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 brindan ese formato, ahí es donde he conocido el problema.
Aquí está la fórmula mágica YUV-> RGB con números secretos incluidos: http://www.fourcc.org/fccyvrgb.php