Loading [MathJax]/extensions/TeX/AMSsymbols.js

1 de mayo de 2013

Actividad 8: Detección de Polígonos

Laboratorio de Visión Computacional
Actividad 8

Para esta semana de laboratorio la actividad fue detectar polígonos. Para la elaboración de esta entrega seguí la serie de pasos que se explica en el PDF visto en clase del cual se hace referencia al final de esta publicación.

Los resultados de una primer prueba con un solo polígono, en este caso un cuadrado.

Imagen original.


Imágenes después de usar máscaras.


Las intersección de las líneas.


Y el resultado.




Esta es la imagen original generada, y volví a colocar cuadrados ya que con estos no tuve problemas en la detección.


Ahora los cruces de líneas, y como pueden ver ahora hay algo de ruido, ya que para un solo lado de la figura repliqué dos veces la misma línea para mover una hacia su interior y otra a su exterior, lo cual debe ser solucionado detectando correctamente que el lugar hacia donde debe trasladarse la línea es hacia donde se encuentre el fondo de la figura.


Así es la salida en la ventana que se despliega.


Y como acostumbramos, en el terminal se imprime el porcentaje de la figura, su centro detectado y como extra, en base a su número de lados detectado, la impresión del nombre del polígono.


Código


En el siguiente gist hay fragmentos importantes de mi código. Las partes que también son elementales pero que ya se han repetido en entregas anteriores no las muestro, como la parte de convolución y búsqueda BFS para la detección de formas.

def draw_polygons_detected(self, image, polygons_found):
draw = ImageDraw.Draw(image)
max_w, max_h = get_image_size(image)
counter = 0
for polygon in polygons_found:
center, sides = polygon
x, y = center
r = random.randint(100, 255)
g = random.randint(100, 255)
b = random.randint(100, 255)
image, count, copy = self.bfs(image, center, (r, g, b))
percentage = (count * 100.0)/(max_w*max_h)
print 'Whit the %0.2f%% of all the image' % percentage
print 'Polygon %d detected at center (%d, %d)' % (counter, x, y)
self.what_polygon(sides)
draw.ellipse((x-2, y-2, x+2, y+2), fill=(255, 255, 0), outline=(255, 255, 0))
draw.text((x+5, y), 'Poly '+str(counter), fill=(255, 0, 0))
counter += 1
return image
def search_polygon(self, can_be_polygons, image, Gx, Gy):
width, height = get_image_size(image)
pixels_gx = Gx.load()
pixels_gy = Gy.load()
points_orientation = []
polygons_found = []
for i in range(width):
points_orientation.append([0] * height)
for polygon in can_be_polygons:
pixels = image.load()
for point in polygon:
px, py = point
color_of_the_ploygon = pixels[px, py]
gx = pixels_gx[px-1, py][0]
gy = pixels_gy[px, py+1][0]
if abs(gx) + abs(gy) <= 0:
theta = None
else:
theta = math.atan2(gy, gx)
points_orientation[px][py] = theta
lines, image = self.detect_lines(image, color_of_the_ploygon, points_orientation)
filtered_lines = []
for line in lines:
if len(line) > 5:
# save true line segemnt
filtered_lines.append(line)
else:
# delete false line segment
for point in line:
pixels[point] = (0, 0, 0)
for line in filtered_lines:
px1, py1 = line[0]
px2, py2 = line[-1]
px = (px1+px2)/2
py = (py1+py2)/2
dis = math.sqrt((px2-px1)**2+(py2-py1)**2)
dis_to_move = dis/2
theta = points_orientation[px][py]
x0 = px - dis * math.cos(theta)
y0 = py - dis * math.sin(theta)
x1 = px + dis * math.cos(theta)
y1 = py + dis * math.sin(theta)
draw = ImageDraw.Draw(image)
#draw.line((x0, y0, x1, y1), fill=(255, 255, 0))
for point in line:
x, y = point
color = pixels[x, y]
pixels[x, y] = (0, 0, 0)
if theta > 0:
try: pixels[x, y+dis_to_move] = color
except: pass
try: pixels[x, y-dis_to_move] = color
except: pass
else:
try: pixels[x+dis_to_move, y] = color
except: pass
try: pixels[x-dis_to_move, y] = color
except: pass
image.save('output.png', 'png')
polygons_found.append(((px-dis_to_move, py), len(filtered_lines)))
return image, polygons_found
def detect_lines(self, image, color_of_the_ploygon, points_orientation):
width, height = get_image_size(image)
pixels = image.load()
lines = []
for i in range(width):
for j in range(height):
if pixels[i, j] == color_of_the_ploygon:
r = random.randint(100, 255)
g = random.randint(100, 255)
b = random.randint(100, 255)
image, line_points = self.line_segment(image, (i, j), (r, g, b), points_orientation)
lines.append(line_points)
pixels = image.load()
return lines, image
def line_segment(self, image, start_pixel_pos, color, points_orientation):
width, height = get_image_size(image)
pixels = image.load()
queue = []
copy = []
queue.append(start_pixel_pos)
original = pixels[start_pixel_pos]
orientation_original = points_orientation[start_pixel_pos[0]][start_pixel_pos[1]]
while 0 < len(queue):
(x, y) = queue.pop(0)
current = pixels[x, y]
if current == original or current == color:
for pos_x in [-1, 0, 1]:
for pos_y in [-1, 0, 1]:
pixel_x = x + pos_x
pixel_y = y + pos_y
if pixel_x >= 0 and pixel_x < width and pixel_y >= 0 and pixel_y < height:
if pixels[pixel_x, pixel_y] == original and orientation_original == points_orientation[pixel_x][pixel_y]:
pixels[pixel_x, pixel_y] = color
queue.append((pixel_x, pixel_y))
copy.append((pixel_x, pixel_y))
return image, copy
def action(self):
original_image = Image.new('RGB', (SIZE, SIZE), (255, 255, 255))
original_image = self.draw_some_polygons([(40, 40, 40, 160, 160, 160, 160, 40)], original_image)
original_image = grayscale(original_image)
# detect all the edges
h = [[0, 1, 0], [1, -4, 1], [0, 1, 0]]
image = self.convolution(h, original_image)
can_be_polygons, image_bfs = self.detect_forms(image)
# gradient
sobely = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
sobelx = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
Gx = self.convolution(sobelx, original_image)
Gy = self.convolution(sobely, original_image)
image, polygons_found = self.search_polygon(can_be_polygons, image_bfs, Gx, Gy)
image = self.draw_polygons_detected(original_image, polygons_found)
self.update_image(image)
view raw polygons.py hosted with ❤ by GitHub

Por motivos de tiempo, no me fue posible mejorar este código, por eso es algo extenso y poco modular. Tiene muchas secciones de código que se pueden mejorar, entre ellas la parte en donde se obtiene theta para determinar la orientación de cada pixel, lo que me provocó el problema de no detectar eficientemente las líneas que no son horizontales o verticales, una vez arreglado esto debería de ser posible detectar polígonos simétricos que no forzosamente sean cuadrados.

Si en algún momento modifico este código los cambios no se verán aquí en este gist, pero pueden buscar en mi repositorio por nuevas versiones.


Referencias:
Detección de Polígonos, por Elisa Schaeffer, Abril 2013

1 comentario:

  1. Aún con sus deficiencias quedó bastante lindo y es la única que he visto hasta ahora que usa el método que se solicitó. 10 pts.

    ResponderEliminar

Nota: solo los miembros de este blog pueden publicar comentarios.