El color no se considera como un atributo que tienen los objetos, sino como el resultado de un proceso visual entre la retina del ojo y el cerebro ya que el color se produce por la percepción de la luz. Debido a los tipos de conos fotoreceptores que poseen los animales, el humano en particular, se clasifican estos receptores en: los que responden a la luz roja del espectro visible, los que responden a la luz azul y los que responden a la luz verde.
Con base en esto se define el modelo de color RGB, el más conocido y utilizado. En este modelo cada color está representado por tres valores: el rojo (R), verde (G) y azul (B); de manera convencional se puede ubicar este modelo de color en un espacio cartesiano de 3 ejes, donde cada uno corresponde a uno de los tres valores del modelo en el rango [0,255] como se ve en la siguiente imagen:
De esta manera el negro se representa como (0,0,0) y el blanco como (255,255,255); para el caso particular de los colores en escala de grises, estos se obtienen con valores idénticos de R, G, y B.
Existen diversas técnicas de conversión a escala de grises a partir del modelo RGB. Desde el promedio, la tonalidad (basada en el modelo HSL), la luminosidad o Luma, entre otros; en el presente ejercicio se realizarán implementaciones de los algoritmos de Promedio RGB y Luma. El promedio RGB es el método más simple de lograr una conversión, ya que solo se necesita tomar los valores RGB de cada pixel y promediarlos, su formula es la siguiente:
Por su parte, el método de la Luminosidad (o Luma) consiste en una verión más sofisticada que la del promedio, ya que se realiza una suma de las ponderaciones de los valores de los componentes R, G y B con base en que el ojo humano es más sensible al color verde que a los otros colores (por esto su ponderación es mayor). Estos valores fueron establecidos a través de la recomendación Rec. 601 NTSC por la International Telecommunication Union - Radiocommunications.
A continuación en la pestaña Imagen RGB y Luma se podrá visualizar la implementación de los dos métodos mencionados anteriormente aplicados a una imagen por medio de shadders en WEBGL, lo cual permite que se ejecute el código directamente en la unidad de procesamiento gráfica GPU. Se crea una textura con la imagen y a esa textura se le calcula el promedio RGB y luma según el usuario especifique con las siguientes teclas:
Tecla | Resultado |
---|---|
0 | Imagen/Video Original |
1 | Imagen/Video Promedio RGB |
2 | Imagen/Video Luma |
La representación de la imagen convertida se visualizará aplicada a una elipse y a un cubo que rota, con el ánimo de explorar una de las capacidades de WEBGL que es el manejo de elementos en 3D. De igual manera veremos como la luz puede afectar principalmente a el mencionado objeto 3D al pasar el cursor sobre el mismo y ver como la luz de distorsiona sobre el objeto (se observa mejor al dejar el cursor estático en un lugar cerca al cubo).
En la pestaña Video RGB y Luma se visualizan las mismas conversiones pero esta vez aplicadas a la captura de video por cámara en tiempo real. El video responde a los mismos comandos por teclas mencionados anteriormente, igualmente aplicando las texturas a un shader de WEBGL.
Por su parte, la pestaña Instrucciones describe un paso a paso del proceso de conversión de los elementos mencionados (imagen y video) ya que son pasos en su mayoría similares; Iniciando con la creación de los shaders respectivos a partir de los Fragment Shader y Vertex Shader correspondientes, una vez creado el canvas tipo WEBGL se pasan los datos de imagen o video al fragment shader para que identifique según la tecla presionada por el usuario que tipo de transformación desea. Por último el Fragment Shader calcula la escala de grises deseada y devuelve el renderizado de la imagen/video para ser mostrada.
Finalmente, las pestañas Código Imagen y Código Video muestra el código de implementación para los fragment shaders usados en la imagen y el video respectivamente, ambos tienen comentarios de su funcionamiento para mayor comprensión.
No. | Descripción |
---|---|
1 | Precargar Shader para imagen/ video con el vertex y fragment shader. |
2 | Crear canvas de WEBGL. |
3 | Crear el shader a partir del precargado. |
4 | Pasar datos de imagen/video y tecla de control al Fragment Shader. |
5 | El fragment shader carga la textura (ya sea video o imagen). |
6 | Calcula el valor en escala de grises a representar según el comando recibido en la tecla de control. |
7 | Renderizar el valor de color deseado y mostrar en pantalla. |
8 | En el caso de Imagen, aplicar la textura renderizada en 2D(elipse) y 3D (cubo). |
1link// Funcion para convertir un color a escala de grises
2linkfloat grayscale(vec3 color) {
3link float lightness;
4link // Si la tecla de control es 1 se calcula el promedio RGB
5link if (u_key==1){
6link float I=(color.r + color.g + color.b) / 3.0; // Promedio de los tres componentes
7link lightness = I;
8link } else if (u_key==2){
9link // Si la tecla de control es 2 se calcula el valor luma
10link // Promedio ponderado de RGB con correccion gamma (Luma)
11link float Y= dot(color, vec3(0.299, 0.587, 0.114)); // SDTV
12link lightness = Y;
13link }
14link return lightness;
15link}
16link
17linkvoid main() {
18link vec2 uv = vTexCoord;
19link
20link //Invierte la posicion de la cordenada para que la imagen no quede al reves
21link uv.y = 1.0 - uv.y;
22link
23link vec4 tex = texture2D(u_img, uv);
24link // Calculo de escala de grises
25link float gray =grayscale(tex.rgb);
26link
27link float threshR = gray ;
28link float threshG = gray ;
29link float threshB = gray ;
30link
31link // Si la tecla de control es 0 se muestra la imagen original
32link if (u_key==0){
33link threshR = tex.r ;
34link threshG = tex.g ;
35link threshB = tex.b ;
36link }
37link vec3 thresh = vec3(threshR, threshG, threshB);
38link
39link // Se renderiza la salida
40link gl_FragColor = vec4(thresh, 1.0);
41link}
42link
1link// Funcion para calculo de valor Luma de un color
2linkfloat luma(vec3 color) {
3link return dot(color, vec3(0.299, 0.587, 0.114));
4link}
5link
6link// Funcion para calculo del promedio RGB
7linkfloat grayRGB(vec3 color) {
8link float lightness=(color.r + color.g + color.b) / 3.0; // Promedio de los tres componentes
9link return lightness;
10link}
11linkvoid main() {
12link
13link vec2 uv = vTexCoord;
14link // voltear la textura para mostrarse al derecho
15link uv = 1.0 - uv;
16link
17link vec4 tex = texture2D(tex0, uv);
18link
19link float gray;
20link //Dejar valores de color originales desde el inicio
21link
22link float threshR = tex.r ;
23link float threshG = tex.g ;
24link float threshB = tex.b ;
25link
26link // Si la tecla de control es 1 se calcula la el promedio RGB
27link if (u_key==1){
28link
29link gray =grayRGB(tex.rgb);
30link
31link threshR = gray ;
32link threshG = gray ;
33link threshB = gray ;
34link }else if (u_key==2){
35link // Si la tecla de control es 2 se calcula el valor luma
36link gray = luma(tex.rgb);
37link
38link threshR = gray ;
39link threshG = gray ;
40link threshB = gray ;
41link }
42link
43link vec3 thresh = vec3(threshR, threshG, threshB);
44link
45link // Se renderiza la salida
46link gl_FragColor = vec4(thresh, 1.0);
47link}
48link
Se mostró exitosamente como es la implementación lógica y fundamentación teórica de la conversión a escala de grises por medio del promedio RGB y cálculo de Luma. A pesar de haber mostrado un acercamiento mínimo al renderizado 3D, se estima y se evidencia la alta capacidad para la representación de objetos con las texturas deseadas en un entorno espacial definido; las principales aplicaciones de lo mostrado son relacionadas con la creación de videojuegos e incluso de realidad virtual. Sin embargo cabe la posibilidad de la incursión en rubros como la medicina en el diagnóstico de imagenes, al pensar en una representación 3D del cuerpo humano y sus organos internos con texturas analizadas en laboratorio. De igual manera las simulaciones en cualquier ámbito pueden ser ejecutadas con ayuda de los shaders.
Por su parte la escala de grises ayuda a la comparación de la luminosidad de los colores, lo que permite la clasificación de los mismos y también a distinguir los grados de claridad en las atenuaciones y degradados de color. Todas estas son parte fundamental en el diseño gráfico y sus lineas de desempeño. Una de las aplicaciones más novedosa consiste en la recuperación de imagenes con sus colores originales a partir de su versión en escala de grises, sin embargo para esto hay que ajustar el brillo y el componenete gamma (Separación entre el color azul y el negro), entre otros. Tal como lo muestra el estudio realizado por Jesús Gustavo folres Eraña.