最近对图像处理算法比较感兴趣,也看了一些数字图像处理相关书籍,自己也实现过一些简单的图像处理算法。随着了解的深入,发现要真正理解图像处理各种骚操作,绕不开基于傅里叶变换的各种频率域滤波。对于lz这种数学渣来说,看到各种数学公式推导,简直令人头大,通过傅里叶变换把直观图像转换为抽象的频谱图更是让人难以理解。

上面是一张傅里叶变换后的频谱图,如果不了解傅里叶变换,很难从上图中分析出原图包含的一些特征。研究了一段时间傅里叶变换,按照lz的理解,其实图像的傅里叶变换就是根据空间位置对图像灰度值进行拆分,分离出从高到低不同频率,频谱图就是展示一张图像从低频(频谱中心,图像平均灰度)到高频(远离频谱中心,对应灰度变化大的区域)的分布。而频率域滤波则是根据图像的频率特征,采用不同滤波器,理想低通、高通,高斯低通、高通等,对频率域的图像数据进行处理,之后通过逆傅里叶变换还原出滤波后的图像。

冈萨雷斯的《数字图像处理》第四章节用了将近70页的篇幅对傅里叶变换进行了逐步讲解,同时也表明了频率域滤波在图像滤波中的重要性。虽然是图像处理的业余爱好者,lz还是决定有必要把傅里叶变换尽量搞清楚一些。因为没有接触过MATLAB和OpenCV(暂时也不打算使用第三方工具),所以文章所涉及到的代码都使用lz比较熟悉的java来实现。

为了更好的理解傅里叶变换,lz将傅里叶变换从一些基本概念到应用拆分为不同层次,基本概念及推导、一维离散傅里叶变换、快速傅里叶变换、二维傅里叶变换、频率域滤波。这里就对傅里叶变换的一些基本概念做个总结。

傅里叶变换涉及的一些基本概念:复数、欧拉公式、傅里叶公式、取样和卷积。

一、复数

复数的形式:C = a + jb

a为实部,jb为虚部,其中b为实数,,为虚数。复数也可以理解为一个二维平面上的点,实部为x轴,虚部为y轴。

复数的共轭复数:C’ = a - jb,实部相同,虚部符号相反。

复数满足四则运算法则

例如:C’’ = c + jd;

复数相加:C + C’’ = (a + c) + j(b+d)

复数相减:C - C” = (a - c) + j(b - d)

复数相乘:C * C” = (a + jb) * (c + jd) = a*c - bd + j(ad + bc)

复数相除:C / C” = (a + jb)/(c + jd) = (a + jb)*(c - jd)/(c + jd)(c - jd)

=[(ac + bd) - j(bc - ad)] / (c2 + d2)

复数的模长:C = a + jb模长为|C| =

根据三角函数,复数可变换为:复数可变换为:C = |C|()形式,实际上在编程中傅里叶变换也是通过这种形式进行计算的。

二、欧拉公式

傅里叶变换公式也就是通过欧拉公式变换为方便计算的复数形式。

三、傅里叶变换公式

傅里叶变换公式:

傅里叶反变换公式:

以上两个公式就是傅里叶变换和逆变换,但这是在连续函数上的变换,我们实际使用的是离散函数的傅里叶变换。

傅里叶变换公式的简单推导过程:

例:常数函数f(t)=A ,在有限区间内,傅里叶公式可做如下变换:

根据欧拉公式

上面公式可以做进一步变换

上式结果也可由三角恒等式直接变换过来:

三角恒等式:

通常,为了显示,需要处理幅值,变换为傅里叶谱或频谱:

四、取样和卷积

上面所讲的傅里叶公式及推导都是在连续函数上进行的,而要实现计算机能够处理的数据必须是离散的信号,所以这就           涉及到取样。连续的数字信号,例如音频、电磁波信号等,需要对原始信号采样后再进行处理,而图像处理方面,可                   以把每一个像素上的灰度值看做已经采样后的数据,我们只需要把图像数据作为离散的信号输入即可。

至于卷积,做过图像空间域滤波以后不难理解,图像的傅里叶变换,是以整个图像所有对图像上每个像素进行傅里叶计           算,也就是说以整个图像作为一个周期,计算不同频率在某个像素位置上的叠加。那么一幅像素数量为N的图像,需要进             行的离散傅里叶变换计算次数为N * N。例如,对一幅2000万像素的图片做傅里叶变换计算,需要计算2000万 * 2000万                 次,这对超级计算机来说也是一个不小的挑战,于是有了快速傅里叶变换,把计算量降低为N * log2N,这才使傅里叶变换           有了实用价值,至于快速傅里叶变换,后面再详细讲。

五、复数类的实现

上面只是对傅里叶变换概念及公式做了个简单的讲解,其实从代码上实现傅里叶变换并没有那么复杂。由于傅里叶变换          是在复数基础上进行计算的,接下来就迈出傅里叶变换的第一步,复数的代码实现。

附上java代码:

