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.
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 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 |
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.
El rango de posibles círculos está medio arbitrario. 8 pts.
ResponderEliminar