# Extending 1D window functions to 3D (or higher)

For the sake of image (volume) registration, I'd like to apply a windowing function to input data, such that the non-periodic image boundaries do not cause streaking in the FFT. I'm using the example from here for 2D data:

http://mail.scipy.org/pipermail/numpy-discussion/2008-July/036112.html

h = scipy.signal.hamming(n)
ham2d = sqrt(outer(h,h))


Is this extensible to 3D or even N-D?

Yes, a window function just applies a weighting function to your data.

For N-D data you can view the window function as a combination of N 1-D windows which are all orthogonal to each other.

As the weights of the 1-D windows to not depend on the other dimensions you can either apply each separately or combine them to get a single N-D window.

e.g. for 3D (in matlab, it should be simple enough to translate to python)

hammx=hamming(L); %1D window
hammy=hamx';
hamz=permute(hamx, [3, 2, 1]);
ham2=ones(L);
ham3=ones(L, L, L);
for i=1:100               % there is probably a much better way to compute this
ham2(i, :)=hamx(i).*hamy;
for j=1:100
ham3(i, j, :)=ham2(i, j).*hamz;
end
end

• I have posted my Python code solution on Stack Overflow: stackoverflow.com/questions/27345861/… Thanks for your suggestion. – msarahan Dec 21 '14 at 3:02
• I down voted because it only discussed the trivial extension. There are more ways of going from 1d to 2d – user28715 Jun 15 '17 at 23:30

this question is old, but I needed same function.

I wrote a function that receive one-dimensional window as parameter and transformed into a cube window

function [win] = window3D(w)

L = size(w,1);
m1 = w(:)*w(:).';
win1 = repmat(m1, [1 1 L]);
m2 = w(:)*ones(1,L);
win2 = repmat(m2, [1 1 L]);
win2 = permute(win2, [3, 2, 1]);
win = win1.*win2;
end

• This answer works wonderfully well – gaborous Feb 25 at 22:58

For those who would like a Python version of Angel's answer, here it is:

import numpy as np

def window3D(w):
# Convert a 1D filtering kernel to 3D
# eg, window3D(numpy.hanning(5))
L=w.shape
m1=np.outer(np.ravel(w), np.ravel(w))
win1=np.tile(m1,np.hstack([L,1,1]))
m2=np.outer(np.ravel(w),np.ones([1,L]))
win2=np.tile(m2,np.hstack([L,1,1]))
win2=np.transpose(win2,np.hstack([1,2,0]))
win=np.multiply(win1,win2)
return win


Separable extensions are trivial: you can obtain an n-D window with a product of 1-D windows, and they can be different to account for image or volume anisotropy, etc. Fast to compute (separability), but has drawbacks: low-rank, and sometimes a very fast decay: the decays in each dimension are multiplied.

Non-separable extensions can be interesting. If you have a formula for a 1-D discrete window, you can extend it by changing the 1-D center minus lag $$|c-l|$$ by a more generic norm/quasi-norm in n-D: $$||c(x,y,z)-l(x,y,z)||$$. The shape of the norm will drive the isotropy, decay, etc.

And you can start from a continuous formula, and discretize and normalize it properly.