[TOC]

深入浅出傅里叶变换:从信号分解到视觉重构

“如果不了解傅里叶变换,你就无法真正理解现代电子文明。”

这句话一点都不夸张。从我们听的 MP3 音乐,到看的 JPEG 图片,再到使用的 5G 网络,甚至是你刚才按下的键盘信号处理,背后都站着傅里叶变换(Fourier Transform, FT)这个巨人。

本文将跳出枯燥的公式推导,从直观理解出发,结合Python 代码实战,带你领略图像处理中频域的魅力。


一、 核心直觉:两个世界的桥梁

1.1 时域 vs 频域

我们的世界大部分时间是以时域(Time Domain)展现的:

  • 声音:空气压强随时间的变化。
  • 图像:像素亮度随空间位置的变化。

傅里叶变换告诉我们:任何连续的周期信号,都可以由一组不同频率、不同振幅、不同相位的正弦波(或余弦波)叠加而成。

这就像是一个棱镜,把混合在一起的“白光”(时域信号),分解成了清晰的“七色光谱”(频域信号)。

1.2 数学直觉:欧拉公式与旋转的圆

核心公式:

这里的 $e^{-i\omega t}$ 并不是什么可怕的东西,根据欧拉公式 $e^{ix} = \cos x + i\sin x$,它代表一个在复平面上旋转的单位圆

直观理解
想象你在绕着一个圆圈跑步(旋转),如果你的跑步频率($\omega$)和信号本身的某种震动频率一致,那么你在特定的位置就会“共振”,积分的值就会很大。如果不一致,你的轨迹就会在圆上抵消,积分接近于零。
傅里叶变换本质上就是一台“频率扫描仪”,用不同速度的圆去试探信号,看看哪个频率上有能量。


二、 实战一:图像的频率与滤波

在图像中,“频率”衡量的是亮度变化的剧烈程度

  • 低频:变化平缓的区域(背景、皮肤、整体轮廓)。
  • 高频:变化剧烈的区域(边缘、噪点、纹理细节)。

我们使用 Python (OpenCV + Numpy) 来对一张图片进行频谱分析,并尝试进行“低通滤波”和“高通滤波”。

2.1 核心代码实现

我们读取一张图片 FT.jpg,对其进行二维傅里叶变换,然后分别保留中心低频和四周高频。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import cv2
import numpy as np
from matplotlib import pyplot as plt
import os

# 1. 读取图像
# 确保 'FT.jpg' 在同目录下
img_path = "FT.jpg"
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)

# 2. 傅里叶正向变换
# np.fft.fft2 得到一个复数数组,包含了振幅和相位信息
f = np.fft.fft2(img)

# 3. 中心化 (Shift)
# 默认 DFT 结果中,低频在左上角 (0,0)。
# 使用 fftshift 将零频率分量移动到频谱中心,这样看起来更直观。
fshift = np.fft.fftshift(f)

# 4. 计算振幅谱 (Magnitude Spectrum)
# 因为振幅值范围极大(几十万到几),直接看是全黑的。
# 使用 20*log 对数变换,把动态范围压缩到 0-255,让人眼能看清。
magnitude_spectrum = 20 * np.log(np.abs(fshift))

# --- 滤波器设计 ---
rows, cols = img.shape
crow, ccol = rows//2 , cols//2

# A. 高通滤波器 (High Pass Filter) - 只保留四周,遮住中心
# 创建一个全是 1 的掩码
mask_high = np.ones((rows, cols), np.uint8)
# 把中心 60x60 的区域(低频)涂黑(置0)
mask_high[crow-30:crow+30, ccol-30:ccol+30] = 0

# 应用掩码
fshift_high = fshift * mask_high
# 逆中心化 (Inverse Shift)
f_ishift_high = np.fft.ifftshift(fshift_high)
# 逆傅里叶变换
img_high_pass = np.abs(np.fft.ifft2(f_ishift_high))

