7

Próbuję zrozumieć implementację algorytmu LBP w języku Matlab, która została znaleziona: here. Próbuję znaleźć sposób obliczania plików binarnych dla każdego piksela? Po prostu oblicza, gdzie sąsiedni piksel jest większy niż rzeczywisty rozmiar centrum pikseli. Chcę obliczyć pliki binarne dla każdego piksela, aby użyć lokalnych histogramów do obliczenia cech obrazu.Kod Matlaba dla lokalnego wzorca binarnego

[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 

Iteracyjnie dodaje trochę wartości do wyników dla wszystkich 8 sąsiadów każdego piksela. Ale w jaki sposób jest on skorelowany z plikami binarnymi LBP? Jak to jest skorelowane z następującego kodu w następnym podejściu 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

wyświetlasz tylko część kodu. proszę opublikuj cały odpowiedni kod i odpowiednio wcń go. – Shai

Odpowiedz

7

Jest to wektorowy realizacja LBP, raczej dobrze nadaje się do Matlab.

Po instrukcji inicjalizacji spójrzmy na główną pętlę, zaczynając od linii "for i = 1:neighbors". Pętla jest całkiem jasna: oblicza porównanie sąsiada z pikselem środkowym, pętla przechodzi przez wszystkie sąsiednie. Masz ten punkt, więc teraz wejdź głęboko w pętlę, aby zrozumieć, w jaki sposób gromadzi wszystkie wyniki.

Rdzeń pętli jest w rzeczywistości zbyt skomplikowany, ponieważ bierze pod uwagę rzeczywiste koło zamiast przybliżonego koła całkowitoliczbowego. Tak więc celem większości instrukcji jest obliczenie intensywności interpolacji sąsiedniego piksela. Tutaj różni się od kodu C++, który masz jako odniesienie, gdzie zajmuje tylko okrąg całkowity o promieniu 1 piksela. Pamiętaj, że z kodem lbp.m możesz - teoretycznie, omówię to później - obliczyć LBP wzdłuż okręgu o promieniu R z N punktami próbkowania, więc C++ będzie odpowiadać okręgowi o promieniu 1 i 8 próbkowaniu punktów, jeśli tylko nie było interpolacji. Ale istnieje interpolacja, gdy sąsiad nie pasuje do siatki pikseli obrazu, gdy (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6) jest fałszywa).

Jeśli (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6) ma wartość true, nie ma interpolacji, więc obliczenia wszystkich porównań między pikselem centralnym a bieżącym sąsiadem są zapisywane bezpośrednio w D. W przeciwnym razie oblicza dwuliniową interpolację natężenia w punkcie poboru próbkowania na całym obrazie: 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);.

I na koniec przejdź do części aktualizacji: v = 2^(i-1); result = result + v*D;. v jest odpowiednikiem przesunięcia: dla tego sąsiada przesuwasz wartość porównania o i-1 po lewej stronie, lub równoważnie mnożąc wartość 2^(i-1). Następnie sumujesz z result. Tak więc na końcu pętli obliczenia są naprawdę równoważne z twoim C++, z tym wyjątkiem, że są wykonywane na całym obrazie zamiast na jednym pikselu. A kod C++ można zobaczyć jako rozwiniętą wersję pętli matlab z kręgu sąsiada o punktach próbkowania o promieniu 1 i 8. W tym momencie obliczana jest mapa LBP, kolejne bloki są dodatkowym przetwarzaniem mapy LBP (przerzucanie przez tabelę mapowania i opcjonalnie obliczanie histogramu obrazu LBP zamiast samego obrazu LBP).

