一、DPCM编解码原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
二、DPCM编码系统的设计
在本次实验中,我们采用固定预测器和均匀量化器。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。
三、PSNR
PNSR(Peak Signal to Noise Ratio),即峰值信噪比,计算公式如下:
其中,MAXI是表示图像点颜色的最大数值,如果每个像素值用 8 位表示,那么就是 255
MSE(Mean squared error),均方误差,计算公式如下:
m*n表示图像大小,I(i,j)和K(i,j)分别为两幅图像对应点的像素值。
PSNR越大表示重建图像越接近原始图像
四、实验步骤
1.得到yuv文件
利用 bmp2yuv 程序将bmp文件转换成能处理的yuv文件,本实验中只对y通道进行处理。
2.DPCM函数
DPCM函数开三个buffer,一个存放原始图像数据origin=yBuff,一个存放预测误差predict=(当前值-预测值)并进行 i bit量化,一个存放重建图像的数据rebuild。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include<stdint.h>
using namespace std;
void dpcm(unsigned char *yBuf, unsigned char *prBuf, unsigned char *reBuf, int w, int h, int depth)
{
int r = pow(2, (double)(9 - depth));//计算除数
for (int i = 0; i < h; i++)
for(int j = 0; j < w; j++)
{
if (j == 0)//由于第一列的像素无参考重建值,故将其参考值固定地设为128。
{
prBuf[i * w] = ((yBuf[i * w] - 128) + 255) / pow(2, (double)(9 - depth)) ;
reBuf[i * w] = prBuf[i * w] * pow(2, (double)(9 - depth)) - 255 + 128;
}
else
{
prBuf[i * w + j] = ((yBuf[i * w + j] - reBuf[i * w + j - 1]) + 255) / pow(2, (double)(9 - depth));
reBuf[i * w + j] = prBuf[i * w + j] * pow(2, (double)(9 - depth)) - 255 + reBuf[i * w + j - 1];
}
if (prBuf[i * w + j] > 255)
prBuf[i * w + j] = 255;
if (prBuf[i * w + j] < 0)
prBuf[i * w + j] = 0;
if (reBuf[i * w + j] > 255)
reBuf[i * w + j] = 255;
if (reBuf[i * w + j] < 0)
reBuf[i * w + j] = 0;
}
}
3.主函数
int main(void)
{
int bits_depth = 2;
unsigned char *yBuf, *uBuf, *vBuf;
int w = 256, h = 256;
yBuf = (unsigned char*)malloc(sizeof(unsigned char) * (w * h));
uBuf = (unsigned char*)malloc(sizeof(unsigned char) * (w * h / 4));
vBuf = (unsigned char*)malloc(sizeof(unsigned char) * (w * h / 4));
FILE* src = NULL;
src = fopen("C:\\Users\\孟建成\\Desktop\\lab4\\Lena256B.yuv","rb");
if (src == NULL)
{
printf("error opening source file!\n");
system("pause");
exit(-1);
}
fread(yBuf, sizeof(unsigned char), w * h, src);
fread(uBuf, sizeof(unsigned char), w * h / 4, src);
fread(vBuf, sizeof(unsigned char), w * h / 4, src);
fclose(src);
unsigned char *prBuf, *reBuf;
prBuf = (unsigned char*)malloc(sizeof(unsigned char) * (w * h));
reBuf = (unsigned char*)malloc(sizeof(unsigned char) * (w * h));
dpcm(yBuf, prBuf, reBuf, w, h, bits_depth);
FILE* obj1 = NULL;
FILE* obj2 = NULL;
obj1 = fopen("C:\\Users\\孟建成\\Desktop\\lab4\\pr_Lena256B(2bit).yuv","wb");
obj2 = fopen("C:\\Users\\孟建成\\Desktop\\lab4\\re_Lena256B(2bit).yuv","wb");
if (obj1 == NULL || obj2 == NULL)
{
printf("error opening objective file!\n");
system("pause");
exit(-1);
}
fwrite(prBuf, sizeof(unsigned char), w * h, obj1);
fwrite(uBuf, sizeof(unsigned char), w * h / 4, obj1);
fwrite(vBuf, sizeof(unsigned char), w * h / 4, obj1);
fwrite(reBuf, sizeof(unsigned char), w * h, obj2);
fwrite(uBuf, sizeof(unsigned char), w * h / 4, obj2);
fwrite(vBuf, sizeof(unsigned char), w * h / 4, obj2);
fclose(obj1);
fclose(obj2);
}
4.Huffman编码
5.PSNR计算压缩质量
//计算PSNR
int max = 255;
double mse = 0;
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
{
mse += (yBuf[i * w + j] - reBuf[i * w + j]) * (yBuf[i * w + j] - reBuf[i * w + j]);
}
mse = (double)mse / (double)(w * h);
double psnr = 10 * log10((double)(max * max) / mse);
cout << "PSNR = " << psnr;
system("pause");
五、实验结果
8bit:原图像,预测误差图像和重建图像
4bit:原图像,预测误差图像和重建图像
2bit:原图像,预测误差图像和重建图像
压缩质量分析:
8bit压缩比 = 96.0/ 45.0 = 2.13
4bit压缩比 = 96.0/ 23.4 = 4.10
2bit压缩比 = 96.0/ 22.5 = 4.27
仅进行熵编码:
压缩比 = 96.0/ 68.2 = 1.41
概率分布图:
六、结果分析
1.DPCM+熵编码比仅进行熵编码压缩比要大。
2.DPCM+熵编码压缩比更大的原因是预测误差图像的概率分布更集中(偏像于高斯分布),熵更大,更易压缩。
3.量化比特数越高,图像质量越好。经过8bit量化后的图像已经很接近原图像(4bit,2bit,1bit量化后又经过熵编码虽然得到了较高的压缩比但图像质量大大损失,所以不予考虑)
4.综上所述,8bitDPCM+熵编码这样组合起来的算法系统能获得最好的压缩效果。