天天看點

二維DCT變換

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('原始灰階圖像');      

運作結果:

二維DCT變換

參考文獻