DPCM 压缩系统的实现和分析

DPCM 压缩系统的实现和分析

原理

在这里插入图片描述

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

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

内容

利用左侧像素进行线性预测,量化器采用8bit均匀量化和4bit均匀量化

并对压缩后的文件和压缩质量进行分析

代码设计

#include<stdio.h>
#include< stdlib.h>
#include<iostream>
using namespace std;

void Qualify_8bit(unsigned char a, unsigned char b, unsigned char& e, unsigned char& y) {
	int e1 = a - b;
	e = e1 / 2 + 128;
	y = b + (e -128) * 2;
	e = (e - 128) * 2 + 128;//提升电平
	return;

}

void Qualify_4bit(unsigned char a,unsigned char b,unsigned char &e,unsigned char &y) {
	int e1 = a - b;
	e = e1 / 32 + 16;
	y = b + (e - 16) * 32;
	e = (e-16)*32+128;//提升电平
	return;

}

int main(int argc, char* argv[]) {
	//argv[1]为文件名
	//argv[2][3]为宽高
	//argv[4]:重建文件名
	//argv[5]:差值文件名
	FILE* inYuvFileP = NULL;
	if (fopen_s(&inYuvFileP, argv[1], "rb") == 0) {
		cout << "open inputYUVFile successfully!" << endl;
		fseek(inYuvFileP, 0, SEEK_SET);
	}
	FILE* preYuvFileP = NULL;
	if (fopen_s(&preYuvFileP, argv[4], "wb") == 0) {
		cout << "open predYUVFile successfully!" << endl;
	}
	FILE* eFileP = NULL;
	if (fopen_s(&eFileP, argv[5], "wb") == 0) {
		cout << "open eFile successfully!" << endl;
	}


	int W = atoi(argv[2]);
	int H = atoi(argv[3]);
	int imgSize = W * H;
	unsigned char* Ybuf = (unsigned char*)malloc(sizeof(unsigned char)*imgSize);
	unsigned char* Ubuf = (unsigned char*)malloc(sizeof(unsigned char) * imgSize/4);
	unsigned char* Vbuf = (unsigned char*)malloc(sizeof(unsigned char) * imgSize/4);

	unsigned char*preYbuf= (unsigned char*)malloc(sizeof(unsigned char)*imgSize);
	unsigned char* ebuf = (unsigned char*)malloc(sizeof(unsigned char) * imgSize);
	fread(Ybuf, imgSize, sizeof(unsigned char), inYuvFileP);
	

	//相减
	int e1 = 0;

	for (int i = 0; i < H; i++) {
		//e = Qualify_8bit(e1);
		//ebuf[i*W] = e;//固定第一列与128相减得到差值
		//preYbuf[i * W ] = 128 + (ebuf[i * W]-128)*2;
		unsigned char e = 0;
		unsigned char y = 0;
		Qualify_8bit(Ybuf[i * W], 128,e,y);
		ebuf[i * W] = e;
		preYbuf[i * W] = y;
		for (int j = 1; j < W; j++) {
			//e1 = Ybuf[i * W + j] -preYbuf[i * W + j - 1];
			//e = Qualify_8bit(e1);
			//ebuf[i * W + j] = e;
			防止溢出判断
			//y = preYbuf[i * W + j - 1] + (e - 128) * 2;
			Qualify_8bit(Ybuf[i * W+j],preYbuf[i*W+j-1],e,y);
			ebuf[i * W+j] = e;
			cout << e << " ";
			//其实没有必要!!!!判断
			if ( y> 255) { y = 255; }
			if (y < 0) { y = 0; }
			//
			preYbuf[i * W + j] = y;
			//cout << preYbuf[i * W + j] << " ";
		}
	}

	for (int i = 0; i < W * H / 4; i++) {
		Ubuf[i] = 128;
		Vbuf[i] = 128;
	}


	fwrite(preYbuf, sizeof(unsigned char), imgSize, preYuvFileP);
	fwrite(Ubuf, sizeof(unsigned char), imgSize/4, preYuvFileP);
	fwrite(Vbuf, sizeof(unsigned char), imgSize/4, preYuvFileP);


	fwrite(ebuf, sizeof(unsigned char), imgSize, eFileP);
	fwrite(Ubuf, sizeof(unsigned char), imgSize / 4, eFileP);
	fwrite(Vbuf, sizeof(unsigned char), imgSize / 4, eFileP);
	free( Ybuf);
	free(Ubuf);
	free(Vbuf);
	free(ebuf);
	free(preYbuf);
	fclose(inYuvFileP);
	fclose(preYuvFileP);
	fclose(eFileP);
}

还是对C++语法不熟,遇见了不少困难。

逻辑上主要出现的问题只有一个问题

如何显示我们实际上传输的图像??

我思考了挺久,如果将相减后的量化值直接存于预测误差图像,结果基本全黑或全灰(单纯提升128电平后),但实际上接收端收到的信息应该是(e-16)*32+128,所以将这个存入预测误差图像就是我们实际上传输的图像。

每行第一列像素我都默认以128为基准

实验效果

4bit量化

在这里插入图片描述

8bit量化

在这里插入图片描述

经过哈夫曼编码后的效果

8bit量化:原Lena.yuv从96K到69K

压缩后的:原Lena.yuv从96K到43K

因为4bit量化个人觉得失真度太大,就不计算了

在这里插入图片描述

PSNR计算

峰值信噪比(PSNR), 一种评价图像的客观标准。它具有局性,PSNR是“Peak Signal to Noise Ratio”的缩写。peak的中文意思是顶点。而ratio的意思是比率或比列的。整个意思就是到达噪音比率的顶点信号,psnr一般是用于最大值信号和背景噪音之间的一个工程项目。通常在经过影像压缩之后,通常输 出的影像都会在某种程度与原始影像不同。为了衡量经过处理后的影像品质,我们通常会参考PSNR值来衡量某个处理程序能否令人满意。它是原图像与被处理图 像之间的均方误差相对于(2n-1)2的对数值(信号最大值的平方,n是每个采样值的比特数),它的单位是dB

PSNR高于40dB说明图像质量极好(即非常接近原始图像),

在30—40dB通常表示图像质量是好的(即失真可以察觉但可以接受),

在20—30dB说明图像质量差;

最后,PSNR低于20dB图像不可接受

img

img

img

8bit量化后结果为:51.265dB

PSNR计算:

float calPSNR(unsigned char* Ybuf, unsigned char* predYbuf,int n) {
	float a = 0;
	unsigned char max = 255;
	for (int i = 0; i < n; i++) {
		a = a+(Ybuf[i] - predYbuf[i]) * (Ybuf[i] - predYbuf[i]);
		

	}
	float mse = a / n;
	float tmp = max * max / mse;
	float psnr = 10 * log10(tmp);
	return psnr;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值