1. 程式人生 > >DCT變換編碼及C語言實現

DCT變換編碼及C語言實現

離散餘弦變換(Discrete Cosine
Transform,簡稱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(“%f\t”,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(“%f\t”,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(“%f\t”,f[i-1]);
  if(i%N==0)
   printf(“\n”);
 
 }
 //printf(“\n”);

 delete []f;
 delete []F;
 end=clock();
 printf(“耗時:%f\n”,(double)(end-start)/CLK_TCK);
 return 0;
}