什么是DCT?
一維DCT變換
一維DCT變換時二維DCT變換的基礎,所以我們先來討論下一維DCT變換。一維DCT變換共有8種形式,其中最常用的是第二種形式,由於其運算簡單、適用范圍廣。我們在這里只討論這種形式,其表達式如下:
其中,f(i)為原始的信號,F(u)是DCT變換后的系數,N為原始信號的點數,c(u)可以認為是一個補償系數,可以使DCT變換矩陣為正交矩陣。
其中,f(i)為原始的信號,F(u)是DCT變換后的系數,N為原始信號的點數,c(u)可以認為是一個補償系數,可以使DCT變換矩陣為正交矩陣。
二維DCT變換
二維DCT變換其實是在一維DCT變換的基礎上在做了一次DCT變換,其公式如下:
由公式我們可以看出,上面只討論了二維圖像數據為方陣的情況,在實際應用中,如果不是方陣的數據一般都是補齊之后再做變換的,重構之后可以去掉補齊的部分,得到原始的圖像信息,這個嘗試一下,應該比較容易理解。
另外,由於DCT變換高度的對稱性,在使用Matlab進行相關的運算時,我們可以使用更簡單的矩陣處理方式:
二維DCT逆變換
在圖像的接收端,根據DCT變化的可逆性,我們可以通過DCT反變換恢復出原始的圖像信息,其公式如下:
同樣的道理,我們利用之前的矩陣運算公司可以推導出DCT反變換相應的矩陣形式
對二維圖像進行離散余弦變換
由以上對二維離散余弦變換的定義及公式(7)可知,求二維圖像的離散余弦變換要進行以下步驟:
- 1.獲得圖像的二維數據矩陣f(x,y);
- 2.求離散余弦變換的系數矩陣[A];
- 3.求系數矩陣對應的轉置矩陣[A]T;
- 4.根據公式(7)[F(u,v)]=[A][f(x,y)][A]T 計算離散余弦變換;
優點
1、DCT變換較DFT變換具有更好的頻域能量聚集度(說人話就是能夠把圖像更重要的信息聚集在一塊),那么對於那些不重要的頻域區域和系數就能夠直接裁剪掉(有點像淘金,你把石頭里重要的金子都弄到一塊,剩下沒啥用的石子不就可以扔了么),因此,DCT變換非常適合於圖像壓縮算法的處理,例如現在大名鼎鼎的jpeg就是使用了DCT作為圖像壓縮算法
2、DCT變換是可分離的變換,其變換核為余弦函數。DCT除了具有一般的正交變換性質外, 它的變換陣的基向量能很好地描述人類語音信號和圖像信號的相關特征。因此,在對語音信號、圖像信號的變換中,DCT變換被認為是一種准最佳變換。
二維DFT與二維DCT的頻譜特征分析
1、細節(高頻分量)較少的圖像實驗:
Conclusion:
對於比較平滑的圖像/數據,DFT變換數據集中在中間(低頻信號區),DCT變換數據集中在左上角,幾乎無法看出DCT的優勢在哪里。
2、細節豐富的圖像實驗
Conclusion:
DCT變化后的數據很發散,DCT變化后的數據仍然比較集中。如果同樣從頻率譜恢復原始圖像,那么選用DCT更合理,因為DCT只需要存儲更少的數據點。正是這個原因,是的DCT廣泛地應用於圖像壓縮。
應用
DCT應用於圖像壓縮
16*16 進行分區做DCT變換,然后按照不同的模板進行數據存留與重建。我們會發現,如果保存的數據過少,會有塊效應現象發生。
64*64的分區設置,塊效應更明顯。此時就要在每個分區內多采集點數據。
DCT在JPEG壓縮編碼中的應用
DCT又稱離散余弦變換,是一種塊變換方式,只使用余弦函數來表達信號,與傅里葉變換緊密相關。常用於圖像數據的壓縮,通過將圖像分成大小相等(一般為8*8)的塊,利用DCT對其進行變換,得到更加簡潔的數據。因為圖像像素間存在較大的空間相關性,DCT可以大大減小這些相關性,使圖像能量集中在左上角區域,從而利於數據壓縮。變換后得到的數據稱為DCT系數。這一過程是無損的。
根據人類視覺系統理論,人眼對圖像平滑區域的變換比較敏感,而對紋理區域的變換不太敏感,經過離散余弦變換之后,圖像信息集中在少數低頻系數上,而紋理和邊緣信息則在中低頻系數中,所以低頻系數的改變對圖像視覺 上的影響遠大於高頻系數。
DCT變換將圖像信號從空間域變換到頻域,是JPEG(有損圖像數字壓縮技術)的核心步驟。
在 JPEG壓縮中,為了在圖像畫面降質不明顯的前提下獲得較高的壓縮比,保留的恰是對人眼視覺重要的低頻系數,而將大部分高頻系數變成了零, 因此 JPEG壓縮對低頻系數不敏感,而對高頻系數敏感, 將信息數據嵌入在高頻部分可能在有損壓縮中丟 失, 作為一種權衡,可以將信息嵌入在圖像的中頻系數之間
圖像經過DCT變換后,空域中的總能量在變換域中得到保持,但像素之 間的相關性下降,能量將會重新分布,由空域中所表現出的能量發散形式變換為頻域能量相對集中的形式,並集中在變換域的低頻系數上。
JPEG算法的主要計算步驟:
- 正向離散余弦變換(FDCT)
- 量化(quantization)
- Z字形編碼(zigzag scan)
- 使用差分脈沖編碼調制(differential pulse code modulation,DPCM)對直流系數(DC)進行編碼
- 使用行程長度編碼(run-length encoding,RLE)對交流系數(AC)進行編碼
- 熵編碼(entropy coding)
DCT在數字水印中的應用

