Numpy fft中的频率轴

时间:2015-04-08 13:05:58

标签: numpy fft frequency dft

我有一个32x32像素的图像,我想计算1D功率谱(沿图像的y轴平均)。这就是我的工作。

import numpy as np

size_patch=32 

# Take the fourier transform of the image.
F1_obs = np.fft.fft2(image_obs)

# Now shift the quadrants around so that low spatial frequencies are in
# the center of the 2D fourier transformed image.
F2_obs = np.fft.fftshift(F1_obs)

# Calculate a 2D power spectrum
psd2D_obs=np.abs(F2_obs)**2

freq = np.fft.fftfreq(size_patch, d=1.)

#Compute the 1D power spectrum (averaged along y axis)
psd1D_obs[i] = np.average(psd2D_obs,axis = 0)[size_patch/2:] # we keep the end values of the array : the fft is symmetric

我在掌握功率谱中精确绘制的x轴方面遇到了一些麻烦。是波数还是空间频率?这里采用的惯例是什么?自然单位周期/像素? numpy.fft.fftfreq的文档对我来说有点过于模糊。 这可能是一个非常简单的问题,但我在任何地方都没有找到任何明确的答案。能不能请你开导?

2 个答案:

答案 0 :(得分:1)

np.fft.fftfreq(N, d = spacing)以周期/间距返回采样频率。如果你想要角波数而不是乘以2 * np.pi

你也很可能希望在降低你的2d fft进行1d表示时有角度的平均值。如果你想使用一个很好地包装所有这些细节的便利功能,那么看看https://github.com/keflavich/agpy/blob/master/AG_fft_tools/psds.py

答案 1 :(得分:0)

如果要平均2D光谱,则应进行径向平均,而不是沿轴。 r和r + dr之间的径向平均值是像素的值的总和,这些像素的距离r与中心之间的距离在r和dr之间,除以那些像素的数量。这对于循环是可行的,但我宁愿使用numpy.histogram两次。

这是一个完成工作的课程,可能会出现窗口问题。它针对您需要处理许多相同大小的图像(或补丁)的常见情况进行了优化。我还使用numexpr来加速可能的目标。

在下文中,我将空间频率命名为q

import numpy as np
import numexpr

class ImageStructureFactor:
    """A class to compute rapially averaged structure factor of a 2D image"""
    def __init__(self, shape):
        assert len(shape) == 2, "only 2D images implemented"
        L = max(shape)
        self.qs = np.fft.fftfreq(L)[:L/2]
        self.dists = np.sqrt(np.fft.fftfreq(shape[0])[:,None]**2 + np.fft.fftfreq(shape[1])**2)
        self.dcount = np.histogram(self.dists.ravel(), bins=self.qs)[0]
        self.has_window = False

    def set_window(self,w='hanning'):
        if w == False:
            self.has_window = False
        elif hasattr(np, w):
            self.window = [getattr(np,w)(self.dists.shape[0])[:,None], getattr(np,w)(self.dists.shape[1])]
            self.has_window = True
        elif isinstance(w, np.ndarray):
            assert w.shape == self.dists.shape
            self.window = w
            self.has_window = True

    def windowing(self, im):
        if not self.has_window:
            return im
        if isinstance(self.window, np.ndarray):
            return numexpr.evaluate('im*w', {'im':im, 'w':self.window})
        return numexpr.evaluate('im*w0*w1', {'im':im, 'w0':self.window[0], 'w1':self.window[1]})

    def __call__(self, im):
        spectrum = numexpr.evaluate(
            'real(abs(f))**2',
            {'f':np.fft.fft2(self.windowing(im))}
            )
        return np.histogram(self.dists.ravel(), bins=self.qs, weights=spectrum.ravel())[0] / self.dcount

导入后,您的问题会写:

size_patch=32
isf = ImageStructureFactor((size_patch,size_patch))
psd1D_obs = np.zeroes((len(patches), len(isf.qs)-1))
for i, patch in enumerate(patches):
    psd1D_obs[i] = isf(patch)

我认为你有一个补丁列表。如果你想要窗口,只需添加

isf.set_window()
构建isf

。您可以将窗口的名称(请参阅numpy.windowing)指定为字符串。

频率可用isf.qs。根据numpy手册,第一个非零频率是1 / size_patch,因此比脉冲频率f更具脉动性。要获得(空间)频率,您需要乘以2 * pi。