Un poco de procesamiento de imagenes

Aca les voy a contar algo sobre procesamiento de imagenes. Les mostrare como hacer dos tipos conversiones a archivos de imagenes en bitmap. El formato bmp es el mas simple de procesar porque tiene un header de 53 bytes y despues cada pixel de la imagen esta formado por tres bytes que corresponden con sus valor rgb.



En el primer ejemplo les muestro como pasar una imagen color a blanco y negro (mejor dicho a grises). La imagen en escala de gris tiene la particularidad de que sus tres valores rgb son iguales, entonces para convertir una imagen solamente tendremos que poner el mismo valor en los tre bytes de cada pixel. El header del archivo queda tal cual, solamente se cambian los datos a partir del byte 54. Aca esta el programa hecho en C:
/*Programa para pasar de color a blanco y negro imagenes en bitmap*/
/*Este programa fue desarrollado en FreeBSD 6*/
/*Por Mariano Maccarrone*/


#include <stdio.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*/

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

        for(i=0;i<53;i++)                               /*Lee header del b 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*/

                if (r>215 && g>215 && b>215)            /*si los tres valores (r,g,b) 
 on mayores a 215 tiene mucho brillo*/
                        n = ((r-40)+(g-40)+(b-40)/3);   /*le saca el brillo*/
                else n=(r+g+b)/3;                       /*si no, promedia los tres valores*/

                putc(n,file_out);                       /*escribe los tres valores del pixel en la salida*/
                putc(n,file_out);
                putc(n,file_out);
        }
        fclose(file_in);                                /*Cierra los FILES*/
        fclose(file_out);
}


Aca va una muestra:
La primer imagen es la original y la segunda esta procesada con el programa anterior:
En el proximo ejemplo se ve como hacer el negativo de una imagen, el proceso tambien es muy simple, hallar el complemento de los valores rgb. Por eso el header tambien queda como esta y despues se le resta el valor rgb al numero 255.
/*Programa para hacer el negativo de una imageni*/
/*Este programa fue desarrollado en FreeBSD*/
/*Por Mariano Maccarrone*/


#include <stdio.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*/


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

        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*/
        {
                putc((int)(255-getc(file_in)),file_out);   /*lee color del pixel,calcula el conjugado y lo escribe a la salida*/
                putc((int)(255-getc(file_in)),file_out);
                putc((int)(255-getc(file_in)),file_out);
        }
        fclose(file_in);                                   /*cierra archivos*/
        fclose(file_out);
}

Y una vez compilado y ejecutado este programa tendriamos esta salida:
Bueno, espero que les sirvan estos dos programas, proximamente subire mas.


Agregado 10 de junio de 2008
Si les interesa el lenguaje de programacion python en este link nuestro amigo Sebastian de Libertad Digital esta escribiendo unos articulos muy interesantes sobre este mismo tema.

Agregado 15 de junio de 2008

Aca sigue el tema, esta vez con filtros diferenciadores.


Agregado 21 de Agosto de 2008

Aca les dejo un codigo en python para pasar a escala de grises las imagenes:
#!/usr/bin/python

# Programa para pasar imagenes bmp a escala de grises
# Por Mariano Maccarrone

import sys
import struct

def main():
        f_in=open(sys.argv[1],"r")
        f_out=open(sys.argv[2],"w")

        for i in range(52):
                f_out.write( f_in.read(1) )

        while True:
                r=f_in.read(1)
                g=f_in.read(1)
                b=f_in.read(1)
                if not r or not g or not b:
                        break
                n=(struct.unpack("B",r)[0]+struct.unpack("B",g)[0]+struct.unpack("B",b)[0])/3
                if n > 245:
                        n=245           #esta forma de bajar el brillo no es muy elegante, pero bue..
                        f_out.write(3*struct.pack("B",n))
                else:
                        f_out.write(3*struct.pack("B",n))

        f_out.close()
        f_in.close()

main()
Su uso es similar al anterior en C.
Y aca esta el codigo en python para hacer el negativo de la imagen:
#!/usr/bin/python

