Python OpenCV实现图像傅里叶变换

沈知远
沈知远
发布时间:2026-10-12 | 3人浏览过
原创

本文详解利用Python OpenCV进行图像二维离散傅里叶变换(DFT)的方法。涵盖cv.dft函数参数、频谱计算、归一化处理及性能优化策略,通过示例代码展示如何高效实现图像频域分析。

二维离散傅里叶变换(DFT)

在二维图像处理场景中,通常使用x和y表示离散的空间域坐标变量,而用u和v表示离散的频率域变量。二维离散傅里叶变换(DFT)及其反变换(IDFT)的数学定义如下:

二维离散傅里叶变换还可以采用极坐标形式进行表示:

傅里叶频谱(Fourier spectrum)的计算公式为:

傅里叶相位谱(Fourier phase spectrum)的计算公式为:

傅里叶功率谱(Fourier power spectrum)的计算公式为:

空间采样间隔与频率间隔存在对应关系,频率域中离散变量间的间隔由公式Δu=1/MΔT和Δv=1/NΔZ给出。这意味着频域样本间的间隔与空间样本间隔及样本数量的乘积成反比。

空间域滤波器与频率域滤波器之间存在对应关系,二维卷积定理是连接空间域滤波与频率域滤波等价关系的理论基础:

上述公式表明,F和H分别是f和h的傅里叶变换;空间域中f和h的卷积,其傅里叶变换等于它们各自傅里叶变换的乘积。

OpenCV 实现图像傅里叶变换(cv.dft)

利用OpenCV库中的cv.dft()函数可以实现图像的傅里叶变换,而cv.idft()函数则用于执行傅里叶逆变换。

函数说明:

cv.dft(src[, dst[, flags[, nonzeroRows]]]) → dst
cv.idft(src[, dst[, flags[, nonzeroRows]]]) → dst

参数说明:

src:输入图像,需为单通道灰度图像,且数据类型必须为np.float32。

dst:输出图像,其尺寸与src保持一致,具体数据类型由flag参数决定。

flag:转换标识符,用于指定变换类型。

cv.DFT_INVERSE:使用一维或二维逆变换替代默认的正向变换。

cv.DFT_SCALE:缩放比例标识,根据元素数量自动计算缩放结果,通常与DFT_INVERSE配合使用。

cv.DFT_ROWS:对输入矩阵的每一行执行正向或反向傅里叶变换,常用于三维或更高维度的复杂变换操作。

cv.DFT_COMPLEX_OUTPUT:对一维或二维实数数组进行正向变换,这是默认方法。结果是一个由两个通道表示的复数阵列,其中第一通道存储实数部分,第二通道存储虚数部分。

cv.DFT_REAL_OUTPUT:对一维或二维复数数组进行逆变换,结果通常是一个与原尺寸相同的复数矩阵。

注意事项:

1. 输入图像src必须为np.float32格式。如果原始图像是np.uint8格式,必须先转换为np.float32格式。

2. 在使用默认方法cv.DFT_COMPLEX_OUTPUT时,输入src为np.float32格式的单通道二维数组,输出dst则是包含两个通道的二维数组。其中,dft[:,:,0]表示实数部分,dft[:,:,1]表示虚数部分。

3. 傅里叶变换的结果不能直接用于图像显示。可以使用cv.magnitude()函数将变换结果转换到[0,255]的灰度范围以便显示。

4. idft(src, dst, flags)的功能等价于dft(src, dst, flags=DFT_INVERSE)。

5. 使用OpenCV实现傅里叶变换的计算速度通常比Numpy更快。

当转换标识符设置为cv.DFT_COMPLEX_OUTPUT时,cv.dft()函数的输出是一个包含两个通道的二维数组。此时,可以使用cv.magnitude()函数来计算二维矢量的幅值。

函数说明:

cv.magnitude(x, y[, magnitude]) → dst

参数说明:

x:一维或多维数组,表示复数的实部,数据类型为浮点型。

y:一维或多维数组,表示复数的虚部,数据类型为浮点型,且数组大小必须与x相同。

dst:输出数组,其大小和数据类型与x保持一致。运算公式为:

傅里叶变换及相关操作的数值范围可能不适合直接用于图像显示,因此需要进行归一化处理。OpenCV中的cv.normalize()函数可以实现图像的归一化操作。

函数说明:

cv.normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]) → dst

参数说明:

src:输入图像。

