class="markdown_views prism-github-gist">
1. 图像的二维离散变换
与一维的有限长离散非周期信号存在傅里叶变换(DFT)一样,图像作为一个二维离散信号同样存在着二维离散变换(注意这里是介绍一个通用的概念,二维离散变换,包括了DFT、DCT等多种变换在内的一种通式写法),其通式可以表达为
1.1 二维变换的可分性与对称性
如果一个二维变换核同时具备可分性与对称性,此时允许用两个一维变换来计算二维变换,即首先沿着输入的行(列)进行一维变换,接着用第一步得到的结果再对列(行)进行一维变换。当变换对的正反变换都满足这个条件时,且 f(x,y)f(x,y) 是大小为 M×MM×M 的方形图像时,式(2.6-30)和式(2.6-31)可表示为矩阵形式
T=AFAT
其中 FF 矩阵是包含元素 f(x,y)f(x,y) 的 的M×M的M×M 矩阵,AA 矩阵是有元素 ai,j=r1(i,j)ai,j=r1(i,j) 的 M×MM×M 矩阵,TT 是 M×MM×M 变换的结果,其值为 T(u,v),u,v=0,1,…,M−1T(u,v),u,v=0,1,…,M−1,其中的 AA 矩阵并不是所说的基函数或者基图像,而由r(x,y,u,v)r(x,y,u,v) 构成的图像才是基图像。具体什么事基函数,如何获得基图像将在下面说明。
1.2 为什么二维变换可以用矩阵表示
首先回顾一下什么样的图像可以使用 T=AFATT=AFAT 来进行表示,要求二维变换核同时具备可分性与对称性且图像是正方形的图。当满足上述条件式,一个二维变换可以用两个一维变换计算,即首先变换图像的每一列再变换图像的每一行。对每一列进行变换就是用矩阵乘以图像的每一列,有线性代数知识可知 :XF=X[f1,f2,f3,…,fn],其中的F是图像矩阵,而 f1,…fnf1,…fn 是图像矩阵中的每一列。
1.3 二维离散余弦变换
正变换
反变换
由上可知当 M=NM=N的时候,DCT变换可以表示为矩阵相乘的形式,其中T=AFATT=AFAT 的 AA 的形式为
注意矩阵中有一个元素写错了,第3行第1列的元素应该是 cos(2π/2N)cos(2π/2N) 。在上述利用矩阵进行DCT变换的过程中,关于矩阵的维数是需要说明的,根据定义可以知道,被变换的图像必须是一个正方形的图像,也就是说图像矩阵必须是一个方阵。根据最开始关于二维离散变换的定义我们可以知道,被变换的图像是一个 M×NM×N 矩阵,但是这里使用一个方阵主要是因为这样的图像在计算的时候才会产生 T=AFATT=AFAT ,否则 FF 前后矩阵的维数不相同,计算出的变换矩阵当然也不同,这时的计算就变成了 T=AFBTT=AFBT 的形式了。所以为了分解方便都会假设图像是正方形的,如果图像不是正方形的,会在图像上取一个个正方形块,分块计算(实际上常常在图像上取 8 × 8 的子图象进行计算,因为这样的计算量不是很大。这时矩阵 F 和 A 都是方阵。
2. DCT余弦变换的相关代码
2.1 编写DCT余弦变化矩阵 A 的代码
clc;clear all;close all;
N = 8; % 这个是一个可以修改的参数,与原始的正方形图像的尺寸相同。
I = rand(N) % 被变换的矩阵,这里是一个随机生成的、元素分布在0到1的N*N的方阵
for i = 0:N-1
for j = 0:N-1
if i == 0
a = sqrt(1/N);
else
a = sqrt(2/N);
end
A(i+1,j+1) = a*cos((j+0.5)*pi*i/N)
end
end
D = A*I*A' % DCT变换
D1 = dct2(I) % matlab DCT函数进行DCT变换
D2 = A'*D*A % DCT逆变换
2.2 用矩阵相乘代替上述的 for 循环
无论是在MATLAB中,还是在puthon中使用numpy都有一个共同的特点,使用向量相乘或者矩阵相乘可以加快计算速度,所以下面的代码是在 2.1 代码的基础上,用矩阵相乘来代替 for 循环的一种形式。如果想了解这种方法的具体原理,可以参考博客《从 DTFT 的角度用矩阵相乘代替 for 循环进行计算》
clc;clear all;close all;
N = 4; % 这个是一个可以修改的参数,与原始的正方形图像的尺寸相同。
I = rand(N) % 被变换的矩阵,这里是一个随机生成的、元素分布在0到1的N*N的方阵
A = sqrt(2 / N)*cos((0:N-1)'*((0:N-1)+0.5)*pi/N);
A(1,:) = A(1,:) / sqrt(2)
D = A*I*A' % DCT变换
D1 = dct2(I) % matlab DCT函数进行DCT变换
D2 = A'*D*A % DCT逆变换
上面通过10行进行的计算在这里通过三行的矩阵相乘就可以代替了,代码精简了,而且会提高运算速度。
2.3 DCT 余弦变换的MATLAB命令
D = dct2(I) % matlab DCT函数对I进行DCT变换
D = dctmtx(N) % 如果矩阵A是N×N方阵,则A的DCT变换可用D×A×D’来计算,注意其中的N是维数,不是矩阵