7

Sto lottando per capire l'implementazione di Matlab dell'algoritmo LBP trovato here. Sto cercando di scoprire come calcola i binari per ogni pixel? Calcola solo dove il pixel del vicino è maggiore della dimensione effettiva del pixel centrale. Voglio calcolare i binari per ogni pixel per poter utilizzare gli istogrammi locali per calcolare le caratteristiche dell'immagine.Codice Matlab per modello binario locale

[ysize, xsize] = size(image); 

miny=min(spoints(:,1)); 
maxy=max(spoints(:,1)); 
minx=min(spoints(:,2)); 
maxx=max(spoints(:,2)); 

% Block size, each LBP code is computed within a block of size bsizey*bsizex 
bsizey=ceil(max(maxy,0))-floor(min(miny,0))+1; 
bsizex=ceil(max(maxx,0))-floor(min(minx,0))+1; 

% Coordinates of origin (0,0) in the block 
origy=1-floor(min(miny,0)); 
origx=1-floor(min(minx,0)); 

% Minimum allowed size for the input image depends 
% on the radius of the used LBP operator. 
if(xsize < bsizex || ysize < bsizey) 
    error('Too small input image. Should be at least (2*radius+1) x (2*radius+1)'); 
end 

% Calculate dx and dy; 
dx = xsize - bsizex; 
dy = ysize - bsizey; 

% Fill the center pixel matrix C. 
C = image(origy:origy+dy,origx:origx+dx); 
d_C = double(C); 

bins = 2^neighbors; 

% Initialize the result matrix with zeros. 
result=zeros(dy+1,dx+1); 

%Compute the LBP code image 
% the whole process here 
for i = 1:neighbors 
    y = spoints(i,1)+origy; 
    x = spoints(i,2)+origx; 
    % Calculate floors, ceils and rounds for the x and y. 
    fy = floor(y); cy = ceil(y); ry = round(y); 
    fx = floor(x); cx = ceil(x); rx = round(x); 
    % Check if interpolation is needed. 
    if (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6) 
    % Interpolation is not needed, use original datatypes 
    N = image(ry:ry+dy,rx:rx+dx); 
    D = N >= C; 
    else 
    % Interpolation needed, use double type images 
    ty = y - fy; 
    tx = x - fx; 

    % Calculate the interpolation weights. 
    w1 = roundn((1 - tx) * (1 - ty),-6); 
    w2 = roundn(tx * (1 - ty),-6); 
    w3 = roundn((1 - tx) * ty,-6) ; 
    % w4 = roundn(tx * ty,-6) ; 
    w4 = roundn(1 - w1 - w2 - w3, -6); 

    % Compute interpolated pixel values 
    N = w1*d_image(fy:fy+dy,fx:fx+dx) + w2*d_image(fy:fy+dy,cx:cx+dx) + ... 
w3*d_image(cy:cy+dy,fx:fx+dx) + w4*d_image(cy:cy+dy,cx:cx+dx); 
    N = roundn(N,-4); 
    D = N >= d_C; 
end 
    % Update the result matrix. 
    v = 2^(i-1); 
    result = result + v*D; 
end 

%Apply mapping if it is defined 
if isstruct(mapping) 
bins = mapping.num; 
for i = 1:size(result,1) 
    for j = 1:size(result,2) 
     result(i,j) = mapping.table(result(i,j)+1); 
    end 
    end 
end 

if (strcmp(mode,'h') || strcmp(mode,'hist') || strcmp(mode,'nh')) 
    % Return with LBP histogram if mode equals 'hist'. 
    result=hist(result(:),0:(bins-1)); 
    if (strcmp(mode,'nh')) 
    result=result/sum(result); 
    end 
else 
%Otherwise return a matrix of unsigned integers 
if ((bins-1)<=intmax('uint8')) 
    result=uint8(result); 
elseif ((bins-1)<=intmax('uint16')) 
    result=uint16(result); 
else 
    result=uint32(result); 
end 
end 
size(result) 
end 

Iterativamente aggiunge un valore nei risultati per tutti e 8 i vicini di ogni pixel. Ma come è correlato con i binari LBP? Come si correla con il seguente codice per il seguente approccio C++ LBP:

uchar lbp(const Mat_<uchar> & img, int x, int y) 
{ 
    // this is pretty much the same what you already got.. 
    uchar v = 0; 
    uchar c = img(y,x); 
    v += (img(y-1,x ) > c) << 0; 
    v += (img(y-1,x+1) > c) << 1; 
    v += (img(y ,x+1) > c) << 2; 
    v += (img(y+1,x+1) > c) << 3; 
    v += (img(y+1,x ) > c) << 4; 
    v += (img(y+1,x-1) > c) << 5; 
    v += (img(y ,x-1) > c) << 6; 
    v += (img(y-1,x-1) > c) << 7; 
    return v; 

}

