Architettura di un sistema di PR Ciclo di progettazione di un sistema di PR Estrazione delle feature Una volta acquisito il dato da elaborare, tramite gli appositi sensori, è necessario estrarre le misure in grado di caratterizzarlo (features). L'oggetto da classificare sarà quindi rappresentato da un insieme (vettore) di features, denominato pattern. Il problema principale della scelta delle features consiste nel fatto che la mia rappresentazione numerica dell'oggetto da classificare deve consentire di discriminare le diverse classi, ovvero: Oggetti appartenenti alla stessa classe devono essere “simili” fra loro, ed il più possibile “diversi” da quelli delle altre classi. Estrazione delle features La scelta delle features risulta quindi di primaria importanza e dipende dalla tipologia del dato (fotografia, impronta, volto, testo, ...) e dalle categorie in cui classificarlo, esempio: immagine di interni o di esterni; immagine di mare, montagna, o città; e-mail di spam o leggittima; documento di sport, economia, politica o tecnologia; riconoscimento o verifica dell'identità In alcuni casi, nonostante sia abbastanza semplice individuare le feature discriminanti, risulta particolarmente complessa la loro estrazione (es. posizione di occhi, naso e bocca in un volto). Estrazione delle features Consideriamo due problemi pratici di estrazione delle features da immagini: Catalogazione di immagini “Indoor” e “Outdoor” Riconoscimento di immagini di spam Estrazione delle features Catalogazione di immagini “Indoor” e “Outdoor” Che cosa è in grado di distinguere le due categorie? Indoor: meno luminose, possono avere pareti o comunque aree uniformi Outdoor: possono contenere cielo, alberi e prati, hanno spesso più dettagli (es foglie) Possibili feature: distribuzione dei colori (istogramma della frequenza dei colori) texture (es Wavelet, DCT, ...) Estrazione delle features Riconoscimento di immagini di spam Che cosa è in grado di distinguere le due categorie? Legittime: tipicamente sono fotografie, potrebbero essere banner Spam: tipicamente contengono testo su sfondo uniforme (o quasi uniforme) Possibili feature: Informazioni estratte dalla distribuzione dei colori come: numero dei colori e occupazione del colore più comune aspect ratio dell'immagine area del testo Calcolo distribuzione dei colori La distribuzione dei colori di una immagine è tipicamente data dall'istogramma dei colori, ovvero dalla stima del numero di occorrenze (o della frequenza) di ciascun colore. La distribuzione può essere calcolata separatamente per ciascun canale (RGB, HSV, …) o globalmente ottenendo un istogramma in 3 dimensioni Calcolo distribuzione dei colori Vediamo come calcolare la distribuzione dei colori di ciascun canale usando la funzione “imhist” di matlab: %carico l'immagine da disco I = imread('foto.png'); %costruisco l'istogramma dei colori dei singoli canali nbins = 15; for idx=[1:3], h{idx} = imhist(I(:,:,idx), nbins); %calcolo le frequenze dei colori h{idx} = h{idx} / sum(h{idx}); end %plot figure(1); subplot(1,4,1); imshow(I); for idx=[1:3], subplot(1,4, 1+idx); bar(h{idx}); end Calcolo distribuzione dei colori Matlab non fornisce funzioni predefinite per il calcolo dell'istogramma dei colori in 3 dimensioni, per cui sarà necessario costruire una funzione specifica. function h3D = imColorHist(I, nbins) % Calcola istogramma dei colori 3D per immagini % con tre livelli in [0:255] if nbins>256, nbins =256; end; h3D = zeros(nbins,nbins,nbins); h3D = zeros(nbins,nbins,nbins); for r=[1:size(I,1)], for c=[1:size(I,2)], %Estraggo la terna RGB in vettore v = I(r,c,:); % rQ gQ bQ end end Quantizzo i valori e trasformo in indici (>=1) = min(fix(nbins* double(v(1))/255), nbins-1)+1; = min(fix(nbins* double(v(2))/255), nbins-1)+1; = min(fix(nbins* double(v(3))/255), nbins-1)+1; h3D(rQ, gQ, bQ) = h3D(rQ, gQ, bQ)+1; %h3D=reshape(h3D, [numel(h3D),1]); return; Calcolo distribuzione dei colori La funzione di quantizzazione deve ricampionare i livelli di colore nell'intervallo [0:NBINS-1]. La funzione ValQ = fix(nbins* Val/255) distribuisce equamente tutti valori in [0:NBINS-1] tranne val=255, pertanto è necessario aggiungere un controllo sul valore massimo. La formula finale diverrà: ValQ = min(fix(nbins* Val/255),nbins-1); Per ottenere gli indici dei vettori (>=1) è sufficiente sommare 1 Calcolo distribuzione dei colori Vediamo lo stesso codice in una versione ottimizzata, che sfrutta la capacità di matlab di lavorar con le matrici. function h3D = imColorHist(I, nbins) % Calcola istogramma dei colori 3D per immagini % con tre livelli in [0:255] if nbins>256, nbins =256; end; h3D = zeros(nbins,nbins,nbins); % Quantizzo i valori Iq = fix(double(I) * nbins/255); % per I=255 ottengo Iq =nbins Iq = min(Iq, nbins-1); % impongo valore massimo a nbins-1 Iq = Iq+1 % Trasformo in indici (>= 1) for r=[1:size(I,1)], for c=[1:size(I,2)], %Estraggo la terna quantizzata RGB in vettore v = Iq(r,c,:); %rQ = v(1); gQ = v(2); bQ = v(3); end end h3D(v(1), v(2), v(3)) = h3D(v(1), v(2), v(3))+1; %h3D=reshape(h3D, [1, numel(h3D)]); %trasformo in vettore riga return; Calcolo distribuzione dei colori Nel caso dello spam la distribuzione dei colori contiene più informazioni di quelle necessarie, il che potrebbe essere anche fonte di errori. Per questo problema può bastare contare il numero di colori diversi (numero elementi diversi da zero nell'istogramma) e/o valutare se e in che quantità è presente un colore molto comune (il massimo dell'istogramma) %carico l'immagine da disco I = imread('foto.png'); %considero l'immagine a livelli di grigi G = rgb2gray(I); histGL = imhist(G); histGL = histGL /sum(histGL); numColors = sum(histGL >0); %numColors = numel(unique(unique(G))); %conto i valori unici firstColorFreq = max(histGL); Estrazione Wavelet In termini molto generali l'analisi wavelet 2D è un metodo di analisi delle immagini nello spazio delle frequenze, in cui l’immagine corrente viene decomposta in più immagini, ciascuna delle quali mostra dettagli in scala crescente (secondo le direzioni verticali e/o orizzontali), che permettono una analisi a multi-risoluzione dell’immagine iniziale. Tramite le wavelet (come per FFT DCT) è possibile ottenere informazioni sul contenuto in frequenza di una immagine e quindi sulle texture. HL LH HH Estrazione Wavelet Matlab mette a disposizione, tramite il toolbox di image processing, una funzione per il calcolo della trasformata wavelt discreta DWT %carico l'immagine da disco I = imread('foto.png'); G = rgb2gray(I); % converto a livelli di girgio %dwt primo livello [cDW1,cLH1,cHL1,cHH1] = dwt2(double(G),'haar'); figure(1); imagesc([cDW1,cHL1; cLH1,cHH1]); colormap('gray') % dwt secondo livello [cDW2,cLH2,cHL2,cHH2] = dwt2(cDW1,'haar'); figure(2); tmp1 = [cDW2 cHL2; cLH2 cHH2]; if any(size(tmp1) ~= size(cDW1)), tmp1 = tmp1(1:size(cDW1,1), 1:size(cDW1,2)); end imagesc([tmp1, cHL1; cLH1,cHH1]); colormap('gray'); Estrazione Wavelet In alternativa è possibile scaricare da internet funzioni create da altri utenti. Consideriamo il codice prelevato da (link): www.mathworks.com/matlabcentral/fileexchange/ 11133-wavelet-transforms-in-matlab WAVELET Discrete wavelet transform. Y = WAVELET(W,L,X) computes the L-stage discrete wavelet transform (DWT) of signal X using wavelet W. The length of X must be divisible by 2^L. For the inverse transform, WAVELET(W,-L,X) inverts L stages. ... Exemple: Y = wavelet('2D CDF 9/7',2,X); Estrazione Wavelet %carico l'immagine da disco I = imread('foto.png'); G = double(rgb2gray(I)); % converto a livelli di girgio dwtLevels = 1; cropSize = fix([size(I,1) size(I,2)]/2^dwtLevels) … *(2^dwtLevels); imgDWT = wavelet('2D Le Gall 5/3', dwtLevels, … G(1:cropSize(1), 1:cropSize(2),1)); figure(1) imagesc(imgDWT); colormap('gray'); Estrazione Wavelet Consideriamo il risultato della trasformata wavelet, in alcuni casi è necessario poter estrarre i singoli canali dall'immagine completa HL LH HH Estrazione Wavelet % Per ciasucn livello l recupero le sottoimmagini k=1; dwtChannels={}; for l=1:dwtLevels rDim = size(imgDWT,1) / (2^l); % numero righe sottoimmagine rEND = size(imgDWT,1) / (2^(l-1)); % ultima riga livello %(fine sottoimmagine 3) rMDL = rEND-rDim; % riga punto centrale livello %(inizio sottoimmagine 3) cDim = size(imgDWT,2) / (2^l); % numero colonne sottoimmagine cEND = size(imgDWT,2) / (2^(l-1)); % ultima colonna livello cMDL = cEND-cDim; % colonna punto centrale livello end dwtChannels{k} = imgDWT( 1:rMDL, cMDL+1:cEND); k=k+1;%HL dwtChannels{k} = imgDWT(rMDL+1:rEND, 1:cMDL); k=k+1;%LH dwtChannels{k} = imgDWT(rMDL+1:rEND, cMDL+1:cEND); k=k+1;%HH if(l == dwtLevels) dwtChannels{k} = imgDWT(1:rMDL, 1:cMDL); k=k+1; %LL end Dataset Tipicamente, durante lo sviluppo del proprio sistema di classificazione, non è conveniente estrarre ad ogni simulazione le feature dai campioni. L'approccio miglio consiste nell'estrarre le feature da tutti campioni a disposizione e costruire una raccolta di pattern con le relative etichette di classe denominato dataset. Tipicamente un dataset è costituito da una matrice delle feature, in cui ogni riga rappresenta un pattern ed ogni colonna una singola feature, e da un vettore colonna contenete le etichette di classe (labels) tipicamente rappresentate da numeri interi. feature h labels 1 1 1 2 2 2 pattern k 1 2 2 Esempio costruzione dataset Consideriamo il problema di riconoscimento delle immagini di spam e di avere a disposizione una serie di immagini pre-etichettate su disco divise in due cartelle: 'spam' ed 'ham'. Supponiamo di voler estrarre le feature: numero dei livelli di grigio, rapporto dimensioni immagini, logaritmo del numero di pixel. Nota1: si consiglia di creare un funzione che dato il nome dell'immagine restituisca il vettore riga delle features function pattern = extractFeatures1(nomeFile) ImgRGB = imread(nomeFile); .... .... pattern = [numColori, numPixel, aspectRatio]; return; Nota2: Utilizziamo la funzione “dir” per avere l'elenco dei file in una cartella Es: dirClass1 = 'dataset/spam_imgset/trn/spam'; listFileName1 = dir([dirClass1 '/*.png']); .... fileName = [dirClass1 '/' listFileName1(idx).name]; .... pattern = extractFeatures1(fileName) .... Esempio costruzione dataset function pattern = extractFeatures1(nomeFile) imgRGB = imread(nomeFile); imgGL = rgb2gl(imgRGB); numColori = numel(unique(unique(imgGL))); numPixel = log(numel(imgGL)); apectRatio = size(imgGL,1)/size(imgGL,2); pattern = [numColori, numPixel, aspectRatio]; return; Esempio costruzione dataset function [featureMat labels] = createDataset(dirClass1, dirClass2) listFileName1 = dir([dirClass1 '/*.png']); numFiles1 = length(listFileName1); listFileName2 = dir([dirClass2 '/*.png']); numFiles2 = length(listFileName2); numFeatures=3; featureMat = zeros(numFiles1+numFiles2, numFeatures); labels = zeros(numFiles1+numFiles2, 1); iPatt = 1; for idx=[1:numFiles1] fileName = [dirClass1 '/' listFileName1(idx).name]; featureMat(iPatt,:) = extractFeatures(fileName); labels(iPatt) = 1; iPatt = iPatt +1; end for idx=[1:numFiles2] fileName = [dirClass2 '/' listFileName2(idx).name]; featureMat(iPatt,:) = extractFeatures(fileName); labels(iPatt) = 2; iPatt = iPatt +1; end return