Cómo diferenciar (busca las diferencias) de dos imágenes con JavaScript usando js-imagediff

Cómo diferenciar (busca las diferencias) de dos imágenes con JavaScript usando js-imagediff

Alguna vez jugaste "Encuentra las diferencias"? Si no lo hiciste, no tuviste infancia. Este juego es un tipo de puzzle en el cual la meta es encontrar cierto numero de diferencias poco notables en un par de imágenes, usualmente colocadas de lado a lado. Algunas veces este juego puede convertirse en un verdadero dolor de cabeza.

Observa el siguiente ejemplo e intenta encontrar las diferencias por ti mismo (en caso de que quieras relajarte un rato y si tienes tiempo, de otra manera solo sigue leyendo, te garantizamos que hay 4 diferencias):

Spot the difference example JavaScript

Pero, en serio ? Esto luce bastante complicado, tomaría bastante tiempo encontrar las diferencias por ti mismo. Que tal si escribimos algo de JavaScript que nos permita encontrar las diferencias entre 2 imágenes y que genere una imágen similar a la siguiente:

Differences spot the game JavaScript

Mucho mejor, allí están las diferencias de las imágenes ! La diferenciación de imágenes es algo increible, además puede ser llevado a cabo en JavaScript fácilmente gracias a js-imagediff.js. Esta librería basada en Canvas te permite diferenciar imágenes y crear una imágen a partir de ellas en el explorador y en Node.js. Para más información acerca de esta librería, por favor visita el repositorio oficial en Github aquí.

En este artículo te mostraremos como usar esta librería para encontrar las diferencías entre 2 imágenes o verificar si son identicas o no.

1. Instalación

Lo primero que necesitas hacer es descargar el script de js-imagediff en versión minificada u original e incluirlo en tu documento HTML usando el tag de script:

<!-- Incluir la librería image-diff -->
<script src="image-diff.min.js"></script>

Una vez incluida, podrás acceder a ella en el explorador con window.imagediff ó solamente imagediff.

2. Busca las diferencias

Esta librería es realmente fácil de usar, para comenzar necesitarás obviamente 2 imágenes que comparar. Luego, crea respectivamente una variable con el elemento de imágen y obten su valor, el valor puede ser un objeto del DOM <img> o una instancia de la clase Image de JavaScript (necesitarás el atributo src manualmente con JavaScript).

Luego usa el método diff de la librería que espera como argumentos las imágenes a diferenciar. Este método es completamente síncrono y retornara inmediatamente una variable ImgData que contiene una imágen de fondo negro en la que aparecen las diferencías de las imágenes proveidas. La variable obtenida puede ser dibujada en un canvas (usando el método putImageData del canvas) para poder mostrarla a tu usuario:

// Instancia de la primera imágen
var ImageA = document.getElementById("image-element-1");
// ó
// var ImageA = new Image();
// ImageA.src = "image1-file.png";

// Instancia de la segunda imágen
var ImageB = document.getElementById("image-element-2");
// ó
// var ImageB = new Image();
// ImageB.src = "image2-file.png";

// Crea la imágen que muestra las diferencias entre las imágenes
var diff = imagediff.diff(ImageA, ImageB);

// Crea un canvas a partir del método createCanvas de la librería (no del DOM) con el tamaño de la imágen
var canvas = imagediff.createCanvas(diff.width, diff.height);

// Obten el contexto 2d
var context = canvas.getContext('2d');

// Dibuja la imágene generada con las diferencias en el canvas
context.putImageData(diff, 0, 0);

// Ahora puedes hacer lo que quieras con el canvas
// por ejemplo renderizarlo dentro de algun div:
document.getElementById("some-div-id").appendChild(canvas);

Por el otro lado, puedes verificar tambien cuando una imágen es igual a otra o no usando el método equal:

// Instancia de la primer imágen
var ImageA = document.getElementById("imageA");
// ó
// var ImageA = new Image();
// ImageA.src = "image1-file.png";

// Instancia de la segunda imágen
var ImageB = document.getElementById("imageB");
// ó
// var ImageB = new Image();
// ImageB.src = "image2-file.png";

// Crea la imágen que muestra las diferencias entre las imágenes
var isEqual = imagediff.equal(ImageA, ImageB , 0);

// Verdadero o Falso de acuerdo a las imágenes
console.log(isEqual);

El tercer argumento especifica la tolerancia en pixeles.

Nota

El único problema con el que tienes que lidiar, es la manera en la que verificas cuando las 2 imágenes han sido completamente cargadas o no (pues obviamente no puedes hallar las diferencias entre 2 imágenes que nisiquiera existen). En nuestros ejemplos usamos una variable bandera que incrementa su valor cuando una imágen es cargada. Esta aumenta su valor haciendo que el callback de onload sea el mismo para ambas imágenes (cuando la variable bandera alcanza el número 2, es decir el mismo número de imágenes que esperan ser cargadas, se podrá proceder a la diferenciación de las imágenes).