Teraz mała dyskusja na temat całego scenariusza. Tutaj jest wada, która jest ukryta na końcu skryptu. W rzeczywistości, za pomocą kodu, jesteś ograniczony do 32 sąsiadów, nie więcej, ponieważ na końcu obraz LBP jest rzutowany na int32. Wada polega na tym, że zmienna result jest alokowana jako podwójna macierz, a nie jako macierz całkowitoliczbowa, więc mam naprawdę nadzieję, że nie ma problemu z przybliżeniem podczas aktualizowania result i późniejszego podczas rzutowania na liczbę całkowitą, co prowadzi do zmiany bitów w LBP. Zwykle nie powinno być, ponieważ jest co najmniej 52 bitów precyzyjnych (zgodnie z wikipedia dla specyfikacji IEEE 754). Myślę, że to ryzykowne ...a wręcz przeciwnie, nie jestem świadomy typu matlab dla długiego, wydajnego wektora bitowego o ustalonej wielkości. Chciałbym użyć int64 zamiast int32, ale limit będzie tam na 64 pobranych próbek sąsiadów.

EDIT

Teraz, jeśli życzeniem jest commpute niektórych lokalnych wzorców binarnych zastrzeżonych w sąsiedztwie 3 * 3, ta funkcja Matlab jest zdecydowanie zbyt ogólne dla ciebie, a najlepsze jest to, aby rozwinąć pętlę dla tej dzielnicy, a tym samym być naprawdę blisko kodu C++. Oto fragment kodu za to (używam bitowego lub zamiast dodatku, ale to odpowiednik):

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; 

Jest to dokładne tłumaczenie z kodu C do skryptu Matlab, dzięki zastosowaniu wektoryzacji. Mając to wszystko pod ręką, bardzo łatwo jest zmienić kolejność lub inne testy w tej okolicy. Wspominam również o tym, ponieważ w tym przypadku występuje błąd w skrypcie Matlab, linia 53 ma zły znak: sąsiada jest lepsza niż spoints=[-1 -1; -1 0; -1 1; 0 -1; 0 -1; 1 -1; 1 0; 1 1]; zamiast spoints=[-1 -1; -1 0; -1 1; 0 -1; -0 1; 1 -1; 1 0; 1 1];.

+0

Dość jasne. Chciałbym zmienić kod. Aby zmienić porównania za pomocą podejścia LGP, które porównuje względem pikseli zamiast porównywania wszystkich pikseli sąsiednich względem środkowego piksela. W języku C++ jest łatwo po prostu muszę zmienić linie funkcji v + = (img (y-1, x)> c) << 0;. (Porównanie musi dotyczyć pikseli w kierunku piksela centrum) . Jak mogę zrobić to samo w kodzie MATLAB? –

+0

@FereRes Mówisz o lokalnych wzorach gradientowych, prawda? Czy mógłbyś edytować swój OP, aby ten punkt był jasny (z referencją, byłoby miło). Edytuję odpowiedź po tym [artykuł] (http://www.academia.edu/4876261/Local_Gradient_Pattern_-_A_Novel_Feature_Representation_for_Facial_Expression_Recognition) – Bentoy13

+0

Ok Po prostu chcę zrozumieć zarówno kod C++ i Matlab, aby móc go zmienić z LBP na LGB, która jest tylko jedną modyfikacją porównań. (Mówię o prostym przypadku r = 1 i 8 sąsiadów). Moje odniesienie do LGP to http://ac.els-cdn.com/S0031320312001094/1-s2.0-S0031320312001094-main.pdf?_tid=c52c9234-7960-11e4-9b66-00000aacb35e&acdnat=1417441906_2c6ff3b2b2339ca7ebe5e1ea57be796a –

7

Zrobiłem mój ostatni projekt roku na Local Binary Pattern. Widziałem ten kod, który wskazałeś, ale postanowiłem napisać własny kod.

To jest mój kod:

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 jest obraz jesteś przejazdem i LBP jest wyjście. Napisano dla lokalnego wzorca binarnego: http://quantgreeks.com/local-binary-pattern-in-matlab/. Wiem, że mogę napisać kod w bardziej wydajnej formie. Ale pisanie tego w ten sposób, wyjaśnia, jak działa lokalny wzór binarny.

Powiązane problemy