jueves, 7 de marzo de 2013

Lab: Detección de círculos con diferente radio

Para esta entrada de laboratorio, se nos pide realizar el detectar círculos donde no sepamos información de estos, es decir, a diferencia de la entrada anterior, ahora tenemos que saber cual es el radio del circulo, al igual que su centro.

Primero que nada, hice una rutina en la cual podamos ir cambiando el radio y obtengamos los votos de cada radio aumentado, de manera que estamos utilizando la transformada de Hough de una forma canónica, como la siguiente imagen.

Tomada de las diapositivas Rochester Institute of Technology

Por lo que primero que nada genero una lista con todos los centros posibles y con todos los radios posibles, en donde yo pongo los radios mínimos y máximos para luego adivinar cual es el radio que queremos detectar.

Luego de tener todos los centros, ahora hago repeticiones de radios disponibles hasta que concuerde con los bordes detectados con la mascara laplaciana, de manera que podamos obtener los siguientes resultados.

Este es el código.
def crea_circulo(min, max, cuantos, dim):
imagen_circulo = Image.new('RGB', (dim, dim), (255, 255, 255))
dibuja = ImageDraw.Draw(imagen_circulo)
x, y = imagen_circulo.size
for i in range(cuantos):
radio = randint(min,max)
pos_y = randint(radio, y-radio)
pos_x = randint(radio, x-radio)
dibuja.ellipse((pos_x-radio, pos_y-radio, pos_x+radio, pos_y+radio), fill= "black")
print "Dibujado en (%s, %s) con radio %s" %(pos_x, pos_y, radio)
return imagen_circulo
def obtener_votos(imagen_hori, imagen_verti, imagen, radio):
pixeles_hori = imagen_hori.load()
pixeles_verti = imagen_verti.load()
dim_x, dim_y = imagen.size
votos = []
for pos in range(dim_x):
votos.append([0] * dim_x)
for y_m in range(dim_x):
y = dim_y / 2 - y_m
for x_m in range(dim_x):
x = x_m - dim_x / 2
gra_y = pixeles_hori[y_m, x_m][0]
gra_x = pixeles_verti[y_m, x_m][0]
gra = sqrt(gra_x ** 2 + gra_y ** 2)
if fabs(gra) > 0:
x_c = int(round(x - radio * (gra_x/gra)))
y_c = int(round(y - radio * (gra_y/gra)))
x_c_m = x_c + dim_x /2
y_c_m = dim_y / 2 - y_c
if y_c_m >= 0 and x_c_m < dim_x and y_c_m < dim_y and x_c_m >= 0:
votos[y_c_m][x_c_m] = votos[y_c_m][x_c_m] + 1
for rango in range(1, int(round(dim_x * 0.1))):
agrega = True
while agrega:
agrega = False
for y in range(dim_y):
for x in range(dim_x):
v = votos[y][x]
if v > 0:
for dx in range(-rango, rango):
for dy in range(-rango, rango):
if not (dx == 0 and dy == 0):
if y + dy < dim_x and y + dy >= 0 and x + dx >= 0 and x + dx < dim_x:
w = votos[y + dy][x + dx]
if w > 0:
if v - rango >= w:
votos[y][x] = v + w
votos[y + dy][x + dx] = 0
agrega = True
return votos
def obtener_centros(imagen, votos):
suma = 0.0
max = 0
dim_x, dim_y = imagen.size
#print 'Dimx = %d, Dimy = %d' % (dim_x, dim_y)
for x in range(dim_x):
for y in range(dim_y):
v = votos[y][x]
suma += v
if v > max:
max = v
prom = suma / (dim_x * dim_y)
umbral = (max + prom) / 2.0
centros = []
for x in range(dim_x):
for y in range(dim_y):
v = votos[y][x]
if v > umbral:
#print 'Centro en %d, %d. ' % (y,x)
centros.append((y,x))
return centros, max
def boton_circulo():
inicio = time.time()
label.destroy()
max = 0
suma = 0.0
#A grises
imagen = cambiar_agrises(path_imagen_original)
imagen.save("paso_1.jpg")
votos = list()
h_hori = numpy.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
h_verti = numpy.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
h_lap = numpy.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
imagen_hori = convolucion(imagen, numpy.multiply(1.0/1.0,h_verti))
imagen_hori.save("paso_2.jpg")
imagen_verti = convolucion(imagen, numpy.multiply(1.0/1.0,h_hori))
imagen_verti.save("paso_3.jpg")
imagen_lap = convolucion(imagen, numpy.multiply(1.0/1.0,h_lap))
imagen_lap = cambiar_umbral(imagen_lap, 0.5)
imagen_lap.save("paso_lap.jpg")
centros_posibles = []
for i in range(30,60):
votos = obtener_votos(imagen_hori, imagen_verti, imagen, i)
centros, max = obtener_centros(imagen, votos)
for con in range(len(centros)):
centros_posibles.append(centros[con])
print centros_posibles
dibuja = ImageDraw.Draw(imagen)
global frame
barra = frame.winfo_height()
pixeles = imagen_lap.load()
conta = 0
for con in range(len(centros_posibles)):
centro_prueba = centros_posibles[con]
for radios in range(30, 60):
a = centro_prueba[0]
b = centro_prueba[1]
try:
pixel_norte = pixeles[a-radios,b]
except IndexError:
pixel_norte = (0, 0, 0)
try:
pixel_sur = pixeles[a+radios, b]
except IndexError:
pixel_sur = (0, 0, 0)
try:
pixel_este = pixeles[a, b+radios]
except IndexError:
pixel_este = (0, 0, 0)
try:
pixel_oeste = pixeles[a, b-radios]
except IndexError:
pixel_oeste = (0, 0, 0)
veces = 0
if pixel_norte == (255, 255, 255):
veces = veces + 1
if pixel_sur == (255, 255, 255):
veces = veces + 1
if pixel_este == (255, 255, 255):
veces = veces + 1
if pixel_oeste == (255, 255, 255):
veces = veces + 1
if veces >= 3:
conta = conta + 1
posible_radio = radios
tono = randint(128,255)
dibuja.ellipse((a-radios, b-radios, a+radios, b+radios), fill=None, outline=(tono, tono, 0))
dibuja.ellipse((a-radios+1, b-radios+1, a+radios+1, b+radios+1), fill=None, outline=(tono, tono, 0))
dibuja.ellipse((a-radios-1, b-radios-1, a+radios-1, b+radios-1), fill=None, outline=(tono, tono, 0))
dibuja.ellipse((a-2, b-2, a+2, b+2), fill="green")
label_fig = Label(text = str(conta))
label_fig.place(x=a,y=b+barra)
print "Centro seleccionado (" + str(a) + "," + str(b) + ") - ID: " + str(conta) + " con Diametro = " + str(radios*2)
imagen.save("Resultado.png")
poner_imagen(imagen)
#Tiempo
fin = time.time()
tiempo = fin - inicio
print "Tiempo que trascurrio -> " + str(tiempo)
return tiempo
view raw circulos.py hosted with ❤ by GitHub

Estos son los resultados.











Como pueden ver, mi código no funciona bien, estuve moviéndole a que estuviera una combinación entre el número de bordes a detectar y la cantidad de círculos, teniendo resultados no favorables, nada más detectando un solo circulo, aunque si detecta el radio desconocido, no calcula varios.

Como pueden ver en la ultima imagen si me detecto en la mayoría de los círculos, no se si este bien.

Minimo tamaño de borde

Maximo tamaño de borde


Espero que si alguien me puede comentar cual es la manera de mejorarlo o que debería de haber hecho.

1 comentario: