DPCM(差分脉冲编码调制)是一种典型的预测编码系统。在传输图像、视频数据的时候,相邻的像素点的值往往差别很小,在空间上存在很大的冗余,DPCM便是利用这种冗余,通过相邻像素对当前像素的值进行预测,对图像进行数据压缩。
DPCM编解码原理图示:
DPCM当前像素和预测像素相减得误差值进行量化,以8bit量化为例,误差值的范围在【-255,255】之间,所需要的容量为9bit。
将值为负的像素进行单极性化,即加255,故Nbit量化便为加255再除以2^(9-n)。重建图像时,将差值和预测值相加即可得到。
为对重建图像进行性能评价,引入PSNR(峰值信噪比)的概念。
PSNR的计算公式:
其中MSE为图像的均方误差:
其中M为图像的长x高,ym与y^m分别为原始图像和重建图像在相应位置的像素值。
经过PSNR的计算便能够对图像质量进行评判。
实验以左侧像素为参考值,对第一列像素的误差值设为128处理,得到输出码流、给出概率分布图并计算压缩比。
#include
#include
#include
#pragma warning(disable:4996);
void dpcm_encode(unsigned char*ybuf, unsigned char*qbuf, unsigned char*rebuf, int width, int height,int bitdepth)
{
for (int i = 0; i < height; i++)
{
qbuf[i*width] = (ybuf[i*width] - 128 + 255) / pow(2, (9 - bitdepth));
rebuf[i*width] = qbuf[i*width] * pow(2, (9 - bitdepth))+255 - 128;
}
for (int i = 0; i < width; i++)
{
for (int j = 1; j < height; j++)
{
qbuf[i*width+j] = (ybuf[i*width+j] - rebuf[i*width + j-1] + 255) / pow(2, (9 - bitdepth));
rebuf[i*width+j] = qbuf[i*width+j] * pow(2, (9 - bitdepth)) - 255 + rebuf[i*width + j - 1];
}
}
for (int i = 0; i < width*height; i++)
{
if (qbuf[i] > 255)
qbuf[i] = 255;
if (qbuf[i] < 0 )
qbuf[i] = 0;
if (rebuf[i] > 255)
rebuf[i] = 255;
if (rebuf[i] < 0)
rebuf[i] = 0;
}
}
int main()
{
FILE *yuv = NULL; FILE *qyuv = NULL; FILE *reyuv = NULL;
const int width = 256; const int height = 256;
if (!(yuv = fopen("lena.yuv", "rb")))
{
printf("open file error!");
exit(-1);
}
else
{
printf("open file success");
}
if (!(qyuv = fopen("lena_q.yuv", "wb")))
{
printf("open file error!");
exit(-1);
}
else
{
printf("open file success");
}
if (!(reyuv = fopen("lena_re.yuv", "wb")))
{
printf("open file error!");
exit(-1);
}
else
{
printf("open file success");
}
unsigned char *ybuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
unsigned char *ubuf= (unsigned char*)malloc(sizeof(unsigned char) * width * height*0.25);
unsigned char *vbuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height*0.25);
unsigned char *qbuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
unsigned char *rebuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
fread(ybuf, sizeof(unsigned char), width* height, yuv);
fread(ubuf, sizeof(unsigned char), width* height*0.25, yuv);
fread(vbuf, sizeof(unsigned char), width* height*0.25, yuv);
int bitdepth = 8;
dpcm_encode(ybuf, qbuf, rebuf, width, height, bitdepth);
double freq_q[256] = { 0 };double freq_lena[256] = { 0 };
for (int i = 0; i < 256; i++)
{
freq_q[i] = double(qbuf[i]) / (width*height);
freq_lena[i] = double(ybuf[i]) / (width*height);
}
FILE *qfile; FILE *lenafile;
if ((qfile = fopen("q.txt", "w")) == NULL)
printf("fail\n");
else
printf("success\n");
if ((lenafile = fopen("lena.txt", "w")) == NULL)
printf("fail\n");
else
printf("success\n");
char s[] = "symbol\frequency\n";
fprintf(qfile, s); fprintf(lenafile, s);
for (int i = 0; i < 256; i++)
{
fprintf(qfile, "%d\t%f\n", i, freq_q[i]);
fprintf(lenafile, "%d\t%f\n", i, freq_lena[i]);
}
fwrite(qbuf, sizeof(unsigned char), width * height, qyuv);
fwrite(ubuf, sizeof(unsigned char), width * height*0.25, qyuv);
fwrite(vbuf, sizeof(unsigned char), width * height*0.25, qyuv);
fwrite(rebuf, sizeof(unsigned char), width * height, reyuv);
fwrite(ubuf, sizeof(unsigned char), width * height*0.25, reyuv);
fwrite(vbuf, sizeof(unsigned char), width * height*0.25, reyuv);
free(ybuf); free(ubuf); free(vbuf);
free(qbuf); free(rebuf);
fclose(yuv);
fclose(qyuv);
fclose(reyuv);
fclose(qfile);
fclose(lenafile);
}
实验结果如图,从左至右分别为原始图像、8bit量化预测误差图像、重建图像:
原始图像和误差值图像的概率分布图如下:
接着进行6bit、4bit、2bit量化的对比:
可以看出,4bit以上量化时,图像没有出现明显的失真现象;4bit量化时,重建图像的失真现象可以分辨;在2bit量化时,图像的失真已经让人难以忍受。
对8bit、6bit、4bit、2bit的图像进行PSNR计算得到
量化比特数 | 8 | 6 | 4 | 2 |
---|---|---|---|---|
PSNR(db) | 51.12 | 35.04 | 18.23 | 11.64 |
PSNR的值越小,则图像的质量越差,和我们肉眼的观感相吻合。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。
最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率。
使用已有的Huffman编码器,在命令界面输入huffcode-i lena.yuv-o lena.huff-c>encode.txt