一、实验目的
- 掌握DPCM编解码系统的基本原理
- 用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。
二、实验内容
1.DPCM编解码原理:
DPCM,即差分的PCM,简称插值编码,基本原理是对信号插值进行量化。
由于图片间像素的相关性,插值后的重复值会比较多,因此信源的熵就会减小。因此经过DPCM系统后再进行熵编码有利于提高压缩效率。
在DPCM系统中,需要对前一个值进行解码,以作为当前的预测值。编解码框图如图所示。
xn是输入信号,xn是重建信号,作为预测器确定下一个信号估计值的输入信号。pn是预测语音信号,dn是预测误差信号,dn=xn-pn。DPCM系统对差值信号dn进行量化编码,用来补偿过去编码中产生的量化误差,它是一个反馈系统,采用这种结构可以避免量化误差的积累。d^n是量化后的差值信号。最后将量化后的差值信号送入编码器编码。该系统内嵌了一个解码器如右上图所示。
PSRN
2.具体实现:
(1)代码实现
main.c
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
#include"DPCM.h"
using namespace std;
int main(int argc, char* argv[]) {
char* yuvaddr = argv[1];
char* yuv2addr = argv[2];
int W = atoi(argv[3]);
int H = atoi(argv[4]);
char* yuverraddr = argv[5];
int imgsize = W * H * 3 / 2;
int q = atoi(argv[6]);
unsigned char* yuvbuffer = new unsigned char[imgsize];
unsigned char* ybuffer = new unsigned char[imgsize * 2 / 3];
unsigned char* ubuffer = new unsigned char[imgsize / 6];
unsigned char* vbuffer = new unsigned char[imgsize / 6];
unsigned char* preerrbuffer = new unsigned char[imgsize * 2 / 3];
unsigned char* levelbuffer = new unsigned char[imgsize * 2 / 3];
FILE* imgopen = fopen(yuvaddr, "rb");
if (imgopen == NULL) {
cout << "打开yuv文件失败" << endl;
}
FILE* yuvsave = fopen(yuv2addr, "w");
if (yuvsave == NULL) {
cout << "创建yuv空白文件失败" << endl;
}
FILE* yuvsave2 = fopen(yuverraddr, "w");
if (yuvsave2 == NULL) {
cout << "创建yuv空白文件失败" << endl;
}
fread(yuvbuffer, sizeof(unsigned char), imgsize, imgopen);
int i;
for (i = 0; i < imgsize * 2 / 3; i++) {
ybuffer[i] = yuvbuffer[i];
}
for (i = 0; i < imgsize / 6; i++) {
ubuffer[i] = yuvbuffer[i + imgsize * 2 / 3];
}
for (i = 0; i < imgsize / 6; i++) {
vbuffer[i] = yuvbuffer[i + imgsize * 2 / 3 + imgsize / 6];
}
DpcmEn(ybuffer, preerrbuffer, levelbuffer, H, W, q);
fwrite(levelbuffer, sizeof(unsigned char), W * H, yuvsave);
fwrite(ubuffer, sizeof(unsigned char), W * H / 4, yuvsave);
fwrite(vbuffer, sizeof(unsigned char), W * H / 4, yuvsave);
for (i = 0; i < imgsize / 6; i++) {
ubuffer[i] = 128;
}
for (i = 0; i < imgsize / 6; i++) {
ubuffer[i] = 128;
}
fwrite(preerrbuffer, sizeof(unsigned char), W * H, yuvsave2);
fwrite(ubuffer, sizeof(unsigned char), W * H / 4, yuvsave2);
fwrite(vbuffer, sizeof(unsigned char), W * H / 4, yuvsave2);
PrintPSNR(ybuffer, levelbuffer, W, H);
}
DPCM.h
#define DPCM_H_INCLUDED
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
using namespace std;
void DpcmEn(unsigned char* yBuff, unsigned char* preerr, unsigned char* level, int h, int w, int q) {
int prediction;
int err;
int i;
int j;
int a;
int b;
for (i = 0; i < h; i++) {
prediction = 128;
err = yBuff[i * w] - prediction;
a = (err + 128) / pow(2, 8 - q);
if (a > pow(2, q) - 1) {
a = pow(2, q) - 1;
}
if (a < 0) {
a = 0;
}
preerr[i * w] = a;
b = preerr[i * w] * pow(2, 8 - q) - 128 + prediction;
if (b > 255) {
b = 255;
}
if (b < 0) {
b = 0;
}
level[i * w] = b;
for (j = 1; j < w; j++) {
prediction = level[i * w + j - 1];
err = yBuff[i * w + j] - prediction;
a = (err + 255) / pow(2, 9 - q);
if (a > pow(2, q) - 1) {
a = pow(2, q) - 1;
}
if (a < 0) {
a = 0;
}
preerr[i * w + j] = a;
b = preerr[i * w + j] * pow(2, 9 - q) - 255 + prediction;
if (b > 255) {
b = 255;
}
if (b < 0) {
b = 0;
}
level[i * w + j] = b;
}
}
}
void PrintPSNR(unsigned char* ybuffer, unsigned char* levelbuffer, int w, int h) {
double mse;
double psnr;
double sum = 0;
double temp;
int i;
for (i = 0; i < w * h; i++) {
temp = pow((ybuffer[i] - levelbuffer[i]), 2);
sum += temp;
}
mse = sum / (w * h);
psnr = 10 * log10((pow(2, 8) - 1) * (pow(2, 8) - 1) / mse);
cout << "the psnr is: " << psnr << endl;
}
(2)实验结果
- 重建图像与误差图像
原图如下:
8bit量化的重建图片以及预测差值图片如下:
在这里插入图片描述
在进行 7~1bit 量化时,7bit图片没有太明显的差别,但 6bit 之后出现了块效应。且bit数越小,失真越明显。
3.PSNR的计算:
double thepsnr(unsigned char* buf1, unsigned char* buf2)
{
double mse = 0;
double div = 0;
double psnr = 0;
int width = 768;
int height = 512;
int k = width * height;
for (int i = 0; i < k; i++)
{
div = buf1[i] - buf2[i];
mse += div * div;
}
mse = mse / (width * height);
psnr = 10 * log10(255 * 255 / mse);
return psnr;
}
统计计算所得实验结果为:
图像 PSNR
1比特量化 8.708083
2比特量化 6.655150
4比特量化 7.568289
8比特量化 51.155397
4.编码效率的比较:
使用huffman编码器进行压缩,比较DPCM+熵编码和只用熵编码的效率:
使用matlab 绘制概率分布图:
统计结果:
方式 压缩比
仅进行熵编码压缩比 28.125%
1比特量化+熵编码压缩比 81.076%
2比特量化+熵编码压缩比 71.875%
4比特量化+熵编码压缩比 62.326%
8比特量化+熵编码压缩比 67.708%
三、实验总结与分析
1.根据实验结果可以看出,DPCM+熵编码的压缩效率明显更好,能达到更高的压缩率,而从PSNR可知8比特量化图像效果最好,在利用DPCM进行预测编码时,空间冗余越大,压缩效率越高。
2.注意算法中的先算出量化间隔再取整是下取整,不会导致溢出。
3.算法中的残差值的量化方法是除以量化间隔再取整,这种量化方法相当于每次取下电平。
4.1bit图像出现严重问题,也跟量化有关,按照这个算法,残差负值全部被量化为-255,正值全被量化为0。这会导致重建图像的值只减不增,最后全变成0了,所以图像是黑的。