Тип производимого ядра - PullRequest
       2

Тип производимого ядра

0 голосов
/ 29 сентября 2018

Я пытаюсь понять реализацию MATLAB алгоритма фильтрации нелокальных средних из здесь .Я хочу понять, какое ядро ​​производит следующая часть кода:

kernel=zeros(2*f+1,2*f+1);   
for d=1:f    
  value= 1 / (2*d+1)^2 ;    
  for i=-d:d
      for j=-d:d
          kernel(f+1-i,f+1-j)= kernel(f+1-i,f+1-j) + value ;
      end
  end
end
kernel = kernel ./ f;

Я попытался просмотреть промежуточные результаты и думаю, что это ядро ​​с гауссовым взвешиванием, но я не уверен, что этоправильно.

Вывод:

kernel =

0.0200    0.0200    0.0200    0.0200    0.0200
0.0200    0.0756    0.0756    0.0756    0.0200
0.0200    0.0756    0.0756    0.0756    0.0200
0.0200    0.0756    0.0756    0.0756    0.0200
0.0200    0.0200    0.0200    0.0200    0.0200

Указанная бумага: Buades-NonLocal Раздел 3

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Buades и соавт.определенно предназначен для использования гауссовых весов.Это ядро, если оно предназначено для приближения, дает очень грубое приближение.Вот как это выглядит в 1D для f=3, f=10 и f=100:

kernels

Я добавил ядро ​​Гаусса для сравнения,Кроме того, гауссиан является совершенно изотропным, тогда как это приближение далеко от него (потому что оно состоит из квадратов).

И я нахожу это странным, потому что четыре вложенных цикла алгоритма NL означают, что ониспользуется не делается быстрее, используя это приближение по истинному гауссову.Квадрат разности патчей умножается на ядро, стоимость этой операции не зависит от того, как сгенерировано ядро ​​или какие значения оно содержит.

Я бы предложил заменить make_kernel чем-то вроде этого, который создает настоящее двумерное гауссовское ядро:

function kernel = make_kernel2(f)
x = linspace(-2,2,2*f+1);
kernel = exp(-0.5*x.^2);
kernel = kernel .* kernel.'; % requires newer MATLAB, otherwise use bsxfun
kernel = kernel / sum(kernel(:));

Я никогда раньше не видел этого конкретного приближения к гауссову (и я видел много).Как правило, гауссова свертка аппроксимируется повторяющимися применениями свертки с коробчатым ядром (говорят, что 3x достаточно для достаточно хорошего приближения, , но требуется больше, если производная должна быть вычислена после ).Недостатком этого подхода является невозможность повторного использования интегрального изображения, поскольку каждая свертка применяется к разному изображению (т.е. результат предыдущей свертки).Свертка с ядром блока может быть вычислена с использованием интегрального изображения, где выход для одного пикселя может быть вычислен путем сложения 4 значений плюс одно деление, независимо от размера блока.

img = imread('cameraman.tif');
out = imfilter(img,ones(3,3)/9);
out = imfilter(out,ones(3,3)/9);
out = imfilter(out,ones(3,3)/9);

Если вместо многократного применения свертки блоков вычислить несколько сверток блоков разных размеров, используя одно и то же интегральное изображение, и сложить результаты вместе, то получится свертка с ядром, о котором спрашивается в этом вопросе.Это было бы грубым приближением к гауссовскому и не изотропным, но это было бы очень дешевым для вычисления.(Демонстрационный код, приведенный ниже, не использует целостное изображение, это не предназначено для демонстрации времени, а только того, как выглядит результат.)

img = imread('cameraman.tif');
out = imfilter(img,ones(3,3)/9) / 3;
out = out + imfilter(img,ones(4,4)/16) / 3;
out = out + imfilter(img,ones(5,5)/25) / 3;

Могу поспорить, что это то, откуда пришло это ядро.Однако, создавая это ядро, а не применяя различные свертки отдельно и добавляя результаты, все преимущества скорости в этом методе не используются, оставляя только многие его отрицательные стороны.

0 голосов
/ 29 сентября 2018

Во-первых, обратите внимание, что два самых внутренних цикла - это не векторизованный способ определения постоянной матрицы размером (2d+1) x (2d+1), которая суммируется с 1 (value является просто обратной величиной 1*(2*d+1)^2).Это определяет ядро ​​размытия рамки .

Так что получается, что ядро ​​(2f+1) x (2f+1) определяется путем суммирования концентрических ядер размытия рамки размером 3 x 3, 5 x 5, ..., (2f+1) x (2f+1).Поскольку свертка является линейной операцией, сумма прямоугольных размытий будет применяться отдельно, а выпуклая комбинация отдельных ядер является допустимым ядром.

В то время как прямоугольные размытия можно использовать для аппроксимации размытия по Гауссу, используя рекурсивновыпуклая комбинация, такая как приведенная выше, вероятно, будет вести себя по-разному (как отмечено Cris Luengo в комментарии ).Даже симметрия отключена: ядро ​​Гаусса является сферически симметричным, в то время как у этих коробчатых ядер есть углы.

В заключение, я полагаю, что ответ на ваш вопрос «нет», вероятно, он не приближается к ядру Гаусса., но это все еще размытое ядро.


Если бы мне нужно было создать вышеуказанное ядро, я бы векторизовал его:

kernel = zeros(2*f+1,2*f+1);   
for d=1:f
    kernel(f+1-d:f+1+d,f+1-d:f+1+d) = kernel(f+1-d:f+1+d,f+1-d:f+1+d) + 1/(2*d+1)^2;
end
kernel = kernel / f;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...