002 OpenCV dft 傅里叶变换

目录

一、傅里叶变换

[1.1 傅里叶变换概念](#1.1 傅里叶变换概念)

[1.2 opencv中傅里叶变换](#1.2 opencv中傅里叶变换)

二、实验代码

一、环境

本文使用环境为:

  • Windows10
  • Python 3.9.17
  • opencv-python 4.8.0.74

二、傅里叶变换

2.1 傅里叶变换概念

傅里叶变换(Fourier Transform)是一种在数学、物理和工程领域广泛应用的算法,用于分析信号或数据的频率成分。它是由法国数学家约瑟夫·傅里叶(Joseph Fourier)于19世纪初提出的,因此得名。傅里叶变换的基本思想是将一个时域信号转换为频域信号,或者将一个频域信号转换回时域信号。这种转换可以帮助我们更好地理解和分析信号的特性,例如幅度、频率和相位等。

傅里叶变换可以分为连续傅里叶变换(Continuous Fourier Transform,CFT)和离散傅里叶变换(Discrete Fourier Transform,DFT)。连续傅里叶变换用于处理连续时间信号,而离散傅里叶变换用于处理离散时间信号。在实际应用中,由于计算机处理的是离散数据,因此离散傅里叶变换更为常用。

离散傅里叶变换(DFT)的基本步骤如下:

  1. 对输入信号进行采样,得到离散时间信号。采样频率通常为原始信号频率的整数倍,以满足奈奎斯特采样定理。

  2. 对离散时间信号进行窗函数处理。窗函数的作用是减小信号截断引起的频谱泄漏,同时减小频谱旁瓣的影响。常用的窗函数有矩形窗、汉宁窗和海宁窗等。

  3. 计算离散时间信号的离散傅里叶变换。这可以通过快速傅里叶变换(Fast Fourier Transform,FFT)算法来实现,以提高计算效率。快速傅里叶变换是一种基于蝶形运算的高效算法,其计算复杂度为O(nlogn),其中n为信号长度。

  4. 对离散傅里叶变换的结果进行分析。通过观察频谱图,可以了解信号的频率分布、幅值和相位等信息。此外,还可以利用傅里叶变换的性质进行信号处理,例如滤波、降噪和压缩等。

傅里叶变换具有以下重要性质:

  1. 线性性质:傅里叶变换满足线性叠加原理,即两个信号的傅里叶变换之和等于这两个信号分别进行傅里叶变换后再相加的结果。

  2. 共轭对称性:对于实数信号,其傅里叶变换的共轭复数表示了信号的频谱。这意味着实数信号的频谱是以原点为中心的对称分布。

  3. 时移性质:对于任意实数τ,信号x(t)与其自身延时τ的信号x(t-τ)的傅里叶变换之比等于e^(j2πτ),其中j为虚数单位。这表明时移操作可以通过乘以复指数因子来实现。

  4. 频移性质:对于任意实数ω,信号x(t)与其频率为ω的信号cos(2πωt)的乘积的傅里叶变换等于X(f)与δ(f-ω)的卷积,其中δ(f)表示狄拉克δ函数。这表明频率调制可以通过乘以复指数因子和滤波操作来实现。

  5. 能量守恒:离散傅里叶变换的能量守恒性质表明,信号的总能量在时域和频域之间是平衡的。这意味着在频域中去除某些频率分量后,信号的总能量会相应地转移到其他频率分量上。

总之,傅里叶变换是一种强大的数学工具,广泛应用于通信、图像处理、音频处理、生物信息学等领域。通过傅里叶变换,我们可以更好地理解和分析信号的特性,从而实现信号的滤波、降噪、压缩等功能。

2.2 opencv中傅里叶变换

在数字图像处理中,空间域滤波和频域滤波都是常见的方法,但它们之间存在一些关键的区别。

  1. 空间域滤波:这种方法直接对图像进行操作,通常使用各种模板与图像进行卷积运算来实现图像的处理。由于其直接在图像空间上操作,这种方法的实现相对简单和直观。

  2. 频域滤波:频域滤波首先将图像从空间域转换到频域,然后对频率域中的图像数据进行处理,最后再将其转换回空间域。这种处理方法的优点在于,某些图像处理任务在频域中比在空间域中更为简单。例如,根据卷积定理,可以通过傅立叶变换将空域卷积滤波变换为频域滤波。此外,频域滤波允许设计者使用复杂的滤波器设计,这可能在空间域中难以实现。然而,需要注意的是,如果选用的频域滤波器具有陡峭的变化,可能会导致输出图像产生"振铃"现象,这是由于灰度剧烈变化处产生的。

在OpenCV库中,傅里叶变换和逆傅里叶变换的实现主要依赖于**cv2.dft()cv2.idft()**两个函数。在进行傅里叶变换时,你需要将原始图像转换为np.float32格式。

具体来说,cv2.dft() 函数的定义是:cv2.dft(原始图像,转换标识)。其中,原始图像必须是np.float32格式,转换标识用于说明是傅里叶变换还是傅里叶逆变换。此函数返回与前一个相同的结果,但是有两个通道。第一个通道是结果的实部,第二个通道是结果的虚部。

另一方面,**cv2.idft()**函数被用来执行逆傅里叶变换。例如,如果你有一个通过傅里叶变换得到的复数矩阵,你可以使用这个函数来恢复原始图像。

需要注意的是,OpenCV提供的这两个函数的效率较高(比OpenCV自带的函数快3倍)。这是因为它们实现了一种称为快速傅立叶变换(FFT)的快速算法。

三、实验代码

cpp 复制代码
from __future__ import print_function
import sys

import cv2 as cv
import numpy as np


def print_help():
    print('''
    代码演示离散傅里叶变换,同时也显示幅度谱''')

def main(argv):
    print_help()
    I = cv.imread("d:/Data/1.jpg", cv.IMREAD_GRAYSCALE)
    if I is None:
        print('Error opening image')
        return -1
    ## [expand]
    rows, cols = I.shape
    m = cv.getOptimalDFTSize( rows )
    n = cv.getOptimalDFTSize( cols )
    # 把图像边界拓展下
    padded = cv.copyMakeBorder(I, 0, m - rows, 0, n - cols, cv.BORDER_CONSTANT, value=[0, 0, 0])
    ## [complex_and_real]
    planes = [np.float32(padded), np.zeros(padded.shape, np.float32)]
    complexI = cv.merge(planes)         # Add to the expanded another plane with zeros
    ## [complex_and_real]
    ## [dft]
    cv.dft(complexI, complexI)         # this way the result may fit in the source matrix
    ## [dft]
    # compute the magnitude and switch to logarithmic scale
    # = > log(1 + sqrt(Re(DFT(I)) ^ 2 + Im(DFT(I)) ^ 2))
    ## [magnitude]
    cv.split(complexI, planes)                   # planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
    cv.magnitude(planes[0], planes[1], planes[0])# planes[0] = magnitude
    magI = planes[0]
    ## [magnitude]
    ## [log]
    matOfOnes = np.ones(magI.shape, dtype=magI.dtype)
    cv.add(matOfOnes, magI, magI) #  switch to logarithmic scale
    # 取log是为了拉伸值
    cv.log(magI, magI)
    ## [log]
    ## [crop_rearrange]
    magI_rows, magI_cols = magI.shape
    # crop the spectrum, if it has an odd number of rows or columns
    magI = magI[0:(magI_rows & -2), 0:(magI_cols & -2)]
    cx = int(magI_rows/2)
    cy = int(magI_cols/2)

    q0 = magI[0:cx, 0:cy]         # Top-Left - Create a ROI per quadrant
    q1 = magI[cx:cx+cx, 0:cy]     # Top-Right
    q2 = magI[0:cx, cy:cy+cy]     # Bottom-Left
    q3 = magI[cx:cx+cx, cy:cy+cy] # Bottom-Right

    tmp = np.copy(q0)               # 交换象限(左上和右下交换)
    magI[0:cx, 0:cy] = q3
    magI[cx:cx + cx, cy:cy + cy] = tmp

    tmp = np.copy(q1)               # 交换象限(右上和左下交换)
    magI[cx:cx + cx, 0:cy] = q2
    magI[0:cx, cy:cy + cy] = tmp
    # 归一化到 [0, 1]范围内
    cv.normalize(magI, magI, 0, 1, cv.NORM_MINMAX)
    # 原图得灰度图
    cv.imshow("Input Image"       , I   )
    # 幅度谱,也叫频谱
    cv.imshow("spectrum magnitude", magI)
    cv.waitKey()

if __name__ == "__main__":
    main(sys.argv[1:])

原图:

灰度图:

幅度谱如下:中间是高频区域、边界是低频区域、幅度谱是关于图像中心对称的。

相关推荐
安静读书3 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小陈phd3 小时前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Yang.997 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王7 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_7 小时前
C++自己写类 和 运算符重载函数
c++
如若1237 小时前
主要用于图像的颜色提取、替换以及区域修改
人工智能·opencv·计算机视觉
六月的翅膀8 小时前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++