OpenCV 笔记(32):图像处理的傅里叶变换——初探

在图像处理中,图像可以用不同域来表示和分析。

下面是几种最常用的域:

  • 空间域是指由图像像素组成的空间。
  • 时域是指图像随时间变化的域。对于动态图像,例如视频,时域表示图像帧随时间的变化。时域处理是指对图像序列进行操作,例如运动分析、视频压缩等。
  • 频域是将图像从空间域变换到频率域得到的表示。在频域中,图像被表示为一个二维复数矩阵,其中每个元素代表图像中某一特定频率分量的幅度和相位。

图像的空间域、时域和频域是三种不同的表示图像信息的视角,这三者之间可以相互转换。

1. 频域

图像的频域 是通过傅里叶变换将图像从空间域转换到频率域而得到的。在频域中,图像的每个像素点都被表示为一个复数,其幅度表示该频率分量的能量,相位表示该频率分量的初始相位。

在空间域中,图像由像素值矩阵表示,每个像素值代表图像在该位置的颜色或亮度。在频率域中,图像由频谱图表示,频谱图上的每个点代表图像中特定频率的成分。图像的频率域与空间域具有互补关系,图像的任何信息都可以在空间域和频率域中找到。

频率域滤波的基本原理是将图像变换到频率域,然后利用滤波器对图像的频谱分量进行处理,最后将滤波后的频谱分量变换回空间域得到滤波后的图像。

在频率域中,图像的每个像素点都对应着一个频率分量。低频分量对应于图像中的平滑区域和整体形状,而高频分量对应于图像中的细节和边缘。

空间域和频率域的滤波器可以分为四类: 低通、高通、带阻、带通滤波器。

  • 低通滤波器 允许低频分量通过,抑制高频分量。低频分量通常对应于图像中的平滑区域和整体亮度变化,可以用于平滑图像,去除噪声和模糊细节。
  • 高通滤波器 允许高频分量通过,抑制低频分量。高频分量对应于图像中的边缘和细节,可以用于锐化图像,增强图像的边缘和细节。
  • 带通滤波器 只允许特定频率范围内的信号通过,抑制其他频率范围内的信号。可以用于提取图像中的特定特征,例如纹理或边缘。
  • 带阻滤波器 抑制特定频率范围内的信号,允许其他频率范围内的信号通过。可以用于去除图像中的特定噪声,例如摩尔纹。

2. 图像锐化的原理

在该系列的第三十一篇文章中介绍过图像锐化。锐化的目的是为了突出图像的边缘信息 ,加强图像的轮廓特征,以便于人眼的观察和机器的识别。

在空间域,可以用空间微分来实现锐化。微分算子的响应强度与图像在该点的突变程度有关,图像微分增强了边缘和其他突变(如噪声)而消弱了灰度变化缓慢的区域。

在频率域,由于图像中的边缘、线条等细节部分与图像频谱中的高频分量相对应,在频率域中使用高通滤波器能够使图像的边缘或线条变得清晰,从而使图像得到锐化。高通滤波器衰减傅立叶变换中的低频分量,让高频分量顺利通过,使低频分量受到抑制,就可以增强高频的成分。使图像的边沿或线条变得清晰,从而实现图像的锐化。

3. 傅里叶变换

空间域、时域和频域之间可以通过傅立叶变换(Fourier Transform)进行转换。傅立叶变换是一种数学工具,可以将信号从一个域变换到另一个域。

  • 空间域到频域的傅立叶变换 :将图像从空间域 (x,y) 变换到频域 (u,v) ,可以得到图像的频谱。图像的频谱可以反映图像的频率成分,例如图像中边缘、纹理等信息的分布。

  • 频域到空间域的傅立叶逆变换:将图像从频域变换回空间域,可以得到原始图像。

先上基础的公式作为直观地感受,后续文章会做介绍。

一维连续傅里叶变换:

F ( μ ) = ∫ − ∞ ∞ f ( t ) e − j 2 π μ t   d t F(\mu)=\int_{-\infty}^{\infty}f(t)e^{-j2\pi\mu t}\,dt F(μ)=∫−∞∞f(t)e−j2πμtdt

