一、实验内容
1、DPCM编解码原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
2.DPCM编码系统的设计
在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可 (本实验采用的时左侧编码) 。量化器采用8比特均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化,还可对预测误差进行1比特、2比特和4比特的量化设计。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统 (1.DPCM+熵编码 2.仅进行熵编码) 之间的编码效率 (压缩比和图像质量)。压缩质量以Psnr 进行计算。
二、实现方法
1、基本思路
- 读取一个yuv文件,提取其中的Y、U、V分量(本实验主要对Y分量进行编码),计算Y分量的概率分布;
- 将Y分量进行DPCM变换,期间得出误差图像和重建图像并输出,DPCM编码后传输的时误差图像,计算误差图像各分量的概率分布,与原始图像进行对比;
- 将原始图像和误差图像分别输入Huffman编码器,计算压缩比;
- 计算psnr,作为判断压缩质量的标准;
- 分别比较原始图像和不同量化比特下的误差图像的压缩比、压缩质量(psnr),观察概率分布,得出实验结论。
2、具体问题及其主要模块
1、量化
- 在DPCM编码过程中要实现量化和反量化这两个过程,不同的量化比特数会产生不同的压缩效果(量化比特数越小,压缩比越大,压缩质量越差);
- 本实验中对误差值(也就是最后传输的数据)进行量化后输出,同时对其进行反量化,将复原后(但与原数值已存在偏差)某点的数值与该点左侧的重建值相加,得该点重建值;
- 具体方法是先将范围在[-255,255]的原数值映射到[0,255]的区间上,再根据不同的量化比特数将数值量化到 [ 0 , 2 b i t − 1 ] [0,2^{bit}-1] [0,2bit−1]上,最后进行归一化,将数值映射到各自的量化级上,最后数值范围仍为[0,255];
- 实现方法如下:
//量化
int Quantify(int temp, int bit)
{
temp = (temp + 255) / 2;
temp = floor(temp / pow(2, 8 - bit));
temp = temp * pow(2, 8 - bit);
if (temp > 255)
temp = 255;
if (temp < 0)
temp = 0;
return temp;
}
//反量化
int Re_Quantify(int temp)
{
temp = temp * 2 - 255;
return temp;
}
2、DPCM编码
- 本次实验采用左侧编码的方法,先将原图像第一列的值赋给重建图像第一列,第一列误差值都赋为0,从第二列开始,将该点原图数值与左侧重建值相减后进行量化,得到要传输的误差值,再进行反量化,将恢复后的误差值再与左侧重建值相加,得该点重建值;
- 具体实现过程如下:
unsigned char * DpcmCoder(unsigned char buffer[], int bit)
{
int temp;
unsigned char pre[w*h] = {
0 }, d[w*h] = {
0 }, Q_d[w*h] = {
0 };
for (int line = 0; line < h; line++)
{
pre[line*w] = buffer[line*w];
Q_d[line*w] = Quantify(0, bit);
for (int i = 1; i < w; i++)
{
temp = buffer[i + line * w] - pre[i + line * w - 1];
//temp = d[i + line * w];//原始差值
temp = Quantify(temp, bit);//对差值量化
Q_d[i + line * w] = temp;
temp = Re_Quantify(temp);//反量化
temp = pre[i + line * w - 1] + temp;
if (temp > 255)
temp = 255;
if (temp < 0)
temp = 0;
//防止溢出
pre[i + line * w] = temp;
}
}
//以下部分为差值图像和重建图像两组数据返回主函数的工作
unsigned char ret[w*h * 2] = {
0 };
for (int i = 0; i < w*h ; i++)
{
ret[i] = Q_d[i];
}