DCT(Discrete Consine Transform),又叫离散余弦变换,它的第二种类型,经常用于信号和图像数据的压缩。经过DCT变换后的数据能量非常集中,一般只有左上角的数值是非零的,也就是能量都集中在离散余弦变换后的直流和低频部分。

1. 一维DCT变换

一维DCT变换共有8中,其中最实用的是第二种形式,公式如下:

\[F(u)=c(u)\sum_{i=0}^{N-1}f(i)\cos{[\frac{(i+0.5)\pi}{N}u]}
\]

\[c(u)=\begin{cases}\sqrt{\frac{1}{N}}, & u=0 \\ \sqrt{\frac{2}{N}}, & u\neq0\end{cases}
\]

其中\(c(u)\)就是加上去一个系数,为了能使DCT变换变成正交矩阵。\(N\)是\(f(x)\)的总数。

2. 二维DCT变换

二维DCT变换是在一维的基础上再进行一次DCT变换,公式如下:

\[F(u,v)=c(u)c(v)\sum_{i=0}^{N-1}\sum_{i=0}^{N-1}f(i,j)\cos{[\frac{(i+0.5)\pi}{N}u]}\cos{[\frac{(i+0.5)\pi}{N}v]}
\]

这里只讨论了两个\(N\)相等的情况,也就是数据是方阵的形式,在实际应用中对不是方阵的数据都是先补齐再进行变换的。

写成矩阵形式:

\[\mathrm{F}=\mathrm{A}f\mathrm{A}^\mathrm{T}
\]

\[\mathrm{A}(i,j)=c(i)\cos{[\frac{(j+0.5)\pi}{N}i]}
\]

用MATLAB进行验证:

  1. clear;
  2. clc;
  3. X = round(rand(4) * 100); % 生成随机数据
  4. A = zeros(4); % 变换矩阵
  5. for i = 0 : 3
  6. if i == 0
  7. c = sqrt(1/4);
  8. else
  9. c = sqrt(2/4);
  10. end
  11. for j = 0 : 3
  12. A(i + 1, j + 1) = c * cos(pi * (j + 0.5) * i / 4);
  13. end
  14. end
  15. Y = A * X * A'; % DCT变换
  16. YY = dct2(X); % 使用MATALAB函数进行DCT变换
  17. disp('使用公式进行DCT变换:')
  18. disp(Y)
  19. disp('使用MATLAB函数DCT变换:')
  20. disp(YY)

输入结果:

  1. 使用公式进行DCT变换:
  2. 204.7500 -2.5322 27.2500 24.5909
  3. 32.1461 3.7448 -20.9667 24.5450
  4. 54.2500 -1.9287 -2.2500 -24.9079
  5. 12.9327 -40.4550 -25.1401 9.7552
  6. 使用MATLAB函数DCT变换:
  7. 204.7500 -2.5322 27.2500 24.5909
  8. 32.1461 3.7448 -20.9667 24.5450
  9. 54.2500 -1.9287 -2.2500 -24.9079
  10. 12.9327 -40.4550 -25.1401 9.7552

3. 二维DCT逆变换

DCT逆变换的公式如下:

\[f(i,j)=\sum_{u=0}^{N-1}\sum_{v=0}^{N-1}c(u)c(v)F(u,v)\cos[\frac{(i+0.5)\pi}{N}u]\cos[\frac{(j+0.5)\pi}{N}v]
\]

\[c(u)=\begin{cases}\sqrt{\frac{1}{N}},&u=0\\\sqrt{\frac{2}{N},}&u\neq0\end{cases}
\]

矩阵形式的变换公式推到如下:

\[\begin{align}&\quad\mathrm{F}=\mathrm{A}f\mathrm{A}^{\mathrm{T}}\\&\because{\mathrm{A}^{-1}=\mathrm{A}^{\mathrm{T}}}\\&\therefore{f=\mathrm{A}^{-1}\mathrm{F}(\mathrm{A}^{T})^{-1}}=\mathrm{A}^{T}\mathrm{F}\mathrm{A}\end{align}
\]

用MATALAB进行验证:

  1. clear;
  2. clc;
  3. X = round(rand(4) * 100); % 生成随机数据
  4. A = zeros(4); % 变换矩阵
  5. for i = 0 : 3
  6. if i == 0
  7. c = sqrt(1/4);
  8. else
  9. c = sqrt(2/4);
  10. end
  11. for j = 0 : 3
  12. A(i + 1, j + 1) = c * cos(pi * (j + 0.5) * i / 4);
  13. end
  14. end
  15. Y = A * X * A'; % DCT变换
  16. XX = A'* Y* A; % DCT逆变换
  17. disp('原始矩阵:')
  18. disp(X)
  19. disp('使用公式进行DCT逆变换:')
  20. disp(XX)
  21. disp('使用MATLAB函数DCT逆变换:')
  22. disp(idct2(Y))

