一、实验目的
掌握DPCM编解码系统的基本原理。初步掌握实验用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。
二、实验原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中, 需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是 因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实 际内嵌了一个解码器,如编码器中虚线框中所示。
三、实验内容
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像 写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。 将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质 量)。压缩质量以PSNR进行计算。
代码实现
此实验DPCM编码阶段中需要创建三个buffer,分别是:
unsigned char* y_buffer=NULL//当前样本预测值;
unsigned char* p_buffer=NULL//当前样本重建值;
unsigned char* d_buffer=NULL//图像预测误差值;
所有代码:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
using namespace std;
//计算PSNR
double PSNR( unsigned char* standard, unsigned char* image,int height,int width,int bitNum )
{
double psnr = 0, MSE = 0;
for( int i = 0; i < height * width; i++ )
{
MSE += 1ll* (image[i] - standard[i]) * (image[i] - standard[i]);
}
MSE /= height * width;
long long t = 1 << bitNum; t -= 1; t *= t;
psnr = 10 * log10( t / MSE);
return psnr;
}
//得到频率分布
void GetFrequency( unsigned char* buffer, double* frequency,int height,int width )
{
int length = height * width;
for( int i = 0; i < length; i++ )
frequency[buffer[i]] ++;
for( int i = 0; i < 256; i++ )
frequency[i] /= length;
}
int main(int argc,char** argv)
{
char *yuvfilename=NULL;//原始图像
char *p_filename=NULL;//重建图像
char *d_filename=NULL;//预测误差
FILE* yuvfile=NULL;
FILE* p_file=NULL;
FILE* d_file=NULL;
int width=256,height=256;
yuvfilename=argv[1];
p_filename=argv[2];
d_filename=argv[3];
width=atoi(argv[4]);
height=atoi(argv[5]);
unsigned char* u_buffer=NULL;
unsigned char* v_buffer=NULL;
unsigned char* y_buffer=NULL;
unsigned char* p_buffer=NULL;
unsigned char* d_buffer=NULL;
yuvfile=fopen("/Users/997xyq/Desktop/down.yuv","rb");
if(yuvfile==0)
{
printf("cannot find yuv file.\n");
}
else
{
printf("open yuv file successfully!\n");
}
y_buffer=(unsigned char*)malloc(width*height);
u_buffer=(unsigned char*)malloc(width*height/4);
v_buffer=(unsigned char*)malloc(width*height/4);
d_buffer=(unsigned char*)malloc(width*height*1.5);
p_buffer=(unsigned char*)malloc(width*height*1.5);
fread(y_buffer,1,width*height,yuvfile);
fread(u_buffer,1,width*height/4,yuvfile);
fread(v_buffer,1,width*height/4,yuvfile);
//原始图像的概率分布
FILE *orig;
orig=fopen("/Users/997xyq/Desktop/down_o.txt","wb");
double frequency[256]={0};
GetFrequency(y_buffer,frequency,height,width);
for(int i=0;i<256;i++)
{
fprintf(orig,"%d\t%f\n",i,frequency[i]);
}
//DPCM编码
for(int i=0;i<width*height;i++)
{
float d;//误差
if(i%width==0)
{
d=float(y_buffer[i])-128;//假设预测值为128
d_buffer[i]=(unsigned char)(d/2+128);//对预测误差量化
p_buffer[i]=(unsigned char)(128+(d_buffer[i]-128)*2);//重建值=反量化后的误差+预测值
}
else
{
d=float(y_buffer[i]-p_buffer[i-1]);//选取前一像素的重建值作为预测值
d_buffer[i]=(unsigned char)(d/2+128);
p_buffer[i]=(unsigned char)(p_buffer[i-1]+(d_buffer[i]-128)*2);
}
}
//得到残差的概率分布
FILE *d;
d=fopen("/Users/997xyq/Desktop/down_d.txt","wb");
double frequency_[256]={0};
GetFrequency(d_buffer,frequency_,height,width);
for(int i=0;i<256;i++)
{
fprintf(d,"%d\t%f\n",i,frequency_[i]);
}
//计算PSNR
cout<<"psnr="<<PSNR(y_buffer,p_buffer,height,width,8)<<endl;
p_file=fopen("/Users/997xyq/Desktop/down_p.yuv","wb");
d_file=fopen("/Users/997xyq/Desktop/down_d.yuv","wb");
fwrite(p_buffer,width*height,1,p_file);
fwrite(u_buffer,width*height/4,1,p_file);
fwrite(v_buffer,width*height/4,1,p_file);
fwrite(d_buffer,width*height,1,d_file);
fwrite(u_buffer,width*height/4,1,d_file);
fwrite(v_buffer,width*height/4,1,d_file);
fclose(p_file);
fclose(d_file);
}
实验结果
得出图像
生成的文件
huffman编码器还未完成,未完待续