Conversión de RGB a escala de grises/intensidad

Resuelto ypnos asked hace 15 años • 8 respuestas

Al convertir de RGB a escala de grises, se dice que se deben aplicar pesos específicos a los canales R, G y B. Estos pesos son: 0,2989, 0,5870, 0,1140.

Se dice que la razón de esto es la diferente percepción/sensibilidad humana hacia estos tres colores. A veces también se dice que estos son los valores utilizados para calcular la señal NTSC.

Sin embargo, no encontré una buena referencia para esto en la web. ¿Cuál es la fuente de estos valores?

Ver también estas preguntas anteriores: aquí y aquí .

ypnos avatar Mar 27 '09 02:03 ypnos
Aceptado

Los números específicos de la pregunta son del CCIR 601 (consulte el artículo de Wikipedia ).

Si convierte RGB -> escala de grises con números ligeramente diferentes/métodos diferentes, no verá mucha diferencia en una pantalla de computadora normal en condiciones de iluminación normales; pruébelo.

Aquí hay algunos enlaces más sobre el color en general:

wikipedia luma

El excelente sitio web de Bruce Lindbloom

capítulo 4 sobre Color en el libro de Colin Ware, "Visualización de información", isbn 1-55860-819-2; Este enlace largo a Ware en books.google.com puede funcionar o no.

cambridgeincolor : "tutoriales excelentes y bien escritos sobre cómo adquirir, interpretar y procesar fotografías digitales utilizando un enfoque visual que enfatiza el concepto sobre el procedimiento"

Si se topa con RGB "lineal" versus "no lineal", aquí hay parte de una vieja nota para mí sobre esto. Repito, en la práctica no verás mucha diferencia.


### RGB -> ^gamma -> Y -> L*

En la ciencia del color, los valores RGB comunes, como en html rgb (10%, 20%, 30%), se denominan "no lineales" o con corrección gamma . Los valores "lineales" se definen como

Rlin = R^gamma,  Glin = G^gamma,  Blin = B^gamma

donde gamma es 2,2 para muchas PC. Los RGB habituales a veces se escriben como R' G' B' (R' = Rlin ^ (1/gamma)) (clic de lengua de los puristas), pero aquí dejaré el '.

El brillo en una pantalla CRT es proporcional a RGBlin = RGB ^ gamma, por lo que el 50 % de gris en una CRT es bastante oscuro: 0,5 ^ 2,2 = 22 % del brillo máximo. (Las pantallas LCD son más complejas; además, algunas tarjetas gráficas compensan la gamma).

Para obtener la medida de luminosidad obtenida L*desde RGB, primero divida RGB por 255 y calcule

Y = .2126 * R^gamma + .7152 * G^gamma + .0722 * B^gamma

Esto está Yen el espacio de color XYZ; es una medida de la "luminancia" del color. (Las fórmulas reales no son exactamente x^gamma, pero se acercan; quédese con x^gamma para una primera pasada).

Finalmente,

L* = 116 * Y ^ 1/3 - 16

"... aspira a la uniformidad perceptiva [y] se acerca mucho a la percepción humana de la ligereza". -- Espacio de color del laboratorio de Wikipedia

denis avatar Mar 27 '2009 12:03 denis

Encontré esta publicación a la que se hace referencia en una respuesta a una pregunta similar anterior. Es muy útil y la página tiene varias imágenes de muestra:

Evaluación perceptiva de conversiones de imágenes de color a escala de grises por Martin Čadík, Foro de gráficos por computadora, volumen 27, 2008

La publicación explora varios otros métodos para generar imágenes en escala de grises con diferentes resultados:

  • CIE Y
  • Color2Gris
  • Descolorizar
  • herrero08
  • rasche05
  • bala04
  • Neumann07

Curiosamente, concluye que no existe un método de conversión universalmente mejor, ya que cada uno funcionó mejor o peor que otros dependiendo de la entrada.

ypnos avatar Mar 26 '2009 21:03 ypnos

Aquí hay un código en c para convertir rgb a escala de grises. La ponderación real utilizada para la conversión de rgb a escala de grises es 0,3R+0,6G+0,11B. Estos pesos no son absolutamente críticos, así que puedes jugar con ellos. Los he hecho 0.25R+ 0.5G+0.25B. Produce una imagen ligeramente más oscura.

NOTA: El siguiente código asume el formato de píxeles xRGB de 32 bits

unsigned int *pntrBWImage=(unsigned int*)..data pointer..;  //assumes 4*width*height bytes with 32 bits i.e. 4 bytes per pixel
unsigned int fourBytes;
        unsigned char r,g,b;
        for (int index=0;index<width*height;index++)
        {
            fourBytes=pntrBWImage[index];//caches 4 bytes at a time
            r=(fourBytes>>16);
            g=(fourBytes>>8);
            b=fourBytes;

            I_Out[index] = (r >>2)+ (g>>1) + (b>>2); //This runs in 0.00065s on my pc and produces slightly darker results
            //I_Out[index]=((unsigned int)(r+g+b))/3;     //This runs in 0.0011s on my pc and produces a pure average
        }
twerdster avatar Jan 30 '2011 00:01 twerdster