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