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 |
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 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 |
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:
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 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 |
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:
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
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") |
Resultados:
![]() |
Esquinas conectadas |
![]() |
Esquinas conectadas |
Referencias
Repositorio
Perfecto; 10 pts.
ResponderEliminar