DCT变换以及量化,反量化,逆DCT变换的实现。

  • Post author:
  • Post category:其他


一. 编程思路

对一幅bmp格式的图像进行变换,首先要做的是将bmp图像的信息读入,因此在程序中我利用了BITMAPINFOHEADER的结构,对文图信息头中的信息进行读取,除了对图像的读取以外,其他的操作主要是DCT,量化,反量化,逆DCT这样几个操作。把每个操作用一个函数表示方便程序的编写。还有一个问题就是量化表,由于是对一幅灰度图像进行操作,在课件中可以查找到常用的量化表,如下图所示:

这里写图片描述

量化的部分无外乎就是对两个矩阵进行乘除的操作,而DCT和逆DCT的部分是对一个分块矩阵进行变换,DCT变换公式如下:

这里写图片描述

这样大体上就有了思路,在主函数中每进行一次变换,将变换后的矩阵输出到一个文本中便于对实验结果的检测。

二. 源代码部分

#include <iostream>
#include <stdlib.h>
#include "windows.h"
#include <memory>
#include <cmath>

using namespace std;

#define PI  3.14159262
#define N 8

int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD *pColorTable;//颜色表指针
int biBitCount;//图像类型,每像素位数

int image[256][256]={0};//读入的图像
float DCTimage[256][256]={0};//DCT变换后的图像数据 
int SCHimage[256][256]={0};//量化后的图像数据 
int _SCHimage[256][256]={0};//反量化后的图像数据 
int IDCTimage[256][256]={0};//逆DCT变换后的图像数据 

float m[8][8]={0.0};
int n[8][8]={0},a[8][8]={0};//8*8图像块;
int Fy[8][8]={{16,11,10,16,24,40,51,61},//色差量化表 
              {12,12,14,19,26,58,60,55},
              {14,13,16,24,40,57,69,56},
              {14,17,22,29,51,87,80,62},
              {18,22,37,56,68,109,103,77},
              {24,35,55,64,81,104,113,92},
              {49,64,78,87,103,121,120,101},
              {72,92,95,98,112,100,103,99}};

double round(double r){return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);}

/*
读取图像文件的函数部分,故意省略,留给大家自己思考
*/

void DCT(int input[N][N],float output[N][N]){   //偶余弦变换EDCT 
    short i,j,p,q;
    double coefficient1,coefficient2;
    for(p=0;p<N;p++)
    {
        for(q=0;q<N;q++)
        {
            if(p==0) coefficient1=sqrt(1.0/N);
            else coefficient1=sqrt(2.0/N);
            if(q==0) coefficient2=sqrt(1.0/N);
            else coefficient2=sqrt(2.0/N);
            double tmp=0.0;
            for(i=0;i<N;i++)
                for(j=0;j<N;j++)
                    tmp+=input[i][j]*cos((2*i+1)*PI*p/(2*N))*cos((2*j+1)*PI*q/(2*N));//形成新的矩阵 
            output[p][q]=short(round(coefficient1*coefficient2*tmp));
        }
    }
}

void IDCT(float input[N][N],int output[N][N]){
    short i,j,p,q;
    double coefficient1,coefficient2;
    for(i=0;i<N;i++)
    {
        for(j=0;j<N;j++)
        {
            double tmp=0.0;
            for(p=0;p<N;p++)
                for(q=0;q<N;q++)
                {
                    if(p==0) coefficient1=sqrt(1.0/N);
                    else coefficient1=sqrt(2.0/N);
                    if(q==0) coefficient2=sqrt(1.0/N);
                    else coefficient2=sqrt(2.0/N);
                    tmp+=coefficient1*coefficient2*input[p][q]*cos((2*i+1)*PI*p/(2*N))*cos((2*j+1)*PI*q/(2*N));
                }
                output[i][j]=short(round(tmp));
        } 
    }
}                                    

void SCH()
{    //量化子程序,m是需要量化的系数。n是量化后的系数
    int x,y;
    int tr[8][8] ;
    for(x=0;x<=7;x++)
        for(y=0;y<=7;y++)
        {
            tr[x][y]=(int)(m[x][y]/Fy[x][y]);  //除量化系数,取整数
            n[x][y]=tr[x][y];
        }
}

