Saltar a contenido

Tutorial y ejercicios

Introducción

Desde el punto de vista del procesado de imagen, un filtro modifica una imagen calculando nuevos valores para los píxeles. En muchos casos, el nuevo valor depende de los píxeles que hay alrededor, es decir, de un vecindario local. Cuando esta combinación es lineal, se puede describir mediante una convolución con una pequeña matriz de pesos llamada kernel.

Aunque aquí se trabaje principalmente en el dominio espacial, también es útil recordar la interpretación frecuencial. Las variaciones lentas corresponden a zonas suaves de la imagen, mientras que las variaciones rápidas suelen aparecer en bordes, textura o ruido. Los filtros de suavizado reducen estas variaciones rápidas, y los filtros de realce las hacen más visibles.

En esta práctica se estudian distintos filtros de suavizado y realce aplicados a imágenes en escala de grises. El objetivo es comprender cómo actúan estos filtros, tanto a nivel matemático como visual, y analizar su comportamiento frente al ruido.

Manipulación básica de imágenes

Cargamos las imágenes que se utilizarán a lo largo de la práctica y las convertimos a escala de grises cuando es necesario, para trabajar únicamente con niveles de intensidad.

lena = imread("Imagenes\lena_gray_512.tif");

universo = imread("Imagenes\Universo.jpg");

universo = rgb2gray(universo);

Mostramos las imágenes cargadas para comprobar que se han leído correctamente.

montage({lena,universo})

figure_0.png

Filtros de suavizado

Los filtros de suavizado reducen el ruido y las variaciones bruscas de intensidad, a costa de perder detalle fino en la imagen.

El tamaño del vecindario y los pesos del kernel determinan hasta qué punto se modifica la imagen. Un vecindario pequeño conserva mejor los detalles, pero puede reducir poco el ruido. Un vecindario grande suaviza más, pero también puede eliminar bordes débiles o estructuras pequeñas que podrían ser importantes en una segmentación posterior.

Producto de convolución. Definimos un kernel de la media 3x3, que asigna el mismo peso a todos los píxeles de la vecindad.

El filtro de la media sustituye cada píxel por el promedio de los valores de su entorno. Esto reduce variaciones pequeñas y ruido aleatorio, pero también puede difuminar bordes porque mezcla píxeles de lados distintos de un contorno.

w = (1./9.)*[1,1,1;1,1,1;1,1,1];

Aplicamos la convolución usando conv2. Esta función no gestiona automáticamente los bordes, lo que provoca artefactos visibles.

lena_conv = conv2(lena,w);

montage({lena,uint8(lena_conv)}) % Observa los bordes

figure_1.png

Filtro de la media usando imfilter. La función imfilter permite aplicar el mismo kernel, pero gestionando mejor los bordes.

lena_media = imfilter(lena,w);

montage({lena,lena_media})

figure_2.png

Padding en imfilter. Por defecto se utiliza zero-padding, pero se pueden usar otras opciones para mejorar el resultado en los bordes.

lena_media_r = imfilter(lena,w,'replicate');

lena_media_s = imfilter(lena,w,'symmetric');

montage({lena,lena_media,lena_media_r,lena_media_s}) % Comparar especialmente los bordes

figure_3.png

Filtro gaussiano. El filtro gaussiano asigna mayor peso al píxel central y suaviza de forma más natural.

Un filtro gaussiano es un filtro de suavizado basado en la distribución gaussiana. Los píxeles cercanos al centro del kernel tienen más peso que los píxeles lejanos, de modo que el suavizado es más progresivo que con una media uniforme. El parámetro sigma controla la anchura de la gaussiana: cuanto mayor es sigma, más fuerte es el suavizado y más detalles finos pueden perderse.

Kernel gaussiano 3x3 con sigma = 1

w_gaussian = (1./16.)*[1,2,1;2,4,2;1,2,1];

lena_gaussian = imfilter(lena,w_gaussian);

montage({lena,lena_gaussian})

figure_4.png

Filtros gaussianos de mayor tamaño usando fspecial

Cuando se utiliza un kernel gaussiano más grande, el filtro puede tener en cuenta un vecindario más amplio. Esto es útil si el ruido es importante, pero también aumenta el riesgo de eliminar texturas finas o bordes débiles. Por este motivo, el tamaño del kernel y sigma deben escogerse según la escala de los detalles que se quieren conservar.

w_gaussian = fspecial("gaussian",5,5);

lena_gaussian = imfilter(lena,w_gaussian);

montage({lena,lena_gaussian})

figure_5.png

Filtro de la media genérico con fspecial

w_media = fspecial("average",5);

lena_media = imfilter(lena,w_media);

montage({lena,lena_media})

