我有一个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的文档对我来说有点过于模糊。 这可能是一个非常简单的问题,但我在任何地方都没有找到任何明确的答案。能不能请你开导?
答案 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。