dst:输出结果,其尺寸和类型与输入图像相同。

alpha:归一化后的最小值,为可选参数,默认值为0。

beta:归一化后的最大值,为可选参数,默认值为1。

norm_type:归一化类型。

  • NORM_INF:Linf范数(绝对值的最大值)。
  • NORM_L1:L1范数(绝对值的和)。
  • NORM_L2:L2范数(欧几里德距离),这是默认类型。
  • NORM_MINMAX:线性缩放,这是常用类型。

dtype:可选参数,默认值为-1,表示输出矩阵的类型与输入图像类型相同。

mask:掩模遮罩,为可选参数,默认情况下无遮罩。

理论上,傅里叶变换需要O(MN)²次运算,耗时较长;而快速傅里叶变换(FFT)仅需O(MN㏒(MN))次运算即可完成。

OpenCV中的傅里叶变换函数cv.dft()在处理行数和列数均可分解为2^p*3^q*5^r形式的矩阵时,计算性能最佳。为了提高运算效率,可以对原矩阵的右侧和下方进行零填充,以满足该分解条件。OpenCV提供的cv.getOptimalDFTSize()函数可用于获取图像的最优DFT尺寸扩充值,该函数适用于cv.dft()和np.fft.fft2()。

函数说明:

cv.getOptimalDFTSize(versize) → retval

参数说明:

versize:数组大小。

retval:DFT扩充后的最优数组大小。

示例代码

    # 8.11:OpenCV 实现二维图像的离散傅里叶变换
    imgGray = cv2.imread("../images/Fig0424a.tif", flags=0)  # flags=0 读取为灰度图像

    # cv2.dft 实现图像的傅里叶变换
    imgFloat32 = np.float32(imgGray)  # 将图像转换成 float32
    dft = cv2.dft(imgFloat32, flags=cv2.DFT_COMPLEX_OUTPUT)  # 傅里叶变换
    dftShift = np.fft.fftshift(dft)  # 将低频分量移动到频域图像的中心

    # 幅度谱
    # ampSpe = np.sqrt(np.power(dft[:,:,0], 2) + np.power(dftShift[:,:,1], 2))
    dftAmp = cv2.magnitude(dft[:,:,0], dft[:,:,1])  # 幅度谱,未中心化
    dftShiftAmp = cv2.magnitude(dftShift[:,:,0], dftShift[:,:,1])  # 幅度谱,中心化
    dftAmpLog = np.log(1 + dftShiftAmp)  # 幅度谱对数变换,以便于显示
    # 相位谱
    phase = np.arctan2(dftShift[:,:,1], dftShift[:,:,0])  # 计算相位角(弧度制)
    dftPhi = phase / np.pi*180  # 将相位角转换为 [-180, 180]

    print("dftMag max={}, min={}".format(dftAmp.max(), dftAmp.min()))
    print("dftPhi max={}, min={}".format(dftPhi.max(), dftPhi.min()))
    print("dftAmpLog max={}, min={}".format(dftAmpLog.max(), dftAmpLog.min()))

    # cv2.idft 实现图像的逆傅里叶变换
    invShift = np.fft.ifftshift(dftShift)  # 将低频逆转换回图像四角
    imgIdft = cv2.idft(invShift)  # 逆傅里叶变换
    imgRebuild = cv2.magnitude(imgIdft[:,:,0], imgIdft[:,:,1])  # 重建图像

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.title("Original image"), plt.axis('off')
    plt.imshow(imgGray, cmap='gray')
    plt.subplot(232), plt.title("DFT Phase"), plt.axis('off')
    plt.imshow(dftPhi, cmap='gray')
    plt.subplot(233), plt.title("Rebuild image with IDFT"), plt.axis('off')
    plt.imshow(imgRebuild, cmap='gray')
    plt.subplot(234), plt.title("DFT amplitude spectrum"), plt.axis('off')
    plt.imshow(dftAmp, cmap='gray')
    plt.subplot(235), plt.title("DFT-shift amplitude"), plt.axis('off')
    plt.imshow(dftShiftAmp, cmap='gray')
    plt.subplot(236), plt.title("Log-trans of DFT amp"), plt.axis('off')
    plt.imshow(dftAmpLog, cmap='gray')
    plt.tight_layout()
    plt.show()

到此这篇关于Python OpenCV实现图像傅里叶变换的文章就介绍到这了,更多相关Python OpenCV傅里叶变换内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表