5

ここにあるLBPアルゴリズムのMatlab実装を理解するのに苦労しています。すべてのピクセルのバイナリを計算する方法を見つけようとしていますか? 隣接ピクセルが実際の中心ピクセル サイズよりも大きい場所を計算するだけです。ローカル ヒストグラムを使用して画像の特徴を計算するために、すべてのピクセルのバイナリを計算したいと考えています。

[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

反復的に、すべてのピクセルの 8 つの近傍すべての結果に何らかの値が追加されます。しかし、LBP バイナリとどのように相関しているのでしょうか? 次の 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;

}

4

2 に答える 2

8

これは、LBP のベクトル化された実装であり、Matlab に適しています。

初期化命令の後、行 " " から始まるメイン ループを見てみましょうfor i = 1:neighbors。ループは非常に明確です。1 つの近傍と中心ピクセルの比較を計算し、ループはすべての近傍を反復します。この点は理解できたので、ループを深く掘り下げて、すべての結果がどのように蓄積されるかを理解してください。

ループのコアは、近似整数円ではなく実際の円を考慮しているため、実際には複雑すぎます。したがって、命令の大部分の目的は、隣接ピクセルの補間強度を計算することです。ここでは、参照として持っている C++ コードとは異なります。ここでは、整数の 1 ピクセル幅の半径の円のみを使用します。lbp.m コードを使用すると、理論的には後で説明しますが、N 個のサンプリング ポイントを持つ半径 R の円に沿って LBP を計算できることを思い出してください。したがって、C++ は半径 1 の円に対応し、8 個のサンプリングがあります。ポイント、補間がない場合のみ。しかし、隣人が画像のピクセル グリッドに適合しない場合(abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6)(が false の場合) は補間されます)。

が true の場合(abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6)、補間は行われないため、中央のピクセルと現在の隣接ピクセルとの間のすべての比較の計算は に直接格納されDます。それ以外の場合は、画像全体にわたって、サンプリング近傍点での強度の双一次補間を計算します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);

そして最後に、更新部分に目を向けます: v = 2^(i-1); result = result + v*D;. vはシフトと同等です。i 番目の隣人については、比較の値をi-1左にシフトするか、同等に be を乗算します2^(i-1)。次に、 で合計しresultます。したがって、ループの最後での計算は、1 つのピクセルではなく画像全体に対して行われることを除けば、実際には C++ コードと同じです。また、C++ コードは、半径 1 と 8 のサンプリング ポイントの隣接円を含む、matlab ループの展開バージョンと見なすことができます。この時点で、LBP マップが計算されます。次のブロックは、LBP マップの追加処理です (マッピング テーブルを介して再マップし、オプションで LBP 画像自体の代わりに LBP 画像のヒストグラムを計算します)。

ここで、スクリプト全体について少し説明します。ここには、スクリプトの最後に隠されている欠陥があります。実際、このコードでは、最終的に LBP 画像が にキャストされるため、近傍数は 32 に制限されていint32ます。欠点は、変数resultが整数行列ではなく倍精度行列として割り当てられることです。そのため、更新時resultおよび後で整数にキャストするときに近似の問題が発生せず、LBP のビットが変更されることを願っています。通常、少なくとも 52 の精度ビットがあるため、存在しないはずです ( IEEE 754 仕様のウィキペディアによると)。ここでは危険だと思います...逆に、固定サイズの効率的なビットベクトルのmatlabタイプを認識していません。int64代わりに使用しますint32、しかし制限は 64 のサンプリング ネイバーにあります。

編集

ここで、3*3 近傍に制限されたローカル バイナリ パターンを計算したい場合、この Matlab 関数は一般的すぎます。最善の方法は、この近傍のループを展開することです。 C++ コード。そのためのコードを次に示します (加算の代わりにビットごとの or を使用しますが、同等です)。

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;

これは、強力なベクトル化を使用して、C コードを Matlab スクリプトに正確に変換したものです。これがあれば、この近隣で別の注文や別のテストに変更するのは非常に簡単です。この場合、Matlab スクリプトにエラーがあるため、この点についても言及します。53 行目には間違った記号がspoints=[-1 -1; -1 0; -1 1; 0 -1; 0 -1; 1 -1; 1 0; 1 1];ありますspoints=[-1 -1; -1 0; -1 1; 0 -1; -0 1; 1 -1; 1 0; 1 1];

于 2014-12-01T10:08:04.413 に答える