实验原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
实验内容
在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。量化器采用8比特均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求) 。还可对预测误差进行1比特、2比特和4比特的量化设计。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。
实验结果
原始图像 | 8bit量化 | 4bit量化 | 2bit量化 | 1bit量化 | |
---|---|---|---|---|---|
量化误差图像 | / | ![]() | ![]() | ![]() | ![]() |
重建图像(或者原始图像) | ![]() | ![]() | ![]() | ![]() | ![]() |
(量化误差图像)概率分布 | ![]() | ![]() | ![]() | ![]() | ![]() |
熵编码后的文件大小(byte) | 223771 | 205920 | 140689 | 93626 | 93626 |
压缩比 | 0.299 | 0.275 | 0.188 | 0.125 | 0.125 |
PSNR | / | ![]() | ![]() | ![]() | ![]() |
可以看出:DPCM+熵编码比仅进行熵编码编码效率提高,但图像质量无明显差别,告诉我们通过组合编码可以提高效率;都使用DPCM+熵编码的条件下,随着量化比特数的降低,压缩比越来越高,但图像质量越来越差,这也反映了效率和可靠性不能兼得,要折中考虑图像压缩效率和图像质量的关系。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#define WIDTH 464
#define HEIGHT 538
#define bit 8
void count(unsigned char *data, int *count,int i,double *freq)
{
int n=0,m=0;
for(n=0;n<i;n++)
{
for(m=0;m<256;m++)
if(data[n]==m)
count[m]++;
}
for(m=0;m<256;m++)
freq[m]=(double)count[m]/i;
}
double PSNR( unsigned char* standard, unsigned char* rebuild)
{
double psnr = 0, MSE = 0;
for( int i = 0; i < WIDTH*HEIGHT; i++ )
MSE +=pow((rebuild[i] - standard[i])*1.0,2);
MSE /= WIDTH*HEIGHT;
psnr = 10 * log10( pow(4.0,8) / MSE);
return psnr;
}
int main ()
{
FILE* AFile =NULL;
FILE* pre_File=NULL;
FILE* re_File=NULL;
FILE* fre_File=NULL;
AFile=fopen(".\\data\\moon.yuv","rb");
pre_File=fopen(".\\data\\pre.yuv","wb");
re_File=fopen(".\\data\\rebuild.yuv","wb");
fre_File=fopen(".\\data\\frequent.txt","wb");
if(AFile==NULL)
{
printf("cannot find moon.yuv\n");
exit(1);
}
if(pre_File==NULL)
{
printf("cannot find moon_1.yuv\n");
exit(1);
}
if(re_File==NULL)
{
printf("cannot find moon_2.yuv\n");
exit(1);
}
unsigned char *yBuf;
yBuf=(unsigned char *)malloc(WIDTH*HEIGHT);
int *pre;
pre=(int *)malloc(sizeof(int)*WIDTH*HEIGHT);//注意sizeof
unsigned char *pre_1;
pre_1=(unsigned char *)malloc(WIDTH*HEIGHT);
unsigned char *rebuild;
rebuild=(unsigned char *)malloc(WIDTH*HEIGHT);
int *rebuild_1;
rebuild_1=(int *)malloc(sizeof(int)*WIDTH*HEIGHT);
if (!feof(AFile))
{
if(!fread(yBuf,1,WIDTH*HEIGHT,AFile))
{
printf("cannot read y%d ");
}
for (int j=0; j<HEIGHT; j++)
{
for (int i=0;i<WIDTH;i++)
{
if (i==0)
{
pre_1[j*WIDTH+i]=0;
pre[j*WIDTH+i]=0;
rebuild[j*WIDTH+i]=yBuf[j*WIDTH+i];
}
else
{
/**预测***/
pre[j*WIDTH+i]=yBuf[j*WIDTH+i]-rebuild[j*WIDTH+i-1];
/***量化***/
pre_1[j*WIDTH+i]=((pre[j*WIDTH+i]+256)/2);
int erta=pow(2.0,(8-bit));
pre_1[j*WIDTH+i]=(pre_1[j*WIDTH+i]/erta+0.5);
/***反量化和重建**/
pre_1[j*WIDTH+i]=pre_1[j*WIDTH+i]*erta;//算量化还是反量化?
pre[j*WIDTH+i]=pre_1[j*WIDTH+i]*2-256;
// pre[j*WIDTH+i]=pre_1[j*WIDTH+i];
// pre[j*WIDTH+i]=(pre[j*WIDTH+i]*erta)*2-256;
rebuild[j*WIDTH+i]=pre[j*WIDTH+i]+rebuild[j*WIDTH+i-1];
}
}
}
}
int y_count[256]={0};
double freq[256]={0};
count(pre_1,y_count,WIDTH*HEIGHT,freq);
/**输出数据的概率分布**/
fprintf(fre_File,"Freq_B\tSymol\n");
for (int m=0;m<256;m++)
{
fprintf(fre_File,"%.8f\n",freq[m]);
}
/*输出psnr*/
printf("psnr:%f",PSNR( yBuf, rebuild ));
/*写入预测误差图像和重建图像*/
fwrite(rebuild,1,WIDTH*HEIGHT,re_File);
for (int n=0;n<WIDTH*HEIGHT;n++ )
rebuild[n]=128;//填充U,V
fwrite(rebuild,1,WIDTH*HEIGHT,re_File);
fwrite(rebuild,1,WIDTH*HEIGHT,re_File);
fwrite(pre_1,1,WIDTH*HEIGHT,pre_File);
for (int n=0;n<WIDTH*HEIGHT;n++ )
pre_1[n]=128;//填充U,V
fwrite(pre_1,1,WIDTH*HEIGHT,pre_File);
fwrite(pre_1,1,WIDTH*HEIGHT,pre_File);
free(yBuf);
free(pre);
free(pre_1);
free(rebuild);
free(rebuild_1);
fclose(AFile);
fclose(pre_File);
fclose(re_File);
getchar();
return 0;
}