lunes, 22 de abril de 2013

Tarea 6

Tarea 6 - Detección de agujeros

Hola, esta entrada corresponde a la tarea número 6 de la materia de Visión Computacional, consiste en la detección de agujeros por medio de histogramas.


Bien, para la detección de agujeros usé la técnica de histograma lateral, lo primero que realicé fue obtener los histogramas lateral vertical y horizontal, esto lo realicé sumando cada uno de los pixeles por fila y al final se obtenía un total en cada fila; también realicé lo mismo con las columnas, esto se hace con el propósito de obtener las intensidades de pixeles y así por medio de picos (superior o inferior) de intensidades de pixeles se obtienen los posibles agujeros.

A continuación muestro el proceso no tan detallado (eso se verá en el laboratorio).

Bien lo primero que tengo es la imagen original (tomada con mi cámara), a esta le pasó por el proceso de escala de grises que habíamos desarrollado en tareas pasadas. 

(Imagen original) 

(Imagen escala de grises)
 
Teniendo la imagen en esacala de grises, sabemos que cada pixel tiene el mismo valor en sus 3 componentes (RGB), de esta manera sumamos cualquiera de ellos a su pixel consecutivo, y así hasta terminar la fila o columna. Si continuamos con el proceso podemos concluir que tendremos 2 listas del tamaño de las dimensiones de la imagen, y cada elemento de la lista será el total de la suma de intensidades de pixeles para una respectiva fila o columna. El código que hace todo este proceso es el siguiente:


Como pueden observar en el código también fui rellenando archivos dat (uno para histograma lateral vertical y otro para horizontal), en los que contiene el resultado de las sumas de cada fila y columna, junto con su correspondiente número de fila/columna, esto con el objetivo de graficar en gnuplot cada uno de los histogramas.

Este es el resultado del archivo "horizontal.dat" usado para graficar el histograma en gnuplot, el valor de la columna 1 son las filas de la imagen (solo puse hasta el 25, pero son mucho más, obviamente depende de las dimensiones de tu imagen); la columna 2 son las sumas de la intensidad de los pixeles.


0 141835
1 141895
2 141890
3 141757
4 141698
5 141803
6 141817
7 141685
8 141859
9 142024
10 141962
11 141760
12 141657
13 141662
14 141812
15 142030
16 141920
17 141918
18 141951
19 142003
20 142015
21 141910
22 141774
23 141748
24 142089
25 142136

Este es el resultado del archivo "vertical.dat" el valor de la columna 1 corresponde a las columnas de la imagen, mientras que el de la columna 2 corresponde  a las sumas de las intensidades de la respectiva columna (obviamente tampoco puse todas, solo las primeras 25).


0 134999
1 134896
2 134912
3 135076
4 135153
5 135076
6 135008
7 135046
8 134931
9 134854
10 135049
11 135276
12 135119
13 134867
14 134904
15 135087
16 134957
17 135071
18 134839
19 134753
20 134903
21 135025
22 135075
23 134918
24 135052

Los resultados ploteados en gnuplot se ven de la siguiente manera:

(Lateral horizontal)


(Lateral vertical)


Después calculé umbrales para poder tomar solo los picos resultantes, los umbrales los obtuve promediando la listas donde contenía todas las sumas de las filas y las columnas, es decir, tengo 2 umbrales; luego filtré los puntos obtenidos para pintar una linea por cada supuesto agujero (pico). El código que realiza este proceso es el siguiente:




El resultado es el siguiente:


A partir de aquí, sabiendo los puntos en donde se intersectan los picos obtenidos, rellené los posibles agujeros con bfs (de distintas tonalidades de morado), además agregué un punto en amarillo sobre las intersecciones y una etiqueta a cada agujero. También calculé los porcentajes que ocupa cada agujero con respecto a las diemnsiones de toda la imagen. El código que hace este proceso es el siguiente: 



El resultado del proceso es el siguiente:



Prueba 2

Esta vez ya no explico el proceso porque es prácticamente lo mismo.

(Imagen original)

(Lateral horizontal)


(Lateral vertical)


(Trazado de líneas en posibles agujeros)


(Resultado final)