Ejemplo: Cargando imágenes via img tag

El siguiente ejemplo muestra como diferenciar 2 imágenes que están siendo cargadas a través de el tag <img> en el documento. El callback onload será ejecutado solamente una ves que las imágenes hayan sido cargadas (para verificar revisar los eventos de carga de las imágenes) y una vez la diferenciación finaliza, la imágen generada será agregada al mismo elemento div donde se encuentras las imágenes:

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <!-- Div en el que se muestras las imágenes -->
    <div id="result-container">
        <img src="example_a.png" id="imageA"/>
        <img src="example_b.png" id="imageB"/>
    </div>
    
    <!-- Incluir la librería de image-diff -->
    <script src="image-diff.min.js"></script>
    
    <script>
        // Una variable bandera que indica cuando las 2 imágenes hayan sido cargadas
        var loadedImages = 0;

        // Crea una variable a partir de la primera imágen
        var ImageA = document.getElementById("imageA");
        
        // Crea una variable a partir de la segunda imágen
        var ImageB = document.getElementById("imageB");

        /**
         * Callback ejecutado cuando las imágenes hayan sido finalmente cargadas
         *  
         **/
        var onImagesLoaded =  function () {
            // Incrementar la variable bandera
            loadedImages++;

            // Saltar ejecución del callback si las 2 imágenes no han sido cargadas
            // de otra manera continue con la diferenciación
            if(loadedImages != 2){
                return;
            }

            // Crea la imágen que muestra las diferencias entre las 2 imágenes
            var diff = imagediff.diff(ImageA, ImageB);
            // Crea un canvas con el método imagediff (con las dimensiones de la imágen generada)
            var canvas = imagediff.createCanvas(diff.width, diff.height);
            // Obtener contexto en 2d
            var context = canvas.getContext('2d');
            // Dibujar la imágen generada con las diferencias en el canvas
            context.putImageData(diff, 0, 0);
            // Agrega el elemento canvas al div para mostrar
            document.getElementById("result-container").appendChild(canvas);

            // Mostrar una alerta !
            alert("Listo!");
        };

        // Ejecuta el callback declarado una ves carguen las imágenes
        ImageA.addEventListener("load", onImagesLoaded, false);
        ImageB.addEventListener("load", onImagesLoaded, false);
    </script>
</body>

</html>

Con algunas imágenes de ejemplo, el resultado sería el siguiente:

Image differences JavaScript

Ejemplo: Cargando imágenes dinámicamente con JavaScript

Si las imágenes con las que tienes que trabajar no tienen que ser cargadas en el documento sino manipuladas de manera abstracta con JavaScript, obviamente no tendrás ningun tag <img> a tu alcance, lo que significa que tendrás que manipular las imágenes con la clase Image de JavaScript. 

Sin embargo, de la misma manera en la que lo haces con imágenes cargadas en el documento, necesitarás verificar cuando la imágen haya sido cargada o no a través del callback onload. Una vez la diferenciación finaliza, un canvas se agregará al div result-container para mostrar los resultados gráficamente:

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <!-- Algun elemento div al que agregar el resultado luego -->
    <div id="result-container"></div>
    
    <!-- Incluir la librería -->
    <script src="image-diff.min.js"></script>
    
    <script>
        // Una variable bandera que indica cuando las 2 imágenes hayan sido cargadas
        var loadedImages = 0;

        // Crea una variable a partir de la primera imágen
        var ImageA = new Image();
        ImageA.src = "./example_a.png";

        // Crea una variable a partir de la segunda imágen
        var ImageB = new Image();
        ImageB.src = "./example_b.png";

        /**
         * Callback ejecutado cuando las imágenes hayan sido finalmente cargadas
         *  
         **/
        var onImagesLoaded =  function () {
            // Incrementar la variable bandera
            loadedImages++;

            // Saltar ejecución del callback si las 2 imágenes no han sido cargadas
            // de otra manera continue con la diferenciación
            if(loadedImages != 2){
                return;
            }

            // Crea la imágen que muestra las diferencias entre las 2 imágenes
            var diff = imagediff.diff(ImageA, ImageB);
            // Crea un canvas con el método imagediff (con las dimensiones de la imágen generada)
            var canvas = imagediff.createCanvas(diff.width, diff.height);
            // Obtener contexto en 2d
            var context = canvas.getContext('2d');
            // Dibujar la imágen generada con las diferencias en el canvas
            context.putImageData(diff, 0, 0);
            // Agrega el elemento canvas al div para mostrar
            document.getElementById("result-container").appendChild(canvas);

            // Mostrar una alerta
            alert("Listo 2!");
        };

        // Usar el callback en eventos onload
        ImageA.onload = onImagesLoaded;
        ImageB.onload = onImagesLoaded;
    </script>
</body>

</html>

El ejemplo generaría la misma imágen generada en el anterior ejemplo:

Differences image javascript js-imagediff

Que te diviertas !

Esto podría ser de tu interes

Conviertete en un programador más sociable