lunes, 4 de febrero de 2013

Actividad 1: Filtros


En ésta entrada veremos como aplicar diferentes tipos de filtros a una determinada imagen, para eso se empleo python junto con la librería PIL, donde los filtros aplicados son:
  • Escala de grises.
  • Escala de grises mínimo.
  • Escala de grises máximo.
  • Negativo.
  • Binaria.
El programa lo que hace es mostrarte en una ventana la imagen seleccionada, donde en la misma ventana te muestran botones para aplicar las diferentes tipos de escalas, al final dejo el código completo junto a la liga de github.


Algoritmo:
Para poder sacar los filtros primero se obtuvo cada pixel de la imagen, para después tener el rgb.

Escala de grises:
En la escala de grises, una vez obtenido el rgb del pixel, sacamos su media y este nuevo valor será el del rojo, verde y azul, para así obtener el nuevo pixel.
    def grayScale(self):
        for i in range(self.img.size[0]): #recorremos las de i & j para tener cada pixel de la iamgen
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0] #obtenemos r, g, b
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                media = (r+g+b)/3 #Lo explicado
                pixel = tuple([media, media, media]) #Creamos nuestro nuevo pixel
                self.img.putpixel((i, j), pixel) #En la imagen ponemos el nuevo pixel           

        self.img.save('grayScale.png', 'PNG') #Guardamos la imagen
        return self.img #regresamos la imagen, para manipolarla posteriormente


[escala de grises]


Escala de grises máximo y mínimo
En ésta escala de grises, lo que hago es obtener el pixel completo, sacando el máximo o mínimo del rgb, para después el obtenido ponerlo en cada rbg
    def grayScaleMax(self):
        for i in range(self.img.size[0]): #Se aplica lo mismo mencionado
            for j in range(self.img.size[1]):
                
                pixel = max(self.rgb.getpixel((i, j))) #Sacamos el máximo
                
                pixel = tuple([pixel, pixel, pixel])
                self.img.putpixel((i, j), pixel)            

        self.img.save('grayScaleMax.png', 'PNG')
        return self.img

    def grayScaleMin(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                
                pixel = min(self.rgb.getpixel((i, j))) #Sacamos en mínimo
                
                pixel = tuple([pixel, pixel, pixel])
                self.img.putpixel((i, j), pixel)            

        self.img.save('grayScaleMin.png', 'PNG')
        return self.img


[escala de grises mínimo]

[escala de grises máximo]


Umbral:
El del umbral, interactúa un poco con el de la escala de grises, ya que nosotros pondremos un límite del valor obtenido (media), en mi caso si es mayor a 127 es 255, de lo contrario es 0.
    def binaryScale(self, umbral):
        if(umbral == None): umbral = 122
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0]
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                media = (r+g+b)/3 #Obtenemos la media
                pixel = tuple([media, media, media])
                self.img.putpixel((i, j), pixel)            

                if media > umbral: media = 255 #Dependiendo del umbral nos asigna el nuevo valor
                else: media = 0

                pixel = tuple([media, media, media])
                self.img.putpixel((i, j), pixel)

        self.img.save('BinaryScale.png', 'PNG')
        return self.img


[filtro binario]


Negativo:
Investigando un poco del algoritmo para sacar el negativo, lo que se hace es tener el valor maximo de un color (el cual es 255) y éste es restado por el valor de cada rgb, pra despues tener el pixel.
    def negativeScale(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0]
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                nr = 255 - r # 255 que es nuestro valor máximo es restado por rgb
                ng = 255 - g
                nb = 255 - b
                pixel = tuple([nr, ng, nb])
                self.img.putpixel((i,j), pixel)

        self.img.save('negativeScale.png', 'PNG')
        return self.img


[filtro negativo]



Código:
Al igual dejo el enlace de github.

from Tkinter import * 
from PIL import ImageTk, Image
from sys import argv

