Alcuni importanti filtri basati sulla convoluzione

Nella teoria dell'image filtering i filtri lineari hanno una
determinante importanza, tra questi alcuni sono particolarmente noti sia
per le loro proprietà matematiche che per l'efficacia dimostrata nelle
applicazioni reali. Vogliamo mostrarne qui alcuni senza particolari
esigenzea di formalizzazione teorica.

Contents

Filtro gaussiano

Il filtro Gaussiano consiste nel convolvere l'immagine con una risposta
all'impulso consistente in una campana di Gauss centrata e normalizzata
per aver somma unitaria, si tratta di un filtro separabile, quindi molto
efficiente se applicato prima per righe e poi per colonne (o viceversa).
Si osservi che la trasformata di Fourier di una Gaussiana è ancora una
Gaussiana, quindi il filtro Gaussiano approssima un filtro passa-basso.
% Leggo l'immagine originale:
img = imread('coins.png');

% Preparo la risposta all'impulso 1d:
h = gauss(-50:50,15); h = h/sum(h);

% Filtro le righe, le colonne, entrambe in sequenza:
img1 = filter2(h,img);
img2 = filter2(h',img);
img3 = filter2(h',img1);

% Vediamo il risultato:
figure;
subplot(221); imshowscale(img); title('Immagine originale');
subplot(222); imshowscale(img1); title('Filtering per righe');
subplot(223); imshowscale(img2); title('Filtering per colonne');
subplot(224); imshowscale(img3); title('Immagine filtrata');
% Vediamo l'anatomia del filtro:
figure; surf(h'*h); title('Filtro gaussiano');

DoG

Se da una immagine eliminiamo le basse frequenze (ottenute con il filtro
Gaussiano) rimangono le alte frequenze, ovvero i bordi:
% Vediamo la differenza di immagini filtrate con il filtro Gaussiano:
h = gauss(-5:5,1.5); h = h/sum(h);
img1 = filter2(h,img);
img3 = filter2(h',img1);
figure; imshowscale(double(img)-img3);
Se utilizziamo filtri Gaussiani a frequenze differenti e calcoliamo la
differenza, dei risultati (o dei filtroi stessi prima di applicarli)
otteniamo una specifica banda di frequenze:
% Creo due filtri a frequenze diverse:
h1 = gauss(-6:6,1.8); h1 = h1/sum(h1);
h2 = gauss(-6:6,1.5); h2 = h2/sum(h2);

% Li applico entrambe:
img1 = filter2(h1,filter2(h1',img));
img2 = filter2(h2,filter2(h2',img));

% Vediamo la composizione:
figure;
subplot(221); imshowscale(img); title('Immagine originale');
subplot(222); imshowscale(img2-img1); title('Immagine filtrata');
subplot(223); imshowscale(img1); title('Frequenze più basse');
subplot(224); imshowscale(img2); title('Frequenze più alte');
Questo filtro si chiama DoG (Difference of Gaussians) e si comporta
approssimativamente come la wavelet nota con il nome di "Mexican Hat":
% Creiamone uno a frequenze più basse (per vederne meglio la forma):
h1 = gauss(-26:26,7.2); h1 = h1/sum(h1);
h2 = gauss(-26:26,6.0); h2 = h2/sum(h2);

% Vediamolo:
figure; surf(h2'*h2 - h1'*h1);
view([45,45,-10]);

Derivata della Gaussiana

L'estrazione di bordi direzionali di angolo noto può essere ottenuta
grazie ad un altro filtro ben noto: la derivata della Gaussiana. In
ambito di elaborazione delle immagini la derivata 1d della Gaussiana
viene utilizzata in combinazione con un filtro Gaussiano 1d ottenendo
(sempre grazie alla separabilità) il seguente filtro:
% Creo i filtri 1d:
g = gauss(-4:4,1.5); g = g/sum(g);
dg = gaussDer(-4:4,1.5); % La derivata della gaussiana somma a zero.

% Vediamolo:
figure; surf(g'*dg);
% Applico il filtro:
img1 = filter2(g,filter2(dg',img));
img2 = filter2(g',filter2(dg,img));

% Vediamo i risultati:
figure;
subplot(221); imshowscale(img); title('Immagine originale');
subplot(222); imshowscale(abs(img1) + abs(img2)); title('Immagine filtrata');
subplot(223); imshowscale(abs(img1)); title('Derivata in verticale');
subplot(224); imshowscale(abs(img2)); title('Derivata in orizzontale');
Per rendere orientabile il filtro è sufficiente comporre linearmente le
immagini filtrate utilizzando i coefficienti generati da coseno e seno
dell'angolo di interesse (Perché? Ragionare sulla trasformata di Fourier
e sull'equazione di Eulero).
% L'angolo:
alpha = 70*pi/180;

% Composizione:
img3 = img1*sin(alpha) + img2*cos(alpha);

% Vediamo:
figure; imshowscale(abs(img3)); title('Filtro direzionale');
Per convicerci "animiamo la situazione":
% Finestra in fullscreen:
figure;
screen_size = get(0, 'ScreenSize');
set(gcf,'Position',[0,0,screen_size(3),screen_size(4)]);

% Itero sugli angoli:
for alpha = 0:0.1:2*pi
    % Filtro:
    img3 = img1*sin(alpha) + img2*cos(alpha);

    % Mostro:
    clf;
    imshow(imscale(img3),'InitialMagnification','fit');
    title('Filtro direzionale');

    % Disegno e aspetto:
    drawnow;
    pause(0.1);
end

Filtro Laplaciano

Nell'ambito dell'edge-detection, il filtro Laplaciano acquista la sua
importanza permettendo di evidenziare bordi e zero-crossing, in
particolare il Laplaciano di una funzione è definito come segue:
\Delta^2(I)=\frac{\partial^2I}{\partial x^2}+\frac{\partial^2I}{\partial y^2}

ma spesso in image processing viene approssimato da un filtro convolutivo come il seguente (si osservi l'evidenziazzione delle variazioni esterne):

% Preparo i filtri:
h = [0, 1, 0
     1,-4, 1
     0, 1, 0];

% Alternativamente:
% h = [0.5, 1.0, 0.5
%      1.0,-6.0, 1.0
%      0.5, 1.0, 0.5];

% Lo applico a una scacchiera:
img = checkerboard;
img1 = filter2(h, img);

% Vediamo:
figure;
subplot(121); imshow(img); title('Immagine originale');
subplot(122); imshowscale(abs(img1)); title('Immagine filtrata');

LoG

La funzione Gaussiana presenta caratteristiche interessanti anche dal
punto di vista delle sue derivate parziali secode, per questo il filtro
Laplacian of Gaussian (LoG) viene utilizzato per l'evidenziazione di
bordi. La sua forma chiusa è:
LoG(x,y)=-\frac{1}{\pi\sigma^4}\left[1-\frac{x^2+y^2}{2\sigma^2}\right]e^{-\frac{x^2+y^2}{2\sigma^2}}
% Uso la funzione di Matlab:
h = fspecial('log', 30, 4);

% Vediamolo:
figure; surf(h);
view([45,45,10]);
% Creo un LoG con frequenze accettabili:
h = fspecial('log', 10, 1.5);

%  Applichiamo LoG all'immagine delle monete:
img = imread('coins.png');
img1 = filter2(h,img);

% Risultato:
figure;
subplot(121); imshow(img); title('Immagine originale');
subplot(122); imshowscale(abs(img1)); title('Immagine filtrata');