¿Cómo obtener por separado el canal RGB de una imagen con HTML5 y la API Canvas?

- Andrés Cruz

In english

¿Cómo obtener por separado el canal RGB de una imagen con HTML5 y la API Canvas?

El procesamiento digital de imágenes es una labor que tenemos que realizar en nuestras aplicaciones día a día, desde cambiar el tamaño de imágenes para así optimizarlas a nuestras aplicaciones, como recortes como inclusive alterarse el color, brillo, saturación, e inclusive obtener por separado el canal RGB de una imagen empleando el Canvas como veremos en esta entrada.

En este artículo veremos un tutorial de como obtener los tres canales RGB de una imagen y operarlos por separados, es decir, que los tendremos los canales RGB individualmente como vemos en la imagen promocional de esta entrada; al igual que los en los artículos pasados, usaremos HTML5 y javaScript nativo para lograr el objetivo; el cuerpo del documento no difiere mucho de los otros ejercicios que ya hemos realizado:

Definiendo el HTML

El HTML es realmente simple, al igual que hemos empleado en entradas anteriores consisten en un tag Canvas el cual emplearemos para dibujar la imagen base, es decir, la imagen con sus tres canales que es como está por defecto:

<canvas id="canvas">
        <p>Tu navegador no soporta Canvas.</p>
</canvas>

Y tres imágenes en donde serán colocados los tres canales RGB mediante un JavaScript que mostraremos en la siguiente sección de este tutorial:

<img id="r"/>
<img id="g"/>
<img id="b"/>

Definiendo el JavaScript para obtener los canales RGB de la imagen

Lo primero que hacemos es definir las variables globales de siempre para obtener el canvas y su contexto, luego obtenemos acceso a las imágenes que por defecto esta vacías (el atributo src que es el que define la imagen no tiene nada) y lo llenaremos un poco más adelante con el procesamiento que haremos mediante la API Canvas para obtener el canal RGB:

var canvas = document.getElementById('canvas');// canvas
var ctx = canvas.getContext('2d'); // contexto

var imgR = document.getElementById('r');// imagen que representa el canal R
var imgG = document.getElementById('g');// imagen que representa el canal G
var imgB = document.getElementById('b');// imagen que representa el canal B

var srcImg = "image.png";// imagen fuente

Creamos un objeto de tipo Image y le asignamos una imagen fuente que es la que especificamos anteriormente:

    img = new Image();
    img.src = srcImg;

Una vez que la imagen fuera cargada, vamos a redimensionar el Canvas a el tamaño original de la imagen; dibujamos la imagen en el Canvas y colocamos los canales RGB por separados en la imagen invocando al método getRGB(); son esos los 3 pasos fundamentales que puedes detallar en el siguiente código:

// cargo la imagen
img.onload = function() {

    // reescalamos el canvas a las dimenciones de la imagen
    canvas.width = img.width;
    canvas.height = img.height;

    // dibujamos la imagen en el Canvas
    ctx.drawImage(this, 0, 0);
    getRGB();

};

La siguiente función permite separar los tres canales RGB de una imagen (que en nuestro caso es la que cargamos anteriormente) y la guardamos en variables individuales, como vemos obtenemos es la imageData que es un string o un texto muy largo con el contenido de la imagen (algo similar a lo que ocurre cuando abres una imagen con un bloc de notas u otro procesador de texto sencillo).

El siguiente paso que hacemos es volcar el contenido de la imageData de cada uno de los canales que ya tenemos separados desde el paso anterior en el source o fuente de cada una de nuestras imágenes HTML que definimos anteriormente en nuestro HTML y que referenciamos anteriormente también:

// pinta una imagen por canal
function getRGB() {

    // obtenemos el ImageData
    var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para R
    var imgdR = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para G
    var imgdG = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para B
    var imgdB = ctx.getImageData(0, 0, canvas.width, canvas.height);

    // cada una de estos array va a tener un solo canal
    var pixR = imgdR.data;
    var pixG = imgdG.data;
    var pixB = imgdB.data;
    // va a tener los 3 canales; la usaremos 
    //para reestablecer los colores originales en el canvas
    var pix = imgd.data;

    // cambiamos el contraste
    for (var i = 0, n = pixR.length; i < n; i += 4) {
        //Mantengo el canal R
        pixR[i + 1] = 0;//G
        pixR[i + 2] = 0;//B

        //Mantengo el canal G
        pixG[i] = 0;//R
        pixG[i + 2] = 0;//B

        //Mantengo el canal B
        pixB[i] = 0;//R
        pixB[i + 1] = 0;//B
    }

    // retornamos la data modificada al Canvas; canal R
    ctx.putImageData(imgdR, 0, 0);
    dataURL = canvas.toDataURL();
    imgR.src = dataURL;
    // retornamos la data modificada al Canvas; canal G
    ctx.putImageData(imgdG, 0, 0);
    dataURL = canvas.toDataURL();
    imgG.src = dataURL;
    // retornamos la data modificada al Canvas; canal B
    ctx.putImageData(imgdB, 0, 0);
    dataURL = canvas.toDataURL();
    imgB.src = dataURL;
    // retornamos la data original al Canvas; canal RGB
    ctx.putImageData(imgd, 0, 0);
}

Para colocar cada uno de los canales RGB en imágenes individuales tenemos que procesar la data de la imagen que obtuvimos en un array en donde solo prevalece uno de los canales, los otros dos son establecidos con el valor de cero.

Analizando la función anterior para obtener procesar los canales RGBs de las imágenes

Obtenemos la ImageData o data sobre toda la imagen dibujada en el Canvas, la cual nos permitirá operar la data que compone a la imagen a nivel de píxel en su escala RGB; puedes ver más sobre el ImageData en el siguiente enlace:

// obtenemos el ImageData
var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para R
var imgdR = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para G
var imgdG = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para B
var imgdB = ctx.getImageData(0, 0, canvas.width, canvas.height);

El siguiente paso consiste en obtener todos los píxeles que componen a la imagen; esta información viene almacenado en un Array:

// cada una de estos array va a tener un solo canal
var pixR = imgdR.data;
var pixG = imgdG.data;
var pixB = imgdB.data;
// va a tener los 3 canales; la usaremos 
// para reestablecer los colores originales en el canvas
var pix = imgd.data;

Esta sección de código representa el corazón del ejercicio; se obtiene un canal por vez, estableciendo los restantes en cero:

// cambiamos el contraste
for (var i = 0, n = pixR.length; i < n; i += 4) {
    //Mantengo el canal R
    pixR[i + 1] = 0;//G
    pixR[i + 2] = 0;//B

    //Mantengo el canal G
    pixG[i] = 0;//R
    pixG[i + 2] = 0;//B

    //Mantengo el canal B
    pixB[i] = 0;//R
    pixB[i + 1] = 0;//B
}

Luego de que tengamos divididos los canales; el siguiente paso consiste en guardar los tres canales RGB en imágenes separadas:

// retornamos la data modificada al Canvas; canal R
ctx.putImageData(imgdR, 0, 0);
dataURL = canvas.toDataURL();
imgR.src = dataURL;
// retornamos la data modificada al Canvas; canal G
ctx.putImageData(imgdG, 0, 0);
dataURL = canvas.toDataURL();
imgG.src = dataURL;
// retornamos la data modificada al Canvas; canal B
ctx.putImageData(imgdB, 0, 0);
dataURL = canvas.toDataURL();
imgB.src = dataURL;
// retornamos la data original al Canvas; canal RGB
ctx.putImageData(imgd, 0, 0);

Resultado Final

Por último puedes ver el resultado de nuestro experimento en la siguiente sección y descargar el código fuente:

Ver demo Descargar Fuente

Como podemos apreciar, con HTML podemos hacer prácticamente todo: juegos, procesadores de texto, de imágenes en donde la imaginación es el límite.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.

!Cursos desde!

10$

En Udemy

Quedan 3d 21:31!


Udemy

!Cursos desde!

4$

En Academia

Ver los cursos

!Libros desde!

1$

Ver los libros
¡Hazte afiliado en Gumroad!