DPCM编码原理及代码实现

本文详细介绍了DPCM编码的工作原理,包括基于预测的编码方式,以及通过C++代码实现的DPCM编码器和解码器。通过实例展示了如何压缩和重构图像,并计算了PSNR作为质量评估指标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、DPCM编码

DPCM编码,英文名称Differential pulse-code modulation,是一种信号编码器,它以脉冲编码调制(PCM)为基础,基于信号样本的预测添加了一些功能。DPCM的输入信号可以是模拟信号,也可以是数字信号。

二、DPCM编码原理

DPCM并不是对每个抽样值进行独立编码,而是对根据前一个抽样值的预测值与当前抽样值的差值进行编码。因为相邻抽样值之间相关性较大,因此预测值与抽样值会很接近,其差值也会很小,因此对这个小的差值进行编码可以很有效的压缩数据量。

三、DPCM编码器

DPCM编码器:

image-20220710173716771

四、DPCM解码器

DPCM解码器:

image-20220710173936471

五、DPCM代码实现

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
int main()
{
	unsigned int width = 256;
	unsigned int height = 256;
	
	// 读取文件 
	char *yuvtest = NULL;
	char *newyuvtest = NULL;
	FILE* yuvFile = NULL;
	FILE* newyuvFile = NULL;
	char *pname = NULL;
	FILE* pFile = NULL;
    
    unsigned char* yuvbuffer = NULL;
	unsigned char* ubuffer = NULL;
	unsigned char* vbuffer = NULL;
    unsigned char * pbuffer = NULL;
	float* dbuffer = NULL;
	unsigned char* rbuffer = NULL;
    
	yuvtest = "···/test.yuv";
	newyuvtest = "···/testrebuild.yuv";
	pname= "···/error.yuv";
	yuvFile = fopen(yuvtest, "rb");
	if (!yuvFile)
		printf("YUV测试文件打开失败\n");
	else
		printf("成功打开YUV测试文件\n");
	newyuvFile = fopen(newyuvtest, "wb");
	if (!newyuvFile)
		printf("重建YUV文件打开失败\n");
	else
		printf("重建YUV文件打开成功\n");
	pFile = fopen(pname, "wb");
	if (!pFile)
		printf("误差文件打开失败\n");
	else
		printf("误差文件打开成功\n");
		
	
	yuvbuffer = (unsigned char*)malloc(width*height);
	ubuffer = (unsigned char*)malloc(width*height / 4);
	vbuffer = (unsigned char*)malloc(width*height / 4);
	pbuffer = (unsigned char*)malloc(width*height);//预测误差的量化值
	rbuffer = (unsigned char*)malloc(width*height);//重现图像
	dbuffer = (float*)malloc(width*height*4);//输入预测误差
	unsigned char* dobuffer = (unsigned char*)malloc(width*height * 4);
	
	if (yuvbuffer == NULL || ubuffer == NULL || vbuffer == NULL || pbuffer == NULL)
	{
		printf("ERROR");
	}
 
	fread(yuvbuffer, 1, width * height * 1, yuvFile);
 
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			if (j == 0) {
				pbuffer[i*width + j] = 0;
				rbuffer[i*width + j] = yuvbuffer[i*width + j];
				dbuffer[i*width + j] = 0;
			}
			else {
				dbuffer[(i*width + j)] = float(yuvbuffer[i*width + j]) - float(rbuffer[i*width + j - 1]);
				if (dbuffer[ (i*width + j)] >= 0) {
					pbuffer[i*width + j] = floor(dbuffer[(i*width + j)] + 0.5);
					rbuffer[i*width + j] = rbuffer[i*width + j - 1] + pbuffer[i*width + j] * 1;
				}
				else {
					pbuffer[i*width + j] = floor(fabs(float(dbuffer[i*width + j]) + 0.5));
					rbuffer[i*width + j] = rbuffer[i*width + j - 1] - pbuffer[i*width + j] * 1;
				}
			}
		}
	}
    
    //计算误差
	int sum=0;
	for (int i = 0; i < height; i++) {
 
		for (int j = 0; j < width; j++) {
			sum += abs(pbuffer[i*width + j]);
		}
	}
	float MSE = float(sum) / float(width*height);
	float PSNR = 10 * log10(65025 / MSE);
	printf("PSNR=%f", PSNR);
	
	// 写入重建YUV文件和预测误差文件 
	for (int i = 0; i < width*height / 4; i++) {
		ubuffer[i] = 128;
		vbuffer[i] = 128;
	}
	fwrite(rbuffer, 1, width*height, newyuvFile);
	fwrite(ubuffer, 1, width*height / 4, newyuvFile);
	fwrite(vbuffer, 1, width*height / 4, newyuvFile);
	
	for (int i = 0; i < width*height ; i++) {
		dobuffer[i] = (unsigned char)(dbuffer[i])+128;
	}
	fwrite(dobuffer, 1, width*height, pFile);
	fwrite(ubuffer, 1, width*height / 4, pFile);
	fwrite(vbuffer, 1, width*height / 4, pFile);
	
	fclose(newyuvFile);
	fclose(yuvFile);
	fclose(pFile);
 
	return 0;
}

六、代码结果

原图像:

image-20220712092334820

重建图像:

image-20220712092441014

误差图像:

image-20220712092734180

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值