February 11, 2013

Máscaras de convolución y detección de bordes

En esta entrada les mostraré como aplicar una máscara de convolución y como detectar los bordes binarizando una imagen y utilizando la máscara o filtro Sobel

Aplicar una máscara de convolución consiste en utilizar una matriz, comúnmente de 3x3 creada o determinada por matemáticos o personas dedicadas al filtrado de imágenes, para aplicarla en los pixeles de una imagen. El proceso consiste en tomar un pixel para utilizar sus vecinos y de esta manera colocar la matriz encima y provocar distintos filtros o cambios en la imagen.

Pueden consultar estas páginas que me sirvieron de mucho para comprender este concepto:
Como primer prueba utilicé un filtro Gaussiano, que es el siguiente:

Y como resultado obtuve el efecto que se conoce como Blur o difuminado en escala de grises, esto tan solo como pruebas.

Lo que realicé fue tomar un pixel, sumar todos sus vecinos y multiplicar por la posición correspondiente a la matriz Gaussiana y el resultado colocarlo en el pixel. Ésta es la fórmula que seguí para esto:

Donde f(x,y) es el pixel de la imagen que se está tratando, g(x,y) es la posición en la máscara.

Aquí la rutina que utilicé para realizar esto. Cabe aclarar que cambié todo mi código ya que estoy leyendo un libro de Python y quise poner en práctica las clases y objetos en python.

def convolucion(self):
 pixeles = self.imActual.load()
 imCon = Image.new("L", (self.w, self.h))
 conPix = imCon.load()
        h = [(0,0.2,0), (0.2,0.2,0.2), (0,0.2,0)]

        for x in range(self.h):
            for y in range(self.w):
         suma = 0
  for i in range(3):
                    for j in range (3):
   try:
                            if x < self.w or y < self.h:
                                suma += int(pixeles[(x-1)+i,(y-1)+j] * h[j][i])
                        except IndexError:
                            suma += 0
                    #print suma                                                 
                    conPix[x,y] = suma
        imCon.save('convolusion.png')
        self.imActual = imCon
        self.actualizarFondo()

El resultado obtenido es el siguiente:

Imagen Original:

Imagen con Convolución


Ahora para obtener los bordes de la imagen lo que utilicé fue una máscara o filtro sobel, el procedimiento que hice fue primero binarizar la imagen, después seguí el mismo procedimiento de la concolución con la máscara de Gauss pero para poder utilizar el filtro Sobel fue necesario cambiar el sentido de recorrer los pixeles de la imagen ya que de hacerlo ancho x largo la imagen la obtenía de manera invertida.

Este operador utiliza dos matrices para calcular las gradientes en x y en y para de esta manera determinar cuando hay un cambio de intensidad en los pixeles y así saber cuando es un borde


Este es el código para obtener los bordes:

def bordes(self):
        '''Aplica mascara Sobel para obtener los bordes de una imagen '''
        tiempoIn = time.time()
        if self.imActual.mode == 'RGB':
            self.binarizar()

        pixeles = self.imActual.load()
        imBor = Image.new("L", (self.w, self.h))
        borPix = imBor.load()

        gx = ([-1,0,1], [-2,0,2], [-1,0,1])
        gy = (([1,2,1], [0,0,0], [-1,-2,-1]))


        for y in range(self.h):
            for x in range(self.w):
                sumaX = 0
                sumaY = 0
                for i in range(len( gx[0] )):
                    for j in range(len( gy[0] )):
                        try:
                            resX = gx[i][j] * pixeles[x+j,y+i]
                            resY = gy[i][j] * pixeles[x+j,y+i]
                        except IndexError:
                     resX = 0
                     resY = 0

   sumaX = resX + sumaX
                        sumaY = resY + sumaY
                cuadradosX = pow(sumaX,2)
         cuadradosY = pow(sumaY,2)
                g = int(math.sqrt(cuadradosX + cuadradosY))
                suma = g

                if suma > 255:
                    borPix[x,y] = 255
                elif suma < 0:
                    borPix[x,y] = 0
        imBor.save('bordes.png')
        tiempoFin = time.time()
        print 'Mascara Sobel tardo: ', tiempoFin - tiempoIn, ' segundos'
 self.imActual = imBor
 self.actualizarFondo()

El resultado de aplicar este filtro es el siguiente:

Tiempo de procesamiento: 5.25 segundos

El resultado no es muy preciso con todas las imágenes como se puede apreciar en la imagen anterior, pero obtiene casi todos los bordes.

En promedio utilizando esta imagen a color y pasando por la binarización y el filtro Sobel, el tiempo de procesamiento fue de 5.25 segundos.

Otra prueba realizada:

Tiempo de procesamiento promedio: 6.56 segundos

La información de este filtro la pueden comprobar en Wikipedia que fue donde consulté

Aquí mi git con todo el código: git

1 comment: