martes, 5 de marzo de 2013

Detección de círculos del mismo radio

Para la materia de visión computacional se nos pide detectar circulos, es por eso que utilizando la transformada de Hough y utilizando las mascaras de gradiente para 0 y 90 grados de Sobel, detecto los círculos de un mismo radio de una imagen.

Mi repositorio de los códigos. Liga.

Primero que nada, sacamos el gradiente de tal forma que podamos analizar la imagen.



Para luego, procesarlo de manera que tengamos su información relevante de cada pixel, para sacar los valores más significativos y los pintamos de manera que un color el centro y a partir del centro calculado dibujar con el radio dado, el circulo, para este caso, utilicé diferentes tonalidades de amarillo para cada circulo al igual que pongo en el centro, para la imagen guardada, un punto verde y múltiples círculos para remarcar su contorno, este es el código.

def boton_circulo():
inicio = time.time()
label.destroy()
radio = 100
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]])
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")
#Obtener votos
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
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))
dibuja = ImageDraw.Draw(imagen)
dim_x, dim_y = imagen.size
for conta in range(len(centros)):
x = centros[conta][0]
y = centros[conta][1]
tono = randint(128,255)
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio + 1
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio - 1
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio - 2
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio + 2
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio - 3
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
radio = radio + 3
dibuja.ellipse((x-radio, y-radio, x+radio, y+radio), fill=None, outline=(tono, tono, 0))
dibuja.ellipse((x-2, y-2, x+2, y+2), fill="green")
imagen.save("Resultado.png")
poner_imagen(imagen)
global frame
barra = frame.winfo_height()
for conta in range(len(centros)):
x = centros[conta][0]
y = centros[conta][1]
label_fig = Label(text = str(conta))
label_fig.place(x=x,y=y+barra)
#Tiempo
fin = time.time()
tiempo = fin - inicio
print "Tiempo que trascurrio -> " + str(tiempo)
return tiempo
view raw Circulo.py hosted with ❤ by GitHub


Estos son los resultados de diferentes imágenes cambiando el radio y numero de círculos.













Estas son algunas capturas de pantalla, los resultados que nos dio por medio de las imágenes guardadas con el punto verde en el centro y por otra parte las capturas de la ventana en donde pongo sus etiquetas del ID de cada circulo.

Es importante decir, yo empecé a utilizar otras máscaras para sacar los gradientes en 0 y 90 grados, pero al momento de hacerlo los círculos quedaban muy mal ubicados y computacionalmente tardaba más, esto es porque por ejemplo al usar Prewitt quedaban los gradientes bien definidos pero no en los grados dados, por lo que al utilizar Sobel, es mucho mas rápido al utilizar solo ceros y unos, y computacionalmente menos pesado, solo un poco.

1 comentario: