DPCM 压缩系统的实现和分析

一、实验目的

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

二、DPCM编解码原理在这里插入图片描述

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

在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。

三、PSNR原理

PSNR 是“Peak Signal to Noise Ratio”的缩写,即峰值信噪比,是一种评价图像的客观标准,它具有局限性,一般是用于最大值信号和背景噪音之间的一个工程项目。

其数学公式如下图所示:
在这里插入图片描述
其中,MSE是原图像(语音)与处理图像(语音)之间均方误差。

四、实验代码

头文件:

void DPCM_Pixel(unsigned char* YOrigi, unsigned char* YError, unsigned char* YRestr, int pre, int j, int bits);
void RDPCM(unsigned char* YError, unsigned char* YRestr, int height, int width, int bits);
void RDPCM_Pixel(unsigned char* YError, unsigned char* YRestr, int pre, int j, int bits);
double PSNR(unsigned char* YOrigi, unsigned char* YRestr, int height, int width);

DPCM_code.cpp:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <cmath>
#include "DPCM_code.h"

using namespace std;

//double sign(double x)
//{
//	if (x < 0)
//		return -1;
//	else if (x > 0)
//		return 1;
//	else
//		return 0;
//}

int OverflowX(int x, int High, int Low)
{
	if (x > High)
		return High;
	else if (x < Low)
		return Low;
	else
		return x;
}

double MSE(unsigned char* YOrigi, unsigned char* YRestr, int height, int width)
{
	int size = height * width;
	long long int sum = 0;
	double mean;
	for (int i = 0; i < size; i++)
	{
		long long int temp = (long long int)(YOrigi[i] - YRestr[i]) * (long long int)(YOrigi[i] - YRestr[i]);
		sum += temp;
	}
	mean = (double)sum / (double)size;
	return mean;
}

int ErrorQuantity(int X, int bits)
{
	X = X + 255;//化为无符号数
	X = X / 2;//将误差范围归一到[0,255]
	X = floor(X / pow(2, 8 - bits));
	X = X * pow(2, 8 - bits);
	X = OverflowX(X, 255, 0);
	return X;
}

int invErrorQuantity(int X, int bits)
{
	X = X * 2;//将误差放回原来的范围
	X = X - 255;//将无符号数转为有符号数
	return X;
}

void DPCM_Pixel(unsigned char* YOrigi, unsigned char* YError, unsigned char* YRestr, int pre, int j, int bits)
{
	/*for the first Pixel,suppose YError[0]=128-YOrigi[0],
	then quantify it and store*/
	int E_temp, R_temp;
	switch (j)
	{
	case 0:
		E_temp = 128 - YOrigi[pre + j];
		E_temp = ErrorQuantity(E_temp, bits);//quantity
		YError[pre + j] = E_temp;
		E_temp = invErrorQuantity(E_temp, bits);//inverse quantization
		R_temp = 128 - E_temp;
		R_temp = OverflowX(R_temp, 255, 0);//prevent overflow
		YRestr[pre + j] = (unsigned char)R_temp;
		break;
	default:
		E_temp = YOrigi[pre + j] - YRestr[pre + j - 1];
		E_temp = ErrorQuantity(E_temp, bits);//quantity
		YError[pre + j] = E_temp;
		E_temp = invErrorQuantity(E_temp, bits);//inverse quantization
		R_temp = E_temp + YRestr[pre + j - 1];
		R_temp = OverflowX(R_temp, 255, 0);//prevent overflow
		YRestr[pre + j] = (unsigned char)R_temp;
		break;
	}
}

void RDPCM_Pixel(unsigned char* YError, unsigned char* YRestr, int pre, int j, int bits)
{
	int E_temp, R_temp;
	switch (j)
	{
	case 0:
		E_temp = YError[pre + j];
		E_temp = invErrorQuantity(E_temp, bits);
		R_temp = 128 - E_temp;
		R_temp = OverflowX(R_temp, 255, 0);
		YRestr[pre + j] = (unsigned char)R_temp;
		break;
	default:
		E_temp = YError[pre + j];
		E_temp = invErrorQuantity(E_temp, bits);
		R_temp = E_temp + YRestr[pre + j - 1];
		R_temp = OverflowX(R_temp, 255, 0);
		YRestr[pre + j] = (unsigned char)R_temp;
		break;
	}

}