输出结果:

  1. 原始矩阵:
  2. 28 69 44 19
  3. 5 32 38 49
  4. 10 95 77 45
  5. 82 3 80 65
  6. 使用公式进行DCT逆变换:
  7. 28.0000 69.0000 44.0000 19.0000
  8. 5.0000 32.0000 38.0000 49.0000
  9. 10.0000 95.0000 77.0000 45.0000
  10. 82.0000 3.0000 80.0000 65.0000
  11. 使用MATLAB函数DCT逆变换:
  12. 28.0000 69.0000 44.0000 19.0000
  13. 5.0000 32.0000 38.0000 49.0000
  14. 10.0000 95.0000 77.0000 45.0000
  15. 82.0000 3.0000 80.0000 65.0000

4. DCT变换的可分离性

DCT变换是可分离的变换。通常根据可分离性,二维DCT可用两次一维DCT变换来完成,即

\[\begin{align}f(x,y)&\to F_{行}[f(x,y)]=F(x,v)\\&\to F(x,v)^{\mathrm{T}}\to F_{列}[f(x,v)^{\mathrm{T}}]=F(u,v)^{\mathrm{T}}\\&\to F(u,v)\end{align}
\]

先进行行变换,再进行列变换和先进行列变换,再进行行变换的结果是一样的。

Python scipy模块中的fftpack.dct()函数提供了一维DCT变换功能(默认是沿着矩阵的最后一个axis进行变换),下面使用Python代码进行验证。

  1. import numpy as np
  2. from scipy import fftpack
  3. def dct(mat2x2):
  4. return fftpack.dct(fftpack.dct(mat2x2, norm='ortho').T, norm='ortho').T
  5. def dct2(mat2x2):
  6. return fftpack.dct(fftpack.dct(mat2x2.T, norm='ortho').T, norm='ortho')
  7. if __name__ == '__main__':
  8. sample = np.random.rand(3, 3)
  9. print('先进行行变换,再进行列变换:')
  10. print(dct(sample))
  11. print('先进行列变换,再进行行变换:')
  12. print(dct2(sample))

输出结果:

  1. 先进行行变换,再进行列变换:
  2. [[ 1.3763706 -0.42355794 0.03903157]
  3. [-0.18270004 0.06454257 -0.05273778]
  4. [ 0.16962548 0.22247218 -0.06953193]]
  5. 先进行列变换,再进行行变换:
  6. [[ 1.3763706 -0.42355794 0.03903157]
  7. [-0.18270004 0.06454257 -0.05273778]
  8. [ 0.16962548 0.22247218 -0.06953193]]

5. DCT用于图像压缩

对于二维灰度图像进行DCT变换,就能得到图像的频谱图:低阶(变化幅度小)的部分反映在DCT的左上方,高阶(变化幅度大)的部分反映在DCT的右下方。由于人眼对高阶部分不敏感,依靠低阶部分就能基本识别出图像内容,所以JPEG进行压缩的时候,基本上只存储DCT变换后的左上部分,而右下部分则直接丢弃。

MATALAB代码验证:

  1. clear;
  2. clc;
  3. im = imread('https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'); % 读入图像
  4. figure(),
  5. subplot(221),
  6. imshow(im);
  7. title('原始彩色图像');
  8. grayim = rgb2gray(im);
  9. dctim = dct2(grayim);
  10. subplot(222),
  11. % imshow(I,[]) displays the grayscale image I scaling the display based on the range of pixel values in I.
  12. imshow(log(abs(dctim)), []),
  13. title('DCT变换图像');
  14. idctim = idct2(dctim);
  15. subplot(223),
  16. imshow(idctim, [])
  17. title('DCT逆变换图像');
  18. subplot(224),
  19. imshow(grayim)
  20. title('原始灰度图像');

运行结果:

