离散傅里叶变换和离散余弦变换公式如下:
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------编程实现-----------------------------------------------------------------------------------------------
可以通过以下3种方式实现:
1. 按照公式定义来编程计算
2. 采用蝶形运算来编程实现
3. 调用现成的fftw算法来实现
对于第1,2两种方法,有很多资料介绍,对于需要快速开发的程序,则可直接调用fftw函数库实现,据说该库函数计算傅里叶变换是全地球最快的。
FFTW中文参考: http://blog.csdn.net/congwulong/article/details/7576012
下面代码是调用fftw的一个示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include "fftw3.h" #pragma comment(lib,"libfftw3-3.lib") //#pragma comment(lib,"libfftw3l-3.lib") //#pragma comment(lib,"libfftw3f-3.lib") int main() //DCT测试 { int M=3; int N=3; // int M=4; // int N=4; double *in; double *out; double In[3][3]={{0,2,4},{6,1,3},{5,7,4}}; // float In[4][4] = { {20,2,4,7}, {6,1,3,8}, {5,7,4,0}, {11,2,12,17} }; fftw_plan p; in = (double*)malloc(sizeof(double)*M*N); out = (double*)malloc(sizeof(double)*M*N); //-------------- DCT: in --------------------- double sum=0; printf("in[][]:\n"); for(int i=0; i<M; i++) { for(int j=0; j<N; j++) { in[i*M+j] = In[i][j]; sum += In[i][j]; printf("in[%d][%d]=%.6f; ",i,j,in[i*M+j]); } printf("\n"); } printf("\n"); printf("mean = %f/%d = %f;\n\n",sum,M*N,sum/(M*N)); p = fftw_plan_r2r_2d(M, N, in, out, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE); fftw_execute(p); // repeat as needed //--------------DCT: out--------------------- printf("DCT: out[][]:\n"); for(int i=0; i<M; i++) { for(int j=0; j<N; j++) { double s = out[i*M+j]; //fftw_plan_r2r_2d 得出的结果不是标准的DCT结果,即系数没有归一化 s /= M * 2; if(i==0 || j==0) { s /= sqrt(2.0); } if(i==0 && j==0) { s /= sqrt(2.0); } printf("out[%d][%d]=%.6f=%.6f; ",i,j,out[i*M+j],s); } printf("\n"); } printf("\n"); //--------------IDCT: out------------------------------ p = fftw_plan_r2r_2d(M, N, out, in, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE); fftw_execute(p); // repeat as needed printf("IDCT: in[][]:\n"); for(int i=0; i<M; i++) { for(int j=0; j<N; j++) { printf("in[%d][%d]=%.6f; ",i,j,in[i*M+j]/(4*M*N)); } printf("\n"); } printf("\n"); fftw_destroy_plan(p); free(in); free(out); system("pause"); return 0; } /* 示例1: (注意:fftw的dct结果并不是按照标准的dct定义来的,而matlab的结果是按照标准dct定义计算的, 只需将fftw结果的所有系数除以sqrt(M*N),以及第一行和第一列再除以sqrt(2.0)就和matlab结果一样了) in[][]: in[0][0]=0.000000; in[0][1]=2.000000; in[0][2]=4.000000; in[1][0]=6.000000; in[1][1]=1.000000; in[1][2]=3.000000; in[2][0]=5.000000; in[2][1]=7.000000; in[2][2]=4.000000; mean = 32.000000/9 = 3.555556; DCT: out[][]: out[0][0]=128.000000=10.666667; out[0][1]=0.000000=0.000000; out[0][2]=4.000000=0.471405; out[1][0]=-34.641016=-4.082483; out[1][1]=-15.000000=-2.500000; out[1][2]=8.660254=1.443376; out[2][0]=4.000000=0.471405; out[2][1]=-15.588457=-2.598076; out[2][2]=-19.000000=-3.166667; IDCT: in[][]: in[0][0]=0.000000; in[0][1]=2.000000; in[0][2]=4.000000; in[1][0]=6.000000; in[1][1]=1.000000; in[1][2]=3.000000; in[2][0]=5.000000; in[2][1]=7.000000; in[2][2]=4.000000; */ /* 示例2: (注意:fftw的dct结果并不是按照标准的dct定义来的,而matlab的结果是按照标准dct定义计算的, 只需将fftw结果的所有系数除以sqrt(M*N),以及第一行和第一列再除以sqrt(2.0)就和matlab结果一样了) in[][]: in[0][0]=20.000000; in[0][1]=2.000000; in[0][2]=4.000000; in[0][3]=7.000000; in[1][0]=6.000000; in[1][1]=1.000000; in[1][2]=3.000000; in[1][3]=8.000000; in[2][0]=5.000000; in[2][1]=7.000000; in[2][2]=4.000000; in[2][3]=0.000000; in[3][0]=11.000000; in[3][1]=2.000000; in[3][2]=12.000000; in[3][3]=17.000000; mean = 109.000000/16 = 6.812500; DCT: out[][]: out[0][0]=436.000000=27.250000; out[0][1]=20.117110=1.778118; out[0][2]=110.308658=9.750000; out[0][3]=55.958037=4.946038; out[1][0]=-30.198196=-2.669169; out[1][1]=63.355339=7.919417; out[1][2]=35.610157=4.451270; out[1][3]=2.526912=0.315864; out[2][0]=115.965512=10.250000; out[2][1]=-3.618595=-0.452324; out[2][2]=62.000000=7.750000; out[2][3]=38.300206=4.787526; out[3][0]=-21.167640=-1.870973; out[3][1]=62.526912=7.815864; out[3][2]=-34.233269=-4.279159; out[3][3]=-7.355339=-0.919417; IDCT: in[][]: in[0][0]=20.000000; in[0][1]=2.000000; in[0][2]=4.000000; in[0][3]=7.000000; in[1][0]=6.000000; in[1][1]=1.000000; in[1][2]=3.000000; in[1][3]=8.000000; in[2][0]=5.000000; in[2][1]=7.000000; in[2][2]=4.000000; in[2][3]=-0.000000; in[3][0]=11.000000; in[3][1]=2.000000; in[3][2]=12.000000; in[3][3]=17.000000; */
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <opencv/cv.h> int main() //DCT测试 { int M = 4; int N = 4; float data0[] = { 20,2,4,7, 6,1,3,8, 5,7,4,0, 11,2,12,17 }; float data1[] = { 20,2,4,7, 6,1,3,8, 5,7,4,0, 11,2,12,17 }; float data2[] = { 20,2,4,7, 6,1,3,8, 5,7,4,0, 11,2,12,17 }; CvMat a, b, c; a = cvMat(M,N,CV_32FC1,data0); b = cvMat(M,N,CV_32FC1,data1); c = cvMat(M,N,CV_32FC1,data2); CvMat *d = cvCreateMat(M, N, CV_32FC1); for(int i=0; i<M; i++) { for(int j=0; j<N; j++) { cvmSet(d, i, j, 0); } } cvDCT(&a, &b, CV_DXT_FORWARD); //离散余弦正变换 cvDCT(&b, &c, CV_DXT_INVERSE); //离散余弦反变换 int row = a.rows; int col = a.cols; //---------------- a ------------------------------ printf("--------------- a --------------------\n"); for(int i=0; i<row; i++) { for(int j=0; j<col; j++) { printf("a[%d,%d]=%.2f; ",i,j,cvmGet(&a,i,j)); } printf("\n"); } //---------------- b ------------------------------ printf("--------------- b --------------------\n"); for(int i=0; i<row; i++) { for(int j=0; j<col; j++) { printf("b[%d,%d]=%.2f; ",i,j,cvmGet(&b,i,j)); } printf("\n"); } //---------------- c ------------------------------ printf("--------------- c --------------------\n"); for(int i=0; i<row; i++) { for(int j=0; j<col; j++) { printf("c[%d,%d]=%.2f; ",i,j,cvmGet(&c,i,j)); } printf("\n"); } return 0;<pre name="code" class="cpp">} /* 可以看出OpenCV的DCT变换是按照离散余弦变换标准定义计算的: --------------- a -------------------- a[0,0]=20.00; a[0,1]=2.00; a[0,2]=4.00; a[0,3]=7.00; a[1,0]=6.00; a[1,1]=1.00; a[1,2]=3.00; a[1,3]=8.00; a[2,0]=5.00; a[2,1]=7.00; a[2,2]=4.00; a[2,3]=0.00; a[3,0]=11.00; a[3,1]=2.00; a[3,2]=12.00; a[3,3]=17.00; --------------- b -------------------- b[0,0]=27.25; b[0,1]=1.78; b[0,2]=9.75; b[0,3]=4.95; b[1,0]=-2.67; b[1,1]=7.92; b[1,2]=4.45; b[1,3]=0.32; b[2,0]=10.25; b[2,1]=-0.45; b[2,2]=7.75; b[2,3]=4.79; b[3,0]=-1.87; b[3,1]=7.82; b[3,2]=-4.28; b[3,3]=-0.92; --------------- c -------------------- c[0,0]=20.00; c[0,1]=2.00; c[0,2]=4.00; c[0,3]=7.00; c[1,0]=6.00; c[1,1]=1.00; c[1,2]=3.00; c[1,3]=8.00; c[2,0]=5.00; c[2,1]=7.00; c[2,2]=4.00; c[2,3]=-0.00; c[3,0]=11.00; c[3,1]=2.00; c[3,2]=12.00; c[3,3]=17.00; 请按任意键继续. . . */