Las tonalidades de morado salieron parecidas, pero sí puse en el código que se obtuvieran valores aleatorios de RGB (con resultados morados) para cada agujero.


Una de las tantas impresiones que hice en terminal fueron los puntos donde se intersectan las líneas con los picos o posibles agujeros.


Eso es todo por esta actividad.  
Liga a mi repositorio: https://github.com/eddypre/VisionTriana
Referencias: http://elisa.dyndns-web.com/~elisa/teaching/comp/vision/agujeros.pdf

Cualquier duda o aclaración pueden dejarla en comentarios.

Saludos!

jueves, 18 de abril de 2013

Laboratorio 6

Laboratorio 6 - Relleno de elipses / círculos

Hola, esta entrada corresponde a la actividad número 6 del laboratorio de Visión Computacional. La actividad consiste en el relleno de elipses y círculos.

Para realizar esta actividad generé elipses con centros y radios (menores y mayores) con valores aleatorios, luego de generar los elipses obtuve las coordenadas de el borde de cada elipse generado, desde 0° hasta 360° mediante las siguiente ecuaciones:

            puntox = centrox + (radiox*cos(angulo))
            puntoy = centroy + (radioy*sin(angulo))

Luego esas coordenadas las uso para recalcar el borde del elipse y usar bfs para rellenar cada uno de los elipses. Seguido de eso pongo puntos en los centros de cada elipse, además de su ID (también en el centro). Al final calculo los porcentajes que ocupa cada elipse con respecto a las dimensiones de la imagen completa.

Bien, al iniciar el programa, tú decides el número de elipses a poner, luego genero los centros y radios aleatoriamente (como lo mencioné anteriormente) de la siguiente manera:


Después mi programa pasa a dibujar cada uno de los elipses con los valores retornados por la función orígenes, esto lo hace mi función dibujar:


 
Además de dibujar los elipses también remarca el contorno de los mismos usando las coordenadas obtenidas del borde (por medio de las ecuaciones antes mencionadas). La función dibujar también rellena mis elipses mandando llamar a bfs, esta misma función marca los centros en color azul y pone las etiquetas con el ID.



Al final calculo los porcentajes de cada elipse con respecto a las dimensiones de la imagen completa:


Ahora les muestro los resultados obtenidos.



Prueba 1.

No se aprecia muy bien el centro de cada elipse, pero si lo marqué con un pixel en azul (se puede corroborar en el código).




Prueba 2.

Pueden notar (en terminal) que paso como parámetro el número de elipses a plasmar. Igual, no se nota el pixel azul central, pero si está presente.





Prueba 3.




Extra.

Bueno, para su deleite, les dejo un arte abstracto que generé pasando un parámetro de 60 elipses. 


Esto es todo por esta actividad.

Liga a mi repositorio: https://github.com/eddypre/VisionTriana

Cualquier duda o aclaración pueden dejarla en comentarios.

Saludos a todos! 

lunes, 8 de abril de 2013

Presentación de proyecto

Presentación de proyecto




Cualquier duda o aclaración pueden dejarla en comentarios.

Saludos!


jueves, 7 de marzo de 2013

Laboratorio 5

Laboratorio 5 - Detección de círculos (radios distintos)

Hola, esta entrada corresponde a la actividad de laboratorio 5 de la materia de Visión computacional y consiste en la detección de círculos (como la tarea 4), pero esta vez con radios distintos para cada círculo.

Bueno, debido a que esta práctica es similar a la tarea 4 de la misma materia solo tuve que realizar unas pocas modificaciones al código que ya había realizado. La implementación consiste en obtener las coordenadas de los bordes para luego determinar los puntos más lejanos (entre cada círculo obviamente); mediante los puntos antes mencionados obtenemos el diámetro de cada círculo, sabiendo de antemano que la mitad de ese diámetro es el radio.

Al conocer el radio, luego repetimos los métodos usados en la práctica anterior para pintar las circunferencias y etiquetar con un ID a cada círculo:

El código que hace todo lo anteriormente explicado es el siguiente:
 