+0

mostra solo parte del codice. per favore pubblica l'intero codice pertinente e indentalo correttamente. – Shai

risposta

7

Si tratta di un'implementazione di vettorializzare LBP, piuttosto ben adattato per Matlab.

Dopo le istruzioni di inizializzazione, diamo un'occhiata al ciclo principale, iniziando dalla riga "for i = 1:neighbors". Il ciclo è abbastanza chiaro: calcola il confronto di un vicino con il pixel centrale, il ciclo scorre su tutti i vicini. Hai questo punto, quindi ora entra in profondità nel ciclo per capire come accumula tutti i risultati.

Il nucleo del loop è in effetti complicato perché prende in considerazione il cerchio reale anziché un cerchio intero approssimativo. Quindi lo scopo della maggior parte delle istruzioni è calcolare l'intensità interpolata del pixel vicino. Qui differisce dal codice C++ che hai come riferimento, dove prende solo il cerchio intero, 1-pixel-wide-radius. Ricorda che con il codice lbp.m puoi - teoricamente, ne discuterò più avanti - calcolare il LBP lungo un cerchio di raggio R con N punti di campionamento, così il C++ corrisponderebbe a un cerchio di raggio 1 e con 8 campionamenti punti, se solo non ci fosse interpolazione. Ma c'è un'interpolazione quando il vicino non si adatta alla griglia di pixel dell'immagine, quando (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6) è falso).

Se (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6) è vero, non vi è alcuna interpolazione, quindi il calcolo di tutti i confronti tra il pixel centrale e il vicino corrente viene memorizzato direttamente in D. Altrimenti, calcola un'interpolazione bilineare dell'intensità nel punto vicino al campionamento, su tutta l'immagine: N = w1*d_image(fy:fy+dy,fx:fx+dx) + w2*d_image(fy:fy+dy,cx:cx+dx) + w3*d_image(cy:cy+dy,fx:fx+dx) + w4*d_image(cy:cy+dy,cx:cx+dx);.

Infine, passare alla parte di aggiornamento: v = 2^(i-1); result = result + v*D;. v è l'equivalente del turno: per il lato destro, si sposta il valore del confronto per i-1 a sinistra, o in modo equivalente moltiplicando per 2^(i-1). Quindi sommi con result. Quindi alla fine del ciclo, il calcolo è davvero equivalente al tuo codice C++, tranne che è fatto sull'intera immagine invece che su un singolo pixel. E il codice C++ può essere visto come una versione srotolata del loop matlab con il cerchio adiacente di raggio 1 e 8 punti di campionamento. A questo punto, la mappa LBP viene calcolata, i blocchi seguenti sono l'elaborazione aggiuntiva della mappa LBP (rimappatura attraverso una tabella di mappatura e facoltativamente calcolando l'istogramma dell'immagine LBP anziché l'immagine LBP stessa).

Ora, una piccola discussione sull'intera sceneggiatura. C'è un difetto qui che è nascosto alla fine della sceneggiatura. Infatti, attraverso il codice, sei limitato a 32 vicini, non di più, perché alla fine l'immagine LBP è castata a int32. Il difetto è che la variabile result è allocata come una matrice doppia e non una matrice di numeri interi, quindi spero davvero che non ci siano problemi di approssimazione durante l'aggiornamento di result e successivi quando si esegue il cast in numero intero, portando alla modifica dei bit nel LBP. Normalmente non dovrebbe esserci in quanto vi sono almeno 52 bit di precisione (secondo lo standard wikipedia per le specifiche IEEE 754). Penso che sia rischioso qui ...e al contrario non sono a conoscenza di un tipo matlab per un vettore di bit lungo ed efficiente. Vorrei usare int64 invece di int32, ma il limite sarà lì in 64 vicini di campionamento.

EDIT

Ora, se il vostro desiderio è quello di commpute alcuni modelli binari locale è limitata sul quartiere 3 * 3, questa funzione Matlab è troppo generico per voi, e la cosa migliore è quella di srotolare il ciclo per questo quartiere, e quindi essere molto vicino al codice C++. Ecco un pezzo di codice per questo (io uso bit per bit o al posto di più, ma è equivalente):