figure_6.png

Aplicación del filtro de la media para reducción de ruido gaussiano. Primero añadimos ruido gaussiano y después aplicamos el filtro para observar su efecto.

lena_ruido = imnoise(lena,"gaussian",0,0.01);

lena_ruido_fil = imfilter(lena_ruido,w_media);

montage({lena,lena_ruido,lena_ruido_fil})

figure_7.png

Suavizado previo para mejorar la binarización. El suavizado reduce pequeñas variaciones y facilita una binarización más estable.

universo_bin = universo>200;

w_media = fspecial("average",25);

universo_fil = imfilter(universo,w_media);

universo_fil_bin = universo_fil>200;

montage({universo,universo_bin,universo_fil_bin})

figure_8.png

Aplicación del filtro gaussiano a la reducción de ruido

w_gausiano = fspecial("gaussian",3,3);

lena_ruido_fil = imfilter(lena_ruido,w_gausiano);

montage({lena,lena_ruido,lena_ruido_fil})

figure_9.png

Filtros estadísticos

Los filtros estadísticos también observan un vecindario local, pero no calculan el resultado como una suma ponderada. En lugar de ello, utilizan una estadística como el mínimo, el máximo o la mediana. Esta diferencia los hace más adecuados en situaciones donde hay valores atípicos, como ocurre con el ruido de sal y pimienta.

Estos filtros se basan en estadísticas locales de la vecindad.

Filtro del máximo. Realza las zonas brillantes y elimina puntos oscuros aislados.

El filtro del máximo asigna a cada píxel el valor más alto de su vecindario. Por eso expande las zonas claras y puede hacer desaparecer pequeños puntos oscuros. Es una operación no lineal y está relacionada con la dilatación morfológica en escala de grises.

w_estadistico = ones(3);

lena_max = ordfilt2(lena,numel(w_estadistico),w_estadistico);

montage({lena,lena_max})

figure_10.png

Filtro del mínimo. Realza las zonas oscuras y elimina puntos brillantes aislados.

El filtro del mínimo realiza la operación contraria: asigna a cada píxel el valor más bajo de su vecindario. Esto expande las zonas oscuras y puede eliminar pequeños puntos brillantes. Conceptualmente se parece a una erosión morfológica en escala de grises.

lena_min = ordfilt2(lena,1,w_estadistico);

montage({lena,lena_min})

figure_11.png

Filtro de la mediana. Es especialmente eficaz para eliminar ruido impulsional (sal y pimienta).

El filtro de la mediana ordena los valores del vecindario y escoge el valor central. Como no calcula una media, los valores extremos producidos por el ruido de sal y pimienta tienen menos influencia. Por eso suele conservar mejor los bordes que el filtro de la media cuando el ruido es impulsional.

lena_mediana = medfilt2(lena,size(w_estadistico));

montage({lena,lena_mediana})

figure_12.png

Aplicación de filtros estadísticos a ruido sal y pimienta

probabilidad = 0.05;

ruido_impulsional = rand(size(lena));

lena_con_ruido = lena;

lena_con_ruido(ruido_impulsional < probabilidad/2) = 0;

lena_con_ruido(ruido_impulsional > 1 - probabilidad/2) = 255;

lena_max = ordfilt2(lena_con_ruido,numel(w_estadistico),w_estadistico);

lena_min = ordfilt2(lena_con_ruido,1,w_estadistico);

lena_mediana = medfilt2(lena_con_ruido,size(w_estadistico));

montage({lena,lena_con_ruido,lena_max,lena_min,lena_mediana})

figure_13.png

Filtros de realce

Los filtros de realce buscan destacar cambios importantes de intensidad. Estos cambios pueden corresponder a bordes de objetos, cambios de textura, sombras o discontinuidades en la escena. Como el ruido también puede producir cambios bruscos, es habitual aplicar algún suavizado antes de calcular gradientes o derivadas.

Estos filtros destacan cambios bruscos de intensidad y permiten detectar bordes.

Derivada digital por definición. Se aproximan las derivadas en las direcciones x e y mediante kernels simples.

w_dx = [0,1,0;0,-1,0;0,0,0];
w_dy = [0,0,0;1,-1,0;0,0,0];

Gradiente digital. Se combina la magnitud de las derivadas en ambas direcciones.

El gradiente mide cómo cambia la intensidad en las direcciones horizontal y vertical. Su magnitud es grande en puntos donde hay una transición fuerte, como un borde. Por eso el gradiente es una herramienta básica para detectar contornos y orientar otros descriptores.

lena_gradiente = abs(imfilter(lena,w_dx)) + abs(imfilter(lena,w_dy));

lena_negativa = 255 - lena_gradiente;

