DCT离散余弦变换编程

离散傅里叶变换和离散余弦变换公式如下:

--------------------------------------------------------------------------------------------------------------------------------------------


--------------------------------------------------------------------------------------------------------------------------------------------


----------------------------------编程实现-----------------------------------------------------------------------------------------------

可以通过以下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;
*/

------------------下面是调用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;
请按任意键继续. . .
*/

 


                
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值