C++實現離散余弦變換(參數為二維指針)


C++實現離散余弦變換(參數為二維指針)

寫在前面

到目前為止已經閱讀了相當一部分的網格水印等方面的論文了,但是論文的實現進度還沒有更上,這個月准備挑選一些較為經典的論文,將其中的算法實現。在實現論文的過程中,發現論文中有用到一些空域轉頻率域的算法。因此也就想到了實現一下離散余弦變換。雖然本文的代碼和網上很多已有的代碼很類似,思路都沒有太多的差別,但是本文有一個比較重要的改進。具體的說,網上現有DCT算法輸入的是一個固定的二維數組。當二維數組作為函數參數進行傳遞時,至少需要給出第二個維度的大小,否則編譯器會報錯。但是在圖形圖像處理中,當我們希望使用DCT變換把某個圖形或者圖像轉換到頻域時,可能我在調用DCT函數之前事先並不知道圖形或者圖像的規模,因此這種傳參方式較大限制了代碼的使用。本文的一個改進就是,DCT函數的參數不再是二維數組,而是傳入一個二維指針,通過手動尋址來實現函數功能。

離散余弦變換理論基礎

我想大家比較熟知的是傅立葉變換。其實離散余弦變換跟傅立葉變換差不多。二維離散余弦變換的定義由下式表示:

enter description here

反變換表示如下:
enter description here

代碼實現

根據上面的公式,很容易就能寫出代碼

// DCT - Discrete Cosine Transform void DCT( double ** input, double ** output, int row, int col ) { cout<<"Test in DCT"<<endl; double ALPHA, BETA; int u = 0; int v = 0; int i = 0; int j = 0; for(u = 0; u < row; u++) { for(v = 0; v < col; v++) { if(u == 0) { ALPHA = sqrt(1.0 / row); } else { ALPHA = sqrt(2.0 / row); } if(v == 0) { BETA = sqrt(1.0 / col); } else { BETA = sqrt(2.0 / col); } double tmp = 0.0; for(i = 0; i < row; i++) { for(j = 0; j < col; j++) { tmp += *((double*) input + col*i + j ) * cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col)); } } *((double*) output + col*u + v) = ALPHA * BETA * tmp; } } cout << "The result of DCT:" << endl; for(int m = 0; m < row; m++) { for(int n= 0; n < col; n++) { cout <<setw(8)<< *((double*) output + col*m + n)<<" \t"; } cout << endl; } } 

注意代碼中的函數參數不是二維數組,而是一個指向二維數組的指針。相應的反變換的代碼如下:

// Inverse DCT void IDCT( double ** input, double ** output, int row, int col ) { cout<<"Test in IDCT"<<endl; double ALPHA, BETA; int u = 0; int v = 0; int i = 0; int j = 0; for(i = 0; i < row; i++) { for( j = 0; j < col; j++) { double tmp = 0.0; for(u = 0; u < row; u++) { for(v = 0; v < col; v++) { if(u == 0) { ALPHA = sqrt(1.0 / row); } else { ALPHA = sqrt(2.0 / row); } if(v == 0) { BETA = sqrt(1.0 / col); } else { BETA = sqrt(2.0 / col); } tmp += ALPHA * BETA * *((double*) input + col*u + v )* cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col)); } }  *((double*) output + col*i + j) = tmp; } } cout << "The result of IDCT:" << endl; for(int m = 0; m < row; m++) { for(int n= 0; n < col; n++) { cout <<setw(8)<< *((double*) output + col*m + n)<<"\t"; } cout << endl; } } 

測試代碼

#include <iostream> #include <math.h> #include<cstdio> #include <iomanip> #include<algorithm> using namespace std; #define PI 3.1415926 int main() { int i = 0; int j = 0; int u = 0; int v = 0; const int rows = 3; const int cols = 3; double inputdata[rows][cols] = { {89,101,114}, {97,115,131}, {114,134,159}, }; double outputdata[rows][cols]; DCT( (double**)inputdata, (double**)outputdata,rows, cols ); IDCT( (double**)outputdata, (double**)inputdata,rows,cols ); system("pause"); return 0; } 

程序運行結果如下:
enter description here

小結

之后可以對代碼進行升級,不再使用二維數組作為參數傳遞,而是使用Eigen類型作為參數,這樣代碼更加清晰,並且內存管理等方面也更加方便。

 

轉載請注明出處:http://www.cnblogs.com/scut-linmaojiang/p/5013590.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM