Код Matlab для локального двоичного шаблона
Я изо всех сил пытаюсь понять реализацию Matlab алгоритма LBP, найденную здесь. Я пытаюсь найти, как он рассчитывает двоичные файлы для каждого пикселя? Он просто вычисляет, где соседний пиксель больше, чем фактический размер центрального пикселя. Я хочу рассчитать двоичные файлы для каждого пикселя, чтобы использовать локальные гистограммы для вычисления особенностей изображения.
[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;
}
2 ответа
Это векторизованная реализация LBP, довольно хорошо подходящая для Matlab.
После инструкций по инициализации, давайте посмотрим на основной цикл, начиная с строки "for i = 1:neighbors
". Цикл довольно понятен: он вычисляет сравнение одного соседа с центральным пикселем, цикл повторяется по всем соседям. У вас есть эта точка, так что теперь войдите глубоко в цикл, чтобы понять, как он накапливает все результаты.
Ядро цикла на самом деле слишком сложное, потому что оно учитывает реальный круг вместо приблизительного целочисленного круга. Поэтому цель основной части инструкций - вычислить интерполированную интенсивность соседнего пикселя. Здесь он отличается от кода C++, который вы используете в качестве справочного, где он занимает только целое число, радиус 1 пиксель в радиусе. Помните, что с кодом lbp.m вы можете - теоретически, я буду обсуждать это позже - вычислить LBP по кругу радиуса R с N точками выборки, так что C++ будет соответствовать кругу радиуса 1 и с 8 выборками Точки, если бы не было интерполяции. Но есть интерполяция, когда сосед не соответствует пиксельной сетке изображения, когда (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6)
ложно).
Если (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
влево или эквивалентно умножить 2^(i-1)
, Тогда вы суммируете с result
, Таким образом, в конце цикла вычисление действительно эквивалентно вашему коду C++, за исключением того, что оно выполняется по всему изображению, а не по одному пикселю. А код C++ можно рассматривать как развернутую версию цикла matlab с соседним кругом радиуса 1 и 8 точек выборки. В этой точке вычисляется карта LBP, следующие блоки являются дополнительной обработкой карты LBP (переназначение через таблицу отображения и, необязательно, вычисление гистограммы изображения LBP вместо самого изображения LBP).
Теперь немного обсудим весь сценарий. Здесь есть недостаток, который скрыт в конце сценария. Фактически, посредством кода вы ограничены 32 соседями, не более, потому что в конце изображение LBP приводится к int32
, Недостаток в том, что переменная result
выделяется в виде двойной матрицы, а не целочисленной матрицы, поэтому я очень надеюсь, что при обновлении не возникает проблем с аппроксимацией result
и позже при приведении к целому числу, что приводит к изменению битов в LBP. Обычно их не должно быть, так как есть как минимум 52 прецизионных бита (согласно википедии для спецификации IEEE 754). Я думаю, что здесь рискованно... и, наоборот, я не знаю, что такое тип MATLAB для длинного, эффективного размера битового вектора фиксированного размера. я хотел бы использовать int64
вместо int32
, но предел будет там в 64 соседях выборки.
РЕДАКТИРОВАТЬ
Теперь, если вы хотите компенсировать некоторые локальные двоичные шаблоны, ограниченные в окрестности 3*3, эта функция Matlab слишком универсальна для вас, и лучше всего развернуть цикл для этой окрестности и, таким образом, быть очень близко к C++ код. Вот фрагмент кода для этого (я использую побитовое или вместо сложения, но это эквивалентно):
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];
,
Я сделал свой последний годовой проект по Local Binary Pattern. Я видел тот код, на который вы указывали, но я решил написать свой собственный код.
Это мой код:
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 - это изображение, которое вы передаете, а LBP - это выход. Написал это для локальной двоичной структуры: http://quantgreeks.com/local-binary-pattern-in-matlab/. Я знаю, что могу написать код в более эффективной форме. Но если написать это таким образом, станет ясно, как работает локальный двоичный шаблон.