En esta tarea tenemos que detectar lo que son los bordes en una imagen, para lo cual se realiza lo siguiente:
- Primero convertimos la imagen a escala de grises
- Le aplicamos filtro
- Aplicamos convolución
- Aplicamos normalización
- Aplicamos binarización
La imagen original es:
Escala de grises: En esta parte se convierte la imagen en escala de grises.
Código
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def escala_grises(self): | |
image = Image.open(self.o_imagen) | |
pixels = image.load() | |
ancho,alto = image.size | |
self.matriz = numpy.empty((ancho, alto)) | |
for i in range(ancho): | |
for j in range(alto): | |
(r,g,b) = image.getpixel((i,j)) | |
escala = (r+g+b)/3 | |
pixels[i,j] = (escala,escala,escala) | |
self.matriz[i,j] = int(escala) | |
return image |
Imagen obtenida:
Le aplicamos filtro:
Para usar el filtro ya trabajamos con la imagén en escala de grises
- Seleccionamos los vecinos de cada uno de los pixeles
- Sumamos la escala de grises q le pertenece a cada pixel vecino
- Sacamos un promedio de la suma de lo anterior
- Y lo asignamos al pixel
Código:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def filtro(self): | |
inicio = time() | |
image = self.escala_grises() | |
pixels = image.load() | |
ancho, alto =image.size | |
lista = [-1,0,1] | |
for i in range(ancho): | |
for j in range(alto): | |
promedio = self.vecindad(i,j,lista,self.matriz) | |
pixels[i,j] = (promedio,promedio,promedio) | |
fin = time() | |
tiempo_t = fin - inicio | |
print "Tiempo que tardo en ejecutarse filtro = "+str(tiempo_t)+" segundos" | |
return image | |
def vecindad(self,i,j,lista,matriz): | |
promedio = 0 | |
indice = 0 | |
for x in lista: | |
for y in lista: | |
a = i+x | |
b = j+y | |
try: | |
if self.matriz[a,b] and (x!=a and y!=b): | |
promedio += self.matriz[a,b] | |
indice +=1 | |
except IndexError: | |
pass | |
try: | |
promedio=int(promedio/indice) | |
return promedio | |
except ZeroDivisionError: | |
return 0 |
Imagen obtenida
Para aplicar convolución utilizamos el operador de sobel, aplicamos el gradiente horizontal y vertical al mismo tiempo obteniendo la magnitud del gradiente, para más información sobre este tema.
Código
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def mascara(self,image): | |
inicio = time() | |
#Mascara Sobel | |
sobelx = ([-1,0,1],[-2,0,2],[-1,0,1]) #gradiente horizontal | |
sobely = ([1,2,1],[0,0,0],[-1,-2,-1]) # gradiente vertical | |
img=self.convolucion(sobelx,sobely,image) | |
fin=time() | |
tiempo_t = fin - inicio | |
print "Tiempo que tardo en ejecutarse convolucion = "+str(tiempo_t)+" segundos" | |
return img | |
def convolucion(self,h1,h2,image): | |
pixels = image.load() | |
ancho,alto = image.size | |
a=len(h1[0]) | |
self.conv = numpy.empty((ancho, alto)) | |
self.minimo = 255 | |
self.maximo = 0 | |
for x in range(ancho): | |
for y in range(alto): | |
sumax = 0.0 | |
sumay = 0.0 | |
for i in range(a): | |
for j in range(a): | |
try: | |
sumax +=(pixels[x+i,y+j][0]*h1[i][j]) | |
sumay +=(pixels[x+i,y+j][0]*h2[i][j]) | |
except: | |
pass | |
gradiente = math.sqrt(pow(sumax,2)+pow(sumay,2)) | |
self.conv[x,y]=gradiente | |
gradiente = int(gradiente) | |
pixels[x,y] = (gradiente,gradiente,gradiente) | |
p = gradiente | |
if p < self.minimo: | |
self.minimo = p | |
if p > self.maximo: | |
self.maximo = p | |
return image |
Aplicamos normalización
Para aplicar normalización se hace de la siguiente manera:
De la imagen que nos arrojo la convolución seleccionamos el valor del pixel mas alto y mas bajo:
r = smaximo-minimo
prop = 255.0/r
p =int(floor((p-minimo)*prop))
El resultado lo aplicamos al pixel
Código:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def normalizar(self,image): | |
pixels = image.load() | |
r = self.maximo-self.minimo | |
prop = 255.0/r | |
ancho,alto = image.size | |
for i in range(ancho): | |
for j in range(alto): | |
p =int(floor((self.conv[i,j]-self.minimo)*prop)) | |
pixels[i,j]=(p,p,p); | |
print 'TERMINO' | |
return image |
Aplicamos binarización
Le damos al programa un valor el cual ayudara a binarizar la imagen, por ejemplo valor=34
si el velor del pixel es mayor al valor 34 el pixel se hace blanco si es menor el pixel se hace negro.
Código:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def binarizar(self,img): | |
pixels = img.load() | |
ancho,alto = img.size | |
minimo = int(argv[2]) | |
for i in range(ancho): | |
for j in range(alto): | |
if pixels[i,j][1] < minimo: | |
p=0 | |
else: | |
p= 255 | |
pixels[i,j]=(p,p,p) | |
return img |
Tiempo que tardo en ejecutarse escala de grises = 1.02590990067 segundos
Tiempo que tardo en ejecutarse filtro = 2.71544289589 segundos
Tiempo que tardo en ejecutarse convolucion = 2.23032712936 segundos
Tiempo que tardo en ejecutarse normalizar = 2.07841897011 segundos
Tiempo que tardo en ejecutarse binzarizar = 0.44579911232 segundos
Muy bien, salvo que hay pequeños detalles de ortografía. 5 pts.
ResponderEliminar