2.2 实验结果解读

  • 左图(Original):这是我们的原始输入图片。
  • 中图(Spectrum):这就是神奇的频谱图
    • 中心亮点:代表直流分量(DC)和低频分量。图片中最亮的部分聚集在这里,说明大部分能量(整体色调、轮廓)都集中在低频。
    • 放射状线条:对应原图中的边缘方向。频谱图的方向与原图垂直(例如原图有水平线,频谱图上就会有垂直的亮线)。
  • 高通滤波(High Pass Filtered)
    • 如上图右侧所示,我们强行抹去了中心的亮斑(低频)。
    • 结果:大片的颜色、平滑的过渡都消失了,只剩下边缘、轮廓和噪点
    • 应用:这就是计算机视觉中边缘检测(Edge Detection)的原理。

三、 实战二:震撼的相位交换实验

傅里叶变换的结果是复数,包含振幅(Amplitude)相位(Phase)

我们通常只关注振幅谱(能量分布),而往往忽略了相位谱。大家潜意识里觉得:“振幅代表强度,肯定最重要吧?”

大错特错!相位才是图像的灵魂!

我们做个实验:取图像 A (cat.jpg) 的振幅,和图像 B (dog.jpg) 的相位,把它们强行组合在一起,逆变换回去,会看到什么?

3.1 实验代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def swap_phase_experiment(img1_path, img2_path):
# 读取两张灰度图
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)

# 统一尺寸(必须尺寸一致才能合并)
h, w = img1.shape
img2 = cv2.resize(img2, (w, h))

# 傅里叶变换
f1 = np.fft.fft2(img1)
f2 = np.fft.fft2(img2)

# 提取振幅与相位
# abs() 提取模长(振幅),angle() 提取辐角(相位)
amp1, phase1 = np.abs(f1), np.angle(f1)
amp2, phase2 = np.abs(f2), np.angle(f2)

# 交换相位重新合成!
# 组合:【猫的振幅】 + 【狗的相位】
combined = amp1 * np.exp(1j * phase2)

# 逆变换
img_combined = np.abs(np.fft.ifft2(combined))
return img_combined

3.2 结果展示与分析

我们使用的原图:

图像 A (提供振幅)

图像 B (提供相位)

交换相位后的结果(振幅来自猫,相位来自狗):

结论令人震惊:
虽然我们使用了猫的振幅(能量),但因为使用了狗的相位,重建出来的图像看起来依然是狗(虽然纹理有点像猫,或者看起来像在雾里的狗)。

物理意义

  • 振幅(Magnitude):告诉我们图像里“有多少”某种频率的成分(比如有多少横条纹,有多少竖条纹)。它决定了纹理的强弱和对比度。
  • 相位(Phase):告诉我们这些正弦波“在哪里”开始波动。它决定了波峰波谷的位置,也就是图像的边缘和几何结构

对于人类视觉来说,结构(Structure)远比纹理(Texture)重要,所以相位起到了决定性作用。


四、 现实应用:JPEG 压缩的秘密

你可能会问:“这东西除了好玩,有什么用?”
其实,你每天都在用的 JPEG 图片,其核心压缩算法(DCT,离散余弦变换)就是傅里叶变换的亲兄弟。

JPEG 压缩原理

  1. 把图像切成 8x8 的小块。
  2. 对每一块做变换,转换到频域。
  3. 丢弃高频信息:人眼对低频(颜色渐变)很敏感,但对高频(极其微小的细节)很不敏感。
  4. 所以,JPEG 会保留左上角的低频系数,把右下角的高频系数直接置零(Quantization)。
  5. 这样就大大减少了需要存储的数据量,实现了压缩。

五、 总结

通过这两场实验,我们重新认识了世界:

  1. 频域视角:世界不仅仅是随时间流逝的,也是由无数频率叠加的。
  2. 滤波:我们可以像修剪树枝一样,精准地控制图像的清晰度与细节(磨皮 vs 边缘检测)。
  3. 相位之魂:在信号重建中,位置信息(相位)往往比强度信息(振幅)更关键。

从像素处理到网格几何处理(Mesh Processing),这种“谱分析”的思想是通用的。希望这篇文章能帮你打开频域的大门!