数据压缩实验四:DPCM编码

一、基本原理

DPCM是典型的预测编码系统,采用负反馈的方式进行,由于解码端无法得到原始值,因此要用量化编码后的重建值来生成预测值,编码器中要内嵌解码器。
DPCM编码框图如下:
数据压缩实验四:DPCM编码_第1张图片

Q为量化器,由于整个系统由预测+量化+熵编码构成,熵编码对形如Laplace分布的信源,有很好的压缩效果,因此量化部分采用均匀量化,能够保持预测误差的Laplace分布特性,在熵编码获得较高的编码效率,非均匀量化会把原本呈现Laplace分布特性的预测误差编程均匀分布,而熵编码所做的就是将非均匀分布的信源符号,变成均匀分布的码元符号,本身均匀分布的信源输入,不能得到好的压缩效果,而且非均匀分布实现更为复杂,所以对于预测+量化+熵编码的系统而言,均匀分布最为合适。
Laplace 分布 数据压缩实验四:DPCM编码_第2张图片

P为预测器,预测编码中,用几个样点的重建值的线性组合作为预测值,就是线性预测,用一个样点的重建值作为预测值就是DPCM,所以上图只用到前一个编码的像素的重建值。

xn :当前输入的像素值
pn :当前像素值的预测值,由已经编码的某些像素的重建值经过一定的计算生成
dn :预测误差,当前像素值减去预测值
d^n :量化后的预测误差
x^n :当前像素的重建值=量化后的预测误差+当前像素的预测值

二、实验流程分析

1. 差分编码流程

预测值:最左一列像素以128作为预测值,其他像素以左侧像素值作为预测值
量化:对原始值与预测值的差进行8bit量化

  • 判断是否最左一列像素,若是,把像素值减去固定预测值128,否则减去预测值,得到范围在-255~255的预测误差

  • 预测误差进行量化,8bit量化即用预测误差除以2,存入数据类型为float的qn,范围在-127.5~127.5

  • 将qn抬高128,强制类型转换成无符号整数,存入输出预测误差图像的qBuf,范围在0~255

  • 将刚存入的qBuf反量化,即减去128再乘以2,范围在-256~254,再加上第一步中减去的预测值,生成重建值,也即下一像素的预测值,存入输出重建图像的dBuf

2. 代码实现步骤

  • 调用实验二BMP2YUV的程序,将BMP文件转成YUV格式
  • 对YUV分量进行预测和量化,输出预测误差图像和重建图像,由于编码器中包含解码器,所以不需要单独做解码器来生成重建图像
  • 把预测误差图像输入到实验三中的huffman代码中,进行熵编码
  • 把原始图像输入到实验三中的huffman代码中,直接进行熵编码
  • 将上两步编码的结果进行对比分析

三、关键代码分析

BMP2YUV及huffman编码的代码参考实验二和实验三,这里只给出差分编码的代码。

1.定义相关变量

/**********定义bcpm变量及缓存***************/
    FILE* qFile = NULL;//输出的预测误差图
    FILE* dFile = NULL;//输出的重建图
    char* qFileName = NULL;//预测误差图文件名
    char* dFileName = NULL;//重建图文件名
    float qn;//差值
    u_int8_t*qBuf=NULL;//预测误差
    u_int8_t*dBuf=NULL;//解码值

2.打开相关文件

 /** open the quantizer outfile **/
    qFile = fopen(qFileName, "wb");
    if (qFile == NULL)
    {
        printf("cannot find quantizer outfile\n");
        exit(1);
    }
    else
    {
        printf("The output quantizer outfile is %s\n", qFileName);
    }
     /** open the decode file **/
    dFile = fopen(dFileName, "wb");
    if (dFile == NULL)
    {
        printf("cannot find decode file\n");
        exit(1);
    }
    else
    {
        printf("The output decode file is %s\n", dFileName);
    }

3.DPCM 编码

由于在调用的BMP2YUV的程序中已经将YUV文件的Y值和UV值分别压缩到16~235和16~240的范围,所以以下程序不会出现溢出。

8bit量化

