2D gaussian filter with a variable sigma
12 views (last 30 days)
Show older comments
I have a large gridded dataset I'd like to lowpass filter. The catch is, need to specify a different sigma value for each pixel of the grid.
Using a single value of sigma for the entire grid is easy with imgaussfilt, so for example, I can filter the grid I using a sigma value of 3 like this:
% A grid of data:
I = 10*rand(100);
% The grid, filtered to sigma=3:
If = imgaussfilt(I,3);
But I don't want tuse a single value of sigma for the entire grid. Instead, I want to specify a different sigma for every pixel. For this 100x100 grid it's easy to loop through each row and column, filtering the grid to specified values of sigma like this:
% A grid of sigma values corresponding to the grid of data:
sigma = abs(peaks(100))+0.1;
% Preallocate:
If2 = NaN(size(I));
% Loop through each row and column:
for row = 1:size(I,1)
for col = 1:size(I,2)
% Perform Gaussian filter on the entire grid using sigma(row,col):
tmp = imgaussfilt(I,sigma(row,col));
% Only save the value corresponding to this row and col:
If2(row,col) = tmp(row,col);
end
end
The nested loop approach gives the answer I want, but it's inelegant, and slow for very large grids. Is there a better way to define a locally-varying filter?
0 Comments
Answers (1)
Wolfgang Schwanghart
on 3 Apr 2019
Edited: Wolfgang Schwanghart
on 3 Apr 2019
Hi Chad,
below is some code that does the trick using nlfilter. To be more efficient, I created a look-up table with a finite set of sliding windows.
% Variable standard deviations
st = 1:100;
% Size of sliding window
% Should be an odd number
m = 101;
kcenter = ceil(m/2);
% Cell array of filters
st = cellfun(@(x) fspecial('gaussian',[m m],x),num2cell(st),'Unif',false);
% Image to be smoothed
A = rand(200);
% Image with variable standard deviations
STSIZE = randi(20,size(A))+5;
% Image with linear indices
IX = reshape(1:numel(A),size(A));
B = nlfilter(IX,[m m],...
@(ix) fun(ix,A,STSIZE,st,kcenter));
imagesc(B)
function out = fun(ix,A,STSIZE,st,kcenter)
if any(ix(:) == 0)
% image is zero padded
% return nan
out = nan;
else
% get window
ixc = ix(kcenter,kcenter);
stsize = STSIZE(ixc);
f = st{stsize};
a = A(ix);
out = f(:)'*a(:);
end
end
3 Comments
Wolfgang Schwanghart
on 3 Apr 2019
Edited: Wolfgang Schwanghart
on 3 Apr 2019
True, the size of the window is fixed, but the standard deviation of the Gaussian Kernel varies. I have now updated the code. While m and n remain fixed (required by nlfilter), the standard deviation of the kernel varies freely, yet it never extends the size of the kernel.
Image Analyst
on 4 Apr 2019
I second this answer - I was going to suggest nlfilter() also, until I saw Wolfgang beat me to it.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!