DPCM 压缩系统的实现和分析

一、实验目的

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

二、相关知识

1.DPCM编解码原理
在这里插入图片描述

DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。

三、实验步骤

在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。量化器采用8比特均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求)。还可对预测误差进行1比特、2比特和4比特的量化设计(提高要求)。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。

四、实验代码

DPCM.cpp

#include<stdio.h>
#include<stdlib.h>
#include<math.h>


int i = 8;	//做i bit的量化

//量化器
unsigned char Q(int error)
{
	unsigned char pre_e;
	pre_e = error / pow(2, 9 - i);
	return pre_e;
}
//反量化器
unsigned char QT(unsigned char pre_e)
{
	unsigned char pre_eT;
	pre_eT = pre_e * pow(2, 9 - i);
	return pre_eT;
}

//DPCM
void DPCM(unsigned char* origin, unsigned char* pre_e, unsigned char* rebuild, int w, int h)
{
	int* error;
	error = (int*)calloc(w * h, sizeof(int));
	//int error[w*h] = { 0 };
	for (int i = 0; i < w; i++)
	{
		for (int j = 0; j < h; j++)
		{
			rebuild[w * j] = origin[w * j];
			pre_e[w * j] = 0;
			if (i > 0)
			{
				error[i] = origin[w * j + i] - rebuild[w * j + i - 1];//预测误差
				pre_e[w * j + i] = Q(error[i]);
				QT(pre_e[w * j + i]);
				rebuild[w * j + i] = rebuild[w * j + i - 1] + QT(pre_e[w * j + i]);
			}
		}
	}
	for (int i = 0; i < w * h; i++)
	{
		pre_e[i] = pre_e[i] + 128;
		if (pre_e[i] > 255)pre_e[i] = 255;
	}
	for (int i = 0; i < w * h; i++)
	{
		if (rebuild[i] > 255)rebuild[i] = 255;
		if (rebuild[i] < 0)rebuild[i] = 0;
	}
}


main.cpp

#include <stdio.h>
#include <windows.h>
#include "bmp2yuv.h"

void main(int argc, char* argv[])
{
	FILE* bmpFile = NULL, * yuvFile = NULL;
	BITMAPFILEHEADER File_header;
	BITMAPINFOHEADER Info_header;
	char* bmpFileName = NULL;
	char* yuvFileName = NULL;
	unsigned char* rgbBuf = NULL;
	unsigned char* yBuff = NULL;
	unsigned char* uBuff = NULL;
	unsigned char* vBuff = NULL;
	int flip = 0;//flip=1时正序,为0时上下翻转

	int width, height;
	//打开yuv文件
	if ((yuvFile = fopen(argv[2], "wb+")) == NULL)
	{
		printf("yuv file failed!");
		exit(0);
	}
	else
	{
		yuvFile = fopen(argv[2], "wb+");
		printf("The output yuv file is %s\n", yuvFile);
	}

	//	打开bmp文件
	if ((bmpFile = fopen(argv[1], "rb+")) == NULL)
	{
		printf("bmp file open failed!");
		exit(0);
	}
	else
	{
		bmpFile = fopen(argv[1], "rb+");
		printf("The input bmp file is %s\n", bmpFile);
	}

	//	读文件头信息
	if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1)
	{
		printf("read file header error!");
		exit(0);
	}
	//判断是否为bmp文件
	if (File_header.bfType != 0x4D42)
	{
		printf("Not bmp file!");
		exit(0);
	}
	//读信息头信息
	if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1)
	{
		printf("read info header error!");
		exit(0);
	}


	width = Info_header.biWidth;
	height = Info_header.biHeight;
	printf("This is a %d bits image!\n", Info_header.biBitCount);
	printf("\nbmp size: \t%d X %d\n", Info_header.biWidth, Info_header.biHeight);

	//开辟4个缓冲区
	rgbBuf = (unsigned char*)malloc(height * width * 3);
	memset(rgbBuf, 0, height * width * 3);//初始化函数,用于清0
	yBuff = (unsigned char*)malloc(height * width);
	uBuff = (unsigned char*)malloc((height * width) / 4);
	vBuff = (unsigned char*)malloc((height * width) / 4);

	ReadRGB(File_header, Info_header, bmpFile, rgbBuf);

	if (RGB2YUV(width, height, rgbBuf, yBuff, uBuff, vBuff, flip))
	{
		printf("rgb2yuv error");
		exit(1);
	}
	for (int i = 0; i < width * height; i++)
	{
		if (yBuff[i] < 16) yBuff[i] = 16;
		if (yBuff[i] > 235) yBuff[i] = 235;
	}

	for (int i = 0; i < width * height / 4; i++)
	{
		if (uBuff[i] < 16) uBuff[i] = 16;
		if (uBuff[i] > 240) uBuff[i] = 240;
		if (vBuff[i] < 16) vBuff[i] = 16;
		if (vBuff[i] > 240) vBuff[i] = 240;
	}


	fwrite(yBuff, 1, width * height, yuvFile);
	fwrite(uBuff, 1, (width * height) / 4, yuvFile);
	fwrite(vBuff, 1, (width * height) / 4, yuvFile);



	//DPCM
	//只对y通道进行操作
	FILE* predictPic = NULL, * rebuildPic = NULL;

	if ((predictPic = fopen(argv[3], "wb+")) == NULL)
	{
		printf("predict.yuv open fail!\n");
		exit(0);
	}
	if ((rebuildPic = fopen(argv[4], "wb+")) == NULL)
	{
		printf("rebuild.yuv open fail!\n");
		exit(0);
	}
	//unsigned char *origin = NULL;
	unsigned char* pre_e = NULL;
	unsigned char* rebuild = NULL;
	//origin = (unsigned char *)malloc(width*height* sizeof(char));
	pre_e = (unsigned char*)malloc(width * height * sizeof(char));
	rebuild = (unsigned char*)malloc(width * height * sizeof(char));



	DPCM(yBuff, pre_e, rebuild, width, height);

	unsigned char* uv;
	uv = (unsigned char*)malloc(width * height / 2 * sizeof(char));
	for (int i = 0; i < width * height / 2; i++)
	{
		uv[i] = 128;
	}

	fwrite(pre_e, 1, width * height, predictPic);
	fwrite(uv, 1, (height * width) / 2, predictPic);

	fwrite(rebuild, 1, width * height, rebuildPic);
	fwrite(uBuff, 1, (height * width) / 4, rebuildPic);
	fwrite(vBuff, 1, (height * width) / 4, rebuildPic);


	//free(origin);
	free(pre_e);
	free(rebuild);

	fclose(predictPic);
	fclose(rebuildPic);


	free(rgbBuf);
	free(yBuff);
	free(uBuff);
	free(vBuff);
	fclose(bmpFile);
	fclose(yuvFile);
}



