【实验四】DPCM压缩系统的实现与分析

一、实验目的

  • 掌握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)实验结果
  1. 重建图像与误差图像

原图如下:
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了,所以图像是黑的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值