Python 实现图像快速傅里叶变换和离散余弦变换

时间:2021-09-10 01:56:15

图像的正交变换在数字图像的处理与分析中起着很重要的作用,被广泛应用于图像增强、去噪、压缩编码等众多领域。本文手工实现了二维离散傅里叶变换二维离散余弦变换算法,并在多个图像样本上进行测试,以探究二者的变换效果。

1. 傅里叶变换

实验原理

对一幅图像进行离散傅里叶变换(DFT),可以得到图像信号的傅里叶频谱。二维 DFT 的变换及逆变换公式如下:

Python 实现图像快速傅里叶变换和离散余弦变换

DFT 尽管解决了频域离散化的问题,但运算量太大。从公式中可以看到,有两个嵌套的求和符号,显然直接计算的复杂度为 \(O(n^2)\) 。为了加快傅里叶变换的运算速度,后人提出快速傅里叶变换(FFT),即蝶形算法,将计算 DFT 的复杂度降低到了 \(O(n\log n)\)。

FFT 利用傅里叶变换的数学性质,采用分治的思想,将一个 \(N\) 点的 FFT,变成两个 \(N/2\) 点的 FFT。以一维 FFT 为例,可以表示如下:

Python 实现图像快速傅里叶变换和离散余弦变换
Python 实现图像快速傅里叶变换和离散余弦变换

其中,\(G(k)\) 是 \(x(k)\) 的偶数点的 \(N/2\) 点的 FFT,\(H(k)\) 是 \(x(k)\) 的奇数点的 \(N/2\) 点的 FFT。

这样,通过将原问题不断分解为两个一半规模的子问题,然后计算相应的蝶形运算单元,最终得以完成整个 FFT。

算法步骤

本次实验中,一维 FFT 采用递归实现,且仅支持长度为 2 的整数幂的情况。

算法步骤如下:

  1. 检查图像的尺寸,如果不是 2 的整数幂则直接退出。
  2. 对图像的灰度值进行归一化。
  3. 对图像的每一行执行一维 FFT,并保存为中间结果。
  4. 对上一步结果中的每一列执行一维 FFT,返回变换结果。
  5. 将零频分量移到频谱中心,并求绝对值进行可视化。
  6. 对中心化后的结果进行对数变换,以改善视觉效果。

主要代码

一维 FFT

def fft(x):
n = len(x)
if n == 2:
return [x[0] + x[1], x[0] - x[1]] G = fft(x[::2])
H = fft(x[1::2])
W = np.exp(-2j * np.pi * np.arange(n//2) / n)
WH = W * H
X = np.concatenate([G + WH, G - WH])
return X

二维 FFT

def fft2(img):
h, w = img.shape
if ((h-1) & h) or ((w-1) & w):
print('Image size not a power of 2')
return img img = normalize(img)
res = np.zeros([h, w], 'complex128')
for i in range(h):
res[i, :] = fft(img[i, :])
for j in range(w):
res[:, j] = fft(res[:, j])
return res

零频分量中心化

def fftshift(img):
# swap the first and third quadrants, and the second and fourth quadrants
h, w = img.shape
h_mid, w_mid = h//2, w//2
res = np.zeros([h, w], 'complex128')
res[:h_mid, :w_mid] = img[h_mid:, w_mid:]
res[:h_mid, w_mid:] = img[h_mid:, :w_mid]
res[h_mid:, :w_mid] = img[:h_mid, w_mid:]
res[h_mid:, w_mid:] = img[:h_mid, :w_mid]
return res

运行结果

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

2. 余弦变换

实验原理

当一个函数为偶函数时,其傅立叶变换的虚部为零,因而不需要计算,只计算余弦项变换,这就是余弦变换。离散余弦变换(DCT)的变换核为实数的余弦函数,因而计算速度比变换核为指数的 DFT 要快得多。

一维离散余弦变换与离散傅里叶变换具有相似性,对离散傅里叶变换进行下式的修改:

Python 实现图像快速傅里叶变换和离散余弦变换

式中

Python 实现图像快速傅里叶变换和离散余弦变换

由上式可见,\(\sum\limits_{x=0}^{2M-1}f_e(x)e^{\frac{-j2ux\pi}{2M}}\) 是 \(2M\) 个点的傅里叶变换,因此在做离散余弦变换时,可将其拓展为 \(2M\) 个点,然后对其做离散傅里叶变换,取傅里叶变换的实部就是所要的离散余弦变换。

算法步骤

基于上述原理,二维 DCT 的实现重用了上文中的一维 FFT 函数,并根据公式做了一些修改。

算法步骤如下:

  1. 检查图像的尺寸,如果不是 2 的整数幂则直接退出。
  2. 对图像的灰度值进行归一化。
  3. 对图像的每一行进行延拓,执行一维 FFT 后取实部,乘以公式中的系数,并保存为中间结果。
  4. 对上一步结果中的每一列进行延拓,执行一维 FFT 后取实部,乘以公式中的系数,返回变换结果。
  5. 对结果求绝对值,并进行对数变换,以改善视觉效果。

主要代码

二维 DCT

def dct2(img):
h, w = img.shape
if ((h-1) & h) or ((w-1) & w):
print('Image size not a power of 2')
return img img = normalize(img)
res = np.zeros([h, w], 'complex128')
for i in range(h):
res[i, :] = fft(np.concatenate([img[i, :], np.zeros(w)]))[:w]
res[i, :] = np.real(res[i, :]) * np.sqrt(2 / w)
res[i, 0] /= np.sqrt(2)
for j in range(w):
res[:, j] = fft(np.concatenate([res[:, j], np.zeros(h)]))[:h]
res[:, j] = np.real(res[:, j]) * np.sqrt(2 / h)
res[0, j] /= np.sqrt(2)
return res

运行结果

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

Python 实现图像快速傅里叶变换和离散余弦变换

完整源码请见 GitHub 仓库

Python 实现图像快速傅里叶变换和离散余弦变换的更多相关文章

  1. JPEG解码——(6)IDCT逆离散余弦变换

    本篇是该系列的第六篇,承接上篇IZigZag变换,介绍接下来的一个步骤--逆离散余弦变换,即逆零偏置前的一个步骤. 该步骤比较偏理论,其业务是对IZigZag变换后的数据,再进一步的处理,使其恢复DC ...

  2. 在python3下使用OpenCV做离散余弦变换DCT及其反变换IDCT

    对图像处理经常用到DCT, Python下有很多带有DCT算法包, 这里使用OpenCV的DCT做变换, 并简单置0部分数据, 再查看反变换图像的效果. import numpy as np impo ...

  3. 在python3下对数据分块(8x8大小)使用OpenCV的离散余弦变换DCT

    在MATLAB中有blkproc (blockproc)对数据处理, 在python下没找到对应的Function, 这里利用numpy 的split(hsplit和vsplit) 对数据分块处理成8 ...

  4. 「快速傅里叶变换(FFT)」学习笔记

    FFT即快速傅里叶变换,离散傅里叶变换及其逆变换的快速算法.在OI中用来优化多项式乘法. 本文主要目的是便于自己整理.复习 FFT的算法思路 已知两个多项式的系数表达式,要求其卷积的系数表达式. 先将 ...

  5. 傅里叶变换通俗解释及快速傅里叶变换的python实现

    通俗理解傅里叶变换,先看这篇文章傅里叶变换的通俗理解! 接下来便是使用python进行傅里叶FFT-频谱分析: 一.一些关键概念的引入 1.离散傅里叶变换(DFT) 离散傅里叶变换(discrete ...

  6. 基于python的快速傅里叶变换FFT(二)

    基于python的快速傅里叶变换FFT(二)本文在上一篇博客的基础上进一步探究正弦函数及其FFT变换. 知识点  FFT变换,其实就是快速离散傅里叶变换,傅立叶变换是数字信号处理领域一种很重要的算法. ...

  7. python 图像的离散傅立叶变换

    图像(MxN)的二维离散傅立叶变换可以将图像由空间域变换到频域中去,空间域中用x,y来表示空间坐标,频域由u,v来表示频率,二维离散傅立叶变换的公式如下: 在python中,numpy库的fft模块有 ...

  8. 图像傅里叶变换(快速傅里叶变换FFT)

    学习DIP第7天,图像傅里叶变换 转载请标明出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对 ...

  9. Discrete cosine transform(离散余弦转换)

    A discrete cosine transform (DCT) expresses a finite sequence of data points in terms of a sum of co ...

随机推荐

  1. LM2596扩流

  2. explode 结合 str_replace对获取的URL处理手记

    今天更新我的一个FKQQ的程序.我的一个PHP文件接收到HQ的QQ号码的字符串.因为获取的内容有大量的垃圾内容所以我用str_replace做了一个处理代码如下: $xx1 = preg_replac ...

  3. 检索n以内所有素数

    #include <iostream>#include <cmath> const int N=500000;//数组大小 using namespace std; int m ...

  4. DP:树DP

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  5. Maven-11&colon; 从命令行调用插件

    mvn -h显示mvn命令帮助: usage: mvn [options] [<goal(s)>] [<phase(s)>] Options: -am,--also-make ...

  6. js重点--原型链

    通过将一个构造函数的原型对象指向父类的实例,就可以调用父类中的实例属性及父类的原型对象属性,实现继承. function animals(){ this.type = "animals&qu ...

  7. Mybatis从认识到了解

    目录 MyBatis的介绍 介绍: 为什么选择MyBatis: 与Hibernate的对比: MyBatis的优点: 入门示例 Mybatis核心组件 四大核心组件 SqlSessionFactory ...

  8. Windows下文件夹扩展名

    回收站.{645ff040-5081-101b-9f08-00aa002f954e} 拨号网络.{992CFFA0-F557-101A-88EC-00DD010CCC48} 打印机.{2227a280 ...

  9. 实例讲解Silverlight 初始控件如何获得焦点

    这个问题本来是在我实际的项目中遇到过的,但这其实是当初项目要求,要求一进入就要使得在用户名那个文字框中聚焦,而不是再用鼠标去点击获得焦点,后来自己费了点时间解决了.本来我没太注意就过去了,没想到在QQ ...

  10. Java系列: 如何在Eclipse中安装Memory Analyzer插件

    一.找到eclipse的插件安装对话框: help->install new software ->work with 二.输入Memory Analyzer的安装路径 具体可以到http ...