![运行结果图片](

参考文献

[1] 二维DCT变换:https://wuyuans.com/2012/11/dct2

[2] 余弦离散变换原理及应用:http://blog.csdn.net/shenziheng1/article/details/52965104

[3] MATLAB分析图像的离散余弦变换(DCT):http://blog.csdn.net/u013354805/article/details/52259471

[4] 图像DCT变换:https://feichashao.com/image_dct/

二维DCT变换的更多相关文章

  1. 二维DCT变换 | Python实现

    引言 最近专业课在学信息隐藏与数字水印,上到了变换域隐藏技术,提到了其中的DCT变换,遂布置了一个巨烦人的作业,让手动给两个\(8\times8\)的矩阵做二维DCT变换,在苦逼的算了一小时后,我决定 ...

  2. DCT变换、DCT反变换、分块DCT变换

    一.引言 DCT变换的全称是离散余弦变换(Discrete Cosine Transform),主要用于将数据或图像的压缩,能够将空域的信号转换到频域上,具有良好的去相关性的性能.DCT变换本身是无损 ...

  3. UWP开发-二维变换以及三维变换

    在开发中,由于某些需求,我们可能需要做一些平移,缩放,旋转甚至三维变换,所以我来讲讲在UWP中这些变换的实现方法. 一. 二维变换: UIElement.RenderTransform a.Trans ...

  4. 【opengl】OpenGL中三维物体显示在二维屏幕上显示的变换过程

    转自:http://blog.sina.com.cn/s/blog_957b9fdb0100zesv.html 为了说明在三维物体到二维图象之间,需要经过什么样的变换,我们引入了相机(Camera)模 ...

  5. SSE图像算法优化系列二十一:基于DCT变换图像去噪算法的进一步优化(100W像素30ms)。

    在优化IPOL网站中基于DCT(离散余弦变换)的图像去噪算法(附源代码) 一文中,我们曾经优化过基于DCT变换的图像去噪算法,在那文所提供的Demo中,处理一副1000*1000左右的灰度噪音图像耗时 ...

  6. C++实现离散余弦变换(参数为二维指针)

    C++实现离散余弦变换(参数为二维指针) 写在前面 到目前为止已经阅读了相当一部分的网格水印等方面的论文了,但是论文的实现进度还没有更上,这个月准备挑选一些较为经典的论文,将其中的算法实现.在实现论文 ...

  7. 二维离散余弦变换(2D-DCT)

    图像处理中常用的正交变换除了傅里叶变换以外,还有一些其它常用的正交变换,其中离散余弦变换DCT就是一种,这是JPEG图像压缩算法里的核心算法,这里我们也主要讲解JPEG压缩算法里所使用8*8矩阵的二维 ...

  8. 通过Matrix进行二维图形仿射变换

    Affine Transformation是一种二维坐标到二维坐标之间的线性变换,保持二维图形的"平直性"和"平行性".仿射变换可以通过一系列的原子变换的复合来 ...

  9. openGL实现二维图形和三维图形

    openGL是一个强大的底层图形库,其命令最初的时候使用C语言实现的.openGL定义了一个图形程序接口,常用于制作处理三维图像,功能强大,调用方便,在图像处理十分受欢迎. 实现图形主要使用的是ope ...

随机推荐

  1. F-stack及其Nginx、redis的编译安装

    F-stack简介 F-stack粘合了dpdk.用户态协议栈和nginx.redis,弥补了dpdk没有协议栈的不足,并用nginx.redis提供了一个调用应用程序的接口. Quick Start ...

  2. Python入门语法

    Python入门语法 动态变量 a=3  整数 a='abc'   a="abc"    字符串 a=3.0       小数 a=true  a=false   布尔型 a=3  ...

  3. Web—12-详解CSS的相对定位和绝对定位

    CSS的相对定位和绝对定位通常情况下,我们元素的position属性的值默认为static 就是没有定位,元素出现在正常的文档流中,,这个时候你给这个元素设置的left,right,bottom,to ...

  4. c++读取ini的Section节名

    // ConsoleApplication1.cpp : 定义控制台应用程序的入口点.// #include "stdafx.h"#include "iostream&q ...

  5. 【五】安装fcig

    安装fcig 安装fcig 此步骤是为了让spawn-fcgi能够识别自定义的demo 编译文件 自定义c文件 测试成功后,启动spawn cgi进行代理托管 此步骤是为了让spawn-fcgi能够识 ...

  6. firefox burp ssl证书配置

    打开浏览器 设置->证书->证书频发机构->添加证书 添加成功->找到位置->编辑信任->信任->查看证书 导出-> win下可直接安装证书->受 ...

  7. git——本地项目上传到git

    1.对于github相信大家写自动化代码的人都不陌生,而且这也可以说是你进军自动化的一项必须解锁的技能,今天抽空开始整理笔记,顺便整理下github的基本使用,从本地上传代码托管: 一.从无到有:先注 ...

  8. PTA基础编程题目集6-2多项式求值(函数题)

    本题要求实现一个函数,计算阶数为n,系数为a[0] ... a[n]的多项式f(x)=∑​i=0​n​​(a[i]×x​i​​) 在x点的值. 函数接口定义: double f( int n, dou ...

  9. 20155212 实验二 Java面向对象程序设计

    20155212 实验二 Java面向对象程序设计 单元测试 三种代码 用编程去解决问题,必须学会写三种码: 伪代码 产品代码 测试代码 例: MyUtil 类解决一个百分制成绩转成"优.良 ...

  10. 20155215宣言 实验四 Andoid开发基础实验报告

    20155215宣言 实验四 Andoid开发基础实验报告 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程: 2.完成实验 ...