void DPCM(unsigned char* YOrigi, unsigned char* YError, unsigned char* YRestr, int height, int width, int bits)
{
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++)
			DPCM_Pixel(YOrigi, YError, YRestr, i * width, j, bits);//for each pixel,use the function DPCM_Pixel() to calculate the YRestr[i] and YError[i] 
}

void RDPCM(unsigned char* YError, unsigned char* YRestr, int height, int width, int bits)
{
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++)
			RDPCM_Pixel(YError, YRestr, i * width, j, bits);
}

double PSNR(unsigned char* YOrigi, unsigned char* YRestr, int height, int width)
{
	int fmax = pow(2, 8) - 1;
	int a = fmax * fmax;
	double mean_se = MSE(YOrigi, YRestr, height, width);
	double peak_SNR = 10 * log10((double)a / mean_se);
	return peak_SNR;
}

main函数:

#include <iostream>
#include <cstdio>
#include <fstream>
#include "DPCM_code.h"

using namespace std;

int main(int argc, char** argv)
{
	//moon图片464 538,使用的是4:4:4的yuv文件
	int width = atoi(argv[1]);
	int height = atoi(argv[2]);
	int bits = atoi(argv[3]);
	int Ysize = height * width;
	int Esize = height * width * 2;

	ifstream OrigiFile(argv[4], ios::binary);
	ofstream ErrorFile(argv[5], ios::binary);
	ofstream RestrFile(argv[6], ios::binary);
	if (!OrigiFile) { cout << "error to open OrigiFile!" << endl; }
	if (!ErrorFile) { cout << "error to open ErrorFile!" << endl; }
	if (!RestrFile) { cout << "error to open RestrFile!" << endl; }

	unsigned char* YOrigi = new unsigned char[Ysize];
	unsigned char* YError = new unsigned char[Ysize];
	unsigned char* YRestr = new unsigned char[Ysize];
	unsigned char* E_File = new unsigned char[Esize];

	//读入Y分量和其余分量
	OrigiFile.read((char*)YOrigi, Ysize);
	OrigiFile.read((char*)E_File, Esize);

	//进行预测和量化
	DPCM(YOrigi, YError, YRestr, height, width, bits);

	//对重建图像进行重置,用以判断解码端工作效果
	for (int i = 0; i < Ysize; i++)
		YRestr[i] = 0;

	//从YError解出量化后的yuv文件
	RDPCM(YError, YRestr, height, width, bits);
	double peak_SNR = PSNR(YOrigi, YRestr, height, width);
	cout << peak_SNR << endl;

	ErrorFile.write((char*)YError, Ysize);
	ErrorFile.write((char*)E_File, Esize);
	RestrFile.write((char*)YRestr, Ysize);
	RestrFile.write((char*)E_File, Esize);

	OrigiFile.close();
	ErrorFile.close();
	RestrFile.close();
	delete[]YOrigi;
	delete[]YError;
	delete[]YRestr;
	delete[]E_File;
	return 0;
}

参数设置:
在这里插入图片描述

五、实验结果

1、输出图像

图像顺序依次为:原始图像、 预测误差图像、重建图像

8bit量化
在这里插入图片描述
4bit量化
在这里插入图片描述
2bit量化
在这里插入图片描述
1bit量化
在这里插入图片描述
量化比特数从8bit到1bit,重建图像质量逐渐下降。

2、计算PSNR值

量化比特数PSNR值
8bit51.1338
4bit23.0725
2bit11.8881
1bit9.86284

六、Huffman编码

在cmd命令提示符中输入命令行:在这里插入图片描述
得到输出文件:
在这里插入图片描述在这里插入图片描述

七、计算、比较压缩比

量化比特数压缩比
原始图像71.9%
8bit36.5%
4bit23.9%
2bit21.9%
1bit21.4%

量化后文件的压缩比随着量化比特数的增加而增大,量化比特数越大,压缩效果越好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值