montage({lena,lena_gradiente,lena_negativa})

figure_14.png

Filtros de Roberts, Sobel y Prewitt. Estos filtros calculan el gradiente usando distintas aproximaciones.

Roberts, Sobel y Prewitt son aproximaciones discretas de la derivada de la imagen. Roberts es más local y puede ser más sensible al ruido, mientras que Sobel y Prewitt incorporan algo de suavizado en la dirección perpendicular. Esto hace que la detección de bordes sea a menudo más estable, aunque la respuesta puede variar según la orientación del borde.

Filtro de Roberts

wR_dx = [1,0;0,-1];
wR_dy = [0,1;-1,0];

lena_gradiente_roberts = abs(imfilter(lena,wR_dx)) + abs(imfilter(lena,wR_dy));

lena_negativa_roberts = 255 - lena_gradiente_roberts;

montage({lena,lena_gradiente_roberts,lena_negativa_roberts})

figure_15.png

Filtro de Sobel

w_sobel = fspecial("sobel");

lena_gradiente_sobel = abs(imfilter(lena,w_sobel)) + abs(imfilter(lena,w_sobel'));

lena_negativa_sobel = 255 - lena_gradiente_sobel;

montage({lena,lena_gradiente_sobel,lena_negativa_sobel})

figure_16.png

Filtro de Prewitt

w_prewitt = fspecial("prewitt");

lena_gradiente_prewitt = abs(imfilter(lena,w_prewitt)) + abs(imfilter(lena,w_prewitt'));

lena_negativa_prewitt = 255 - lena_gradiente_prewitt;

montage({lena,lena_gradiente_prewitt,lena_negativa_prewitt})

figure_17.png

Laplaciano digital. Detecta cambios de intensidad en todas las direcciones.

El Laplaciano es una derivada de segundo orden. A diferencia del gradiente, no proporciona una dirección principal de cambio, sino que responde a variaciones de intensidad en cualquier orientación. Como las derivadas de segundo orden son muy sensibles al ruido, a menudo se combinan con un suavizado previo, como ocurre con el filtro Laplacian of Gaussian.

w_laplaciano = [1,1,1;1,-8,1;1,1,1];

lena_laplaciano = imfilter(lena,w_laplaciano);

lena_laplaciano_negativo = 255 - lena_laplaciano;

montage({lena,lena_laplaciano,lena_laplaciano_negativo})

figure_18.png

Laplacian of Gaussian (LoG). Combina suavizado gaussiano y detección de bordes.

El LoG aplica primero un suavizado gaussiano y después un Laplaciano. El suavizado reduce la respuesta al ruido, mientras que el Laplaciano detecta cambios rápidos de intensidad. Esta combinación es útil porque las derivadas de segundo orden son muy sensibles al ruido si se aplican directamente.

w_ruido_gauss = fspecial('gaussian',3,1);

lena_ruido_gauss = imfilter(lena,w_ruido_gauss);

lena_log = imfilter(lena_ruido_gauss,w_laplaciano);

lena_log_negativo = 255 - lena_log;

montage({lena,lena_laplaciano,lena_laplaciano_negativo,lena_log,lena_log_negativo})

figure_19.png

Difference of Gaussians (DoG). Se resta el resultado de dos filtros gaussianos con distinta sigma.

La Difference of Gaussians compara dos versiones de la imagen suavizadas con valores de sigma distintos. Al restarlas, se resaltan estructuras que son visibles a una cierta escala y se reducen otros detalles. Esta idea de trabajar con escalas diferentes es muy importante en visión por ordenador, especialmente en detectores de puntos de interés como SIFT.

sigma1 = 0.5;
sigma2 = 2;

w_gaussiano1 = fspecial('gaussian',9,sigma1);
w_gaussiano2 = fspecial('gaussian',9,sigma2);

lena_gaussiano_1 = imfilter(lena,w_gaussiano1);
lena_gaussiano_2 = imfilter(lena,w_gaussiano2);

lena_dog = lena_gaussiano_2 - lena_gaussiano_1;

lena_dog_negativa = 255 - lena_dog;

montage({lena,lena_dog,lena_dog_negativa})

figure_20.png

Binarización del resultado DoG para resaltar bordes significativos

Después de calcular una respuesta de bordes o de diferencia de escalas, a menudo hay que decidir qué respuestas son suficientemente importantes. La binarización hace esta selección mediante un umbral: los valores fuertes se conservan y los débiles se eliminan. Esto facilita interpretar el resultado como un conjunto de bordes candidatos.

lena_dog = lena_dog > 5;

lena_dog_negativa = lena_dog_negativa < 250;

montage({lena,lena_dog,lena_dog_negativa})

figure_21.png