一、引言
DCT變換的全稱是離散餘弦變換(Discrete Cosine Transform),主要用于将資料或圖像的壓縮,能夠将空域的信号轉換到頻域上,具有良好的去相關性的性能。DCT變換本身是無損的,但是在圖像編碼等領域給接下來的量化、哈弗曼編碼等創造了很好的條件,同時,由于DCT變換時對稱的,是以,我們可以在量化編碼後利用DCT反變換,在接收端恢複原始的圖像資訊。DCT變換在目前的圖像分析已經壓縮領域有着極為廣大的用途,我們常見的JPEG靜态圖像編碼以及MJPEG、MPEG動态編碼等标準中都使用了DCT變換。
二、一維DCT變換
一維DCT變換時二維DCT變換的基礎,是以我們先來讨論下一維DCT變換。一維DCT變換共有8種形式,其中最常用的是第二種形式,由于其運算簡單、适用範圍廣。我們在這裡隻讨論這種形式,其表達式如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIWZ3FyZuBnLi5UTy0WevwVbvNmLs92bjlWd05iMn1Wavw1LcpDc0RHaiojIsJye.png!web)
其中,f(i)為原始的信号,F(u)是DCT變換後的系數,N為原始信号的點數,c(u)可以認為是一個補償系數,可以使DCT變換矩陣為正交矩陣。
三、二維DCT變換
二維DCT變換其實是在一維DCT變換的基礎上在做了一次DCT變換,其公式如下:
由公式我們可以看出,上面隻讨論了二維圖像資料為方陣的情況,在實際應用中,如果不是方陣的資料一般都是補齊之後再做變換的,重構之後可以去掉補齊的部分,得到原始的圖像資訊,這個嘗試一下,應該比較容易了解。
另外,由于DCT變換高度的對稱性,在使用Matlab進行相關的運算時,我們可以使用更簡單的矩陣處理方式:
接下來利用Matlab對這個過程進行仿真處理:
1 clear;
2 clc;
3 X=round(rand(4)*100) %産生随機矩陣
4 A=zeros(4);
5 for i=0:3
6 for j=0:3
7 if i==0
8 a=sqrt(1/4);
9 else
10 a=sqrt(2/4);
11 end
12 A(i+1,j+1)=a*cos(pi*(j+0.5)*i/4);
13 end
14 end
15 Y=A*X*A' %DCT變換
16 YY=dct2(X) %Matlab自帶的dct變換
運作結果為:
1 X =
2
3 42 66 68 66
4 92 4 76 17
5 79 85 74 71
6 96 93 39 3
7
8
9 Y =
10
11 242.7500 48.4317 -9.7500 23.5052
12 -12.6428 -54.0659 7.4278 22.7950
13 -6.2500 10.7158 -19.7500 -38.8046
14 40.6852 -38.7050 -11.4653 -45.9341
15
16
17 YY =
18
19 242.7500 48.4317 -9.7500 23.5052
20 -12.6428 -54.0659 7.4278 22.7950
21 -6.2500 10.7158 -19.7500 -38.8046
22 40.6852 -38.7050 -11.4653 -45.9341
由上面的結果我們可以看出,我們采用的公式的方法和Matlab自帶的dct變化方法結果是一緻的,是以驗證了我們方法的正确性。
如果原始信号是圖像等相關性較大的資料的時候,我們可以發現在變換之後,系數較大的集中在左上角,而右下角的幾乎都是0,其中左上角的是低頻分量,右下角的是高頻分量,低頻系數展現的是圖像中目标的輪廓和灰階分布特性,高頻系數展現的是目标形狀的細節資訊。DCT變換之後,能量主要集中在低頻分量處,這也是DCT變換去相關性的一個展現。
之後在量化和編碼階段,我們可以采用“Z”字形編碼,這樣就可以得到大量的連續的0,這大大簡化了編碼的過程。
四、二維DCT反變換
在圖像的接收端,根據DCT變化的可逆性,我們可以通過DCT反變換恢複出原始的圖像資訊,其公式如下:
同樣的道理,我們利用之前的矩陣運算公司可以推導出DCT反變換相應的矩陣形式:
下面我們用Matlab對這個過程進行仿真:
1 clear;
2 clc;
3 X=[
4 61 19 50 20
5 82 26 61 45
6 89 90 82 43
7 93 59 53 97] %原始的資料
8 A=zeros(4);
9 for i=0:3
10 for j=0:3
11 if i==0
12 a=sqrt(1/4);
13 else
14 a=sqrt(2/4);
15 end
16 A(i+1,j+1)=a*cos(pi*(j+0.5)*i/4); %生成變換矩陣
17 end
18 end
19 Y=A*X*A' %DCT變換後的矩陣
20 X1=A'*Y*A %DCT反變換恢複的矩陣
運作結果為:
1 X =
2
3 61 19 50 20
4 82 26 61 45
5 89 90 82 43
6 93 59 53 97
7
8
9 Y =
10
11 242.5000 32.1613 22.5000 33.2212
12 -61.8263 7.9246 -10.7344 30.6881
13 -16.5000 -14.7549 22.5000 -6.8770
14 8.8322 16.6881 -35.0610 -6.9246
15
16
17 X1 =
18
19 61.0000 19.0000 50.0000 20.0000
20 82.0000 26.0000 61.0000 45.0000
21 89.0000 90.0000 82.0000 43.0000
22 93.0000 59.0000 53.0000 97.0000
我們可以看到反變換後無損的恢複了原始資訊,是以證明了方法的正确性。但是在實際過程中,需要量化編碼或者直接舍棄高頻分量等處理,是以會出現一定程度的誤差,這個是不可避免的。
五、分塊DCT變換
在實際的圖像進行中,DCT變換的複雜度其實是比較高的,是以通常的做法是,将圖像進行分塊,然後在每一塊中對圖像進行DCT變換和反變換,在合并分塊,進而提升變換的效率。具體的分塊過程中,随着子塊的變大,算法複雜度急速上升,但是采用較大的分塊會明顯減少圖像分塊效應,是以,這裡面需要做一個折中,在通常使用時,大都采用的是8*8的分塊。
Matlab的 blkproc 函數可以幫我們很友善的進行分塊處理,下面給出我們的處理過程:
1 clear;
2 clc;
3
4 X=imread('pepper.bmp');
5 X=double(X);
6 [a,b]=size(X);
7 Y=blkproc(X,[8 8],'dct2');
8 X1=blkproc(Y,[8 8],'idct2');
9
10 figure
11 subplot(1,3,1);
12 imshow(uint8(X));
13 title('原始圖');
14
15 subplot(1,3,2);
16 imshow(uint8(Y));
17 title('分塊DCT變換圖');
18
19 subplot(1,3,3);
20 imshow(uint8(X1));
21 title('分塊DCT恢複圖');
22
23 Y1=dct2(X);
24 X10=idct2(Y1);
25
26 figure
27 subplot(1,3,1);
28 imshow(uint8(X));
29 title('原始圖');
30
31 subplot(1,3,2);
32 imshow(uint8(Y1));
33 title('DCT變換圖');
34
35 subplot(1,3,3);
36 imshow(uint8(X10));
37 title('DCT反變換恢複圖');
運作結果為:
從圖中,我們可以明顯看出DCT變換與分塊DCT變換在使用時的差別。
六、小結
DCT、DWT等是圖像處理的基礎知識,之前一直有用到,但是沒怎麼好好整理下,今天在做稀疏編碼的時候正好有用到,就順便整了下,希望能夠給後來者一些提示。