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之间。
DPCM 压缩系统的实现和分析
如图所示:dn是预测误差,Q是量化器,P是重建图像。

psnr是“Peak Signal to Noise Ratio”的缩写,即峰值信噪比,是一种评价图像的客观标准,PSNR值越大失真越小。
DPCM 压缩系统的实现和分析

三、代码部分

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. 重建图像与误差图像

原图如下:
DPCM 压缩系统的实现和分析

8bit量化的重建图片以及预测差值图片如下:
DPCM 压缩系统的实现和分析
在进行 7~1bit 量化时,7bit图片没有太明显的差别,但 6bit 之后出现了块效应。且bit数越小,失真越明显。

2. PSNR

PSNR的结果如下:

量化bit数 8 7 6 5 4 3 2 1
PSNR 51.15 42.72 35.73 29.24 23.14 17.65 11.94 9.96

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

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

DPCM 压缩系统的实现和分析DPCM 压缩系统的实现和分析
可以看到量化后的预测误差值大多集中在2的n bits次方处。

4. Huffman编码器

将原图和8bit至1bit量化输出的yuv文件输入Huffman编码器:
DPCM 压缩系统的实现和分析DPCM 压缩系统的实现和分析

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

文件(bit) 原文件 8 7 6 5 4 3 2 1
结果(kb) 68.2 46.9 45.2 37.7 31.3 26.6 21.9 19.6 18.3
压缩比 100.0% 68.8% 66.3% 55.3% 45.9% 39.0% 32.1% 28.7% 26.8%

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

上一篇:过渡/动画


下一篇:鼠标悬浮时缓慢放大图片(过渡transition)