for(i=0;i//对Y的预测编码
{
    for(j=0;jif(j==0)//最左侧像素没有左侧像素,用128作为预测值
        {
            qn=(yBuf[i*frameHeight+j]-128)/2;//当前像素值减去预测值128,进行8bit量化,即除以2
            qBuf[i*frameHeight+j]=(u_int8_t)(qn+128);//qn的值在-127.5~127.5之间,将其抬高128,变成一字节无符号0~255,存入预测误差图像
            dBuf[i*frameHeight+j]=((int)qBuf[i*frameHeight+j]-128)*2+128;//重建值等于量化后再反量化的值加上之前减去的预测值128,结果存入重建图像,反量化的值等于量化后的值减去128再乘以2,会出现负数,不会出现小数,所以先强制转换成int
        }
        else
        {
            qn=(yBuf[i*frameHeight+j]-dBuf[i*frameHeight+j-1])/2;//当前像素值减去预测值(左侧像素得重建值),进行8bit量化,即除以2
            qBuf[i*frameHeight+j]=(u_int8_t)(qn+128);//qn的值在-127.5~127.5之间,将其抬高128,变成一字节无符号0~255,存入预测误差图像
            dBuf[i*frameHeight+j]=((float)qBuf[i*frameHeight+j]-128)*2+dBuf[i*frameHeight+j-1];//重建值等于量化后再反量化的值加上之前减去的预测值128,结果存入重建图像,反量化的值等于量化后的值减去128再乘以2,会出现负数,不会出现小数,所以先强制转换成int
        }
    }
}
for (i = 0; i < frameWidth/2; i++)//对U的预测编码
{
    for(j = 0; j < frameHeight/2; j++)
    {
        if(j==0)
        {
            qn=(uBuf[i*frameHeight/2+j]-128)/2;
            qBuf[frameWidth * frameHeight+i*frameHeight/2+j]=(u_int8_t)(qn+128);
            dBuf[frameWidth * frameHeight+i*frameHeight/2+j]=((int)qBuf[frameWidth * frameHeight+i*frameHeight/2+j]-128)*2+128;
        }
        else
        {
            qn=(uBuf[i*frameHeight/2+j]-dBuf[frameWidth * frameHeight+i*frameHeight/2+j-1])/2;
            qBuf[frameWidth * frameHeight+i*frameHeight/2+j]=(u_int8_t)(qn+128);
            dBuf[frameWidth * frameHeight+i*frameHeight/2+j]=((float)qBuf[frameWidth * frameHeight+i*frameHeight/2+j]-128)*2+dBuf[frameWidth * frameHeight+i*frameHeight/2+j-1];
        }
    }
}
for (i = 0; i < frameWidth/2; i++)//对V的预测编码
{
    for(j = 0; j < frameHeight/2; j++)
    {
        if(j==0)
        {
            qn=(vBuf[i*frameHeight/2+j]-128)/2;
            qBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]=(u_int8_t)(qn+128);
            dBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]=((int)qBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]-128)*2+128;
        }
        else
        {
            qn=(vBuf[i*frameHeight/2+j]-dBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j-1])/2;
            qBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]=(u_int8_t)(qn+128);
            dBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]=((float)qBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j]-128)*2+dBuf[frameWidth * frameHeight*5/4+i*frameHeight/2+j-1];
        }
    }
}
fwrite(qBuf, 1, frameWidth * frameHeight *1.5, qFile);
fwrite(dBuf, 1, frameWidth * frameHeight *1.5, dFile);

四、实验结果及分析

1.为了一致性,本实验用了BMP文件转换成的YUV文件作为原文件,来与重建图像和预测误差图像进行对比,表中xxxq.yuv为预测误差图像。

数据压缩实验四:DPCM编码_第3张图片

1

理论上,空间上相邻的像素值相差不大,因此预测误差的动态范围小,其概率分布呈现出离0(抬高后的128)越近越大的规律,这样的分布用huffman编码能得到很好的压缩比,上表显示Noise和Zone 原始文件的压缩比大于差分编码后的压缩比,与理论相悖,通过下面表二的概率分布和表三的图像,可以看到Noise和Zone,预测误差动态范围很宽,图像中黑白相间,0和255这样的极端值出现概率大,所以不易压缩。

