Filtro Gaussiano
Un filtro gaussiano es una clase de filtro que se caracteriza por emplear un kernel (matriz empleada para filtrar) con coeficientes que siguen una distribución gaussiana. Esta clase de filtros son apropiados para emborronar una imagen, lo cual permite que determinados tipos de ruido sean filtrados a costa de algunos detalles de la imagen. En imágenes que no poseen información en alta frecuencia (imágenes con detalles intrincados) esta clase de filtros permite eliminar los detalles sin perder la forma general del objeto (bultos principales).
Imagen con ruido gaussiano
Imagen filtrada
Kernel empleado para el filtrado
Como se puede observar, existe un filtrado del ruido en la imagen, sin embargo también existe una perdida de nitidez como efecto colateral. Cabe recalcarse que el nivel de filtrado se encuentra determinado por el tamaño del kernel empleado para dicha operación. Para el caso ejemplo, el filtro contempla un kernel de 15x15, el cual se fabrica mediante la multiplicación 2D de dos curvas gaussianas. Un ejemplo clásico (redondeado) de esta clase de filtros para 5x5, se presenta a continuación.
kernel = [0, 1, 2, 1, 0]
[1, 3, 5, 3, 1]
[2, 5, 9, 5, 2]
[1, 3, 5, 3, 1]
[0, 1, 2, 1, 0]
Con objeto de generar un filtrado de esta clase, únicamente es requerido definir un kernel de convolución como los antes mencionados y posteriormente multiplicar como si de ventanas caminantes se tratase cada pixel por la ponderación indicada en el kernel sumando los números obtenidos al final, así para una imagen de 100x100, considerando un kernel de 5x5, serian requeridas 96x96 multiplicaciones en bloque con su suma.
Finalmente, una vez se tiene la imagen resultante (de 96x96 pixeles), es requerido reescalar la imagen al dominio de salida (usualmente de 0-255), esto ya que la multiplicación suele reescalar la imagen a números no representables en una pantalla tradicional.
Script empleado en el ejemplo:
Nótese que este código busca dejar las operaciones de forma aparente, sin embargo, existen librerías que facilitan su implementación y aceleran el procedimiento, reduciendo el tiempo de computo.
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Se carga la imagen
imagen = cv2.imread('atomium con ruido.png', 0)
# Se define un tamaño de kernel
tamaño = 15
sig = (tamaño-1)/3
# Se genera una curva gausiana para obtener los valores del filtro
d = np.arange(-(tamaño-1)/2, (tamaño-1)/2+1).astype(int)
s = np.exp(-(np.power(d,2))/(2*np.power(sig,2)))
# Se obtienen los coheficientes del filtro mediante el producto 2D de la curva
kernel = np.zeros((tamaño, tamaño))
for yi in range(tamaño):
for xi in range(tamaño):
kernel[yi, xi]=s[yi]*s[xi]
# Se plotean los coheficientes del filtro
plt.Figure(figsize=(6,6), dpi=300)
plt.axis('off')
plt.imshow(kernel, cmap='Greys_r')
plt.show()
# Se definen variables utiles
y, x = imagen.shape
imagen2 = np.zeros((y-tamaño+1, x-tamaño+1))
inf = int((tamaño-1)/2)
sup = int((tamaño-1)/2+1)
# Para cada ventana valida, se obtiene el promedio ponderado de la vecindad
# considerando una ponderacion gaussiana segun la distancia
for yi in range(inf, y-inf):
for xi in range(inf, x-inf):
ventana = imagen[yi-inf:yi+sup, xi-inf:xi+sup]
imagen2[yi-inf, xi-inf] = (ventana * kernel).sum()
# Debido al cambio de rango generado en el promedio ponderado, se reescala la
# imagen al domino apropiado para su almacenaje y muesta
maximo = imagen2.max()
minimo = imagen2.min()
imagen3 = (((imagen2 - minimo)/(maximo-minimo))*255).astype(int)
# se guarda la imagen
cv2.imwrite('atomium filtrada.png', imagen3)