Procesamiento de imagenes 2 - Filtro diferenciador

Hoy les voy a mostrar un programa, como siempre en C, para hacer un filtro diferenciador. El programa actua con imágenes en grises como las que se explicó en el articulo anterior.Lo que hace un filtro de este tipo es marcar donde se producen cambios de contraste muy grandes. La forma más fáil para diferenciar una imagen es mediante su gradiente (Analisis matematico II, Calculo II, etc).

Como nuestra imagen es una matriz de 2 dimensiones discreta es posible aproximar las derivadas parciales con diferencias entre los pixeles adyacentes. Si tenemos la siguiente disposición de pixels:

y queremos trabajar sobre el pixel z5 podriamos usar la siguiente función:

que a su vez la podemos aproximar de esta forma:
Acá esta el programa:
/*Filtro diferenciador. Por Mariano Maccarrone*/
/*Este programa fue desarrollado en Slackware*/


#include <stdio.h>
#include <stdlib.h>


void main(int argc, char *argv[])
{
        FILE *file_in;                                  /*Declara FILE de entrada*/
        FILE *file_out;                                 /*Declara FILE de salida*/
        int i,n,r,g,b;                                  /*Declara variables auxiliares*/
        int ancho,alto;                                 /*Declara variables ancho y alto*/
        int *vector_ptr;                                /*Declara puntero a vector de trabajo*/
        int *aux_ptr,*aux2_ptr,*aux3_ptr;               /*Declara Punteros auxiliares*/

        file_in=fopen(argv[1],"r");                     /*Abre para lectura FILE de entrada*/
        file_out=fopen(argv[2],"w+");                   /*Abre para escritura File de salida*/

        fseek(file_in,18,SEEK_SET);                     /*toma ancho de la imagen*/
        ancho=getc(file_in);

        fseek(file_in,22,SEEK_SET);                     /*toma alto de la imagen*/
        alto=getc(file_in);

        vector_ptr=malloc(((ancho*alto)+1));            /*asigna memoria para el vector de trabajo*/
        aux_ptr=vector_ptr;                             /*apunta aux_ptr a inicio del vector*/

        fseek(file_in,0,SEEK_SET);
        for(i=0;i<53;i++)                               /*Lee header del bmp y lo escribe en el archivo de salida*/
                putc((getc(file_in)), file_out);


        while(!feof(file_in))                           /*Mientras que el archivo no llegue a su fin*/
        {
                        r=getc(file_in);                        /*Toma valor de rojos del pixel*/
                        g=getc(file_in);                        /*Toma valor de verdes del pixel*/
                        b=getc(file_in);                        /*Tome valor de azules del pixel*/

                        *aux_ptr=r;                             /*carga vector*/
                        aux_ptr++;                              /*incrementa puntero*/
        }
        *aux_ptr=32000;                                         /*setea valor de final de vector*/

        aux_ptr=vector_ptr;                                     /*apunta aux_ptr a inicio del vector*/

        while(*aux_ptr!=32000)                          /*mientras que el vector no llegue a su fin*/
        {
                aux2_ptr=aux_ptr+1;                     /*puntero al siguiente valor del vector*/
                aux3_ptr=aux_ptr+ancho;                 /*puntero al valor del pixel de abajo*/

                n=modulo((*aux_ptr-*aux3_ptr))+modulo((*aux_ptr-*aux2_ptr));   /*calcula el valor del pixel*/

                putc(n,file_out);                       /*escribe los tres valores del pixel en la salida*/
                putc(n,file_out);
                putc(n,file_out);

                aux_ptr++;                              /*incrementa puntero*/
        }
        fclose(file_in);                                /*Cierra los FILES*/
        fclose(file_out);
        free(vector_ptr);                               /*Libera memoria*/
}

int modulo(int valor)                                   /*calcula modulo*/
{
        if(valor>0)
                return valor;
        else
                return -valor;
}

Este programa tiene algunas limitaciones, está hecho para imágenes de hasta 256x256, y se puede dar el caso en que la primer linea de la imagen filtrada tenga algo medio raro, pero sacando estas limitaciones anda muy bién. Como pueden ver, el programa, después de declarar las variables y punteros, sitáa el cursor en las posiciones 19 y 23 del header para sacar los valores de ancho y alto de la imagen y calcular el tamaño del malloc que asigna memoria dinamicamente al vector donde se va a guardar la imagen. Después se escribe el header en el archivo de salida, se carga el vector, se calculan los valores nuevos y se escriben al archivo nuevo. Acá les pongo un ejemplo con nuestra imagen de prueba:
Y para que Tux no se ponga celoso:
NOTA: La primer imagen es la original, la segunda en grises, la tercera es la del filtro que acabamos de ver y la cuarta es el negativo (ver articulo anterior) de la imagen salida del filtro, y asi se pueden ir encadenando filtros para lograr lo que uno necesita. Espero que les haya interesado el articulo, hasta la proxima!
Agregado el 28 de agosto de 2009     Lo anterior es teoria, aca va un ejemplo en Python, usando PIL (Python Imaging Library) que como veran se simplifica mucho la situacion.    
#!/usr/bin/python

#Filtro diferenciador. Por Mariano Maccarrone

import Image
import ImageFilter
import sys

def main():
        im = Image.open(sys.argv[1])

        im = im.filter( ImageFilter.CONTOUR)
        im.show()
        im.save(sys.argv[2])


main()

Autor: Mariano Maccarrone

taxon:

Comentarios