DPCM 压缩系统的实现和分析

DPCM 压缩系统的实现和分析

一. 实验目的

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

二. 实验内容

在这里插入图片描述
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
2.DPCM编码系统的设计
在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。
量化器采用8比特均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求)。还可对预测误差进行1比特、2比特和4比特的量化设计(提高要求)。在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算

三. 代码实现

  1. 向左预测
//向左预测//
void DPCMLeft(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)//DPCM向左预测
{
	unsigned char *yB=NULL;
	yB = (unsigned char *)yBuff;
	unsigned char *recB=NULL;
	recB = (unsigned char *)recBuff;
	unsigned char *errB=NULL;
	errB = (unsigned char *)errBuff;
	int P1,P2;//P1为当前值与预测值的误差,P2为量化后的误差
	unsigned char P3;//P3为反量化后的误差

	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			if(j == 0)//向左进行预测时,图像最左边一列的像素值直接输出,无需进行差分预测
			{
				*(recB+j+i*Width)=*(yB+j+i*Width);//当前值即为重建值,作为下一个像素的参考值
				*(errB+j+i*Width)=0;//误差为0
			}
			else//当不是最左边一列的像素时,进行DPCM
			{
				P1=*(yB+j+i*Width)-*(recB+(j-1)+i*Width);//求当前值与参考值的差值
				if(P1%2==0)//对差值进行8bit均匀量化,并进行+128的偏移以输出
					P2=P1/2+128;
				else
					P2=(P1-1)/2+128;
				*(errB+j+i*Width)=unsigned char(P2);//将误差写入errB缓存区域
				P3=unsigned char(P2*2);//对量化后的误差反量化
				*(recB+j+i*Width)=*(recB+(j-1)+i*Width)+P3;
				//将参考值与反量化得到的误差相加,作为当前像素的重建值,即下一个像素的参考值
			}
		}
	}
}
  1. 向上预测
void DPCMUp(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)//DPCM向上预测
{
	unsigned char *yB=NULL;
	yB = (unsigned char *)yBuff;
	unsigned char *recB=NULL;
	recB = (unsigned char *)recBuff;
	unsigned char *errB=NULL;
	errB = (unsigned char *)errBuff;
	int P1,P2;//P1为当前值与预测值的误差,P2为量化后的误差
	unsigned char P3;//P3为反量化后的误差

	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			if(i == 0)//向上进行预测时,图像最上边一列的像素值直接输出,无需进行差分预测
			{
				*(recB+j+i*Width)=*(yB+j+i*Width);//当前值即为重建值,作为下一个像素的参考值
				*(errB+j+i*Width)=0;//误差为0
			}
			else//当不是最上边一列的像素时,进行DPCM
			{
				P1=*(yB+j+i*Width)-*(recB+j+(i-1)*Width);//求当前值与参考值的差值
				if(P1%2==0)//对差值进行8bit均匀量化,并进行+128的偏移以输出
					P2=P1/2+128;
				else
					P2=(P1-1)/2+128;
				*(errB+j+i*Width)=unsigned char(P2);//将误差写入errB缓存区域
				P3=unsigned char(P2*2);//对量化后的误差反量化
				*(recB+j+i*Width)=*(recB+j+(i-1)*Width)+P3;
				//将参考值与反量化得到的误差相加,作为当前像素的重建值,即下一个像素的参考值
			}
		}
	}
}
  1. psnr计算
//PSNR//
int simplest_yuv420_psnr(void *yBuff1,void *yBuff2, int w, int h, int num)//计算Y分量的PSNR
{
	unsigned char *yB1=NULL;
	yB1 = (unsigned char *)yBuff1;
	unsigned char *yB2=NULL;
	yB2 = (unsigned char *)yBuff2;

	for (int i = 0; i < num; i++)
	{
		double mse_sum = 0, mse = 0, psnr = 0;
		for (int j = 0; j < h ; j++)
		{
			for (int k = 0; k < w; k++)
			{
				mse_sum += pow((double)(*(yB1+k+j*w) - *(yB2+k+j*w)), 2);//取每个差值的平方,并进行累加
			}
		}
		mse = mse_sum / (w * h); //根据公式计算mse
		psnr = 10 * log10(255.0 * 255.0 / mse); //根据公式计算psnr
		printf("%5.3f\n", psnr);
	}
	system("pause");
	return 0;
}
  1. 头文件
void DPCMUp(int Width,int Height,void *yBuff,void *recBuff,void *errBuff);
int simplest_yuv420_psnr(void *yBuff1,void *yBuff2, int w, int h, int num);
  1. 主函数
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <string.h>
#include"DPCM.h"

int main(int argc, char** argv)
{
    int frameWidth;//图像的宽和高
	int frameHeight;

	/* internal variables */
	char* yFileName = NULL;//原文件
	char* recFileName = NULL;//重建值文件
	char* errFileName = NULL;//量化后的预测误差

	FILE* yFile = NULL;
	FILE* recFile = NULL;
	FILE* errFile = NULL;

	unsigned char * yBuf = NULL;
	unsigned char * uBuf = NULL;
	unsigned char * vBuf = NULL;
    unsigned char * recBuf = NULL;
	unsigned char * errBuf = NULL;
	
	yFileName = argv[1];
	recFileName = argv[2];
	errFileName = argv[3];
	frameWidth = atoi(argv[4]);
	frameHeight = atoi(argv[5]);

	/* open the YUV file */
	fopen_s(&yFile,yFileName, "rb");
	if (yFile == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}
	/* open the restruction file */
	recFile = fopen(recFileName, "wb");
	if (recFile == NULL)
	{
		printf("cannot find rec file\n");
		exit(1);
	}
	/* open the difference file */
	errFile = fopen(errFileName, "wb");
	if (errFile == NULL)
	{
		printf("cannot find error file\n");
		exit(1);
	}


	/* get the output buffers for a frame */
	yBuf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char));
	uBuf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char)/4);
	vBuf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char)/4);
	recBuf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char));
	errBuf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char) * 1.5);


	if (yBuf == NULL || recBuf == NULL || errBuf == NULL || uBuf == NULL ||vBuf == NULL)
	{
		printf("wrong\n");
		exit(1);
	}

	fread(yBuf, 1, frameWidth * frameHeight, yFile);
	if (yBuf == NULL)
	{
		printf("no enought memory\n");
		exit(1);
	}

	DPCMUp(frameWidth,frameHeight,yBuf,recBuf,errBuf);


	/*写u v*/
	for(int i=0;i<frameHeight/2;i++)
	{
		for(int j=0;j<frameWidth/2;j++)
		{
			*(uBuf+j+i*frameWidth/2)=128;
			*(vBuf+j+i*frameWidth/2)=128;
		}
	}

	/*写入重建和误差图像*/
	fwrite(recBuf, 1, frameWidth * frameHeight, recFile);

	fwrite(errBuf, 1, frameWidth * frameHeight, errFile);
	fwrite(uBuf, 1, frameWidth * frameHeight/4, errFile);
	fwrite(vBuf, 1, frameWidth * frameHeight/4, errFile);
	
	/*PSNR*/
	simplest_yuv420_psnr(yBuf,recBuf,frameWidth,frameHeight,1);

	/* cleanup */
	free(yBuf);
	free(recBuf);
	free(errBuf);
	free(uBuf);
	free(vBuf);

	fclose(yFile);
	fclose(recFile);
	fclose(errFile);

	system("pause");
	return(0);
}

四.实验结果

  1. psnr/db结果:
    在这里插入图片描述

  2. 原始图像

在这里插入图片描述
向上预测:误差图像&重建图像
在这里插入图片描述

在这里插入图片描述

3.y通道概率统计

-原始图像:
在这里插入图片描述

  • 误差图像:
    在这里插入图片描述
    近似高斯分布,量化效果较好

4.压缩比分析:
在这里插入图片描述
在这里插入图片描述

  1. 生成文件汇总:

在这里插入图片描述
8bit量化后的图像与原图像基本相同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值