前言
一维DFT我们已经玩明白了,知道它能把复杂信号拆成一堆正弦波。那二维DFT呢?简单说,就是把这个“拆解魔法”搬到了图像上。一张图片,其实也可以看作是二维信号,二维DFT就能把它拆解成无数个不同方向、不同频率的二维正弦波。
这篇就带大家从原理、公式、代码、实验,一次性把二维DFT吃透,看完你就能看懂图像的频域谱,还能自己动手做滤波、去噪、锐化。
一、二维DFT是什么?
1.1 核心思想
一维DFT是把一维信号(时间序列拆成不同频率的正弦波);
二维DFT是把二维信号(图像拆成不同频率、不同方向的二维正弦波)。
通俗解释:就像把一张复杂的“油画”,拆成无数个不同粗细、不同方向的“条纹”,这些条纹的频率、强度,就是图像的频域信息。
1.2 数学公式
二维DFT的公式:
F ( u , v ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) ⋅ e − j 2 π ( u x M + v y N ) F(u, v) = \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x, y) \cdot e^{-j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)}F(u,v)=x=0∑M−1y=0∑N−1f(x,y)⋅e−j2π(Mux+Nvy)
每个字母的含义:
- f ( x , y ) f(x,y)f(x,y):原始图像,x xx是行号,y yy是列号,( x , y ) (x,y)(x,y)是像素坐标
- M MM:图像的高度(行数)
- N NN:图像的宽度(列数)
- F ( u , v ) F(u,v)F(u,v):频域谱,u uu是水平频率,v vv是垂直频率
- e − j 2 π ( u x M + v y N ) e^{-j2\pi(\frac{ux}{M}+\frac{vy}{N})}e−j2π(Mux+Nvy):复指数函数,负责把图像从时域(空间域)转换到频域
- j jj:虚数单位,j 2 = − 1 j^2=-1j2=−1
逆二维DFT公式(把频域转回去):
f ( x , y ) = 1 M N ∑ u = 0 M − 1 ∑ v = 0 N − 1 F ( u , v ) ⋅ e j 2 π ( u x M + v y N ) f(x, y) = \frac{1}{MN} \sum_{u=0}^{M-1} \sum_{v=0}^{N-1} F(u, v) \cdot e^{j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)}f(x,y)=MN1u=0∑M−1v=0∑N−1F(u,v)⋅ej2π(Mux+Nvy)
二、二维DFT的频域谱怎么看?
2.1 频域谱的分布规律
直接做二维DFT得到的频域谱,低频部分在四个角落,高频在中间,看起来很别扭。所以通常会用fftshift把频谱中心化,让低频在中心,高频在四周。
中心化后:
- 中心:低频成分,对应图像的整体亮度、大的轮廓
- 四周:高频成分,对应图像的边缘、纹理、噪声
- 对角线:斜向的纹理信息
通俗解释:频域谱的亮度越高,说明这个频率/方向的成分越强。比如一张有很多水平线条的图,频域谱上垂直方向的点会很亮。
2.2 常见图像的频域谱示例
表1 不同图像的频域谱特征
| 图像类型 | 频域谱特征 | 通俗解释 |
|---|---|---|
| 纯色图像 | 只有中心一个亮点 | 没有任何纹理,只有低频亮度 |
| 水平条纹 | 垂直方向有一排亮点 | 水平纹理,对应垂直方向的频率 |
| 斜向条纹 | 对角线方向有亮点 | 斜向纹理,对应对角线方向的频率 |
| 带噪声图像 | 频域谱四周均匀发亮 | 噪声都是高频,分布在所有方向 |
三、核心代码:二维DFT实战
下面是Python实现二维DFT的完整代码,包含频域谱生成、中心化、低通/高通滤波。
importcv2importnumpyasnpimportmatplotlib.pyplotasplt# ===================== 解决中文显示 =====================plt.rcParams["font.family"]=["SimHei","WenQuanYi Micro Hei","Heiti TC"]plt.rcParams["axes.unicode_minus"]=False# 负号正常显示# ========================================================# 1. 读取彩色图像 + 预处理defload_image(path):img=cv2.imread(path)# 读取彩色图returnimg# shape (H, W, 3)# 2. 对 单通道 做二维DFT + 中心化defdft_channel(channel):img_float=np.float32(channel)dft=cv2.dft(img_float,flags=cv2.DFT_COMPLEX_OUTPUT)dft_shift=np.fft.fftshift(dft)magnitude=20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1])+1e-8)returndft_shift,magnitude# 3. 彩色图像 DFT(三通道分别处理)defdft_image(img):b,g,r=cv2.split(img)dft_b,mag_b=dft_channel(b)dft_g,mag_g=dft_channel(g)dft_r,mag_r=dft_channel(r)return(dft_b,dft_g,dft_r),(mag_b,mag_g,mag_r)# 4. 单通道低通滤波deflow_pass_channel(dft_shift,radius=30):rows,cols=dft_shift.shape[:2]crow,ccol=rows//2,cols//2mask=np.zeros((rows,cols,2),np.float32)cv2.circle(mask,(ccol,crow),radius,(1,1),-1)filtered_dft=dft_shift*mask filtered_dft_shift=np.fft.ifftshift(filtered_dft)img_back=cv2.idft(filtered_dft_shift)img_back=cv2.magnitude(img_back[:,:,0],img_back[:,:,1])cv2.normalize(img_back,img_back,0,255,cv2.NORM_MINMAX)returnnp.uint8(img_back)# 5. 彩色低通滤波deflow_pass_filter(dft_tuple,radius=30):dft_b,dft_g,dft_r=dft_tuple b=low_pass_channel(dft_b,radius)g=low_pass_channel(dft_g,radius)r=low_pass_channel(dft_r,radius)returncv2.merge((b,g,r))# 6. 单通道高通滤波defhigh_pass_channel(dft_shift,radius=30):rows,cols=dft_shift.shape[:2]crow,ccol=rows//2,cols//2mask=np.ones((rows,cols,2),np.float32)cv2.circle(mask,(ccol,crow),radius,(0,0),-1)filtered_dft=dft_shift*mask filtered_dft_shift=np.fft.ifftshift(filtered_dft)img_back=cv2.idft(filtered_dft_shift)img_back=cv2.magnitude(img_back[:,:,0],img_back[:,:,1])cv2.normalize(img_back,img_back,0,255,cv2.NORM_MINMAX)returnnp.uint8(img_back)# 7. 彩色高通滤波defhigh_pass_filter(dft_tuple,radius=30):dft_b,dft_g,dft_r=dft_tuple b=high_pass_channel(dft_b,radius)g=high_pass_channel(dft_g,radius)r=high_pass_channel(dft_r,radius)returncv2.merge((b,g,r))# 主函数defmain():img_path="D:/datasets/test/cat.png"# 你的彩色图路径img=load_image(img_path)dft_tuple,mag_tuple=dft_image(img)low_pass_img=low_pass_filter(dft_tuple,radius=50)high_pass_img=high_pass_filter(dft_tuple,radius=50)# 合并频域幅度谱(取平均显示)mag_show=(mag_tuple[0]+mag_tuple[1]+mag_tuple[2])/3# 画图(中文正常显示)plt.figure(figsize=(12,8))plt.subplot(221),plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)),plt.title('原图')plt.subplot(222),plt.imshow(mag_show,cmap='gray'),plt.title('中心化频域谱')plt.subplot(223),plt.imshow(cv2.cvtColor(low_pass_img,cv2.COLOR_BGR2RGB)),plt.title('低通滤波(去噪/模糊)')plt.subplot(224),plt.imshow(cv2.cvtColor(high_pass_img,cv2.COLOR_BGR2RGB)),plt.title('高通滤波(边缘提取)')plt.show()if__name__=="__main__":main()四、实验分析:滤波效果对比
4.1 低通滤波效果
- 原图:清晰但有噪声/细节
- 低通滤波后:图像变模糊,噪声消失,保留了整体轮廓
- 原理:去掉了频域四周的高频噪声,只保留中心低频
通俗解释:低通滤波就是“去噪+模糊”,适合去除图像中的颗粒噪声。
4.2 高通滤波效果
- 原图:包含丰富纹理和边缘
- 高通滤波后:只保留了边缘和纹理,整体亮度消失
- 原理:去掉了频域中心的低频亮度,只保留四周高频
通俗解释:高通滤波就是“边缘提取+锐化”,适合检测图像的轮廓和细节。
表2 不同半径的低通滤波效果对比
| 滤波半径 | 效果 | 适用场景 |
|---|---|---|
| 20 | 轻微模糊,保留细节 | 轻度去噪 |
| 50 | 中等模糊,噪声去除明显 | 常规去噪 |
| 100 | 严重模糊,只剩大轮廓 | 图像简化 |
五、常见问题与注意事项
5.1 为什么频域谱要中心化?
原始DFT的低频在四个角落,不便于观察和滤波。中心化后低频在中心,高频在四周,滤波时直接在中心画圆即可,操作更直观。
5.2 为什么要对频域谱取对数?
频域谱的动态范围很大,直接显示会导致中心过亮、四周过暗,看不清细节。取对数可以压缩动态范围,让高低频的差异更明显。
5.3 滤波时掩码的半径怎么选?
半径越小,保留的低频越少,低通滤波效果越强(图像越模糊);半径越大,保留的高频越少,高通滤波效果越强(边缘越明显)。一般可以通过调试找到适合的半径。
六、二维DFT的应用场景
- 图像去噪:用低通滤波去除高频噪声
- 边缘检测:用高通滤波提取图像边缘
- 图像压缩:保留低频信息,丢弃高频冗余信息
- 图像增强:通过频域处理提升图像对比度
- 纹理分析:通过频域谱判断图像的纹理方向和频率
七、总结
二维DFT把图像从空间域转换到频域,让我们能更直观地分析和处理图像的频率成分。低通滤波去噪、高通滤波提取边缘,都是二维DFT最经典的应用。
这篇博客从原理、公式、代码到实验,完整覆盖了二维DFT的核心内容,大家可以用上面的代码跑一遍,亲自感受一下频域处理的神奇效果。