sábado, 17 de enero de 2015

Automatizar procesamiento de imágenes con C#

En esta ocasión veremos cómo poder ejecutar transformaciones a varias imágenes a la vez. Para ello se ha desarrollado una biblioteca de clases denominada AutomationImages.dll, para dicho fin, y veremos un ejemplo de cómo utilizarla.
De lo que se trata es de, dadas una serie de imágenes (extraídas por ejemplo de una carpeta), aplicar una o varias transformaciones a la vez. Si queremos redimensionar todas las imágenes de una carpeta y pasarlas a blanco y negro, con esta biblioteca de clases lo podremos hacer.
Para que quede más claro, vamos a ver un vídeo de una aplicación desarrollada con la biblioteca.


Ahora vamos a ver cómo funciona AutomationImages.dll. Esta biblioteca se basa fundamentalmente en la clase Execute, a través de la cual le enviamos nuestras funciones para que se generen las imágenes transformadas. La clase Execute, tiene principalmente los siguientes miembros:
  • Constructores: a través de los constructores se le pasan las imágenes que queremos transformar. Se puede enviar un string con la ruta de la carpeta donde se encuentran nuestras imágenes, una lista de strings con la ruta de las imágenes, o una lista de Bitmaps.
  • Método executeTransform: a este método, se le envían nuestros objetos que transformarán la imagen (deben respetar la interface ITransform, más adelante lo explicamos), y un string con la carpeta de salida de nuestras imágenes.
Dicho esto, vamos a ver un ejemplo de cómo utilizar todo esto. Abrimos nuestra versión de Visual Studio favorita y creamos un nuevo proyecto que, en mi caso, se llamará "EjemploAutomatizacionImagenes". Ahora toca agregar la biblioteca de clases AutomationImages.dll (la podéis descargar desde aquí).

Agregar referencia

Seleccionar dll

Una vez agregada la referencia, podemos ver la documentación de la biblioteca.

Documentación

Ahora vamos a explicar un poco en detalle cómo hay que utilizar la clase Execute. Como decíamos, la clase en sí no tiene funciones de procesamiento de imágenes, sino que le tenemos que enviar nosotros las funciones. Para ello tenemos que crear una clase que respete la interface ITransform. Vamos a agregar una clase que se llame Transformaciones.

Clase Transformaciones

Dentro de esta clase, vamos a crear dos clases más, una se llamará BlancoYNegro y la otra FiltroVerde, añadiendo :ITransform a cada una de ellas (en las sentencias using, incluimos using AutomationImages;). Si ejecutamos el proyecto, veremos que nos dan error las clases, ya que no implementan la interface ITransform. Hacemos clic con el botón derecho en cada una de ellas y seleccionamos Implement Interface.

Implementar interface

Una vez implementada quedaría tal que así.

Interface implementada

Como podemos observar, la clase debe tener un método llamado executeTransform que reciba un Bitmap y devuelva otro Bitmap (en este caso, el Bitmap transformado). Vamos a implementar la funcionalidad de la clase.
La clase BlancoYNegro quedaría de la siguiente forma.

Clase BlancoYNegro

La clase FiltroVerde quedaría así.

Clase FiltroVerde

Ya hemos hecho las transformaciones. Ahora volvemos al formulario y añadimos 3 botones y dos cuadros de texto.

Formulario principal

Vamos a incluir el código del formulario.

public partial class Form1 : Form
    {
        //Creamos objetos para ejecutar transformaciones y abrir carpetas
        private Execute execute;
        private ImageIO gestor;

        public Form1()
        {
            InitializeComponent();
            this.gestor = new ImageIO();
        }

        private void ejecutarTransformacion()
        {
            string rutaEntrada = txtCarpetaEntrada.Text;
            string rutaSalida = txtCarpetaSalida.Text;

            //Comprobamos que haya rutas seleccionadas
            if (!string.IsNullOrEmpty(rutaEntrada) && !string.IsNullOrEmpty(rutaSalida))
            {
                //Invocamos al constructor y le enviamos la ruta de entrada y salida de imágenes
                this.execute = new AutomationImages.Execute(rutaEntrada, rutaSalida);
                //Ejecutamos el método executeTransform y le enviamos una lista con nuestras dos transformaciones
                this.execute.executeTransform(new List<ITransform>(){
                    new Transformaciones.BlancoYNegro(),
                    new Transformaciones.FiltroVerde()});
                
                //Abrimos la carpeta de salida
                System.Diagnostics.Process.Start(rutaSalida);
            }
        }

        //Botón para seleccionar carpeta de entrada
        private void button1_Click(object sender, EventArgs e)
        {
            string ruta=this.gestor.openDialogFolder("Carpeta de entrada");
            txtCarpetaEntrada.Text = ruta;
        }

        //Botón para seleccionar carpeta de salida
        private void button2_Click(object sender, EventArgs e)
        {
            string ruta = this.gestor.openDialogFolder("Carpeta de salida");
            txtCarpetaSalida.Text = ruta;
        }
        //Botón para ejecutar la transformación
        private void button3_Click(object sender, EventArgs e)
        {
            ejecutarTransformacion();
        }
}

Ahora ya podemos pulsar F5 para ejecutar el proyecto; si todo va bien, el resultado debería ser algo así.

Resultado transformación

Lo que hemos visto es un pequeño ejemplo de cómo añadir dos funcionalidades (blanco y negro, y filtro verde), pero se podrían añadir todas las que se quisieran, siempre y cuando respeten la interface ITransform.
Cualquier duda/crítica en los comentarios ;)
Biblioteca de clases AutomationImages.dll.

Ejemplo básico (descrito en la entrada).

Ejemplo completo (el del vídeo).

No hay comentarios:

Publicar un comentario