jueves, 9 de mayo de 2013

Detección de esquinas

Parte básica: detectar las esquinas con el método de diferencia de filtro mediano.

Para esta primera parte lo que realice fue primero la imagen original la pase a escala de grises, después de eso, hice una copia de esa imagen y le aplique el filtro de la mediana, en seguida reste las dos imágenes la del filtro de la mediana menos la gris original lo que da como resultado bordes marcados de color gris obscuro y las esquinas de un tono un poco más claras, por lo que apliqué después el umbral para obtener solo las esquinas. Aquí están los resultados:


Prueba #1
Imagen original



Imagen filtro mediana


Resultado de la diferencia


Binarizada


Prueba #2

Imagen original
Imagen con filtro mediana 
Resultado de la diferencia



Binarizada
Código de diferencia:

def diferencia(original, difusa):
"""resta los pixeles de la imagen gris a una imagen gris que se
le haya aplicado el filtro mediano
"""
imagen_nueva = Image.new("RGB", (original.size[0], original.size[1]))
pixeles = []
for a in range(original.size[1]):
for b in range(original.size[0]):
dif = difusa.getpixel((b, a))[0]-original.getpixel((b, a))[0]
if dif > 255:
dif = 255
if dif < 0:
dif = 0
pixeles.append((dif, dif, dif))
imagen_nueva.putdata(pixeles)
imagen_nueva.save("diferencia.png")
return imagen_nueva
view raw gistfile1.py hosted with ❤ by GitHub


Parte avanzada:
Teniendo las esquinas, podemos sacar un “wire-frame” al borde.
Uniendo las esquinas con segmentos de líneas rectas (u otras curvas estimadas desde las partes de borde cubiertas).
Recorriéndolos en un orden que sigue el borde (que habría que detectarse aparte con las técnicas ya conocidas) para saber en qué orden conectar las esquinas.

Lo que se hace es primeramente hacer BFS en las partes que son detectadas como esquinas para tener listas que contienen los pixeles de cada esquina, después se hace de la imagen original también un recorrido BFS para poder saber que esquina corresponde a cada imagen.
El BFS tiene que saber regresar todos los puntos del borde pero no como lo hacemos siempre, necesitamos que lo recorra en una sola dirección es por eso que se pone como una especie de tope a cada figura al inicio del recorrido BFS y así aseguramos que siempre vaya en una dirección y no se confundan las esquinas.
Yo dibuje un circulo de 6 de diámetro y con esto aseguro tapar una parte del borde y así el recorrido se va por una sola dirección, se puede dibujar una línea también o lo que sea.
Con el tope se ve así:

Corte del borde con una línea negra delgada
Corte del borde con un circulo de 6 de diámetro.
BFS modificado:

def bfs2(imagen, origen, color):
"""colorea todo el objeto recibe como parametros el
nuevo color con el que se pinta,la coordenada de inicio y
la imagen, y regresa un arreglo con la masa y la imagen
"""
draw = ImageDraw.Draw(imagen)
c = []
cola = []
cont = 0
masa = []
pixeles = imagen.load()
alto, ancho = imagen.size
cola.append(origen)
original = pixeles[origen]
edges = []
s_x = origen[0]+5
s_y = origen[1]
k = (0,0,0)
draw = ImageDraw.Draw(imagen)
draw.ellipse((s_x-1,s_y-4, s_x-1, s_y+20),
fill="black")
pixeles = imagen.load()
while len(cola) > 0:
(x, y) = cola.pop(0)
actual = pixeles[x, y]
if actual == original or actual == color:
for dx in [-1,0,1]:
for dy in [-1,0,1]:
candidato = (x + dx, y + dy)
pix_x = candidato[0]
pix_y = candidato[1]
if pix_x >= 0 and pix_x < alto and pix_y >= 0 and pix_y < ancho:
contenido = pixeles[pix_x, pix_y]
if contenido == original:
pixeles[pix_x, pix_y] = color
masa.append((pix_x,pix_y))
imagen.putpixel((pix_x, pix_y), color)
cont += 1
cola.append((pix_x, pix_y))
c.append((pix_x, pix_y))
imagen.save('k.png', 'png')
imagen.show()
return imagen, cont, masa, c
view raw gistfile1.py hosted with ❤ by GitHub

Lo que se hace ahora es recorrer todos los puntos del borde en el orden ya dicho, y se busca alguna coincidencia con los puntos que ya teníamos guardados previamente de las esquinas, y cuando coincidan se guarda el punto en una lista a la que llamé vértices, y cuando termina el recorrido de cada figura se empiezan a dibujar las líneas:

todos_contornos, cen = encuentra_figuras2(aux)
#se hacen los filtros para la resta
imagen = filtros.hacer_gris(imagen)
imagen = filtros.normalizar(imagen)
#se aplica filtro de mediana
difusa = filtros.mediana(difusa)
bordes = diferencia(imagen, difusa)
umbral = filtros.umbral(bordes, 80)
#se obtienen todos los pixeles por figura que
#pertenecen a una ESQUINA
#se usa el bfs normal
contornos, cen = encuentra_figuras(umbral)
draw = ImageDraw.Draw(umbral)
for figura in todos_contornos:
#vertices para guardar y dibujar lineas
vertices = []
for punto in figura:
for esquinas in contornos:
if punto in esquinas:
#si el punto del borde es una esquina entonces
#se guarda
vertices.append(punto)
print punto
break
for i, vertice in enumerate(vertices):
#se dibujan el -wireframe-
print i, vertice
try:
draw.line((vertice[0],vertice[1], vertices[i+1][0], vertices[i+1][1]),fill="red")
except:
draw.line((vertice[0],vertice[1], vertices[0][0], vertices[0][1]),fill="red")
umbral.show()
umbral.save("umbral.png")
view raw gistfile1.py hosted with ❤ by GitHub


Resultados:


Esquinas conectadas



Esquinas conectadas

Referencias



Repositorio

1 comentario: