feat: 添加 FFT 和 IFFT功能

- 实现了一维和二维 FFT 和 IFFT 函数- 添加了图像填充函数,以支持非 2 的整数次幂大小的图像
- 编写了主程序,演示了 FFT 和 IFFT 的使用方法
- 使用 Matplotlib 可视化了原始图像、频谱图和恢复后的图像
This commit is contained in:
fly6516 2025-04-25 15:19:24 +08:00
commit 6ab26f2b0a
3 changed files with 87 additions and 0 deletions

BIN
FFT-IFFT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

87
FFT.py Normal file
View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
import numpy as np # 导入NumPy库用于数值计算
import math # 导入math库用于数学运算
import cv2 # 导入OpenCV库用于图像处理
import matplotlib.pyplot as plt # 导入matplotlib库用于绘图
# 一维FFT实现递归 Cooley-Tukey
def fft_1d(x):
N = len(x) # 获取输入序列的长度
if N <= 1: # 如果序列长度小于等于1直接返回序列
return x
even = fft_1d(x[::2]) # 递归计算偶数索引位置的FFT
odd = fft_1d(x[1::2]) # 递归计算奇数索引位置的FFT
T = [np.exp(-2j * np.pi * k / N) * odd[k] for k in range(N // 2)] # 计算旋转因子
return [even[k] + T[k] for k in range(N // 2)] + \
[even[k] - T[k] for k in range(N // 2)] # 合并结果
# 一维IFFT实现
def ifft_1d(x):
N = len(x) # 获取输入序列的长度
x_conj = [np.conj(xi) for xi in x] # 对输入序列取共轭
y = fft_1d(x_conj) # 对共轭序列进行FFT
return [np.conj(yi) / N for yi in y] # 对结果取共轭并除以N得到IFFT结果
# 二维FFT
def fft_2d(image):
image = image.astype(float) # 将图像转换为浮点型
rows, cols = image.shape # 获取图像的行数和列数
# 对每行进行FFT
fft_rows = [fft_1d(list(image[i, :])) for i in range(rows)]
# 对每列进行FFT
fft_cols = [fft_1d([fft_rows[i][j] for i in range(rows)]) for j in range(cols)]
return np.array(fft_cols).T # 返回转置后的结果
# 二维IFFT
def ifft_2d(freq_domain):
rows, cols = freq_domain.shape # 获取频域图像的行数和列数
# 对每列进行IFFT
ifft_cols = [ifft_1d([freq_domain[i][j] for i in range(rows)]) for j in range(cols)]
# 对每行进行IFFT
ifft_rows = [ifft_1d([ifft_cols[j][i] for j in range(cols)]) for i in range(rows)]
return np.array(ifft_rows) # 返回IFFT结果
# 填充图像为2的整数次幂大小
def pad_image(image):
h, w = image.shape # 获取图像的高度和宽度
h2 = 1 << (h - 1).bit_length() # 计算最接近且大于等于h的2的整数次幂
w2 = 1 << (w - 1).bit_length() # 计算最接近且大于等于w的2的整数次幂
padded = np.zeros((h2, w2)) # 创建填充后的零矩阵
padded[:h, :w] = image # 将原图像放入填充矩阵的左上角
return padded # 返回填充后的图像
# 主程序
def main():
# 读取图像
image = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE) # 以灰度模式读取图像
if image is None: # 如果图像读取失败,输出错误信息并返回
print("图像读取失败,请确认 image.jpg 文件存在于当前目录。")
return
# 填充图像
padded_image = pad_image(image) # 对图像进行填充
# 执行FFT和IFFT
freq = fft_2d(padded_image) # 对填充后的图像进行二维FFT
restored = ifft_2d(freq).real # 对频域图像进行二维IFFT并取实部
# 可视化结果
plt.figure(figsize=(12, 4)) # 创建绘图窗口
plt.subplot(1, 3, 1) # 创建第一个子图
plt.title("Original") # 设置子图标题
plt.imshow(image, cmap="gray") # 显示原始图像
plt.subplot(1, 3, 2) # 创建第二个子图
plt.title("FFT Spectrum") # 设置子图标题
plt.imshow(np.log(np.abs(freq) + 1), cmap="gray") # 显示FFT频谱
plt.subplot(1, 3, 3) # 创建第三个子图
plt.title("Restored") # 设置子图标题
plt.imshow(restored, cmap="gray") # 显示恢复后的图像
plt.tight_layout() # 调整子图布局
plt.show() # 显示绘图窗口
if __name__ == "__main__":
main() # 运行主程序

BIN
image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB