DPCM 压缩系统的实现和分析

一、实验内容

DPCM编码,简称差值编码,是对模拟信号幅度抽样的差值进行量化编码的调制方式(抽样差值的含义请参见“增量调制”)。这种方式是用已经过去的抽样值来预测当前的抽样值,对它们的差值进行编码。

在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。量化器采用8比特均匀量化。

本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求)。还可对预测误差进行1比特、2比特和4比特的量化设计(提高要求)。

在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。

二、实验原理

本实验为8bit量化,因为差值的取值范围为-255~255,所以要将差值加上255再除以2^(9-8),从而使最后得到的量化值区间在0到255之间。
在这里插入图片描述
如图所示:dn是预测误差,Q是量化器,P是重建图像。

psnr是“Peak Signal to Noise Ratio”的缩写,即峰值信噪比,是一种评价图像的客观标准,PSNR值越大失真越小。
在这里插入图片描述

三、代码部分

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);
}

2. 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;
}

四、结果分析

1. 重建图像与误差图像

原图如下:
在这里插入图片描述

8bit量化的重建图片以及预测差值图片如下:
在这里插入图片描述
在进行 7~1bit 量化时,7bit图片没有太明显的差别,但 6bit 之后出现了块效应。且bit数越小,失真越明显。

2. PSNR

PSNR的结果如下:

量化bit数87654321
PSNR51.1542.7235.7329.2423.1417.6511.949.96

可以看出,量化bit数越大,重建的图像质量越好,这与我们的常识相符。

3. 预测误差图像概率分布图

在这里插入图片描述在这里插入图片描述
可以看到量化后的预测误差值大多集中在2的n bits次方处。

4. Huffman编码器

将原图和8bit至1bit量化输出的yuv文件输入Huffman编码器:
在这里插入图片描述在这里插入图片描述

输出是.huff文件和.txt文件。比较生成的.huff文件的文件大小。文件大小和压缩比计算如下表所示:

文件(bit)原文件87654321
结果(kb)68.246.945.237.731.326.621.919.618.3
压缩比100.0%68.8%66.3%55.3%45.9%39.0%32.1%28.7%26.8%

可以发现,进行了量化后的文件的压缩比随着量化比特数的减小而减小。即量化比特数越小,压缩效果越差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值