class Filtro(object):
    """docstring for Filtro"""
    def __init__(self, fileName):
        self.img = Image.open(fileName)
        self.rgb = self.img.convert('RGB')

    def grayScale(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0]
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                media = (r+g+b)/3
                pixel = tuple([media, media, media])
                self.img.putpixel((i, j), pixel)            

        self.img.save('grayScale.png', 'PNG')
        return self.img

    def grayScaleMax(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                
                pixel = max(self.rgb.getpixel((i, j)))
                
                pixel = tuple([pixel, pixel, pixel])
                self.img.putpixel((i, j), pixel)            

        self.img.save('grayScaleMax.png', 'PNG')
        return self.img

    def grayScaleMin(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                
                pixel = min(self.rgb.getpixel((i, j)))
                
                pixel = tuple([pixel, pixel, pixel])
                self.img.putpixel((i, j), pixel)            

        self.img.save('grayScaleMin.png', 'PNG')
        return self.img

    def binaryScale(self, umbral):
        if(umbral == None): umbral = 122
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0]
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                media = (r+g+b)/3
                pixel = tuple([media, media, media])
                self.img.putpixel((i, j), pixel)            

                if media > umbral: media = 255
                else: media = 0

                pixel = tuple([media, media, media])
                self.img.putpixel((i, j), pixel)

        self.img.save('BinaryScale.png', 'PNG')
        return self.img

    def negativeScale(self):
        for i in range(self.img.size[0]):
            for j in range(self.img.size[1]):
                r = self.rgb.getpixel((i, j))[0]
                g = self.rgb.getpixel((i, j))[1]
                b = self.rgb.getpixel((i, j))[2]
                
                nr = 255 - r
                ng = 255 - g
                nb = 255 - b
                pixel = tuple([nr, ng, nb])
                self.img.putpixel((i,j), pixel)

        self.img.save('negativeScale.png', 'PNG')
        return self.img


path_image = sys.argv[1]
debug = True
imagen = Filtro(path_image)#Instanciamos la imagen de la clase filtro

def main():
    window()

def window():
 root = Tk()
 frame = Frame()
 frame.pack(fill=X, padx=5, pady=5)
 root.title("Imagen Original")

 call(Image.open(path_image)) #Ponemos la imagen original

 panel1 = Button(text="Original", command=original)
 panel1.pack(in_=frame, side=LEFT)

 panel2 = Button(text="GrayScale", command=grayScale)
 panel2.pack(in_=frame, side=LEFT)

 panel3 = Button(text="GrayScaleMin", command=grayScaleMin)
 panel3.pack(in_=frame, side=LEFT)

 panel4 = Button(text="GrayScaleMax", command=grayScaleMax)
 panel4.pack(in_=frame, side=LEFT)
 
 panel5 = Button(text="BinaryScale", command=binaryScale)
 panel5.pack(in_=frame, side=LEFT)

 panel6 = Button(text="Negative", command=negativeScale)
 panel6.pack(in_=frame, side=LEFT)
 
 root.mainloop()

def call(im): #Metodo que ponemos la nueva imagen
    global panel
    img = ImageTk.PhotoImage(im)
    panel = Label(image = img)
    panel.pict = img
    panel.pack() 

def original(): #Metodo del Boton para llamar la imagen Original
 panel.destroy()   #Destruimos el panel para poner la nueva imagen
 return call(Image.open(path_image)) 

def grayScale(): #Metodo del Boton para llamar la escala de grises
 global imagen
 panel.destroy()
 call(imagen.grayScale()) # de nuestro objeto imagen mandamos llamar la funcion

def grayScaleMin(): #Metodo del Boton para llamar la escala de grises de min
 global imagen
 panel.destroy()
 call(imagen.grayScaleMin())

def grayScaleMax(): #Metodo del Boton para llamar la escala de grises de max
 global imagen
 panel.destroy()
 call(imagen.grayScaleMax())

def binaryScale(): #Metodo del Boton para llamar la escala binaria
 global imagen
 panel.destroy()
 call(imagen.binaryScale(None))

def negativeScale(): #Metodo del Boton para llamar la imagen en negativo
 global imagen
 panel.destroy()
 call(imagen.negativeScale())

if __name__ == '__main__':
    main()

Nota:
Debo de mencionar que me apoyé del crear y poner la imagen en la ventana del código de un compañero de clase, todo lo demás lo algorítmico del procesamiento de imagenes es de mi parte.


Referencias:
http://lodev.org/cgtutor/filtering.html
http://www.pythonware.com/library/tkinter/introduction/hello-again.htm

2 comentarios:

  1. El código mejor incrustarlo con syntax highlighter y números de línea. Cuidado con los acentos de las palabras. Van 9 pts.

    ResponderEliminar