DPCM压缩系统的实现和分析

一、实验目的

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

二、实验内容

DPCM(Differential Pulse Code Modulation——差分脉冲编码调制)

对相邻样本之差编码而不是对样本本身编码,由于相邻样本之差比实际样本幅度小,所以表示差信号需要较小的位数。这种普通方法的一种改进方案是用前面的n个样本根据一定的规律来预测当前的样本,然后将预测值与实际值的误差进行量化后传输,在根据误差信号,采用和发送端相同的预测方法恢复出原始信号。 这就是DPCM.

1、DPCM编解码原理

在这里插入图片描述
Q:量化器
P:预测期
在这里插入图片描述
举例:
在这里插入图片描述

2、DPCM编码系统的设计

在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。量化器采用8比特均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化。

三、实验过程

1、头文件

在这里插入图片描述

2、main

#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;		
	
	char* yFileName = NULL;//原始的灰度文件
	FILE* yFile = NULL;
	unsigned char* y_Buf = NULL;
	char* recFileName = NULL;//重建的图像文件
	FILE* recFile = NULL;
	unsigned char* rec_Buf = NULL;
	char* errFileName = NULL;//量化后的预测误差文件
	FILE* errFile = NULL;
	unsigned char* err_Buf = NULL;

	unsigned char* u_Buf = NULL;
	unsigned char* v_Buf = NULL;
		
	yFileName = argv[1];
	recFileName = argv[2];
	errFileName = argv[3];
	frameWidth = atoi(argv[4]);
	frameHeight = atoi(argv[5]);

	fopen_s(&yFile,yFileName, "rb");//打开灰度文件
	if (yFile == NULL)
	{
		printf("cannot find y file\n");
		exit(1);
	}
	recFile = fopen(recFileName, "wb");//打开重建图像文件
	if (recFile == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}
	errFile = fopen(errFileName, "wb");//打开量化后的误差文件
	if (errFile == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}

	y_Buf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char));  //开辟5个缓存空间
	u_Buf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char) / 4);
	v_Buf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char) / 4);
	rec_Buf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char));
	err_Buf = (unsigned char*)malloc(frameWidth * frameHeight * sizeof(unsigned char)*1.5);
	if (y_Buf == NULL || rec_Buf == NULL || err_Buf == NULL || u_Buf == NULL ||v_Buf == NULL)
	{
		printf("wrong malloc\n");
		exit(1);
	}

	fread(y_Buf, 1, frameWidth * frameHeight, yFile);//读取灰度文件数据
	if (y_Buf == NULL)
	{
		printf("wrong fread\n");
		exit(1);
	}

	DPCMLeft(frameWidth,frameHeight,y_Buf,rec_Buf,err_Buf);//向左进行预测
	//DPCMUp(frameWidth,frameHeight,y_Buf,rec_Buf,err_Buf);//向上进行预测

	for(int i=0;i<frameHeight/2;i++)
	{
		for(int j=0;j<frameWidth/2;j++)
		{
			*(u_Buf+j+i*frameWidth/2)=128;
			*(v_Buf+j+i*frameWidth/2)=128;
		}
	}
	fwrite(rec_Buf, 1, frameWidth * frameHeight, recFile);//将数据写入文件进行输出
	fwrite(err_Buf, 1, frameWidth * frameHeight, errFile);
	fwrite(u_Buf, 1, frameWidth * frameHeight / 4, errFile);
	fwrite(v_Buf, 1, frameWidth * frameHeight / 4, errFile);

	//计算PSNR
	simplest_yuv420_psnr(y_Buf,rec_Buf,frameWidth,frameHeight,1);

	free(y_Buf);
	free(rec_Buf);
	free(err_Buf);
	free(u_Buf);
	free(v_Buf);
	fclose(yFile);
	fclose(recFile);
	fclose(errFile);
}

3、DPCM(向左、向上)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <string.h>
#include"DPCM.h"

//DPCM向左预测
void DPCMLeft(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)
{
	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;
	unsigned char 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均匀量化
					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;
				
			}
		}
	}
}

//DPCM向上预测
void DPCMUp(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)
{
	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;
	unsigned char 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均匀量化
					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;
				
			}
		}
	}
}

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、直接熵编码

在这里插入图片描述
在这里插入图片描述
压缩比:71.1%

2、向左DPCM+熵编码

在这里插入图片描述
在这里插入图片描述
压缩比:46.2%

3、向上DPCM+熵编码

在这里插入图片描述
在这里插入图片描述
压缩比:40.7%

六、结论

DPCM+熵编码(哈夫曼编码)压缩比远低于直接熵编码的压缩比,说明DPCM+熵编码压缩后图像更小,但图像质量也相应的变得更差。

七、失真

1、斜率过载

现象:边缘陡峭处变得平滑
原因:量化步长过小,重建值跟不上原始值上升或下降的速率。

2、边缘忙乱

现象:平坦与陡峭交界处闪烁不定
原因:量化步长过长。

3、颗粒噪声

现象:平坦区域内出现随机噪声
原因:信源输出相对固定的区域,输出以幅值△上下交替。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值