DCT快速變換 下載源代碼 DCT變換是數字圖像處理中重要的變換,很多重要的圖像算法、圖像應用都是基於DCT變換的,如JPEG圖像編碼方式。對於大尺寸的二維數值矩陣,倘若採用普通的DCT變換來進行,其所花費的時間將是讓人難以忍受甚至無法達到實用。而要克服這一難點,DCT變換的快速算法無非是非常吸引人的。 就目前而言,DCT變換的快速算法無非有以下兩種方式: 1.由於FFT算法的普便採用,直接利用FFT來實現DCT變換的快速算法相比來說就相對容易。但是此種方法也有不足:計算過程會涉及到複數的運算。由於DCT變換前後的數據都是實數,計算過程中引入複數,而一對複數的加法相當於兩對實數的加法,一對複數的乘法相當於四對實數的乘法和兩對實數的加法,顯然是增加了運算量,也給硬件存儲提出了更高的要求。 2.直接在實數域進行DCT快速變換。顯然,這種方法相比於前一種而言,計算量和硬件要求都要優於前者。 鑑於此,本文采用第二種方法來實現DCT變換的快速算法。 限於篇幅,在此不能羅列,具體推導過程可參見《DCT快速新算法及濾波器結構研究與子波變換域圖像降噪研究》華南理工大學博士論文。 三、程序實現 DCT快速變換 void initDCTParam(int deg) { // deg 爲DCT變換數據長度的冪 if(bHasInit) { return; //不用再計算查找表 } int total, halftotal, i, group, endstart, factor; total = 1 << deg; if(C != NULL) delete []C; C = (double *)new double[total]; halftotal = total >> 1; for(i=0; i < halftotal; i++) C[total-i-1]=(double)(2*i+1); for(group=0; group < deg-1; group++) { endstart=1 << (deg-1-group); int len = endstart >> 1; factor=1 << (group+1); for(int j = 0;j < len; j++) C[endstart-j-1] = factor*C[total-j-1]; } for(i=1; i < total; i++) C[i] = 2.0*cos(C[i]*PI/(total << 1)); ///C[0]空着,沒使用 bHasInit=true; }DCT變換過程可分爲兩部分:前向追底和後向回根 前向追底: void dct_forward(double *f,int deg) { // f中存儲DCT數據 int i_deg, i_halfwing, total, wing, wings, winglen, halfwing; double temp1,temp2; total = 1 << deg; for(i_deg = 0; i_deg < deg; i_deg++) { wings = 1 << i_deg; winglen = total >> i_deg; halfwing = winglen >> 1; for(wing = 0; wing < wings; wing++) { for(i_halfwing = 0; i_halfwing < halfwing; i_halfwing++) { temp1 = f[wing*winglen+i_halfwing]; temp2 = f[(wing+1)*winglen-1-i_halfwing]; if(wing%2) swap(temp1,temp2); // 交換temp1與temp2的值 f[wing*winglen+i_halfwing] = temp1+temp2; f[(wing+1)*winglen-1-i_halfwing] = (temp1-temp2)*C[winglen-1-i_halfwing]; } } } }後向回根: void dct_backward(double *f,int deg) { // f中存儲DCT數據 int total,i_deg,wing,wings,halfwing,winglen,i_halfwing,temp1,temp2; total = 1 << deg; for(i_deg = deg-1; i_deg >= 0; i_deg--) { wings = 1 << i_deg; winglen = 1 << (deg-i_deg); halfwing = winglen >> 1; for(wing = 0; wing < wings; wing++) { for(i_halfwing = 0; i_halfwing < halfwing; i_halfwing++) { //f[i_halfwing+wing*winglen] = f[i_halfwing+wing*winglen]; if(i_halfwing == 0) { f[halfwing+wing*winglen+i_halfwing] = 0.5*f[halfwing+wing*winglen+i_halfwing]; } else { temp1=bitrev(i_halfwing,deg-i_deg-1); // bitrev爲位反序 temp2=bitrev(i_halfwing-1,deg-i_deg-1); // 第一參數爲要變換的數 // 第二參數爲二進制長度 f[halfwing+wing*winglen+temp1] = f[halfwing+wing*winglen+temp1]-f[halfwing+wing*winglen+temp2]; } } } } }位反序函數如下: int bitrev(int bi,int deg) { int j = 1, temp = 0, degnum, halfnum; degnum = deg; //if(deg<0) return 0; if(deg == 0) return bi; halfnum = 1 << (deg-1); while(halfnum) { if(halfnum&bi) temp += j; j<<=1; halfnum >>= 1; } return temp; }完整實現一維DCT變換: void fdct_1D_no_param(double *f,int deg) { initDCTParam(deg); dct_forward(f,deg); dct_backward(f,deg); fbitrev(f,deg); // 實現位反序排列 f[0] = 1/(sqrt(2.0))*f[0]; } void fdct_1D(double *f,int deg) { fdct_1D_no_param(f,deg); int total = 1 << deg; double param = sqrt(2.0/total); for(int i = 0; i < total; i++) f[i] = param*f[i]; }利用一維DCT變換來實現二維DCT變換: void fdct_2D(double *f,int deg_row,int deg_col) { int rows,cols,i_row,i_col; double two_div_sqrtcolrow; rows=1 << deg_row; cols=1 << deg_col; init2D_Param(rows,cols); two_div_sqrtcolrow = 2.0/(sqrt(double(rows*cols))); for(i_row = 0; i_row < rows; i_row++) { fdct_1D_no_param(f+i_row*cols,deg_col); } for(i_col = 0; i_col < cols; i_col++) { for(i_row = 0; i_row < rows; i_row++) { temp_2D[i_row] = f[i_row*cols+i_col]; } fdct_1D_no_param(temp_2D, deg_row); for(i_row = 0; i_row < rows; i_row++) { f[i_row*cols+i_col] = temp_2D[i_row]*two_div_sqrtcolrow; } } bHasInit = false; } IDCT快速變換 初始化查找表: void initIDCTParam(int deg) { if(bHasInit) return; //不用再計算查找表 int total, halftotal, i, group, endstart, factor; total = 1 << deg; // if(C!=NULL) delete []C; // C=(double *)new double[total]; // 由於正變換已經爲C申請了空間,所以逆變換就需再申請空間了! halftotal = total >> 1; for(i = 0; i < halftotal; i++) C[total-i-1] = (double)(2*i+1); for(group = 0; group < deg-1; group++) { endstart = 1 << (deg-1-group); int len = endstart>>1; factor = 1 << (group+1); for(int j = 0; j < len; j++) C[endstart-j-1] = factor*C[total-j-1]; } for(i = 1; i < total; i++) C[i] = 1.0/(2.0*cos(C[i]*PI/(total << 1))); // C[0]空着沒用 bHasInit=true; }IDCT變換過程也可分爲兩部分:前向追底和後向回根 前向追底 void idct_forward(double *F,int deg) { int total,i_deg,wing,wings,halfwing,winglen,i_halfwing,temp1,temp2; total = 1 << deg; for(i_deg = 0; i_deg < deg; i_deg++) { wings = 1 << i_deg; winglen = 1 << (deg-i_deg); halfwing = winglen >> 1; for(wing = 0; wing < wings; wing++) { for(i_halfwing = halfwing-1; i_halfwing >= 0; i_halfwing--) { if(i_halfwing == 0) { F[halfwing+wing*winglen+i_halfwing] = 2.0*F[halfwing+wing*winglen+i_halfwing]; } else { temp1 = bitrev(i_halfwing,deg-i_deg-1); temp2 = bitrev(i_halfwing-1,deg-i_deg-1); F[halfwing+wing*winglen+temp1] = F[halfwing+wing*winglen+temp1] +F[halfwing+wing*winglen+temp2]; } } } } }後向回根 void idct_backward(double *F, int deg) { int i_deg,i_halfwing,total,wing,wings,winglen,halfwing; double temp1, temp2; total = 1 << deg; for(i_deg = deg-1; i_deg >= 0; i_deg--) { wings = 1 << i_deg; winglen = total >> i_deg; halfwing = winglen >> 1; for(wing = 0; wing < wings; wing++) { for(i_halfwing = 0; i_halfwing < halfwing; i_halfwing++) { temp1 = F[wing*winglen+i_halfwing]; temp2 = F[(wing+1)*winglen-1-i_halfwing]*C[winglen-1-i_halfwing]; if(wing % 2) { F[wing*winglen+i_halfwing] = (temp1-temp2)*0.5; F[(wing+1)*winglen-1-i_halfwing] = (temp1+temp2)*0.5; } else { F[wing*winglen+i_halfwing] = (temp1+temp2)*0.5; F[(wing+1)*winglen-1-i_halfwing] = (temp1-temp2)*0.5; } } } } }完整實現一維IDCT變換: void fidct_1D_no_param(double *F, int deg) { initIDCTParam(deg); F[0] = F[0]*sqrt(2.0); fbitrev(F, deg); idct_forward(F, deg); idct_backward(F, deg); } void fdct_1D(double *f, int deg) { fdct_1D_no_param(f, deg); int total = 1 << deg; double param = sqrt(2.0/total); for(int i = 0; i < total; i++) f[i] = param*f[i]; }利用一維IDCT變換來實現二維IDCT變換: void fidct_2D(double *F, int deg_row, int deg_col) { int rows,cols,i_row,i_col; double sqrtcolrow_div_two; rows = 1 << deg_row; cols = 1 << deg_col; init2D_Param(rows,cols); sqrtcolrow_div_two = (sqrt(double(rows*cols)))/2.0; for(i_row = 0; i_row < rows; i_row++) { fidct_1D_no_param(F+i_row*cols,deg_col); } for(i_col = 0; i_col < cols; i_col++) { for(i_row = 0; i_row < rows; i_row++) { temp_2D[i_row] = F[i_row*cols+i_col]; } fidct_1D_no_param(temp_2D, deg_row); for(i_row = 0; i_row < rows; i_row++) { F[i_row*cols+i_col] = temp_2D[i_row]*sqrtcolrow_div_two; } } bHasInit=false; }多線程的考量由於DCT變換要花費一定的時間,特別是在數據矩陣尺寸比較大的時候。此時,如果沒有增加一個線程來執行DCT變換,操作界面可能因程序忙於DCT變換的計算而失去響應,所以,增加一個用來進行DCT變換的線程是十分必要的。 首先定義一個結構 typedef struct { int row; int col; double *data; //double *data2; //double *data3; // 在計算彩色圖象的數據矩陣時,彩色圖象用RGB三個分量 bool m_bfinished; DWORD m_start,m_end; //以毫秒計,用來計算DCT變換所用的時間; }RUNINFO;DCT變換進程函數: UINT ThreadProcfastDct(LPVOID pParam) { RUNINFO *pinfo = (RUNINFO*)pParam; pinfo->m_start = ::GetTickCount(); fdct_2D((double *)pinfo->data, GetTwoIndex(pinfo->row), GetTwoIndex(pinfo->col)); pinfo->m_end = ::GetTickCount(); pinfo->m_bfinished = true; return 1; }IDCT變換進程函數: UINT ThreadProcfastIDct(LPVOID pParam) { RUNINFO *pinfo = (RUNINFO*)pParam; pinfo->m_start = ::GetTickCount(); fidct_2D((double *)pinfo->data, GetTwoIndex(pinfo->row), GetTwoIndex(pinfo->col)); pinfo->m_end = ::GetTickCount(); pinfo->m_bfinished = true; return 1; }
|
DCT快速變換
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.