package FourierTransform;/*** 复数类* @author admin**/
public class Complex {private double a; //复数实部private double b; //复数虚部//创建一个复数类实例public Complex(double a,double b) {this.a = a;this.b = b;}//获取复数实部public double getRealPart() {return this.a;}//获取复数虚部public double getImaginePart() {return this.b;}//对复数重新赋值public void changeVaule(double a, double b) {this.a = a;this.b = b;}//共轭复数public Complex conjugate() {return new Complex(this.a,-this.b);}//计算复数模长public double absValue() {return Math.sqrt(this.a * this.a + this.b * this.b);}//复数加运算,实部与实部相加,虚部与虚部相加public Complex add(Complex C) {return new Complex(this.a + C.a, this.b + C.b);}//复数相减public Complex minus(Complex C) {return new Complex(this.a - C.a, this.b - C.b);}/*** 复数相乘* a*a1+a*jb1+jb*a1*-b*b1* @param C* @return*/public Complex multiply(Complex C) {double A = this.a * C.a - this.b * C.b;double B = this.a * C.b + this.b * C.a;return new Complex(A, B);}/*** 复数相除* (a + jb) / (c + jd) = [(a + jb) * (c - jd)] / [(c + jd) * (c - jd)]* =[(ac + bd) + j(bc - ad)] / [(c^2 + d^2)]* @param C* @return*/public Complex divide(Complex C) {if (C.a == 0 && C.b == 0) {System.out.println("被除数不能为空!");return null;}double A = (this.a * C.a + this.b * C.b) / (C.a * C.a + C.b * C.b);double B = (this.b * C.a - this.a * C.b) / (C.a * C.a + C.b * C.b);return new Complex(A,B);}//toString方法public String toString() {if (a == 0 && b == 0) {return "复数为空!";}else if (a == 0) {return this.b + "j";}else if (b == 0) {return a + "";}else if (b > 0) {return this.a + "+" + this.b + "j";}else{return this.a + "" + this.b + "j";}}//测试public static void main(String[] args) {Complex c1 = new Complex(1, 2);System.out.println(c1.toString());Complex c2 = c1.conjugate();System.out.println(c2.toString());System.out.println(c1.absValue());}
}

傅里叶变换基本概念及复数类实现相关推荐

  1. 【C++深度剖析教程11】C++学习之编写代码实现复数类

    今天,我来学习将复数的加减乘除以及比较运算,编写一个复数类,方便计算复数之间的运算.具体用的方法就是之前写过的操作符重载的概念来实现(操作符重载的概念学习). 那么为了显得清晰,今天写的程序运用模块化 ...

  2. 【Java例题】2.1复数类

    1.定义复数类,包括实部和虚部变量.构造方法. 加减乘除方法.求绝对值方法和显示实部.虚部值的方法. 然后编写一个主类,在其主方法中通过定义两个复数对象来 显示每一个复数的实部值.虚部值和绝对值, 显 ...

  3. 第十二周项目一-实现复数类中的运算符重载(1)

    /**Copyright(c)2016,烟台大学计算机与控制工程学院*All rights reserved*文件名称:123.cpp*作 者:王蕊*完成日期:2016年5月15日*版 本 号:v1. ...

  4. C++ 复数类加减法运算重载为成员函数形式

    运算符的重载形式有两种,即重载为类的非静态成员函数和重载为非成员函数.运算符重载为类的成员函数的一般语法形式为: 返回类型 operator 运算符(形参表){函数体 } 运算符重载为非成员函数的一般 ...

  5. C++ 复数类运算符重载

    题目描述 定义一个复数类Complex,重载运算符"*","<<",">>",使之能够用于复数的乘法.输入.输出 m ...

  6. 4-1 复数类的运算符重载

    4-1 复数类的运算符重载 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 通过本题目的练习 ...

  7. [YTU]_2440( C++习题 复数类--重载运算符+,-,*,/)

    题目描述 定义一个复数类Complex,重载运算符"+","-","*","/",使之能用于复数的加.减.乘.除.运算符 ...

  8. [YTU]_2443 ( C++习题 复数类--重载运算符3+)

    题目描述 请编写程序,处理一个复数与一个double数相加的运算,结果存放在一个double型的变量d1中,输出d1的值,再以复数形式输出此值.定义Complex(复数)类,在成员函数中包含重载类型转 ...

  9. [YTU]_2441( C++习题 复数类--重载运算符2+)

    题目描述 定义一个复数类Complex,重载运算符"+",使之能用于复数的加法运算.参加运算的两个运算量可以都是类对象,也可以其中有一个是整数,顺序任意.例如,c1+c2,i+c1 ...

最新文章

  1. FT(Fourier Transform)在滤波上的应用
  2. php ajax评论系统,Ajax / jQuery评论系统 - php
  3. C# 数组 二维数组
  4. troch3d open3d例子
  5. mysql function 与 procedure
  6. 挖掘协同的力量 大OA前景广阔
  7. python matplotlib.pyplot中add_subplot subplot函数的用法与区别(其实没什么区别)
  8. Usermod 命令详解
  9. input和raw_input
  10. P4001-[ICPC-Beijing 2006]狼抓兔子【对偶图】
  11. java new expression,JAVA公式解析示例
  12. 一分钟解决 Github 访问慢
  13. 模拟游戏给我带来的产品思维
  14. 人类基因组计划20周年!中科院付巧妹团队登Science特刊,从古DNA中一窥人类演化...
  15. 信息学奥赛一本通(1117:整数去重)
  16. docker .env文件_基于Docker搭建Nacos集群
  17. weex的组件 web的使用(结合webview模块)
  18. Teemo Attacking 提莫攻击
  19. test韩顺平校内网
  20. android手机存储大小设置在哪里看,安卓手机怎么设置增加虚拟内存

热门文章

  1. 01.elasticsearch-security_es鉴权机制
  2. 这或许是讲解Knuth(Shuffle)洗牌算法最好的文章
  3. 【四种解法】剑指 Offer 39. 数组中出现次数超过一半的数字
  4. 同步规则和happen-before规则
  5. 若依的框架怎么样_基于bootstrapTable的若依框架如何获取表格选中行的整行数据?...
  6. python工具打造之实现端口扫描
  7. Windows Server 笔记之磁盘管理
  8. iis php mysql wiki_Windows下安装MediaWiki (iis+php+mysql+mediawiki)
  9. java实例域静态域_有关java 实例域 静态域 静态方法
  10. Android悬浮按钮锚点位置,Android 滑动定位+吸附悬停效果实现