DCT(Discrete Consine Transform),又叫離散餘弦變換,它的第二種類型,經常用于信号和圖像資料的壓縮。經過DCT變換後的資料能量非常集中,一般隻有左上角的數值是非零的,也就是能量都集中在離散餘弦變換後的直流和低頻部分。
1. 一維DCT變換
一維DCT變換共有8中,其中最實用的是第二種形式,公式如下:
F(u)=c(u)∑i=0N−1f(i)cos[(i+0.5)πNu]
c(u)=⎧⎩⎨⎪⎪1N−−√,2N−−√,u=0u≠0
其中c(u)就是加上去一個系數,為了能使DCT變換變成正交矩陣。N是f(x)的總數。
2. 二維DCT變換
二維DCT變換是在一維的基礎上再進行一次DCT變換,公式如下:
F(u,v)=c(u)c(v)∑i=0N−1∑i=0N−1f(i,j)cos[(i+0.5)πNu]cos[(i+0.5)πNv]
這裡隻讨論了兩個N相等的情況,也就是資料是方陣的形式,在實際應用中對不是方陣的資料都是先補齊再進行變換的。
寫成矩陣形式:
F=AfAT
A(i,j)=c(i)cos[(j+0.5)πNi]
用MATLAB進行驗證:
clear;
clc;
X = round(rand(4) * 100); % 生成随機資料
A = zeros(4); % 變換矩陣
for i = 0 : 3
if i == 0
c = sqrt(1/4);
else
c = sqrt(2/4);
end
for j = 0 : 3
A(i + 1, j + 1) = c * cos(pi * (j + 0.5) * i / 4);
end
end
Y = A * X * A'; % DCT變換
YY = dct2(X); % 使用MATALAB函數進行DCT變換
disp('使用公式進行DCT變換:')
disp(Y)
disp('使用MATLAB函數DCT變換:')
disp(YY)
輸入結果:
使用公式進行DCT變換:
204.7500 -2.5322 27.2500 24.5909
32.1461 3.7448 -20.9667 24.5450
54.2500 -1.9287 -2.2500 -24.9079
12.9327 -40.4550 -25.1401 9.7552
使用MATLAB函數DCT變換:
204.7500 -2.5322 27.2500 24.5909
32.1461 3.7448 -20.9667 24.5450
54.2500 -1.9287 -2.2500 -24.9079
12.9327 -40.4550 -25.1401 9.7552
3. 二維DCT逆變換
DCT逆變換的公式如下:
f(i,j)=∑u=0N−1∑v=0N−1c(u)c(v)F(u,v)cos[(i+0.5)πNu]cos[(j+0.5)πNv]
c(u)=⎧⎩⎨⎪⎪1N−−√,2N,−−−√u=0u≠0
矩陣形式的變換公式推到如下:
F=AfAT∵A−1=AT∴f=A−1F(AT)−1=ATFA
用MATALAB進行驗證:
clear;
clc;
X = round(rand(4) * 100); % 生成随機資料
A = zeros(4); % 變換矩陣
for i = 0 : 3
if i == 0
c = sqrt(1/4);
else
c = sqrt(2/4);
end
for j = 0 : 3
A(i + 1, j + 1) = c * cos(pi * (j + 0.5) * i / 4);
end
end
Y = A * X * A'; % DCT變換
XX = A'* Y* A; % DCT逆變換
disp('原始矩陣:')
disp(X)
disp('使用公式進行DCT逆變換:')
disp(XX)
disp('使用MATLAB函數DCT逆變換:')
disp(idct2(Y))
輸出結果:
原始矩陣:
28 69 44 19
5 32 38 49
10 95 77 45
82 3 80 65
使用公式進行DCT逆變換:
28.0000 69.0000 44.0000 19.0000
5.0000 32.0000 38.0000 49.0000
10.0000 95.0000 77.0000 45.0000
82.0000 3.0000 80.0000 65.0000
使用MATLAB函數DCT逆變換:
28.0000 69.0000 44.0000 19.0000
5.0000 32.0000 38.0000 49.0000
10.0000 95.0000 77.0000 45.0000
82.0000 3.0000 80.0000 65.0000
4. DCT變換的可分離性
DCT變換是可分離的變換。通常根據可分離性,二維DCT可用兩次一維DCT變換來完成,即
f(x,y)→F行[f(x,y)]=F(x,v)→F(x,v)T→F列[f(x,v)T]=F(u,v)T→F(u,v)
先進行行變換,再進行列變換和先進行列變換,再進行行變換的結果是一樣的。
Python scipy子產品中的fftpack.dct()函數提供了一維DCT變換功能(預設是沿着矩陣的最後一個axis進行變換),下面使用Python代碼進行驗證。
import numpy as np
from scipy import fftpack
def dct(mat2x2):
return fftpack.dct(fftpack.dct(mat2x2, norm='ortho').T, norm='ortho').T
def dct2(mat2x2):
return fftpack.dct(fftpack.dct(mat2x2.T, norm='ortho').T, norm='ortho')
if __name__ == '__main__':
sample = np.random.rand(3, 3)
print('先進行行變換,再進行列變換:')
print(dct(sample))
print('先進行列變換,再進行行變換:')
print(dct2(sample))
輸出結果:
先進行行變換,再進行列變換:
[[ 1.3763706 -0.42355794 0.03903157]
[-0.18270004 0.06454257 -0.05273778]
[ 0.16962548 0.22247218 -0.06953193]]
先進行列變換,再進行行變換:
[[ 1.3763706 -0.42355794 0.03903157]
[-0.18270004 0.06454257 -0.05273778]
[ 0.16962548 0.22247218 -0.06953193]]
5. DCT用于圖像壓縮
對于二維灰階圖像進行DCT變換,就能得到圖像的頻譜圖:低階(變化幅度小)的部分反映在DCT的左上方,高階(變化幅度大)的部分反映在DCT的右下方。由于人眼對高階部分不敏感,依靠低階部分就能基本識别出圖像内容,是以JPEG進行壓縮的時候,基本上隻存儲DCT變換後的左上部分,而右下部分則直接丢棄。
MATALAB代碼驗證:
clear;
clc;
im = imread('https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'); % 讀入圖像
figure(),
subplot(221),
imshow(im);
title('原始彩色圖像');
grayim = rgb2gray(im);
dctim = dct2(grayim);
subplot(222),
% imshow(I,[]) displays the grayscale image I scaling the display based on the range of pixel values in I.
imshow(log(abs(dctim)), []),
title('DCT變換圖像');
idctim = idct2(dctim);
subplot(223),
imshow(idctim, [])
title('DCT逆變換圖像');
subplot(224),
imshow(grayim)
title('原始灰階圖像');
運作結果: