Identificazione di bordi
I bordi nelle immagini sono elementi che racchiudono forme, rappresentano uno degli elementi fondamentali di descrizione della scena, nello strato V1 della corteccia cerebrale, primo livello di elaborazione del segnale visivo nella corteccia cerebrale dopo il corpo genicolato, ha proprio il compito di identificare i bordi con direzione per poter poi aggregare queste informazioni negli strati successivi della corteccia.Nell’intenzione di imitare il sistema visivo umano per dotare il calcolatore di capacità di interpretazione della realtà che lo circonda, le tecniche di estrazione di bordi assumono dunque importanza fondamentale.
Contents
Metodologie di identificazione di bordi e problematiche
Come visto in precedenza i bordi sono rappresentati dalla parte di segnale presente ad alte frequenze (maggiori di 0 dato che la frequenza 0 rappresenta il valor medio). Differenti problematiche risiedono dietro a tecniche come DoG tra cui la scelta delle frequenze, la complessità computazionale, la robustezza al rumore, la direzionalità.
Derivata della Gaussiana
Identifichiamo per ora un metodo che permetta di rilevare i bordi in una determinata direzione rimanendo robusti al rumore bianco. Tale metodo consiste nell’applicare un filtro lineare che esprima direzionalità e che rimuova le alte frequenze in cui si annida il rumore da attenuare. Si consideri la derivata della gaussiana:
% Vediamo come si presenta in una dimensione: x = -10:10; sigma = 2; gd = -x/sigma^2.*exp(-x.^2/(2*sigma^2)); figure; plot(x,gd); title('Derivata della Gaussiana');
Per identificare bordi orientati attenuando il rumore, nelle immagini convolviamo in una direzione per la derivata della gaussiana, nell’altra direzione per la gaussiana di pari deviazione standard:
% La gaussiana: g = exp(-x.^2/(2*sigma.^2)); g = g/sum(g(:)); % Vediamo il filtro: figure; surf(g'*gd);
Applichiamo a un’immagine il filtro sfruttandone la separabilità:
% Filtering nelle 2 direzioni: img = double(imread('cameraman.tif'))/255; edgev = filter2(gd,g,img); edgeh = filter2(g,gd,img); % Vediamo il risultato: figure; subplot(221); imshow(img); title('Immagine originale'); subplot(222); imshow(abs(edgeh)); title('Bordi orizzontali'); subplot(223); imshow(abs(edgev)); title('Bordi verticali'); subplot(224); imshow(abs(edgeh)+abs(edgev)); title('Bordi');
Ricaviamo ora i bordi in una direzione predefinita, per farlo dobbiamo ruotare il filtro e ricavare l’equazione che ci permette di calcolare le derivate direzionali. La rotazione la otteniamo moltiplicando per l’esponenziale complesso. Questa tecnica di rotazione di un filtro è possibile solo per gli steerable filters, ovvero quei filtri aventi, nel dominio delle frequenze, modulo isotropo (ne ruota solo la fase). Chiamiamo il filtro a 0° e A 90°:
ma essendo:
si ha:
quindi:
% Schegliamo l'angolo e applichiamolo: alpha = pi/6; gdv = g'*gd; gdh = gd'*g; gdAlpha = cos(alpha)*gdv + sin(alpha)*gdh; edgeAlpha = filter2(gdAlpha,img); % Vediamone il risultato: figure;subplot(121); imshow(img); title('Immagine originale'); subplot(122); imshow(abs(edgeAlpha)); title('Bordi diagonali di 30 gradi');
Filtro di Sobel
La derivata della gaussiana ha sicuramente delle ottime caratteristiche compresa separabilità che la rende efficiente, purtroppo costringe a lavorare con numeri reali. Nel caso in cui la deviazione standard sia sufficientemente piccola è possibile ottenerne un’approssimazione il cui calcolo può essere svolto solamente con numeri interi ed esclusivamente utilizzando somme e sottrazioni: il filtro di Sobel.
% Approssimiamo la derivata della gaussiana 1d con la differenza finita: gd = [1,0,-1]; % Approssimiamo il filtro gaussiano come segue: g = [1,2,1]; % Otteniamo il seguente filtro (ovviamente separabile): sobelv = g'*gd, sobelh = gd'*g, % Applichiamoli all'immagine: edgev = filter2(gd,g,img); edgeh = filter2(g,gd,img); % Vediamo il risultato: figure; subplot(221); imshow(img); title('Immagine originale'); subplot(222); imshow(abs(edgeh)); title('Bordi orizzontali'); subplot(223); imshow(abs(edgev)); title('Bordi verticali'); subplot(224); imshow(abs(edgeh)+abs(edgev)); title('Bordi');
sobelv = 1 0 -1 2 0 -2 1 0 -1 sobelh = 1 2 1 0 0 0 -1 -2 -1
Per quanto riguarda le derivate direzionali (bordi obliqui) questa approssimazione non ha simmetria rotazionale, l’operatore di Scharr permette di ottenere una migliore approssimazione con un piccolo costo computazionale in più:
% Bordi con Sobel: g = [1,2,1]; edgeVSobel = filter2(gd,g,img); gdv = g'*gd; gdh = gd'*g; gdAlpha = cos(alpha)*gdv + sin(alpha)*gdh; edgeAlphaSobel = filter2(gdAlpha,img); % Bordi con Scharr: g = [3,10,3]; edgeVScharr = filter2(gd,g,img); gdv = g'*gd; gdh = gd'*g; gdAlpha = cos(alpha)*gdv + sin(alpha)*gdh; edgeAlphaScharr = filter2(gdAlpha,img); % Vediamo il risultato: figure; subplot(221); imshow(abs(edgeVSobel)); title('Sobel'); subplot(222); imshow(abs(edgeVScharr)); title('Scharr'); subplot(223); imshow(abs(edgeAlphaSobel)); subplot(224); imshow(abs(edgeAlphaScharr));
Canny
Passiamo all’identificazione del singolo elemento “bordo” come centro del fronte di variazione di luminosità tramite il filtro di Canny. L’idea è di utilizzare le norme dei gradienti come rappresentanti dell’intensità del bordo, successivamente azzerando tutti i pixel che non si trovano su un massimo lungo il gradiente, non essendo quindi flessi nell’immagine originale (in realtà filtrata con un filtro passa-basso per attenuare il rumore bianco). Una fase di sogliatura e di prolungamento dei bordi permette successivamente di rimuovere bordi dovuti al rumore senza perdere quelli di interesse. Si verifichi l’implementazione del filtro di Canny qui.
% Applichiamo Canny e vediamone i vari step (giocate con i parametri): [bw,im1,im2,im3,im4,im5] = canny(img,1,0.1,0.2); % Vediamo i vari step: figure; subplot(321); imshow(img); title('Immagine originale'); subplot(322); imshow(im1); title('Step 1'); subplot(323); imshow(im2); title('Step 2'); subplot(324); imshow(im3); title('Step 3'); subplot(325); imshow(im4); title('Step 4'); subplot(326); imshow(im5); title('Step 5'); set(gcf, 'Position', [0 0 500,750]); % Vediamo il risultato: figure; imshow(bw); title('Bordi di Canny');