February 25, 2013

Tarea 4. Detección de líneas

Este post consiste en detectar líneas horizontales y verticales en imágenes.

Para comenzar a trabajar con la detección de líneas, primero que nada hay que saber realizar binarización y aplicación de máscaras de convolución. Ambos los pueden encontrar en esta liga

Cuando utilicé una imagen en escala de grsises me generó mucho ruido al final, con líneas muy gruesas y algunas muy desfasadas, el binarizar la imagen me trajo mejores resultados

Detección de líneas

Para detectar líneas en una imagen se utiliza la transformada de Hough; el procedimiento consiste en calcular los gradientes horizontal y vertical de la imagen utilizando máscaras de convolución, en base a estos gradientes calcular el ángulo (θ) de los pixeles de la imagen.

En este caso los gradientes vertical y horizontal son dos imágenes cuyos pixeles son las matrices a tratar, dichos pixeles solo tienen valores binarios, es decir blanco o negro (0 o 255).

Una vez teniendo los gradientes se pasa a calcular el ángulo de cada pixel. Con la imagen binarizada se utiliza la siguiente fórmula:
θ=arctan(gy/gx)


Donde θ es el ángulo, arctan es la función arco tangente, gy el gradiente vertical y gx el gradiente horizontal.

También se toman en cuenta los siguientes aspectos que obtuve al correr múltiples veces el programa y observar los distintos ángulos:
  • Cuando 
    gx = 0
    gy = 0
    θ = nulo, esto es que el ángulo no va en ninguna dirección
  • Cuando 
    gx = 255 
    gy = 0
    θ = 0
  • Cuando 
    gx = 0 

    gy = 255
    θ = 90

Cuando se han calculado los ángulos se calcula una variable ρ (rho) utilizando la siguiente fórmula:
ρ=xcos(θ)+ysin(θ)

Esta ρ se guarda en una lista junto con su respectivo ángulo θ

Después de esto lo que sigue es contar el número de veces que se repite o frecuencia de cada par (ρ,θ). En este caso utilicé un diccionario, estas frecuencias nos permiten determinar que pixeles son líneas ya que cuando un par tiene más repeticiones quiere decir que es más probable que ese par pertenezca a una línea.

Ya como paso final solo es cuestión de pintar cada pixel, yo uyilicé un color verde para las líneas verticales y uno rojo para las líneas horizontales.

El código completo lo pueden encontrar en mi git: github.com/JonathanAlvarado/VisionComputacional/blob/master/lineas.py

La parte más importante es la siguiente y cualquier duda pueden consultar el código completo. Cabe aclarar que tomé como base el código visto en clase de la Dra. Elisa

Código

def convolucion(im,g):
    w, h = im.size
    pixeles = im.load()
    imCon = Image.new('RGB', (w,h))
    pixCon = imCon.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
            pixCon[x,y] = (suma,suma,suma)
    return imCon

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(original,im,umbral):
    '''Transformada de Hough                                                                                                                   
    umbral = lineas a considerar'''
    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 = original.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] = (0,255,0)
                    elif theta == 90:
                        pixeles [x,y] = (0,0,255)
    original.save('lineas.png')

Estas son algunas de las pruebas:
Imagen Original

Detección de líneas


Original

Detección

Como pueden ver en esta imagen las líneas más delgadas no las detectó ya que al binarizar y normalizar la imagen al ser muy delgadas se pierden y pasan a color blanco


Original

Detección

1 comment:

  1. Me da duda el fabs adentro del atan... Bastante bien anyhow; 4 pts.

    ReplyDelete