Laboratorio di Bioimmagini A.A. 2008-2009 Le immagini da utilizzare nei seguenti esercizi ed il codice Matlab delle soluzioni sono scaricabili da: http://www.dei.unipd.it/~enrigri/public/lab Esercizio 2:soluzione Per creare la funzione di clustering, conviene dividere per prima cosa il problema in sottoproblemi più semplici, per poi combinarli ed ottenere l algoritmo completo. In particolare, vediamo che è necessario, ad ogni passo iterativo, procedere al calcolo di: 1. distanza d() di ogni dato dalle medie delle classi, date le medie 2. pesi w di ogni elemento, per ogni classe, date le distanze d() 3. i centri mu aggiornati, dati i pesi 4. la funzione obiettivo, dati i pesi e le distanze Scriveremo dunque 4 funzioni che calcolano tali quantità, ricordando che i dati sono M oggetti appartenenti a R N, e dunque verranno rappresentati in una matrice MxN, i centri μ sono K oggetti in R N e verranno rappresentati in una matrice KxN, mentre le distanze ed i pesi sono delle misure di ogni dato rispetto ad una classe, e quindi verranno rappresentati in matrici MxK (K valori per ognuno degli M dati). La prima funzione calcola la distanza come norma Euclidea di ogni dato da tutte le medie. Ci sarà dunque bisogno di un ciclo for che scorra le classi, e per ogni classe k ε [1,K] calcola la distanza degli elementi nella matrice MxN di dati, e li posiziona nella colonna k-esima della matrice MxK dist. Per evitare un doppio ciclo for (sarebbe necessario scorrere le K classi e gli M oggetti), si sfruttano le operazioni aritmetiche elemento per elemento di Matlab tra matrici con dimensioni uguali. Dal momento che ad ogni elemento N-dimensionale della matrice data devo sottrarre lo stesso vettore di medie, questa operazione può essere fatta in un colpo solo, creando una matrice che in ogni riga ha lo stesso vettore media, tramite l operazione: mk=ones(m,1)*mu(ctclass,:); in cui si ottiene che mk sia una matrice MxN, in cui ognuno delle righe N-dimensionali contiene i valori del vettore 1xN mu(ctclass,:).
function dist=fc_dist(data,mu,dbf) %% dist is MxK K=size(mu,1); N=size(mu,2); M=size(data,1); for ctclass=1:k, mk=ones(m,1)*mu(ctclass,:); dist(:,ctclass)=sqrt(sum((data-mk).^2,2)); end; A questo punto possiamo passare a creare la funzione che calcola i pesi w a partire dalle distanze calcolate con la funzione precedenti e salvate in una matrice dist. Dal momento che i pesi sono l inverso di una distanza (normalizzata), potrebbe essere possibile incappare in una divisione per zero, che creerebbe il problema di gestire valori infiniti (Inf) oppure not a number (nan), che portrebbero al collasso di una media sopra ad uno dei dati. Per evitare questi casi, scegliamo la facile soluzione di aggiungere un valore piccolo ma non nullo a tutti gli elementi della matrice dist function w=fc_w(dist,dbf) %% dist is MxK K=size(dist,2); M=size(dist,1); nfact=sum(dist,2); w=(nfact*ones(1,k))./(dist+1e-6);
Il calcolo delle medie è immediato, ricordando che i pesi vanno normalizzati per ottenere delle medie sensate. Il parametro esp passato alla funzione modula l influenza dei dati nel calcolo della media a seconda della loro distanza. Più è alto il valore di tale parametro, meno i dati lontani dalla media peseranno nel calcolo, e quindi maggiormente i risultati saranno influenzati dalle condizioni iniziali, mentre al limite di esp=0, i centri collasserrano verso la media globale dei dati. function mu=fc_mu(data,w,esp, dbf) K=size(w,2); N=size(data,2); M=size(data,1); for ctclass=1:k, wk=w(:,ctclass).^esp; wk=wk/sum(wk); wk=wk*ones(1,n); mu(ctclass,:)=sum(data.*wk); end; Infine calcoliamo la funzione obiettivo sfruttando l operatore di vettorizzazione di Matlab (:): function obj=fc_obj(w, dist, esp, dbf) %% dist is MxK obj=sum(w(:).^esp.*dist(:));
Ora dobbiamo mettere assieme le funzioni sviluppate per creare l algoritmo iterativo di clustering, provvedendo anche ad una funzione di inizializzazione: function [mu,obj]=fc_init(data,class,esp,dbf) K=class; M=size(data,1); N=size(data,2); w=rand(m,k); w=w./(sum(w,2)*ones(1,k)); mu=fc_mu(data,w,esp, dbf); dist=fc_dist(data,mu,dbf); obj=fc_obj(w, dist, esp, dbf); function [mu,w]=fc(data,class, esp, tol, maxiter, dbf) %% dist is MxK [mu,objnew]=fc_init(data,class,esp,dbf); ec=1; iter=1; whil e(ec & iter<maxiter) end obj=objnew; dist=fc_dist(data,mu,dbf); w=fc_w(dist,dbf); mu=fc_mu(data,w,esp, dbf); obj=fc_obj(w, dist, esp, dbf); iter=iter+1; ec=abs(obj-objnew)>tol;
Per verificare il funzionamento dell algoritmo, possiamo scrivere un piccolo script che crei dei dati sintetici, inizializzi i parametri necessari all algoritmo, lanci il clustering e visualizzi i risultati: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Questo è il programma principale per testare l'algoritmo fi fuzzy %% clustering %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Parametri %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% dbf=0; esp=2; %% esponente per i pesi w tol=1e-4; %% minima differenza fra il valore della funzione obiettivo in due iterazioni successive maxiter=200; %% numero massimo di iterazioni %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generazione dei dati simulati %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% class=3; %% numero di classi ndata=50; %% numero di elementi per ogni classe N=2; %% dimensionalità dei dati data=randn(ndata,n)*2; data(end+1:end+ndata,:)=randn(ndata,n)*2-10; data(end+1:end+ndata,:)=randn(ndata,n)*2+10; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Clustering %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [mu,w]=fc(data,class, esp, tol, maxiter, dbf); figure; plot(data(:,1),data(:,2),'.'); hold on plot(mu(:,1),mu(:,2),'*r'); Esercizio 3 E possibile caricare una immagine xiso, estrarne una regioni xroi di dimensione 51x51 attorno al punto [567,855], solo nel canale verde, e poi visualizzare la regione estratta con le seguenti istruzioni: xiso=im2double(imread('8766-6_iso.tiff')); xroi=xiso(855-25:855+25,567-25:567+25, 2); figure; imagesc(xroi); colormap(gray); Ottenendo la visualizzazione di:
Possiamo utilizzare i dato sul livello di grigio direttamente dalle informazione in xroi applicando la funzione costruita nell Es. 1. dbf=0; esp=2; %% esponente per i pesi w tol=1e-4; %% minima differenza fra il valore della funzione obiettivo in due iterazioni successive maxiter=500; %% numero massimo di iterazioni [mu,w]=fc(xroi(:),2, esp, tol, maxiter, dbf); Ottenendo come risultato che le medie delle due classi sono stimate μ=[0.2510,0.4039]. Per visualizzare il risultato possiamo vedere l istogramma dei livelli di grigio in xroi, a cui sovrapponiamo due linee dove sono le medie dei cluster: Se poniamo una soglia a metà dei due centri di cluster, otteniamo una segmentazione dell immagine basata sulla stima dei clusters sui livelli di grigio. Dal momento che l idea finale è di identificare la parte di vaso nell immagine, sceglieremo di mettere a 1 (pixel selezionati), la parte dell immagine con livelli di grigio inferiore alla soglia trovata: th=0.5*sum(mu); xseg=xroi<th; imagesc(xseg); colormap(gray);
Se applicassimo la trasformata di Hough tramite la funzione hough() oppure la funzione radon()di Matlab direttamente su questa immagine in bianco e nero, otterremo un numero di linee possibili molto elevato, tutt con un numero di pixel votanti simile, cosa che non permette una buona identificazione della linea centrale del vaso e della sua direzione: theta=0:180; [R, theta, rho] = hough(xseg); imshow(r,[],'xdata',theta,'ydata',rho,'initialmagnification','fit') colormap(hot), colorbar Per ottenere una miglior localizzazione della linea che approssima il centro del vaso e la sua direzione, prima della trasformata di Hough si può procedere ad un thinning dell immagine: xskel=bwmorph(xseg,'thin','inf'); imagesc(xskel) colormap(gray) [R, theta, rho] = hough(xskel); imshow(r,[],'xdata',theta,'ydata',rho,'initialmagnification','fit') colormap(hot), colorbar
Si ottiene che il massimo della trasformata di Hough si trova alle coordinate [88,77], corrispondenti a ρ=17 e θ=-13, da cui la linea che si ottiene è: Se si volesse applicare invece il clustering a dati che contengano sia l informzione sul canale rosso, che quello sul canale verde, il clustering e la segmentazione che si otterrebbero sono i seguenti: xroir=xiso(855-25:855+25,567-25:567+25, 1); xroig=xiso(855-25:855+25,567-25:567+25, 2); data=[xroir(:),xroig(:)]; [mu,w]=fc(data,2, esp, tol, 500, dbf); plot(data(:,1),data(:,2),'.'); hold on plot(mu(:,1),mu(:,2),'*r');
th=mean(mu,2); xseg2=xroir<0.5 & xroi<0.1235; imagesc(xseg2); colormap(gray)