if __name__ =="__main__":
  
    #transformar()
    #filtrada()
    #conv()
    #umbrales()

    #********************************************************************* 

    miImagen = Image.open("meh.jpeg")
    dr = ImageDraw.Draw(miImagen)
    p = miImagen.load()
    x, y = miImagen.size
    
    for i in range(x):
      for j in range(y): 
       #print p[i, j]  
       #time.sleep(1)
       if p[i,j] == (255,255,255):
        #print "afserfsefr"
        n, bordes = bfs(miImagen, (i,j), (255,0,0))
        menor, mayor, radio = Diametro(bordes)
        print "menor: ", menor[0], " + mayor: ", mayor[0]
        inicio(miImagen, radio)

    miImagen.show()    


def Diametro(bordes):
 menor = min(bordes)
 mayor = max(bordes)
 diametro = mayor[0] - menor[0]
 radio = int(ceil(diametro / 2.0))
 print radio
 return menor, mayor, radio 


def inicio(im, radio): #Ahora es variable
    #im = Image.open("meh4.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)
     
    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)


El pintado de circunferencia así como la etiqueta de los círculos ya lo habíamos visto y lo pueden encontrar en la entrada anterior.

Esto fue lo "nuevo" para esta entrada,  tuve bastantes problemas con bfs para obtener las coordenadas requeridas.

Uno de los intentos fallidos:



La idea es buena pero  la actividad no la pude terminar por falta de tiempo. Intentaré corregirlo y completarlo lo más pronto posible.

Cualquier duda o aclaración pueden dejarla en comentarios.

Saludos a todos!

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!

jueves, 28 de febrero de 2013

Laboratorio 4

Laboratorio 4 - Detección de diagonales

Hola, esta entrada corresponde a la cuarta actividad del laboratorio de visión computacional. La actividad consiste en localizar y pintar las diagonales de los objetos de una imagen.
En esta misma entrada primero hablaré sobre la detección de lineas horizontales y verticales (esto fue la tarea 4 de la misma materia) continuar con el seguimiento y explicar de donde viene la detección de lineas en diagonal.

Detección de líneas 

Para la detección de lineas usamos la transformada de Hough, lo que realizamos fue hacer el cálculo de los gradientes vertical y horizontal de la imagen usando máscaras de convolución (como lo hicimos en la actividad de detección de bordes) seguido de obtener los gradiente antes mencionados,  continuamos calculando los valores de theta de los pixeles de la imagen.

Cuando tenemos los gradientes, calculamos el ángulo de cada pixel, yo usé una imagen binarizada sin filtro, porque cuando la pasaba por mi filtro tendía a poner demasiadas lineas verticales y horizontales.
Bueno, obtuvimos los ángulo de los pixeles con la siguiente fórmula:


Las variables de esta fórmula son arctan (arcotangente), gy (gradiente y), gx (gradiente x).
Después de calcular los ángulos, se calcula la variable rho usando al fórmula siguiente:


El valor de rho es guardado en una lista con el valor del ángulo theta.

Seguido de esto obtuvimos las frecuencias de cada "theta, rho" usando un diccionario, esto con el fin de determinar qué pixeles son lineas, tomando en cuenta que cuando un par (theta, rho) tiene más repeticiones, quiere decir que hay más probabilidad de que el par sea una línea (mismo ángulo.)

Para terminar pintamos pixeles pertenecientes a las líneas (azules para horizontales, rojo para verticales y verde para las líneas diagonales)

Para las líneas diagonales solo agregué una condición que cuando el ángulo no fuera ni 0 ni 90 ni 180 ni 270 lo tomara como una diagonal (y lo pinté de verde).
A continuación los highlights del código:
'''
Convolucion y deteccion de lineas
'''

def convolucion(im,g):
 w, h = im.size
 pixeles = im.load()
 imConvolucion = Image.new('RGB', (w,h))
 pix = imConvolucion.load()
 
     for x in range(w):
         for y in range(h):
          suma = 0
              for i in range(x-1, x+2):
                  for j in range(y-1, y+2):
                       try:
                           suma += g[i - (x-1)][j - (y-1)] * pixeles[i,j][1]
                       except:
                           pass
              pix[x,y] = (suma,suma,suma)
     return imConvolucion
 