void _SCH()
{    //反量化子程序,n是需要反量化的系数。m是反量化后的系数
    int x,y;
    int tr[8][8];
    for(x=0;x<=7;x++)
        for(y=0;y<=7;y++)
        {
            tr[x][y]=n[x][y]*Fy[x][y];  //乘以量化系数
            m[x][y]=tr[x][y];
        }
}


int main()
{
    int i=0,j=0,k=0,i1=0,j1=0;
    FILE * FP1,*FP2,*FP3,*FP4,*FP5,*FP6;

    unsigned char *aaa=readBmp();//读入图片 

    if ((FP1=fopen("original.txt","w"))==NULL) return 0;//输出原始图像灰度
    for (i=0;i<256;++i)
    {
        for(j=0;j<256;++j)
        {
        image[i][j]=aaa[k];
        fprintf(FP1,"%4d",image[i][j]);
        ++k;
        }
        fprintf(FP1,"\n");
    }
    fclose(FP1);

for(i=0;i<32;++i)
{                                //图像分为32*32块       
    for(j=0;j<32;++j)
    { 
        for(i1=0;i1<8;i1++)
        {
            for(j1=0;j1<8;j1++)
            {
                a[i1][j1]=image[i*8+i1][j*8+j1];
            }
        }
        DCT(a,m);    //调用DCT变换函数,a为需要变换的块,m为变换后的块。   
        SCH(); //调用量化函数,Fy是量化矩阵,m是需要量化的块,n是量化后的矩阵。


        for(i1=0;i1<8;i1++){
            for(j1=0;j1<8;j1++){
                DCTimage[i*8+i1][j*8+j1]=m[i1][j1];
                SCHimage[i*8+i1][j*8+j1]=n[i1][j1];
            }
        }   
    }
}

    if ((FP2=fopen("DCT.txt","w"))==NULL) return 0;
    for (i=0;i<256;++i){
        for(j=0;j<256;++j)
        {
        fprintf(FP2,"%5.0f",DCTimage[i][j]);
        }
        fprintf(FP2,"\n");
    }
    fclose(FP2);

    if ((FP3=fopen("SCH.txt","w"))==NULL) return 0;
    for (i=0;i<256;++i)
    {
        for(j=0;j<256;++j)
        {
        fprintf(FP3,"%4d",SCHimage[i][j]);
        }
        fprintf(FP3,"\n");
    }
    fclose(FP3);

for(i=0;i<32;++i)
{       //图像分为32*32块       
    for(j=0;j<32;++j)
    { 
        for(i1=0;i1<8;i1++)
        {
            for(j1=0;j1<8;j1++)
            {
                n[i1][j1]=SCHimage[i*8+i1][j*8+j1];
            }
        }
        _SCH();   //反量化函数
        IDCT(m,a);      //反DCT变化
        for(i1=0;i1<8;i1++)
        {
            for(j1=0;j1<8;j1++)
            {
                _SCHimage[i*8+i1][j*8+j1]=m[i1][j1];
                IDCTimage[i*8+i1][j*8+j1]=a[i1][j1];
            }
        }
    }
}

    if ((FP4=fopen("_SCH.txt","w"))==NULL) return 0;//输出反量化后的图像数据 
    for (i=0;i<256;++i)
    {
        for(j=0;j<256;++j)
        {
        fprintf(FP4,"%5d",_SCHimage[i][j]);
        }
        fprintf(FP4,"\n");
    }
    fclose(FP4);    

    if ((FP5=fopen("IDCT.txt","w"))==NULL) return 0;//输出逆DCT变换后的图像数据 
    for (i=0;i<256;++i)
    {
        for(j=0;j<256;++j)
        {
        fprintf(FP5,"%4d",IDCTimage[i][j]);
        }
        fprintf(FP5,"\n");
    }
    fclose(FP5);

    if ((FP6=fopen("DEVIATION.txt","w"))==NULL) return 0;//输出差值 
    for (i=0;i<256;++i)
    {
        for(j=0;j<256;++j)
        {
        fprintf(FP6,"%4d",image[i][j]-IDCTimage[i][j]);
        }
        fprintf(FP6,"\n");
    }
    fclose(FP6);
    system("pause");
    return 0; 
}



版权声明:本文为u014518566原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。