# Programa para generar el negativo de una imagen
# Por Mariano Maccarrone

import sys
import struct

def main():
        f_in=open(sys.argv[1],"r")
        f_out=open(sys.argv[2],"w")

        for i in range(52):
                f_out.write( f_in.read(1) )

        while True:
                r=f_in.read(1)
                g=f_in.read(1)
                b=f_in.read(1)
                if not r or not g or not b:
                        break


                f_out.write(struct.pack("B",(255-struct.unpack("B",r)[0])))
                f_out.write(struct.pack("B",(255-struct.unpack("B",g)[0])))
                f_out.write(struct.pack("B",(255-struct.unpack("B",b)[0])))

        f_out.close()
        f_in.close()

main()
Nuevamente el uso es igual al del ejemplo en C.
Agregado 28 de Agosto de 2009

Este es otro ejemplo para pasar una imagen a grises usando las bondades de PIL, Python Imaging Library
#!/usr/bin/python

# Programa para pasar imagenes a escala de grises
# Por Mariano Maccarrone


import Image
import sys

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

        x,y = im.size

        for i in range(x):
                for j in range(y):
                        r,g,b = im.getpixel((i,j))
                        val = (r+g+b)/3
                        im.putpixel((i,j),(val,val,val))

        im.show()
        im.save(sys.argv[2])


main()

El uso es igual a los ejemplos anteriores con la diferencia que este puede manejar otros formatos de archivo.

Agregado 25/10/2009 en respuesta a pregunta de lector

Sergio, aca estoy nuevamente. Me quede pensando como extraer solo los rojos de una imagen e hice este programita:

#!/usr/bin/python

# Por Mariano Maccarrone


import Image
import sys

def main():

        im = Image.open(sys.argv[1])
        im.show()
        x,y = im.size

        for i in range(x):
                for j in range(y):
                        r,g,b = im.getpixel((i,j))

                        if b > g and (r-g) > 40 or (g - b) < 15 and g > b and (r - g) > 40:
                                im.putpixel((i,j),(r,g,b))
                        else:
                                im.putpixel((i,j),(255,255,255))

        im.show()

main()
Si te fijas en el "if" vas a ver que solamente saco los pixels rojos.
Aca te dejo tres ejemplos de como quedan:
El demonio queda asi
Como estamos con el rojo no podia faltar este auto emblematico:
Saludos
Mariano

Hola Sergio, lo que decis es correcto, si pones g y b en cero te quedas con los rojos, pero seguramente te encontras con un problema: los blancos, seguro queres que los blancos sigan siendo blancos. Aca va un ejemplo:

Con el siguiente programa pones en 0 los valores g y b

#!/usr/bin/python

# Por Mariano Maccarrone


import Image
import sys

def main():

        im = Image.open(sys.argv[1])
        im.show()
        x,y = im.size

        for i in range(x):
                for j in range(y):
                        r,g,b = im.getpixel((i,j))
                        im.putpixel((i,j),(r,0,0))

        im.show()

main()

La imagen quedaria asi:

Pero si te pones a jugar con los blancos, grises y sus umbrales podes lograr esto:

#!/usr/bin/python

# Por Mariano Maccarrone


import Image
import sys

def main():

        im = Image.open(sys.argv[1])
        im.show()
        x,y = im.size

        for i in range(x):
                for j in range(y):
                        r,g,b = im.getpixel((i,j))
                        if r > 200 and g > 200 and b > 200:
                                im.putpixel((i,j),(r,g,b))
                        else:
                                im.putpixel((i,j),(r,0,0))

        im.show()
        im.save(sys.argv[2])


main()

Quedaria asi:

Pasa lo mismo con los negros, si no queres ver los negros tendrias que definir un umbral para los negros.

Si lo que quisieras es ver solamente las partes rojas de una imagen deberias definir dos umbrales de rojos, uno superior y otro inferior, y todo lo que quede afuera de esos umbrales lo sacas.

Espero que te haya sido util.

Saludos
Mariano
Autor: Mariano Maccarrone

taxon:

Comentarios