Более быстрый подход к лапласиану Гаусса - PullRequest
0 голосов
/ 07 декабря 2018

В настоящее время я оптимизирую свой код, чтобы сделать обработку изображений более эффективной.Моя первая проблема была из-за vision.VideoFileReader и step, когда открывание каждого кадра занимало много времени.Я ускоряю свой код, сжимая мое изображение в градациях серого в 3 кадра в 1 кадре RGB.Таким образом, я мог загрузить 1 кадр RGB, используя vid.step(), и импортировать 3 кадра, готовых к обработке.

Теперь мой код работает медленно при фильтрации Лапласа Гаусса (LoG).Я читал, что с помощью функции imfilter можно использовать LoG, но это следующий шаг ограничения скорости.

При дальнейшем чтении выясняется, что imfilter - не лучший вариант для скорости,Похоже, MATLAB представил функцию LoG , но она была представлена ​​в R2016b, и я, к сожалению, использую R2016a.

Есть ли способ ускорить imfilter или есть лучшая функция для использованиявыполнить фильтрацию LoG?

Должен ли я позвонить python , чтобы ускорить процесс?

enter image description here

Код:

Hei = gh.Video.reader.info.VideoSize(2);
Wid = gh.Video.reader.info.VideoSize(1);

Log_filter = fspecial('log', filterdot, thresh); % fspecial creat predefined filter.Return a filter.
    % 25X25 Gaussian filter with SD =25 is created.

tic
ii = 1;

bkgd = zeros(Hei,Wid,3);
bkgd(:,:,1) = gh.Bkgd;
bkgd(:,:,2) = gh.Bkgd;
bkgd(:,:,3) = gh.Bkgd;

bkgdmod = reshape(bkgd,720,[]);

while ~isDone(gh.Video.reader)
    frame = gh.readFrame();
    img_temp = double(frame);

    img_temp2 = reshape(img_temp,720,[]);
    subbk = img_temp2 - bkgdmod;

    img_LOG = imfilter(subbk, Log_filter, 'symmetric', 'conv');

    img_LOG =  imbinarize(img_LOG,.002);
    [~, centroids, ~] = gh.Video.blobAnalyser.step(img_LOG);

    toc
end

1 Ответ

0 голосов
/ 07 декабря 2018

Лапласа Гаусса не разделяется напрямую на два одномерных ядра.Поэтому imfilter сделает полную свертку, что довольно дорого.Но мы можем вручную разделить его на более простые фильтры.


Лапласа Гаусса определяется как сумма двух производных второго порядка гауссиана:

LoG = d²/dx² G + d²/dy² G

Сам Гауссиан и его производные отделимы .Следовательно, вышеприведенное может быть вычислено с использованием 4 1D свертки, что намного дешевле, чем одиночная 2D свертка, если ядро ​​не очень маленькое (например, если ядро ​​7x7, нам нужно 49 умножений и сложений на пиксель для 2D ядра, или 4* 7 = 28 умножений и сложений на пиксель для 4-мерных ядер; эта разница увеличивается по мере увеличения ядра).Вычисления будут выглядеть так:

sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
d2G = G .* ((-cutoff:cutoff).^2 - sigma^2)/ (sigma^4);
dxx = conv2(d2G,G,img,'same');
dyy = conv2(G,d2G,img,'same');
LoG = dxx + dyy;

Если вы действительно ограничены во времени и не заботитесь о точности, вы можете установить cutoff в 2*sigma (для меньшего ядра), но этоне идеально.


Альтернативный, менее точный, состоит в том, чтобы отделить операцию по-разному:

LoG * f = ( d²/dx² G + d²/dy² G ) * f
        = ( d²/dx² ? * G + d²/dy² ? * G ) * f
        = ( d²/dx^2 ? + d²/dy² ? ) * G * f

(где * представляет свертку, и del дельта Дирака, сверткаэквивалентно умножению на 1).Оператор d²/dx² ? + d²/dy² ? на самом деле не существует в дискретном мире, но вы можете принять конечно-разностное приближение, которое приводит к знаменитому ядру Лапласа 3x3:

[ 1  1  1             [ 0  1  0
  1 -8  1       or:     1 -4  1
  1  1  1 ]             0  1  0 ]

Теперь мы получаем более грубое приближение, ноэто быстрее для вычисления (2 1D свертки и свертка с тривиальным ядром 3x3):

sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
tmp = conv2(G,G,img,'same');
h = fspecial('laplacian',0);
LoG = conv2(tmp,h,'same'); % or use imfilter
...