lunes, 15 de abril de 2013

Convolución Bidimensional

En la entrada anterior me quedo pendiente profundizar algo en la base del código de la máscara de enfoque. La máscara de enfoque, y casi cualquier filtrado que se haga sobre una imagen, se implementa a partir de la convolución bidimensional discreta. En dicha convolución, el valor del píxel de salida se calcula mediante la suma ponderada de píxeles vecinos. En lo que se refiere al procesamiento de imágenes, la convolución se realiza entre la imagen y una matriz (los coeficientes del filtro) llamada máscara, o kernel. De manera matemática la convolución bidimensional se representa según:


Ya que lo más habitual es emplear una máscara de 3X3 elementos para realizar la convolución bidimensional, entonces la ecuación anterior se convierte en:


Como ejemplo para aclarar las áridas expresiones matématicas anteriores, tomamos una matriz de 4X4 que representa los valores de los píxeles de una imagen, y como máscara una matriz de 3X3

-Matriz imagen

 [15    20    101    100]
 [200  50      55        8]
 [10    11    230    202]
 [100  130  115    120]


-Máscara

 [7 8 3]
 [1 1 0]
 [1 2 1]


Los pasos para realizar la convolución consisten en:

1.- Rotar la máscara 180º a partir del elemento del centro.

 [1 2 1]
 [0 1 1]
 [3 8 7]


2.-Sobreponer el centro de la máscara sobre el elemento de interés.

 [15   1    20 2    101  1    100]
 [200 0    50 1      55  1        8]
 [10   3    11 8    230  7    202]
 [100       130     115        120]


3.-Multiplicar cada valor (peso) de la máscara rotada por el píxel de la matriz de imagen que se encuentra "bajo" la máscara.
4.-Sumar los productos individuales en el apartado anterior.

El resultado entonces es:

 [197   88]
 [181 190]


En el caso de trabajar en los extremos de la imagen lo que se hace es insertar ceros en los extremos, lo que se conoce como zero padding. El resultado del ejemplo es una matriz de 2X2 ya que no hemos trabajado en la zona de los extremos de la imagen.

El  código en Python, usando numpy y Scipy para realizar la convolución bidimensional es:

import numpy as np
import cv2

kernel=np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], 'uint8')
signal=np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], 'uint8')

rows=signal.shape[0]-kernel.shape[0]+1
cols=signal.shape[1]-kernel.shape[1]+1
output=np.zeros((rows,cols), 'uint8')

kernel_reversed=np.rot90(np.rot90(kernel))

for i in range(0, output.shape[0]):
   for j in range(0, output.shape[1]):
       
#desplazando el kernel
        signal_patch=signal[i:i+len(kernel),j:j+len(kernel)]  
        output[i][j]=(kernel_reversed*signal_patch).sum()

print signal_patch
print output


Como referencias pueden valer los dos libros siguientes. El segundo es un clásico en el tratamiento digital de señales, viene a ser la continuación del, más clásico aún, Oppenheim.

-Gonzalez, R.C., and Woods, P.,
Digital Image Processing, Addison Wesley, 2002
-Proakis, John G., and Manolakis, Dimitris G.,
Digital Signal Processing: Principles, Algorithms and applications, Prentice-Hall Inc, 1996.

No hay comentarios:

Publicar un comentario