离散余弦变换(Discrete CosineTransform,简称DCT变换)是一种与傅立叶变换紧密相关的数学运算。在傅立叶级数展开式中,如果被展开的函数是实偶函数,那么其傅立叶级数中只包含余弦项,再将其离散化可导出余弦变换,因此称之为离散余弦变换。
离散余弦变换(DCT)是N.Ahmed等人在1974年提出的正交变换方法。它常被认为是对语音和图像信号进行变换的最佳方法。为了工程上实现的需要,国内外许多学者花费了很大精力去寻找或改进离散余弦变换的快速算法。由于近年来数字信号处理芯片(DSP)的发展,加上专用集成电路设计上的优势,这就牢固地确立离散余弦变换(DCT)在目前图像编码中的重要地位,成为H.261、JPEG、MPEG等国际上公用的编码标准的重要环节。在视频压缩中,最常用的变换方法是DCT,DCT被认为是性能接近K-L变换的准最佳变换,变换编码的主要特点有:
(1)在变换域里视频图像要比空间域里简单。
(2)视频图像的相关性明显下降,信号的能量主要集中在少数几个变换系数上,采用量化和熵编码可有效地压缩其数据。
(3)具有较强的抗干扰能力,传输过程中的误码对图像质量的影响远小于预测编码。通常,对高质量的图像,DMCP要求信道误码率,而变换编码仅要求信道误码率。
DCT等变换有快速算法,能实现实时视频压缩。针对目前采用的帧内编码加运动补偿的视频压缩方法的不足, 我们在Westwater等人提出三维视频编码的基础上, 将三维变换的结构应用于视频图像压缩, 进一步实现了新的视频图像序列的编码方法。
#include <memory.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#define PI 3.1415926
#define CLK_TCK CLOCKS_PER_SEC
int N;
void DCT(double *f,double *F)
{
int n,m,x;
double *dTemp=new double[N*N];//中间矩阵
double *coff=new double[N*N];//变换系数
coff[0]=(double)1/sqrt((double)N);
for(m=1;m<N;m++)
coff[m]=sqrt((double)2)/sqrt((double)N);
memset(dTemp,0,sizeof(double)*N*N);
memset(F,0,sizeof(double)*N*N);
//一维变换
for(n=0;n<N;n++)
for(m=0;m<N;m++)
for(x=0;x<N;x++)
dTemp[m*N+n]+=coff[m]*f[x*N+n]*cos((2*x+1)*PI*m/(2*N));
//第二次一维变换
for(m=0;m<N;m++)
for(n=0;n<N;n++)
for(x=0;x<N;x++)
F[m*N+n]+=coff[n]*dTemp[m*N+x]*cos((2*x+1)*PI*n/(2*N));
delete []dTemp;
delete []coff;
}
void iDCT(double *f,double *F)
{
int m,y,x;
double *dTemp=new double[N*N];//中间矩阵
double *coff=new double[N*N];//变换系数
coff[0]=1/sqrt((double)N);
for(m=1;m<N;m++)
coff[m]= sqrt((double)2) /sqrt((double)N);
memset(dTemp,0,sizeof(double)*N*N);
memset(F,0,sizeof(double)*N*N);
//一维变换
for(x=0;x<N;x++)
for(y=0;y<N;y++)
for(m=0;m<N;m++)
dTemp[x*N+y]+=coff[m]*F[x*N+m]*cos((2*y+1)*PI*m/(2*N));
//第二次一维变换
for(y=0;y<N;y++)
for(x=0;x<N;x++)
for(m=0;m<N;m++)
F[x*N+y]+=coff[m]*dTemp[m*N+y]*cos((2*x+1)*PI*m/(2*N));
delete []dTemp;
delete []coff;
}
int main()
{
clock_t start,end;
start=clock();
int i;
long L;
printf("变换维数:");
scanf("%d",&N);
double *f=new double[N*N];//初始矩阵
double *F=new double[N*N];//变换后输出矩阵
memset(F,0,sizeof(double)*N*N);//初始化为0
for(i=0;i<N*N;i++)
{
printf("f[%d][%d]:",i/N,i%N);
scanf("%lf",&f[i]);
}
printf("循环次数:");
scanf("%d",&L);
//输出初始矩阵
printf("变换前:n");
for(i=1;i<=N*N;i++)
{
printf("%ft",f[i-1]);
if(i%N==0)
printf("n");
}
for(i=0;i<L;i++)
DCT(f,F);//变换
//输出变换后矩阵
printf("变换后:n");
for(i=1;i<=N*N;i++)
{
printf("%ft",F[i-1]);
if(i%N==0)
printf("n");
}
for(i=0;i<L;i++)
iDCT(f,F);
//输出反变换后矩阵
printf("反变换后:n");
for(i=1;i<=N*N;i++)
{
printf("%ft",f[i-1]);
if(i%N==0)
printf("n");
}
//printf("n");
delete []f;
delete []F;
end=clock();
printf("耗时:%fn",(double)(end-start)/CLK_TCK);
return 0;
}