离散傅里叶变换和离散余弦变换公式如下:
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------编程实现-----------------------------------------------------------------------------------------------
可以通过以下3种方式实现:
1. 按照公式定义来编程计算
2. 采用蝶形运算来编程实现
3. 调用现成的fftw算法来实现
对于第1,2两种方法,有很多资料介绍,对于需要快速开发的程序,则可直接调用fftw函数库实现,据说该库函数计算傅里叶变换是全地球最快的。
FFTW中文参考: http://blog.youkuaiyun.com/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;
*/
------------------下面是调用OpenCV的示例----------------------------
#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;
请按任意键继续. . .
*/