%
%% Credit% (ISR-2/LANL)
%%% See also
% Ressembles:% ,
% .% Requires:
% .% .
% .
%% Function implementationfunction [F, S] = bilateralstack_base(I, sigma_d, sigma_r, pstack, destack)
if nargin<5, destack = 'lin';
if nargin<4, pstack = 10; endend
[X,Y,C] = size(I);
%%
% deal with multispectral imagesif C>1
F = I; if nargout==2, S = cell(C,1); end
for i=1:C [F(:,:,i), s] = bilateralstack_base(I(:,:,i), sigma_d, sigma_r, pstack, destack);
if nargout==2, S{i} = s; end end
returnend
%%
% * define the shortcuts functions for filtering
%%% start with the classical Gaussian linear filtering: a convolution can be
% computed either over the spatial domain in $O(N \sigma^2)$ operations or over% the Fourier domain in $O(N \log(N))$ operations. Depending on the value of
% sigma, one should prefer either Fourier or spatial domain.
%%% defining a Gaussian function, centered at the top left corner (because it
% corresponds to the 0 point for the FFT).x = [0:X/2-1, -X/2:-1];
y = [0:Y/2-1, -Y/2:-1];[y,x] = meshgrid(x,y);
gaussfilt = @(s) exp((-x.^2-y.^2)/(2*s^2));% see also GAUSSWIN help
%%
% define the linear Gaussian filtering over the Fourier domain: this function% is able to process in parallel a 3D block |F| by filtering each |F(:,:,i)|
gfilter = @(f, s) ... real(ifft2(fft2(f) .* repmat(fft2(gaussfilt(s)), [1 1 size(f,3)])));
%%
% function to build the weight stack $W_{r_i}$ for $r_i$ uniformly distributed % in [0,1]
gaussian = @(x, sigma) exp( -x.^2 / (2*sigma^2) );weightmap = @(f, sv, p) ...
gaussian( repmat(f, [1 1 p]) - ... repmat( reshape((0:p-1)/(p-1), [1 1 p]) , [size(f,1) size(f,2) 1]), sv );
%%
% shortcut to compute the bilateral stack ${F_{r_i}}_{i=1,\cdots,p}$bilateral_stack_tmp = @(f, sx, W, p) ...
gfilter(W.*repmat(f, [1 1 p]), sx) ./ gfilter(W, sx);
%%% compute the weight stack map: each |W(:,:,i)| is the map $W_{r_i}$ associated
% to the pixel value |r_i|
% W = weightmap(I,sigma_r);bilateral_stack = @(f, sx, sv, p) ...
bilateral_stack_tmp(f, sx, weightmap(f,sv,p), p);
%%% destacking corresponds to selecting a layer $I(x) \in {1,\cdots,p}$ at
% each pixel:% $f_I(x) = F_{r_I(x)}(x)$
% shortcut for de-stacking using a set of indexes:[y,x] = meshgrid(1:X,1:Y);
destacking = @(f,I) f(x + (y-1)*X + (I-1)*X*Y);
switch destack
case 'nn' %%
% the simplest reconstruction method performs the destacking using % the nearest neighbor value:
% shortcut for performing de-stacking by nearest neighbor
% interpolation: bilateral_destack = @(S, f, p) destacking(S, round(f*(p-1))+1);
case 'lin'
%% % a better reconstruction is obtained by using a first order linear
% interpolation to perform the destacking.
% shortcut for the linear interpolation reconstruction. frac = @(x) x - floor(x);
lininterp = @(f1, f2, Fr) f1.*(1-Fr) + f2.*Fr; bilateral_lin = @(F, f, p) ...
lininterp( destacking(F, clamp(floor(f*(p-1))+1,1,p) ), ... destacking(F, clamp(ceil(f*(p-1))+1,1,p)), ...
frac(f*(p-1))); bilateral_destack = @(S, f, p) bilateral_lin(S, f, p);
end
%%% * main computation
%%
% rescale the input image in [0,1]I = rescale(I);
%%
% compute the bilateral stack ${F_{r_i}}$S = bilateral_stack(I, sigma_d, sigma_r, pstack);
%%
% compute the bilateral filterF = bilateral_destack(S, I, pstack);
end % end of bilateralstack_base
##### SOURCE END #####
-->