一维连续傅里叶逆变换:

f ( t ) = ∫ − ∞ ∞ F ( μ ) e j 2 π μ t   d μ f(t)= \int_{-\infty}^{\infty}F(\mu)e^{j2\pi\mu t}\,d\mu f(t)=∫−∞∞F(μ)ej2πμtdμ

一维离散傅里叶变换:

F m = ∑ n = 0 M − 1 f n e − j 2 π m n / M m = 0 , 1 , 2 , . . . , M − 1 F_m = \sum_{n=0}^{M-1}f_n e^{-j2\pi mn/M} \quad m = 0,1,2,...,M-1 Fm=∑n=0M−1fne−j2πmn/Mm=0,1,2,...,M−1

一维离散傅里叶逆变换:

f n = 1 M ∑ m = 0 M − 1 F m e j 2 π m n / M n = 0 , 1 , 2 , . . . , M − 1 f_n = \frac{1}{M}\sum_{m=0}^{M-1}F_m e^{j2\pi mn/M} \quad n = 0,1,2,...,M-1 fn=M1∑m=0M−1Fmej2πmn/Mn=0,1,2,...,M−1

二维连续傅里叶变换:

F ( μ , ν ) = ∫ − ∞ ∞ ∫ − ∞ ∞ f ( t , z ) e − j 2 π ( μ t + ν z )   d t d z F(\mu,\nu)=\int_{-\infty}^{\infty}\int_{-\infty}^{\infty}f(t,z)e^{-j2\pi(\mu t+\nu z)}\,dtdz F(μ,ν)=∫−∞∞∫−∞∞f(t,z)e−j2π(μt+νz)dtdz

二维连续傅里叶逆变换:

f ( t , z ) = ∫ − ∞ ∞ ∫ − ∞ ∞ F ( μ , ν ) e j 2 π ( μ t + ν z )   d μ d ν f(t,z)=\int_{-\infty}^{\infty}\int_{-\infty}^{\infty}F(\mu,\nu)e^{j2\pi(\mu t+\nu z)}\,d\mu d\nu f(t,z)=∫−∞∞∫−∞∞F(μ,ν)ej2π(μt+νz)dμdν

二维离散傅里叶变换:

F ( μ , ν ) = ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) e − j 2 π ( μ x / M + ν y / N ) F(\mu,\nu) = \sum_{x=0}^{M-1}\sum_{y=0}^{N-1}f(x,y) e^{-j2\pi(\mu x/M + \nu y/N)} F(μ,ν)=∑x=0M−1∑y=0N−1f(x,y)e−j2π(μx/M+νy/N)

二维离散傅里叶逆变换:

f ( x , y ) = 1 M N ∑ μ = 0 M − 1 ∑ ν = 0 N − 1 F ( μ , ν ) e j 2 π ( μ x / M + ν y / N ) f(x,y) = \frac{1}{MN}\sum_{\mu=0}^{M-1} \sum_{\nu=0}^{N-1}F(\mu,\nu)e^{j2\pi(\mu x/M + \nu y/N)} f(x,y)=MN1∑μ=0M−1∑ν=0N−1F(μ,ν)ej2π(μx/M+νy/N)

图像傅里叶变换的计算通常使用离散傅里叶变换(Discrete Fourier Transform,DFT)来实现。DFT 是傅里叶变换的离散化版本,它可以将图像离散化成有限大小的矩阵,然后使用矩阵乘法来计算图像的傅里叶变换。

对于二维离散傅里叶变换,f(x,y) 表示大小为 M*N 的数字图像。 F ( μ , ν ) F(\mu,\nu) F(μ,ν) 表示 f(x,y) 的傅里叶变换。

在式中 f(x,y) 所在坐标系被称为空间域, 由 x = 0,1,2,···,M-1 和 y = 0,1,2,···,N-1 所定义的 M x N 矩阵常被称为空间域矩阵。 F ( μ , ν ) F(\mu,\nu) F(μ,ν) 所在坐标系被称为频域,由 u = 0,1,2,···,M-1 和 v = 0,1,2,···,N-1 定义的 M x N 矩阵常称为频域矩阵。