dealdata.cpp

#include <stdio.h>
#include <math.h>
#include <windows.h>
#define w 256
#define h 256
#define bit 8 //量化比特数

void main(int argc, char* argv[])
{
	FILE* dataFile = NULL, * processFile = NULL, * rebuild = NULL, * origin = NULL;
	//打开文件
	if ((dataFile = fopen(argv[1], "rb")) == NULL)
	{
		printf("data file failed!");
		exit(0);
	}
	if ((processFile = fopen(argv[2], "wb")) == NULL)
	{
		printf("process file failed!");
		exit(0);
	}
	if ((rebuild = fopen(argv[3], "rb")) == NULL)
	{
		printf("rebuild file failed!");
		exit(0);
	}
	if ((origin = fopen(argv[4], "rb")) == NULL)
	{
		printf("origin file failed!");
		exit(0);
	}

	unsigned char* originData = NULL;
	int* processData = NULL;
	originData = (unsigned char*)malloc(w * h * 1.5);
	processData = (int*)calloc(256, sizeof(int));
	fread(originData, 1, w * h * 1.5, dataFile);

	for (int i = 0; i < w * h * 1.5; i++)
	{
		for (int j = 0; j < 256; j++)
		{
			if (originData[i] == j)
				processData[j]++;
		}
	}
	for (int i = 0; i < 256; i++)
	{
		fprintf(processFile, "%d\n", processData[i]);
	}


	//PSNR
	unsigned char* orpic = NULL;
	unsigned char* repic = NULL;
	orpic = (unsigned char*)malloc(w * h * 1.5);
	repic = (unsigned char*)malloc(w * h * 1.5);
	fread(orpic, 1, w * h * 1.5, origin);
	fread(repic, 1, w * h * 1.5, rebuild);
	double MSE;
	double k = 0;
	for (int i = 0; i < w * h * 1.5; i++)
	{
		k = pow(orpic[i] - repic[i], 2) + k;
	}
	MSE = k / (w * h * 1.5);
	double psnr;
	double a;
	a = pow(pow(2, bit) - 1, 2);
	psnr = 10 * log10(a / MSE);
	printf("psnr(%dbit)=%lf\n", bit, psnr);

	free(orpic);
	free(repic);
	free(originData);
	free(processData);
	fclose(dataFile);
	fclose(processFile);
	fclose(origin);
	fclose(rebuild);
}

五、实验结果

8bit量化输出结果:
在这里插入图片描述

将预测误差图像、原始图像文件写入文件并将该文件输入Huffman编码器并输出。
在这里插入图片描述

在这里插入图片描述
压缩比:
在这里插入图片描述
压缩质量分析(PSNR):
公式
在这里插入图片描述
计算得:PSNR=49.9dB
概率分布图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值