result = uint8(ysize, xsize); 
result = (image(1:end-2,2:end-1) > image(2:end-1,2:end-1));         % <=> v += (img(y-1,x ) > c) << 0; 
result = result|bitshift((image(1:end-2,3:end) > image(2:end-1,2:end-1)), 1, 'uint8');  % <=> v += (img(y-1,x+1) > c) << 1; 
result = result|bitshift((image(2:end-1,3:end) > image(2:end-1,2:end-1)), 2, 'uint8');  % <=> v += (img(y ,x+1) > c) << 2; 
result = result|bitshift((image(3:end,3:end) > image(2:end-1,2:end-1)), 3, 'uint8');  % <=> v += (img(y+1,x+1) > c) << 3; 
result = result|bitshift((image(3:end,2:end-1) > image(2:end-1,2:end-1)), 4, 'uint8');  % <=> v += (img(y+1,x ) > c) << 4; 
result = result|bitshift((image(3:end,1:end-2) > image(2:end-1,2:end-1)), 5, 'uint8');  % <=> v += (img(y+1,x-1) > c) << 5; 
result = result|bitshift((image(2:end-1,3:end) > image(2:end-1,2:end-1)), 6, 'uint8');  % <=> v += (img(y ,x-1) > c) << 6; 
result = result|bitshift((image(1:end-2,1:end-2) > image(2:end-1,2:end-1)), 7, 'uint8'); % <=> v += (img(y-1,x-1) > c) << 7; 

E 'la traduzione esatta del codice C a uno script Matlab, utilizzando la potente vettorializzazione. Con questo in mano, è piuttosto semplice cambiare per un altro ordine o diversi test in questo quartiere. Ho anche menzionato questo punto perché c'è un errore nello script Matlab per questo caso, la riga 53 indica un segno sbagliato: neighobrhood è migliore come spoints=[-1 -1; -1 0; -1 1; 0 -1; 0 -1; 1 -1; 1 0; 1 1]; anziché spoints=[-1 -1; -1 0; -1 1; 0 -1; -0 1; 1 -1; 1 0; 1 1];.

+0

Abbastanza chiaro. Quello che mi piacerebbe fare è cambiare il codice. Per cambiare i confronti usando l'approccio LGP che confronta i pixel verso anziché il confronto cerchio di tutti i pixel vicini rispetto al pixel centrale. In C++ è semplice, devo solo cambiare le linee della funzione v + = (img (y-1, x)> c) << 0;. (Il confronto deve essere per i pixel verso del pixel del centro) . Come posso fare lo stesso nel codice MATLAB. –

+0

@FereRes Stai parlando di pattern di gradiente locali, giusto? Potresti modificare il tuo OP per rendere chiaro quel punto (con un riferimento, sarebbe bello). Modifico la mia risposta in seguito a questo [articolo] (http://www.academia.edu/4876261/Local_Gradient_Pattern_-_A_Novel_Feature_Representation_for_Facial_Expression_Recognition) – Bentoy13

+0

Ok, in pratica voglio solo capire sia il codice C++ che il codice matlab per poterlo modificare da LBP a LGB che è solo una modifica nei confronti. (Sto parlando del caso semplice di r = 1 e 8 vicini). Il mio riferimento a LGP ​​è http://ac.els-cdn.com/S0031320312001094/1-s2.0-S0031320312001094-main.pdf?_tid=c52c9234-7960-11e4-9b66-00000aacb35e&acdnat=1417441906_2c6ff3b2b2339ca7ebe5e1ea57be796a –

7

Ho fatto il mio progetto per l'ultimo anno su Pattern binario locale. Ho visto quel codice che stavi indicando ma ho deciso di scrivere il mio codice.

Questo è il mio codice:

function [ LBP ] = LBP(I2) 
m=size(I2,1); 
n=size(I2,2); 
for i=2:m-1 
    for j=2:n-1 
     J0=I2(i,j); 
     I3(i-1,j-1)=I2(i-1,j-1)>J0; 
     I3(i-1,j)=I2(i-1,j)>J0; 
     I3(i-1,j+1)=I2(i-1,j+1)>J0; 
     I3(i,j+1)=I2(i,j+1)>J0; 
     I3(i+1,j+1)=I2(i+1,j+1)>J0; 
     I3(i+1,j)=I2(i+1,j)>J0; 
     I3(i+1,j-1)=I2(i+1,j-1)>J0; 
     I3(i,j-1)=I2(i,j-1)>J0; 
     LBP(i,j)=I3(i-1,j-1)*2^7+I3(i-1,j)*2^6+I3(i-1,j+1)*2^5+I3(i,j+1)*2^4+I3(i+1,j+1)*2^3+I3(i+1,j)*2^2+I3(i+1,j-1)*2^1+I3(i,j-1)*2^0; 
    end 
end 
end 

I2 è l'immagine che si sta passando e LBP è l'uscita. Scritto questo per modello binario locale: http://quantgreeks.com/local-binary-pattern-in-matlab/. So che posso scrivere il codice in forma più efficiente. Ma scrivendolo in questo modo, è chiaro come funziona il modello binario locale.