2D-свертка с помощью 1D-свертки с использованием разделяемых свойств

Я пишу программу, в которой я делаю много 2D-сверток. Поэтому я подумал, что более эффективным подходом может быть использование одномерной свертки. Но я, кажется, застрял на этом.

До сих пор я ссылался на эти ссылки:

проверьте это 1) http://blogs.mathworks.com/steve/2006/10/04/separable-convolution/

проверьте это 2) http://blogs.mathworks.com/steve/2006/11/28/separable-convolution-part-2/

У меня есть ядро ​​Гаусса (K) размером 5X5. Мне нужно свернуть эту функцию ядра с изображением. Размер моего изображения вынужден быть 4000X4000. Я даю программу ниже:

clc;clear all;close all;
imgID = 5;
Img = imread([num2str(imgID),'.bmp']);
Img = double(Img(:,:,1));
Img = imresize(Img,[4000 4000]);

sigma=3.0;   
K=fspecial('gaussian',round(2*sigma)*2+1,sigma);     % the Gaussian kernel

%%
%//Trying to use 1D convolution instead of using 2D convolution
[U,S,V] = svd(K);
K1 = U(:,1) * sqrt(S(1,1));
K2 = V(:,1)' * sqrt(S(1,1));

%%
tic
KI=conv2(Img,K,'same');
toc

tic
KI1 = imfilter(Img,K1,'conv');                            
KI1 = imfilter(KI1,K2,'conv');
toc


tic
KI2 = imfilter(Img,K,'conv');
toc

tic
KI3 = conv2(K1,K2,Img,'same');
toc

Я проверил ранг матрицы K. Он равен 1, так что это действительно отделимый вектор, который можно выразить как внешнее произведение двух одномерных векторов. Векторы 1D здесь обозначены как K1 и K2. Затем я рассчитал время, чтобы понять, какой метод быстрее? Результаты показаны ниже :

%//1st method

Elapsed time is 0.375002 seconds.

%//2nd method

Elapsed time is 1.601285 seconds.

%//3rd method

Elapsed time is 1.884165 seconds.

%//4th method

Elapsed time is 0.315134 seconds.

Как видите, первый способ самый быстрый, а третий тоже достаточно быстрый. Третий и второй методы также имеют очень низкую ошибку порядка e-14, но оба эти метода чрезвычайно медленны по сравнению с первым, использующим conv2.

Не могли бы вы, ребята, сказать мне, почему метод с одномерной сверткой является самым медленным?

Заранее спасибо всем!!

Редактировать: см. мой 4-й метод!


person roni    schedule 02.09.2013    source источник
comment
Какой 4-й способ? У вас есть бумага, чтобы сослаться на это? Спасибо   -  person user3051460    schedule 04.08.2014


Ответы (1)


Результат во втором методе не KI1*KI2, а KI2. Обратите внимание, что KI2 уже дважды свертывался. Если вы вычислите KI- KI2 вторым методом, вы получите небольшую ошибку.

Что касается скорости, у меня есть следующие комментарии:

  • Строка KI - KI2 во втором методе и строка KI - KI3 в третьем замедляют работу и не должны включаться в сравнение. Просто удалите их.
  • Во втором методе повторно используйте переменную KI1 вместо определения новой KI2: то есть замените KI2 = imfilter(KI1,K2,'conv'); на KI1 = imfilter(KI1,K2,'conv');. Вероятно, это сокращает время, затрачиваемое на выделение памяти.
  • Ваша матрица Img очень мала. С большими матрицами второй метод самый быстрый.

С матрицей 4000 x 4000 Img и применением других изменений я соответственно получаю:

Elapsed time is 4.924468 seconds.
Elapsed time is 0.793251 seconds.
Elapsed time is 0.854416 seconds.
person Luis Mendo    schedule 02.09.2013
comment
Спасибо, я обновил вопрос. Это было ошибкой с моей стороны. Но не могли бы вы сказать мне, почему результат одномерной свертки самый медленный среди всех трех методов? Или я что-то не так делаю? - person roni; 02.09.2013
comment
Я обновил ответ. Вы неправильно обновили строку во втором методе - person Luis Mendo; 02.09.2013
comment
Спасибо за Ваш ответ - person roni; 02.09.2013
comment
Не могли бы вы опубликовать фрагмент кода? Я не получаю желаемых результатов. Я обновляю новый набор строк кода, чтобы отразить изменения, указанные выше, и все же мой первый метод быстрее. Пожалуйста, опубликуйте свой код. Это будет очень полезно. - person roni; 02.09.2013
comment
Пожалуйста, смотрите мое редактирование и 4-й метод. Я считаю, что 4-й способ будет самым быстрым - person roni; 02.09.2013
comment
Мой код такой же, как ваш текущий, после того, как вы применили предложенные мной изменения. Я пробовал четвертый способ. При больших Img он медленнее, чем второй и третий. С маленьким Img его время вычисления порядка первого, и они оба (приблизительно) самые быстрые - person Luis Mendo; 02.09.2013