一. 编程思路
对一幅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;
}