Laboratorio de Visión Computacional
Actividad 9
Actividad 9
Para la entrega de esta semana se nos pidió detectar esquinas en polígonos y hacer un "wire-frame" del mismo sobre la imagen. Utilizamos la técnica llamada Filtro Mediano, el cual es muy fácil de implementar, y este detecta esquinas de polígonos sin importar si son regulares o irregulares. El único problema se presenta cuando las esquinas de los polígonos son la unión de dos aristas con un ángulo interno muy grande.
Los pasos que se siguieron para esta tarea fueron los siguientes:
- Aplicar filtro de escala de grises a la imagen.
- Aplicar el filtro mediano para encontrar las esquinas.
- Aplicar el filtro de binarización para resaltar estas esquinas.
- Identificar las coordenadas de los puntos donde se encontraron las esquinas.
- Detectar bordes en la imagen original.
- Hacer un pequeño corte donde comienza una de las esquinas.
- Usar BFS para seguir el camino del borde de la figura y marcar que puntos se unen con cuáles.
- De lo anterior se obtienen los puntos pertenecientes a las esquinas de cada figura.
- Y por último se dibujan círculos sobre estos puntos y líneas que los unen.
Pruebas
Imagen original e imagen con detección de bordes.
Detección de esquinas.
Esquinas y líneas.
Código
Enseguida los fragmentos de código relevantes. Si se quiere ver el código completo, pueden encontrarlo en el siguiente repositorio.
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 bfs(self, image, start_pixel_pos, color): | |
pixels = image.load() | |
width, height = get_image_size(image) | |
queue = [] | |
copy = [] | |
count = 0 | |
queue.append(start_pixel_pos) | |
original = pixels[start_pixel_pos] | |
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: | |
pixel_data = pixels[pixel_x, pixel_y] | |
if pixel_data == original: | |
pixels[pixel_x, pixel_y] = color | |
queue.append((pixel_x, pixel_y)) | |
copy.append((pixel_x, pixel_y)) | |
count += 1 | |
return image, count, copy | |
def detect_forms(self, image): | |
pixels = image.load() | |
width, height = get_image_size(image) | |
percentages = [] | |
all_colors = [] | |
polygons = [] | |
for i in range(width): | |
for j in range(height): | |
if pixels[i, j] == (255, 255, 255): | |
r = random.randint(100, 255) | |
g = random.randint(100, 255) | |
b = random.randint(100, 255) | |
image, count, copy = self.bfs(image, (i, j), (r, g, b)) | |
per = float(count)/float(width * height) | |
percentages.append(per) | |
all_colors.append((r, g, b)) | |
pixels = image.load() | |
polygons.append(copy) | |
return polygons, image | |
def median_filter(self, image): | |
width, height = get_image_size(image) | |
image = grayscale(image) | |
pixels = image.load() | |
newimage = image | |
result = newimage.load() | |
for x in range(width): | |
for y in range(height): | |
neighborhood = list() | |
for pos_x in [-1, 0, 1]: | |
for pos_y in [-1, 0, 1]: | |
if pos_x != 0 or pos_y != 0: | |
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: | |
neighborhood.append(pixels[pixel_x, pixel_y][0]) | |
n = int(len(neighborhood)/2) | |
neighborhood.sort() | |
median = (neighborhood[n] + neighborhood[n-1])/2 | |
result[x, y] = (median, median, median) | |
return newimage | |
def find_corners(self, original_image, image): | |
corners = Image.new('RGB', (SIZE, SIZE), (255, 255, 255)) | |
width, height = get_image_size(corners) | |
pixels = corners.load() | |
oim = original_image.load() | |
im = image.load() | |
for i in range(width): | |
for j in range(height): | |
color = abs(oim[i, j][0] - im[i, j][0]) | |
pixels[i, j] = (color, color, color) | |
corners = binarization(corners, 100) | |
return corners | |
def draw_wires_detected(self, image, wires_frames): | |
draw = ImageDraw.Draw(image) | |
counter = 1 | |
for wire_frame in wires_frames: | |
print 'Polygon', counter | |
r = random.randint(100, 255) | |
g = random.randint(100, 255) | |
b = random.randint(100, 255) | |
for corner in wire_frame: | |
x, y = corner | |
draw.ellipse((x-3, y-3, x+3, y+3), fill=(r, g, b)) | |
counter += 1 | |
return image | |
def action(self): | |
original_image = Image.new('RGB', (SIZE, SIZE), (255, 255, 255)) | |
image = Image.new('RGB', (SIZE, SIZE), (255, 255, 255)) | |
#create_polygons = [(20,20,20,100,100,100,100,20), (120,120,120,180,180,180,180,120)] | |
create_polygons = [(20,20,20,100,100,100,100,20), (120,120,120,180,180,180,180,120), (160,20,190,20,190,50,160,50)] | |
#create_polygons = [(70, 20, 40, 90, 80, 160, 160, 120, 180, 40)] | |
#create_polygons = [(100, 30, 160, 70, 160, 120, 100, 160, 40, 120, 40, 70)] | |
original_image = self.draw_some_polygons(create_polygons, original_image) | |
original_image = grayscale(original_image) | |
image = self.draw_some_polygons(create_polygons, image) | |
image = grayscale(image) | |
image = self.median_filter(image) | |
corners_image = self.find_corners(original_image, image) | |
corners_points, trash = self.detect_forms(corners_image) | |
h = [[0, 1, 0], [1, -4, 1], [0, 1, 0]] | |
original_image = average_allneighbors(original_image) | |
original_image = binarization(original_image, 200) | |
edges = self.convolution(h, original_image) | |
polygons, image_bfs = self.detect_forms(edges) | |
wires_frames = self.search_wires_frames(polygons, corners_points) | |
output_image = self.draw_wires_detected(image_bfs, wires_frames) | |
self.update_image(output_image) |
Y por último otro ejemplo más.
Referencias:
Elisa Schaeffer, "Detección de polígonos y esquinas", 2013 [En línea]. Disponible en: http://elisa.dyndns-web.com/~elisa/teaching/comp/vision/poligonos.pdf
OK; 10 pts.
ResponderEliminar