下面的例子,展示了灰度图像经过傅里叶变换后生成频谱图的过程。

为了便于频域和频谱分析,在傅里叶变换后进行频谱中心化,即对调频谱的四个象限。频谱中心化后,中间最亮的点是低频率,属于直流分量,越往外频率越高。

cpp 复制代码
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace std;

void myDFT(Mat src, Mat& dst)
{
    // 扩充边界
    int m = getOptimalDFTSize(src.rows);
    int n = getOptimalDFTSize(src.cols);
    copyMakeBorder(src, src, 0, m - src.rows, 0, n - src.cols, BORDER_CONSTANT, Scalar::all(0));

    // 创建一个双通道矩阵 planes,用来储存复数的实部与虚部
    Mat planes[] = {Mat_<float>(src), Mat::zeros(src.size(), CV_32F) };

    Mat complexI;
    // 增加一个通道,将两个 planes 合并,为了存储复数
    merge(planes, 2, complexI);

    // 进行离散傅立叶变换
    dft(complexI, complexI);

    split(complexI, planes); // 将双通道分为两个单通道,一个表示实部,一个表示虚部
    magnitude(planes[0], planes[1], dst); //计算复数的幅值,保存在频谱图 dst

    // M = log(1 + M)
    dst += Scalar(1);   //  取对数前将所有的像素都加1,防止 log0
    log(dst, dst);      // 取对数

    normalize(dst, dst, 0, 1, NORM_MINMAX); //归一化

    imshow("dft", dst); // 二维离散傅里叶

    // 剪切和重分布幅度图像限,如果有奇数行或奇数列,进行频谱裁剪
    dst = dst(Rect(0, 0, dst.cols & -2, dst.rows & -2));

    // 重新排列傅里叶图像中的象限,将频谱中心移至图像中心
    int cx = dst.cols / 2;
    int cy = dst.rows / 2;
    Mat q0(dst, Rect(0, 0, cx, cy));   // 左上区域
    Mat q1(dst, Rect(cx, 0, cx, cy));  // 右上区域
    Mat q2(dst, Rect(0, cy, cx, cy));  // 左下区域
    Mat q3(dst, Rect(cx, cy, cx, cy)); // 右下区域

    /*
    origin:
       q0 | q1
       q2 | q3
    new:
       q3 | q2
       q1 | q0
     */
    // 交换象限
    Mat tmp;
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);// q0 与 q3 进行交换

    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);// q1 与 q2 进行交换
}

int main()
{
    Mat src = imread(".../girl.jpg");

    Mat gray, dst;
    imshow("src", src);

    cvtColor(src, gray, COLOR_BGR2GRAY);
    imshow("gray", gray);

    myDFT(gray, dst); // 傅里叶变换
    imshow("dst", dst); // 零频率分量移至频谱中心
    waitKey(0);
    return 0;
}

4. 总结

"万物皆可傅里叶",本文是傅里叶变换在该系列的一个开篇,后续还会继续介绍其在图像处理中的应用。

在图像处理领域,傅里叶变换可以将图像从空间域变换到频域,从而揭示图像的频率成分。傅里叶变换在图像处理中有着广泛的应用,例如:图像增强、图像分割、特征提取、图像压缩等。

相关推荐
TTTrees21 小时前
(11)最重要的结构体Mat
opencv
可爱系程序猿1 天前
OpenCV 项目启动时报 opencv_world480.dll:先核对构建与架构
人工智能·opencv·程序人生·架构·电脑
FOAF-lambda1 天前
Python实战:基于OpenCV与单调栈,精准定位PDF中最大的空白区域
python·opencv·pdf
小豆庄2 天前
处理含车牌/人脸的隐私视频,如何做到数据不离机?
opencv·ai·云计算·视频
小徐不徐说2 天前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
晨间晓5 天前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓5 天前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓6 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭6 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓6 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云