水印檢測框圖:

實驗
matlab基礎
DCT變換1
%讀入測試圖像 mypicture=imread('input.jpg');%顯示讀入的圖像 %為了防止后一個顯示的圖像覆蓋前一個顯示結果,每次顯示時調用figure生成一個新窗口 figure(),imshow(mypicture),title('原輸入圖像');
圖一
轉為灰度圖:
grayImage=rgb2gray(mypicture);%如果讀入的是彩色圖像則轉化為灰度圖像(灰度圖像省略這一步) figure(),imshow(grayImage),title('原輸入彩色圖像轉化為灰度圖像');
圖二
對圖像DCT轉換:
%對圖像DCT變換 dctgrayImage=dct2(grayImage); figure(), imshow(log(abs(dctgrayImage)),[]),title('DCT變換灰度圖像'), colormap(gray(4)), colorbar;
圖三
對灰度矩陣進行量化:
%對灰度矩陣進行量化 dctgrayImage(abs(dctgrayImage)<0.1)=0;
DCT逆變換:
%DCT逆變換 I=idct2(dctgrayImage)/255; figure(), imshow(I), title('經過DCT變換,然后逆變換的灰度圖像');
圖四
對比變換傅里葉變換前后的圖像 :
%對比變換傅里葉變換前后的圖像 figure(), subplot(121), imshow(grayImage), title('原灰度圖像'), subplot(122), imshow(I), title('DCT逆變換圖像');
圖五
結果分析:對原始圖像進行離散余弦變換,如圖3所示,由結果可知,變換后DCT系數能量主要集中在左上角,其余大部分系數接近於零,這說明DCT具有適用於圖像壓縮的特性。將變換后的DCT系數進行門限操作,將小於一定值得系數歸零,這就是圖像壓縮中的量化過程,然后進行逆DCT運算,得到壓縮后的圖像,如圖4。由圖5比較變換前后的圖像,肉眼很難分辨出有什么區別,可見壓縮的效果比較理想
DCT變換2
image=imread('input.jpg'); figure; subplot(2,4,1),imshow(image),title("原圖"); grayI=rgb2gray(image); subplot(2,4,2),imshow(grayI),title("灰度圖"); DCTI=dct2(grayI); subplot(2,4,3),imshow(DCTI),title("DCT變換"); ADCTI=abs(DCT1); subplot(2,4,4),imshow(ADCTI),title("取絕對值"); top=max(ADCTI(:)); subplot(2,4,5),imshow(top),title("取最大值"); bottom=min(ADCTI(:)); subplot(2,4,6),imshow(bottom),title("取最小值"); ADCTI=(ADCTI-bottom)/(top-bottom)*100; subplot(2,4,7),imshow(ADCTI),title("量化后"); IDCTI=idct2(DCTI)/255; subplot(2,4,8),imshow(IDCTI),title("DCT逆變換");
所以,能量主要分布在左上角低頻分量處
DCT圖像壓縮
打開一幅圖像,對其進行DCT變換,將高頻置零並進行反變換
image=imread('input.jpg'); figure; subplot(2,2,1),imshow(image),title("原圖"); grayI=rgb2gray(image); subplot(2,2,2),imshow(grayI),title("灰度圖"); DCTI=dct2(grayI); subplot(2,2,3),imshow(DCTI),title("DCT變換"); [h,w]=size(DCTI); cf=60; FDCTI=zeros(h,w); FDCTI(1:cf,1:cf)=DCTI(1:cf,1:cf); gratOut=uint8(abs(idct2(FDCTI))); subplot(2,2,4),imshow(gratOut),title("壓縮重建后");
彩色圖像轉灰度圖
彩圖轉灰度圖有兩種方法:
1、使用rgb2gray()
將RGB三個分量的數值相等,輸出后就是灰度圖
2、使用ycbcr()
將Y分量提取出,YCBCR格式中的Y分量表示是圖像中的亮度和濃度,所以只需輸出Y分量,得到的就是圖像的灰度圖
具體來講:
YCbCr是通過有序的三元組來表示的,三元由Y(Luminance)、Cb(Chrominance-Blue)和Cr(Chrominance-Red)組成,其中Y表示顏色的明亮度和濃度,而Cb和Cr則分別表示顏色的藍色濃度偏移量和紅色濃度偏移量。人的肉眼對由YCbCr色彩空間編碼的視頻中的Y分量更敏感,而Cb和Cr的微小變化不會引起視覺上的不同,根據該原理,通過對Cb和Cr進行子采樣來減小圖像的數據量,使得圖像對存儲需求和傳輸帶寬的要求大大降低,從而達到在完成圖像壓縮的同時也保證了視覺上幾乎沒有損失的效果,進而使得圖像的傳輸速度更快,存儲更加方便。我們要的到灰度圖像,首先要將采集到的彩色圖像轉化為YCbCr。
這是OV7725的手冊中給出的RGB888 to YCbCr的算法公式。簡單明了,將一副圖片的RGB分量提取出來,然后用上面的公式進行運算,得到YcbCr分量,然后在合成顯示即可。這樣顯示出來的是YcbCr色彩空間的圖片,我們只取Y分量作為新的圖片的三個分量合成,得到的即是這幅彩色圖片的灰度圖。
%將一幅640*480的彩色圖片轉換成顯示成灰度顯示? clc; clear all; close all; RGB_data = imread('input.jpg');%圖像讀入 R_data = RGB_data(:,:,1); G_data = RGB_data(:,:,2); B_data = RGB_data(:,:,3); figure; subplot(1,2,1),imshow(RGB_data),title("原圖"); [ROW,COL, DIM] = size(RGB_data); %提取圖片的行列數 Y_data = zeros(ROW,COL); Cb_data = zeros(ROW,COL); Cr_data = zeros(ROW,COL); Gray_data = RGB_data; %YCbCr_data = RGB_data; for r = 1:ROW for c = 1:COL Y_data(r, c) = 0.299*R_data(r, c) + 0.587*G_data(r, c) + 0.114*B_data(r, c); Cb_data(r, c) = -0.172*R_data(r, c) - 0.339*G_data(r, c) + 0.511*B_data(r, c) + 128; Cr_data(r, c) = 0.511*R_data(r, c) - 0.428*G_data(r, c) - 0.083*B_data(r, c) + 128; end end Gray_data(:,:,1)=Y_data; Gray_data(:,:,2)=Y_data; Gray_data(:,:,3)=Y_data; subplot(1,2,2),imshow(Gray_data),title("YCBCR轉灰度圖");
DCT分塊變換
1、使用dct2()
% 讀取灰度圖像 img = imread('huidu.jpg'); % dct2 是2維dct變換函數,得到一個與圖像大小相同的二維矩陣 dct_mtx = dct2(img); % idct2 是逆2維dct變換函數,得到原圖像矩陣 img_idct = idct2(dct_mtx)/255; figure; subplot(1,3,1),imshow(img),title("原圖"); subplot(1,3,2),imshow(dct_mtx),title("DCT變換"); subplot(1,3,3),imshow(img_idct),title("DCT還原");
2、使用dctmtx()
io = double(imread("huidu.jpg")); T = dctmtx(8); % 對載體圖像進行DCT變換 DCT_org = blkproc(io,[8 8], 'P1*x*P2',T, T'); % 對DCT 矩陣進行逆變換 DCT_reverse = blkproc(DCT_org,[8 8], 'P1*x*P2',T', T); figure; subplot(1,3,1),imshow(io),title("原圖"); subplot(1,3,2),imshow(DCT_org),title("DCT分塊變換"); subplot(1,3,3),imshow(DCT_reverse),title("DCT分塊還原");
DCT可逆信息隱藏
原理:利用DCT變換的矩陣進行操作,有很多種方法,這里舉出其中一種方法【原始圖像有損,提取信息無損】
隱藏方法:主要是利用載體中兩個特定數的相對大小來表示隱藏信息。發送方和接收方事先約定好嵌入過程中所使用的兩個DCT系數的位置(為了隱藏的健壯性和不可覺察性,這兩個 DCT 系數應該在 DCT 的中頻系數中選擇)。例如,設定(u,v) 和 (m,n) 為所選定的兩個系數的坐標。嵌入過程為:如果Bi(u,v)> Bi(m,n) ,就代表隱藏信息“1”,如果 Bi(u,v)< Bi(m,n) 就代表 隱 藏 信 息“0”。
如 果 需 要 隱 藏 的 信 息 位 為 1,但 是Bi(u,v)<Bi(m,n) 那么就把這兩個系數交換,最后發送方通過二維逆DCT變換將圖像轉化為空間域進行傳輸。
提取方法:接收方接收到圖像后,對圖像進行二維DCT變換,通過比較每一塊中約定位置的DCT系數的相對大小,得到隱藏信息的比特串,從而提取出秘密信息。
% DCT 變換信息隱藏 io = imread("huidu.jpg"); figure; subplot(1,3,1),imshow(io),title("原圖"); io = double(io); % 待嵌入的秘密信息msg msg = [1,0,1,1]; % 用於計數,嵌入完成后停止操作。 count = length(msg); org_msg = [1,0,1,1]; T = dctmtx(8); %圖像分塊8*8 DCTrgb = blkproc(io,[8 8], 'P1*x*P2',T, T'); % 對載體圖像進行DCT變換 subplot(1,3,2),imshow(DCTrgb),title("DCT分塊變換"); [row,col]=size(DCTrgb); row=floor(row/8); col=floor(col/8); alpha=0.02; k = 1; temp=0; for i=0:(row - 1) for j=0: (col -1) irow = i * 8; jcol = j * 8; if k <= count if msg(k) == 0 %選擇(5,2),(4,3)這兩對系數, % 策略是(5,2)的DCT系數 < (4,3)時,表示嵌入了0 % 如果(5,2) > (4,3) 那我們把兩個系數交換,還表示嵌入了0 if DCTrgb(irow + 5, jcol + 2) < DCTrgb(irow + 4,jcol + 3) temp = DCTrgb(irow + 5, jcol + 2); DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow + 4,jcol + 3); DCTrgb(irow + 4, jcol + 3) = temp; end else if DCTrgb(irow + 5, jcol + 2) > DCTrgb(irow + 4,jcol + 3) temp = DCTrgb(irow + 5, jcol + 2); DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow + 4,jcol + 3); DCTrgb(irow + 4, jcol + 3) = temp; end end %將原本小的系數變的更小,使系數差變大 if DCTrgb(irow + 5, jcol + 2) < DCTrgb(irow + 4,jcol +3) DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow +5, jcol +2) - alpha; else DCTrgb(irow + 4, jcol + 3) = DCTrgb(irow + 4, jcol +3) - alpha; end k = k + 1; end end end wi=blkproc(DCTrgb,[8 8],'P1*x*P2',T',T); %嵌入信息的載體DCT變換,恢復圖像 orgin_wi=wi/255; subplot(1,3,3),imshow(orgin_wi),title("嵌入信息后的"); % 提取消息 % ext_msg是提取出的秘密信息 ext_msg = []; T=dctmtx(8); DCTcheck=blkproc(wi,[8 8],'P1*x*P2',T,T'); %對隱秘圖像進行DCT變換 [row,col]=size(DCTcheck); row=floor(row/8); col=floor(col/8); k = 1; for i=0:(row - 1) for j=0: (col -1) irow = i * 8; jcol = j * 8; %通過比較(5,2),(4,3)這兩對系數,判斷隱藏的信息是1還是0 if k <= count if DCTcheck(irow + 5, jcol + 2) < DCTcheck(irow + 4,jcol + 3) ext_msg(k,1)=1; end if DCTcheck(irow + 5, jcol + 2) > DCTcheck(irow + 4,jcol + 3) ext_msg(k,1)=0; end k = k + 1; end end end fprintf("嵌入的信息:"); disp(msg); fprintf("提取的信息:"); disp(ext_msg);
參考
1、百度百科
2、知乎
5、Matlab實現