DPCM 压缩系统的实现和分析

实验目的

掌握DPCM编解码系统的基本原理。初步掌握实验用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。

方法解释

DPCM编解码

原理

在这里插入图片描述

        DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
        在本次实验中,我们采用固定预测器和均匀量化器。

预测器

本实验采用左侧预测,即误差e= 右侧像素值 - 通过左侧像素值计算得到的预测值

量化器

由于像素值区间为[0,255],所以误差e的区间为[-255,255],约有512种值,超过存储bit数所能表示的范围。

8bit量化

对误差e除于2,e/2区间为[-127.5,127.5],再加128,得到e/2+128区间为[0.5,255.5],对此取整,量化误差区间变为[0,255],成功实现量化。

解码器

反量化+反预测
实现两种逆运算

代码实现

编码器内嵌解码器

	if (y_buffer != NULL) {
		for (i = 0; i < frameHeight; i++)
		{
			/**
			每一行,以第一个值为下一个值得预测值x_pre
			因为是8bit量化,所以第一个像素原值不进行量化操作
			*/
			*(encoded_buffer + i * frameWidth + j) = *(y_buffer + i * frameWidth + j);
			x_pre = *(encoded_buffer + i * frameWidth + j);
			//解码重建,第一个像素值等效为原值
			*(rebuilt_buffer + i * frameWidth + j) = x_pre;
			//每行第二个像素开始进行预测编码(解码重建)
			for (j = 1; j < frameWidth; j++)
			{	//左侧误差e
				e = (int)*(y_buffer + i * frameWidth + j) - (int)x_pre;
				//8bit量化预测误差
				eQ = (unsigned char)(e / 2 + 128);
				//输出量化预测误差
				*(encoded_buffer + i * frameWidth + j) = eQ;
				//反量化+反预测实现图像解码重建
				x_pre = unsigned char((int)x_pre + ((int)eQ-128) * 2);
				//输出解码重建像素
				*(rebuilt_buffer + i * frameWidth + j) = x_pre;
			}
			//列计数器置零
			j = 0;
		}
	}

实验结果

调试DPCM编解码程序

原图片
在这里插入图片描述
编码后图像
在这里插入图片描述
解码重建后图像
在这里插入图片描述

结果分析

huffman编码

分别对量化预测误差图和原图进行huffman编码
在这里插入图片描述
在这里插入图片描述

PSNR视频质量

评价重建图像:PSNR
PSNR,即Peak Signal to Noise Ratio,峰值信噪比,是一种评价图像的客观标准。其数学公式为:
P S N R = 10 ∗ l g ( M A X 2 M S E ) . PSNR = 10*lg(\cfrac{MAX^{2}}{MSE}). PSNR=10lg(MSEMAX2).
其中:MAX指最大值,在8bit灰度图中即等于255.

MSE指均方误差Mean Square Error
M S E = ∑ i = 0 M ∑ j = 0 N ( f ( i , j ) − f ′ ( i , j ) ) 2 M N MSE= \cfrac{\displaystyle\sum_{i=0}^M \displaystyle\sum_{j=0}^N{(f(i,j)−f' (i,j))^{2}}}{MN} MSE=MNi=0Mj=0N(f(i,j)f(i,j))2
具体到本实验中,f(x,y)和f’(x,y)即原图像和重建图像,MN即为图像的宽和高。

代码如下,

	int max = 255;
	double mse = 0;
	for (int i = 0; i < frameHeight; i++)
		for (int j = 0; j < frameWidth; j++)
			mse += (y_buffer[i * frameWidth + j] - rebuilt_buffer[i * frameWidth + j]) * (y_buffer[i * frameWidth + j] - rebuilt_buffer[i * frameWidth + j]);
	mse = (double)mse / (double)(frameWidth * frameHeight);
	double psnr = 10 * log10((double)(max * max) / mse);
	cout << "PSNR = " << psnr << endl;

在这里插入图片描述

结果对比

文件文件大小压缩比图像质量
原文件98,304100%
熵编码69,88571.1%
DPCM+熵编码46,16347.0%51.1772

完整代码

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

using namespace std;


int main() {
	FILE* fp;
	fopen_s(&fp, "Lena256B.yuv", "r");

	unsigned char* y_buffer;
	unsigned char* uv_buffer;


	int frameWidth = 256;
	int frameHeight = 256;

	y_buffer = (unsigned char*)malloc(frameHeight * frameWidth);
	uv_buffer = (unsigned char*)malloc(frameHeight * frameWidth / 2);

	fread(y_buffer, 1, frameHeight * frameWidth, fp);
	fread(uv_buffer, 1, frameHeight * frameWidth / 2, fp);


	unsigned char* encoded_buffer;
	unsigned char* rebuilt_buffer;

	int e;
	unsigned char eQ, x_pre;
	int i, j = 0;

	encoded_buffer = (unsigned char*)malloc(frameHeight * frameWidth);
	rebuilt_buffer = (unsigned char*)malloc(frameHeight * frameWidth);

	if (y_buffer != NULL) {
		for (i = 0; i < frameHeight; i++)
		{
			*(encoded_buffer + i * frameWidth + j) = *(y_buffer + i * frameWidth + j);

			x_pre = *(encoded_buffer + i * frameWidth + j);

			*(rebuilt_buffer + i * frameWidth + j) = x_pre;

			for (j = 1; j < frameWidth; j++)
			{
				e = (int)*(y_buffer + i * frameWidth + j) - (int)x_pre;

				eQ = (unsigned char)(e / 2 + 128);

				*(encoded_buffer + i * frameWidth + j) = eQ;

				x_pre = unsigned char((int)x_pre + ((int)eQ-128) * 2);

				*(rebuilt_buffer + i * frameWidth + j) = x_pre;
			}

			j = 0;
		}
	}

	int max = 255;
	double mse = 0;
	for (int i = 0; i < frameHeight; i++)
		for (int j = 0; j < frameWidth; j++)
			mse += (y_buffer[i * frameWidth + j] - rebuilt_buffer[i * frameWidth + j]) * (y_buffer[i * frameWidth + j] - rebuilt_buffer[i * frameWidth + j]);
	mse = (double)mse / (double)(frameWidth * frameHeight);
	double psnr = 10 * log10((double)(max * max) / mse);
	cout << "PSNR = " << psnr << endl;


	FILE* fp_en;
	fopen_s(&fp_en, "Lena256B_encoded.yuv", "wb");

	fwrite(encoded_buffer, 1, frameHeight * frameWidth, fp_en);
	fwrite(uv_buffer, 1, frameHeight * frameWidth / 2, fp_en);

	FILE* fp_de;
	fopen_s(&fp_de, "Lena256B_rebuilt.yuv", "wb");

	fwrite(rebuilt_buffer, 1, frameHeight * frameWidth, fp_de);
	fwrite(uv_buffer, 1, frameHeight * frameWidth / 2, fp_de);

	fclose(fp);
	fclose(fp_en);
	fclose(fp_de);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值