【问题标题】:Plotting FFT frequencies in Hz in Python在 Python 中以 Hz 为单位绘制 FFT 频率
【发布时间】:2019-12-11 15:21:47
【问题描述】:

我正在实施本文中的方法: https://dspace.mit.edu/bitstream/handle/1721.1/66243/Picard_Noncontact%20Automated.pdf?sequence=1&isAllowed=y

主要思想是使用 10 秒视频中的一组帧 (N=300) 进行心脏脉搏测量,因此帧速率等于 30 fps。

red = [item[:,:,0] for item in imgs]
green = [item[:,:,1] for item in imgs]
blue = [item[:,:,2] for item in imgs]

red_avg = [item.mean() for item in red]
green_avg = [item.mean() for item in green]
blue_avg = [item.mean() for item in blue]

red_mean, red_std = np.array(red_avg).mean(), np.array(red_avg).std()
green_mean, green_std = np.array(green_avg).mean(), np.array(green_avg).std()
blue_mean, blue_std = np.array(blue_avg).mean(), np.array(blue_avg).std()

red_avg = [(item - red_mean)/red_std for item in red_avg]
green_avg = [(item - green_mean)/green_std for item in green_avg]
blue_avg = [(item - blue_mean)/blue_std for item in blue_avg]

data = np.vstack([signal.detrend(red_avg), signal.detrend(green_avg), signal.detrend(blue_avg)]).reshape(300,3)
from sklearn.decomposition import FastICA
transformer = FastICA(n_components=3)
X_transformed = transformer.fit_transform(data)

from scipy.fftpack import fft

first = X_transformed.T[0]
second = X_transformed.T[1]
third = X_transformed.T[2]

ff = np.fft.fft(first)
fs = np.fft.fft(second)
ft = np.fft.fft(third)

imgs - 是具有 300 个图像像素值的数组的初始列表。 如您所见,我将所有帧拆分为 RGB 通道,因此有痕迹x_i(t),其中i = 1,2,3

标准化后,我们去除所有迹线的趋势并将它们堆叠以进一步应用 ICA,然后对所有三个组件进行 FFT。

然后,该方法声称我们需要绘制功率与频率 (Hz) 的关系图,并选择最有可能是心脏脉冲的分量。

最后,我们对选定的源信号应用快速傅里叶变换 (FFT) 获得功率谱。脉冲频率被指定为频率 对应于工作频段内频谱的最高功率。为了 在我们的实验中,我们将操作范围设置为 [0.75, 4] Hz(对应于 [45, 240] bpm) 以提供广泛的心率测量。

这是我尝试将频率可视化的方法:

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

data = ft
print(fs.size)
ps = np.abs(np.fft.fft(data))**2

sampling_rate = 30

freqs = np.fft.fftfreq(data.size, 1/sampling_rate)
idx = np.argsort(freqs)
#print(idx)
plt.plot(freqs[idx], ps[idx])

我得到的完全不同,因为频率范围从 $-15$ 到 $15$,我不知道这是否以赫兹为单位。

上面的三张图片是我在执行代码以可视化频率和信号功率时得到的。

如果有任何帮助或建议,我将不胜感激。

【问题讨论】:

    标签: python numpy scipy signal-processing


    【解决方案1】:

    您应该真正学习如何将图像/视频用作 nD-张量。这样做你可以用更简洁的代码替换所有的数据争吵:

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.fftpack import fft
    from sklearn.decomposition import FastICA
    
    images = [np.random.rand(640, 480, 3) for _ in range(30)]
    
    # Create tensor with all images
    images = np.array(images)
    images.shape
    
    # Take average of all pixels, for each image and each channel individually
    avgs = np.mean(images, axis=(1, 2))
    mean, std = np.mean(avgs), np.std(avgs)
    
    # Normalize all average channels
    avgs = (avgs - mean) / std
    
    # Detrend across images
    avgs = scipy.signal.detrend(avgs, axis=0)
    
    transformer = FastICA(n_components=3)
    X_transformed = transformer.fit_transform(avgs)
    
    X_ff = np.fft.fft(X_transformed, axis=0)
    plt.plot(np.abs(X_ff) ** 2)
    

    稍微回答一下您的问题:我认为您错误地采用了第三个 PCA 分量的傅立叶谱的傅立叶谱

    FFT(FFT(PCA[:, 2]))
    

    虽然您打算只进行一次 FFT:

    FFT(PCA[:, 2]))
    

    关于 -15...15 轴:您已将采样频率设置为 30Hz(或视频术语中的 30fps)。这意味着您可以在视频中检测到高达 15Hz 的任何内容。

    在傅里叶理论中,有一种东西叫做“负频率”。现在,由于我们主要分析真实信号(而不是复杂信号),因此负频率始终与正频率相同。这意味着您的光谱始终是对称的,您可以忽略左半部分。

    但是,由于您已经进行了两次 FFT,因此您正在查看一个复杂信号的 FFT,该信号确实具有负频率。这就是为什么您的光谱不对称且令人困惑的原因。

    此外,我相信您混淆了重塑和转置。在 PCA 之前,您正在组装您的数据,例如

    np.vstack([red, green, blue])  # shape = (3, 300)
    

    你想转置得到(300, 3)。相反,如果您重新整形,则不会交换行和列,而是以不同的形状解释相同的数据。

    【讨论】:

    • 非常感谢您的详细评论。您能否详细说明“两次进行 FFT”是什么意思?该论文中的模型建议在 ICA 之后将 FFT 应用于树跟踪组件。因此,据我了解,我只应用一次 FFT。另一个问题是我应该如何解释频率。我不太明白文章中的这句话:The pulse frequency was designated as the frequency that corresponded to the highest power of the spectrum within an operational frequency band. For our experiments, we set the operational range to [0.75, 4] Hz
    • 查看第一个 sn-p 的底部和第二个 sn-p 的顶部。你打电话给fft() 两次。
    • 我相信np.vstack().reshape(300, 3) 不会像您认为的那样做。你应该改用np.vstack().T
    • 在你的情况下是赫兹,是的。您以 30Hz 的频率对信号进行采样,并相应地生成一个轴。 4Hz 来自关于人体的知识:健康参与者的心率不会低于 0.7 或高于 4Hz(42-210 bpm),因此可以忽略。只需相应地裁剪您的光谱。
    • 不,只是丢弃该范围之外的频率和数据。
    猜你喜欢
    • 2021-11-05
    • 2019-01-19
    • 2018-10-02
    • 2015-08-27
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 2013-06-27
    相关资源
    最近更新 更多