def frecuentes(histo, cantidad):
 frec = list()
 for valor in histo:
  if valor is None:
       continue
  
  frecuencia = histo[valor]
  acepta = False
  if len(frec) <= cantidad:
   acepta = True
  if not acepta:
   for (v, f) in frec:
    if frecuencia > f:
               acepta = True
               break
  if acepta:
   frec.append((valor, frecuencia))
   frec = sorted(frec, key = lambda tupla: tupla[1])
   if len(frec) > cantidad:
           frec.pop(0)
     incluidos = list()
     for (valor, frecuencia) in frec:
         incluidos.append(valor)
 
     return incluidos
 
def deteccionDeLineas():
    umbral = 10
    im = Image.open("meh3.jpg")

    sobelx = [[-1, -1, -1], [2, 2, 2], [-1, -1, -1]]
    sobely = [[-1, 2, -1], [-1, 2, -1], [-1, 2, -1]]
    imx = convolucion(im, sobelx)
    imy = convolucion(im, sobely)
    gx = imx.load()
    gy = imy.load()
    w,h = im.size
    comb = {}
    pixeles = im.load()
    resultado = list()
 
    for x in range(w):
        datos = list()
        for y in range(h):
            hor = gx[x,y][0]
            ver = gy[x,y][0]
 
            if fabs(hor) + fabs(ver) <= 0.0:#nada en ninguna direccion                                                                        
                theta = None
            elif hor == 0 and ver == 255:
                theta = 90
            elif fabs(hor) > 0.0:
                theta = atan(fabs(ver/hor))
            if theta is not None:
                rho = fabs( x * cos(theta) + y * sin(theta))
 
                if x > 0 and x < w-1 and y > 0 and y < h-1:
                    if (rho, theta) in comb:
       comb[ (rho, theta) ] += 1
                    else:
                        comb[ (rho, theta) ] = 1
                datos.append( (rho, theta) )
            else:
                datos.append((None,None))
        resultado.append(datos)
 
    incluir = int(ceil (len(comb) * umbral))
 
    frec = frecuentes(comb, incluir)
 
    for x in range(w):
     for y in range(h):
            if x > 0 and x< w-1 and y > 0 and y < h-1:
    rho, theta = resultado[x][y]
 
   if (rho, theta) in frec:
                    if theta == 0:
                        pixeles[x,y] = (255,0,0)
                    elif theta == 90:
                        pixeles [x,y] = (0,0,255)
              elif theta != 0 and theta != 90 and theta != 180 and theta != 270: #Para diagonales
                    pixeles [x, y] = (0,255,0) #Los pintamos verde
                          print "Soy un pixel diagonal"
    im.save('meh5.jpg')



Ahora algunos resultados con imágenes sencillas (hacer click sobre ellas para ampliarlas):






(Para diagonales)



(Una sección se pinto verde porque traia letras XD)




Mi liga de git: https://github.com/eddypre/VisionTriana

Cualquier duda o aclaración pueden dejarla en comentarios. 

Saludos a todos!


miércoles, 20 de febrero de 2013

Laboratorio 3

Laboratorio 3 - Convex hull

Hola, en esta actividad de laboratorio de Visión computacional realizaremos la actuvidad de convex hull,  que no es más que una región convexa que abarca una figura entera (sobre convexa).

Esta actividad la realizaré a partir del resultado de las actividades anteriores, la base sobre la que se trabajará es una imagen binarizada con bordes identificados, donde los bordes están pintados en color blanco y el resto de la imagen en color negro.

Existen diversos métodos para obtener la cerradura convexa, pero el que usé yo (porque casi todos los compañeros usamos ese) es el de Jarvis, este algoritmo parte de un punto vértice, luego lo que hace es envolver todos los puntos contenidos. 

En este sitio se explica muy bien el funcionamiento, además vienen animaciones muy buenas para entenderlo: http://www.cs.princeton.edu/courses/archive/spr09/cos226/demo/ah/JarvisMarch.html 

Mi código:





Este es el resultado, marqué en rojo los puntos determinados por jarvis y las líneas verdes es el convex hult, pueden observar que hubo muchos errores ya que existen puntos donde no deberían, de esa manera al pintar las lineas tomaba muchos puntos de referencia, intentaré solucionarlo después.


Cualquier duda o aclaración pueden ponerla en comentarios.
Saludos a todos.