2.原文件和预测误差图像的概率分布

原图像 预测误差图像
数据压缩实验四:DPCM编码_第4张图片 数据压缩实验四:DPCM编码_第5张图片
数据压缩实验四:DPCM编码_第6张图片 数据压缩实验四:DPCM编码_第7张图片
数据压缩实验四:DPCM编码_第8张图片 数据压缩实验四:DPCM编码_第9张图片
数据压缩实验四:DPCM编码_第10张图片 数据压缩实验四:DPCM编码_第11张图片
数据压缩实验四:DPCM编码_第12张图片 数据压缩实验四:DPCM编码_第13张图片
数据压缩实验四:DPCM编码_第14张图片 数据压缩实验四:DPCM编码_第15张图片
数据压缩实验四:DPCM编码_第16张图片 数据压缩实验四:DPCM编码_第17张图片
数据压缩实验四:DPCM编码_第18张图片 数据压缩实验四:DPCM编码_第19张图片
数据压缩实验四:DPCM编码_第20张图片 数据压缩实验四:DPCM编码_第21张图片
数据压缩实验四:DPCM编码_第22张图片 数据压缩实验四:DPCM编码_第23张图片

2

从上表可以看出,右边一列的分布,基本是中间多两边少,动态范围小,说明了预测编码的效果。

3.重建图片与原始图片对比

原始图片 重建图片 预测误差图
数据压缩实验四:DPCM编码_第24张图片 数据压缩实验四:DPCM编码_第25张图片
数据压缩实验四:DPCM编码_第26张图片 数据压缩实验四:DPCM编码_第27张图片 数据压缩实验四:DPCM编码_第28张图片
数据压缩实验四:DPCM编码_第29张图片 数据压缩实验四:DPCM编码_第30张图片 数据压缩实验四:DPCM编码_第31张图片
数据压缩实验四:DPCM编码_第32张图片 数据压缩实验四:DPCM编码_第33张图片 数据压缩实验四:DPCM编码_第34张图片
数据压缩实验四:DPCM编码_第35张图片 数据压缩实验四:DPCM编码_第36张图片 数据压缩实验四:DPCM编码_第37张图片
数据压缩实验四:DPCM编码_第38张图片 数据压缩实验四:DPCM编码_第39张图片 数据压缩实验四:DPCM编码_第40张图片
数据压缩实验四:DPCM编码_第41张图片 数据压缩实验四:DPCM编码_第42张图片 这里写图片描述
数据压缩实验四:DPCM编码_第43张图片 数据压缩实验四:DPCM编码_第44张图片 数据压缩实验四:DPCM编码_第45张图片
数据压缩实验四:DPCM编码_第46张图片 数据压缩实验四:DPCM编码_第47张图片 数据压缩实验四:DPCM编码_第48张图片
数据压缩实验四:DPCM编码_第49张图片 数据压缩实验四:DPCM编码_第50张图片 数据压缩实验四:DPCM编码_第51张图片

3

实验中采用左侧像素重建值作为预测值,因此上表最右列预测误差图像的灰色区域对应原图的平坦区域,即预测误差基本在0左右,抬高128后,在128左右呈现灰色,垂直边缘较明显,左黑右白的垂直边缘,会呈现出白色边缘,因为右侧白色减左侧黑色是一个比较大的正值,抬高128后也是128以上的一个比较大的值,同理,左白右黑的垂直边缘,会呈现出黑色边缘。
对-255~255范围的9bit预测误差做8bit量化,量化误差很小,因此中间一列的重建图像与左边一列的原始图像没有明显差别,量化误差可忽略不计。

五、总结

预测+均匀量化+熵编码的系统,通过预测得到近似Laplace分布预测误差,这是非常适合于熵编码的概率分布类型,对预测误差进行均匀量化可以降低编码的信源的符号种类,并且保持这样的概率分布,通过熵编码后达到较好的压缩效果。实验中,对运算过程中数据的动态范围要考虑,以便选择合适的数据类型,防止越界的情况出现。

你可能感兴趣的:(数据压缩实验报告,数据压缩,编码)