2020-05-2213:57:51
變換編碼就是換一種表示方式來表示原始數據,或者說在不同於原始空間的變換空間中來描述原始數據,以使數據獲得某些特點,這些特點有助於獲得更好的編碼效果。
變換編碼原理:
盡管圖像變換本身並不帶來數據壓縮,但由於變換后系數之間的相關性明顯降低,圖像的大部分能量只集中到少數幾個變換系數上,采用適當的量化和熵編碼可以有效地壓縮圖像的數據量。 圖像經某些變換后,系數的空間分布和頻率特性有可能與人眼的視覺特性匹配,因此可以利用人類視覺系統的生理和心理特點來得到較好的編碼系統。
變換編碼通常是將空間域相關的像素點通過正交變換映射到頻域上,使變換后的系數之間的相關性降低。 數據變換后在頻域上應滿足: 所有的系數相互獨立; 能量集中在少數幾個系數上; 這些系數集中在一個最小的區域內。
變換的意義:
是有失真編碼中應用最廣泛的一類編碼方法,與預測編碼一樣,均為通過去除信源序列的相關性來達到數據壓縮的目的。 與預測編碼的不同之:預測編碼是在空間域或時間域內進行的,而變換編碼則是在變換域(頻率域)內進行的。
映射變換的方法很多,一般是指函數變換法,而常用的是正交變換法。 可以使函數的某些特性變得明顯,使問題的處理得到簡化。 在圖像數據壓縮技術中,正交變換編碼(以下簡稱變換編碼)與預測編碼一起成為最基本的兩種編碼方法。 人們最熟悉的是傅里葉變換(FT)、K - L 變換、離散余弦變換(DCT) 、小波變換(WT)。

二維離散余弦編碼:
核函數為:

由於DCT 變換構成的基向量與圖像具體內容無關,且變換是可分離的,故可通過兩個一維DCT 變換得到二維DCT 變換。 即先對圖像的每一行進行一維DCT 變換,再對每一列進行一維DCT 變換。 二維離散IDCT 也可以通過兩次一維IDCT 得到。 DCT 有快速算法,使得運算的復雜度大大降低,從而減少了編解碼延遲。

應用舉例 :
編碼 某個圖象的一個8*8方塊的亮度值。

int a[8][8] = { {52,55,61,66,70,61,64,73}, {63,59,55,90,109,85,69,72}, {62,59,68,113,144,104,66,73}, {63,58,71,122,154,106,70,69}, {67,61,68,104,126,88,68,70}, {79,65,60,70,77,68,58,75}, {85,71,64,59,55,61,65,83}, {87,79,69,68,65,76,78,94} };
由於一個字節是0~255,為了減小絕對值波動,先把數值移位一下,變成-128~127。

//循環定義b矩陣 for (x = 0; x < r; x++){ for (y = 0; y < c; y++) { b[x][y] = 128; } } //數組移位 for (x = 0; x < r; x++){ for (y = 0; y < c; y++) { g[x][y] = a[x][y] - b[x][y]; } }
接着,根據DCT變換公式,各種計算,獲得臨時結果。 (下公式中去掉1/4計算)


for (u = 0; u < r; u++){ for (v = 0; v < c; v++) { double cos_product = 0.; if (u == 0) { a_u = 1. / sqrt((double)r); } else { a_u = sqrt(2. / (double)r); } if (v == 0) { a_v = 1. / sqrt((double)r); } else { a_v = sqrt(2. / (double)r); } /*printf("a_u:\n"); printf("%3.2f ", a_u); if (v == c - 1) printf("\n");*/ for (x = 0; x < r; x++) for (y = 0; y < c; y++) { cos_product += (double)g[x][y] * cos(((2. * (double)x + 1.) * (double)u * pai) / (2. * (double)r)) * cos(((2. * (double)y + 1.)* (double)v * pai) / (2. * (double)r)); } G[u][v] = a_u * a_v * cos_product; } } printf("\nDCT變換后矩陣G:\n\n"); for (u = 0; u < r; u++){ for (v = 0; v < c; v++) { printf("%9.2f ", G[u][v]); if (v == c - 1) printf("\n"); } }
根據亮度量化系數矩陣

獲得量化結果:(上一頁表G除以上面的表Q,四舍五入)

int B[8][8], Q[8][8] = { {16,11,10,16,24,40,51,61}, {12,12,14,19,26,58,60,55}, {14,13,16,24,40,57,69,56}, {14,17,22,29,51,87,80,62}, {18,22,37,56,68,109,103,77}, {24,35,55,64,81,104,113,92}, {49,64,78,87,103,121,120,101}, {72,92,95,98,112,100,103,99} }; printf("\n亮度化后矩陣B:\n\n"); for (x = 0; x < r; x++) { for (y = 0; y < c; y++) { B[x][y] = round(G[x][y] / Q[x][y]);//round�������������� printf("%6d ", B[x][y]); if (y == c - 1) printf("\n"); } }
可見,新的數據,很小,很多是0。這么多0,完全可以用游程編碼,大大縮小數據量。
解碼:
先游程編碼恢復,然后,根據量化表,恢復得到

再根據反離散余弦變換的公式: (下公式中去掉1/4計算)


再右移127,恢復原始數據。

源代碼放在github上 https://github.com/C-O-L/DCT-IDCT
