martes, 5 de marzo de 2013

Tarea 4

Tarea 4 - Detección de círculos

Hola, esta entrada corresponde a la tarea 4 de la clase de visión computacional. La tarea 4 consiste en encontrar círculos en una determinada imagen, lo primero que se hizo fue encontrar los centros de los círculos, luego pintar la circunferencia de cada uno de ellos con distintas tonalidades (de amarillo) y etiquetar los círculos. Todo esto con un radio preestablecido por nosotros.

Para realizar esta práctica hice uso de la transformada de Hough para círculos, además de las siguiente ecuaciones (Enlace sobre información referente):


En donde a y b corresponden al centro del círculo, mientras que "x" y  "y" corresponden a puntos de la circunferencia en cierto ángulo. R es el radio preestablecido (en mi caso yo puse 50).

Primeramente obtenemos los centros de los círculos, para hacer esto se calculan los posibles centros, luego se hace uso de las frecuencias, donde las coordenadas que cuentan con el mayor número de frecuencia serán el centro del círculo.

Para identificar los centros despejamos a y b (centro del círculo) de las ecuaciones anteriores quedando las nuevas ecuaciones de la siguiente manera: 


Para obtener los ángulos, se usan los gradientes(x, y) con los que hemos estado trabajando en posts anteriores, obteniéndolos por medio de máscaras de convolución.

Obtención de los ángulos:


Los centros son etiquetados con un ID y cada circunferencia es pintada con una tonalidad de amarillo distinta (como lo exige la actividad).
Los siguientes códigos códigos realizan los procesos antes mencionados (basados en los códigos de clase):

im = Image.open("circle.png")
    mx = [[-1, -1, -1], [2, 2, 2], [-1, -1, -1]]
    my = [[-1, 2, -1], [-1, 2, -1], [-1, 2, -1]]
    imx = convolucion(im, mx)
    imy = convolucion(im, my)
    radio = 50 # Variando para distintos radios de circulo
    
    frecuencia = centros(imx, imy, im, radio)
    
    maximo = 0
    suma = 0.0
    for i in frecuencia.keys():
        suma += frecuencia[i]
        if frecuencia[i] > maximo:
            maximo = frecuencia[i]

    promedio = suma/len(frecuencia)
    umbral = maximo-promedio

    for i in frecuencia.keys():
        if frecuencia[i] < umbral:
            frecuencia.pop(i)
        
    circulos(im,frecuencia,radio)
    im.save('newone.png')

#Localizacion de centros y pintado de la circunferencia
def centros(imx, imy, im, r):
    ancho,alto = im.size
    frec = dict()
    circulos = dict()
    cx = imx.load()
    cy = imy.load()

    for x in range(ancho):
        for y in range(alto):
            (rx,gx,bx) = cx[x,y]
            (ry,gy,by) = cy[x,y]
            
            gx = float(rx+gx+bx)/3
            gy = float(ry+gy+by)/3
            g = sqrt(pow(gx,2) + pow(gy,2))

            if fabs(g) > 0:
                theta = atan2(gy,gx)
                centro = (int( x - r * cos(theta)), int( y - r * sin(theta)))

                if not centro in frec:
                    frec[centro] = 1
                else:
                    frec[centro] += 1
            
    return frec

def circulos(im, frecuencia, r):
    pixeles = im.load()
    fuente = ImageFont.truetype('/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-C.ttf',20)
    imagen = ImageDraw.Draw(im)
    cont = 1
    color = dict()
    aux = 1
    for i in frecuencia.keys():
        color[i] = (random.randint(250,255), random.randint(100,255), random.randint(0,50)) #Distintos tonos de amarillo, para cada cirunferencia
        imagen.ellipse((i[0]-aux, i[1]-aux, i[0]+aux, i[1]+aux), fill=(0,255,0))
        imagen.text((i[0]+aux+3, i[1]), ('ID: '+str(cont)), fill=(0,0,255), font=fuente)
        cont +=1

    for c in color.keys():
        i ,j = c
        for angulo in range(360): #Pintar
            x = i + r*cos(angulo)
            y = j + r*sin(angulo)
            pixeles[x,y] = color[c] 
    return im


Resultados obtenidos:
En este excluyó al color aqua :(



Fuentes de ayuda:
 

Cualquier duda o aclaración pueden dejarla en comentarios.

Saludos a todos!

1 comentario:

  1. En la descripción concluyes correctamente que no hace falta calcular theta, pero en el código la calculas de todos modos :P Lo del aqua es probablemente por no sobrevivir el umbral de binarización de bordes. 4 pts.

    ResponderEliminar