6、DPCM编解码

目录

一、实验原理

1. DPCM编解码原理

2. PSNR的计算

二、实验代码

三、实验内容

1. bmp格式转yuv格式

2. 不同量化比特的DPCM

(1)8bit量化

(2)1,2,4bit量化

3. DPCM+熵编码和熵编码的比较

(1)编码效率

(2)概率分布图


一、实验原理

1. DPCM编解码原理

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

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

2. PSNR的计算

PSNR(峰值信噪比)是一种度量图像失真的方式,它的单位是dB。本实验使用PSNR作为图像质量评价的指标。峰值信噪比与图像质量近似成正比关系。PSNR值越大,就代表失真越少​​​​​,图像质量越好。


二、实验代码

① dpcm.h

#pragma once
#ifndef DPCM_H_
#define DPCM_H_

void DPCM(unsigned char* y_buffer, unsigned char* differ_buffer, unsigned char* rebuild_buffer, int width, int height, int bitnum);
#endif

#pragma once

② dpcm.cpp

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

void DPCM(unsigned char* y_buffer, unsigned char* differ_buffer, unsigned char* rebuild_buffer, int width, int height, int bitnum)
{
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (j == 0)
			{
				differ_buffer[i * width] = ((y_buffer[i * width] - 128) + 255) / pow(2, (double)(9 - bitnum));
				rebuild_buffer[i * width] = differ_buffer[i * width] * pow(2, (double)(9 - bitnum)) - 255 + 128;
			}
			else
			{
				differ_buffer[i * width + j] = ((y_buffer[i * width + j] - rebuild_buffer[i * width + j - 1]) + 255) / pow(2, (double)(9 - bitnum));
				rebuild_buffer[i * width + j] = differ_buffer[i * width + j] * pow(2, (double)(9 - bitnum)) - 255 + rebuild_buffer[i * width + j - 1];
			}
			if (differ_buffer[i * width + j] > 255)
				differ_buffer[i * width + j] = 255;
			if (differ_buffer[i * width + j] < 0)
				differ_buffer[i * width + j] = 0;
			if (rebuild_buffer[i * width + j] > 255)
				rebuild_buffer[i * width + j] = 255;
			if (rebuild_buffer[i * width + j] < 0)
				rebuild_buffer[i * width + j] = 0;
		}
	}
}

③ main.cpp

#include<stdlib.h>
#include<stdio.h>
#include"math.h"
#include"DPCM.h"
void calculate_fre(unsigned char* buffer, double* frequency, int width, int height)
{
	int size = width * height;
	for (int i = 0; i < size; i++)
	{
		frequency[buffer[i]]++;
	}
	for (int k = 0; k < 256; k++)
	{
		frequency[k] /= size;
	}
}
int main(int argc, char** argv)
{
	const char* ori_name = argv[1];
	const char* differ_name = argv[2];
	const char* rebu_name = argv[3];
	int bitnum = atoi(argv[4]);
	FILE* ori_file = NULL;
	FILE* differ_file = NULL;
	FILE* rebu_file = NULL;
	if ((ori_file = fopen(ori_name, "rb")) == NULL)
		printf("Failed to open the original picture\n");
	else
		printf("succeeded to open the original picture\n");

	if ((differ_file = fopen(differ_name, "wb")) == NULL)
		printf("Failed to open the difference picture\n");
	else
		printf("succeeded to open the difference picture\n");

	if ((rebu_file = fopen(rebu_name, "wb")) == NULL)
		printf("Failed to open the rebulid picture\n");
	else
		printf("succeeded to open the rebulid picture\n");

	int width = 256;
	int height = 256;
	unsigned char* y_buffer = new unsigned char[width * height];
	unsigned char* u_buffer = new unsigned char[width * height / 4];
	unsigned char* v_buffer = new unsigned char[width * height / 4];
	unsigned char* differ_buffer = new unsigned char[width * height];
	unsigned char* rebuild_buffer = new unsigned char[width * height];
	fread(y_buffer, 1, width * height, ori_file);
	fread(u_buffer, 1, width * height / 4, ori_file);
	fread(v_buffer, 1, width * height / 4, ori_file);

	//计算原图像的概率分布
	double frequency[256] = { 0 };
	calculate_fre(y_buffer, frequency, width, height);
	FILE* orin_fre;
	orin_fre = fopen("ori_frequency.txt", "wb");
	fprintf(orin_fre, "%s\t%s\t", "symbol", "freq");
	for (int i = 0; i < 256; i++)
	{
		fprintf(orin_fre, "%d\t%f\t", i, frequency[i]);
	}

	DPCM(y_buffer, differ_buffer, rebuild_buffer, width, height, bitnum);

	//计算预测误差的概率分布
	double frequency2[256] = { 0 };
	calculate_fre(differ_buffer, frequency2, width, height);
	FILE* differ_fre;
	differ_fre = fopen("differ_frequency.txt", "wb");
	fprintf(differ_fre, "%s\t%s\t", "symbol", "freq");
	for (int i = 0; i < 256; i++)
	{
		fprintf(differ_fre, "%d\t%f\t", i, frequency2[i]);
	}
	//写入预测误差图像
	fwrite(differ_buffer, 1, width * height, differ_file);
	fwrite(u_buffer, 1, width * height / 4, differ_file);
	fwrite(v_buffer, 1, width * height / 4, differ_file);

	//写入重建图像
	fwrite(rebuild_buffer, 1, width * height, rebu_file);
	fwrite(u_buffer, 1, width * height / 4, rebu_file);
	fwrite(v_buffer, 1, width * height / 4, rebu_file);


	// 计算PSNR 
	double mse = 0;
	double psnr = 0;
	for (int i = 0; i < width * height; i++) {


		mse += pow((y_buffer[i] - rebuild_buffer[i]), 2);

	}
	mse = mse / (width * height);
	psnr = 10 * log10(pow(255, 2) / mse);
	printf("PSNR=%f", psnr);

	fclose(ori_file);
	fclose(differ_file);
	fclose(rebu_file);

	delete[] y_buffer;
	delete[] u_buffer;
	delete[] v_buffer;
	delete[] differ_buffer;
	delete[] rebuild_buffer;

	return 0;
}

三、实验内容

1. bmp格式转yuv格式

先把bmp格式的图片转换为yuv格式:

2. 不同量化比特的DPCM

设置命令参数:

(1)8bit量化

原图 预测误差 重建图像 PSNR
51.133820
44.182181
27.075617
51.161429
18.241522
17.084278
14.886163

(2)1,2,4bit量化

 8bit 4bit 2bit 1bit

由此可见:量化比特数越小,重建图像质量越差。

3. DPCM+熵编码和熵编码的比较

运行huff_run.exe分别对原始图像和预测误差图像进行Huffman编码。

得到编码后的.huff文件和概率统计文本文件:

 

(1)编码效率

原始图像 原始图像大小 熵编码 压缩比 DPCM+熵编码 压缩比
Lena.yuv 96KB 69KB 71.88% 46KB 47.92%
Fruit.yuv 96KB 78KB 81.25% 43KB 44.79%
Odie.yuv 96KB 22KB 22.92% 20KB 20.83%
Noise.yuv 96KB 74KB 77.08% 77KB 80.21%
Zone.yuv 96KB 78KB 81.25% 78KB 81.25%
Clown 96KB 78KB 81.25% 49KB 51.04%
Camman 96KB 73KB 76.04% 42KB 43.75%

一般情况下,DPCM+熵编码比直接熵编码的压缩效率更高;对于个别图像,经过DPCM后再进行熵编码,压缩效率反而下降,可能是因为图像水平方向的相关性较低,不适合做DPCM。 

(2)概率分布图

原始图像概率分布 预测误差图像概率分布

经过DPCM后,预测误差图像的概率分布趋近于拉普拉斯分布,概率分布较集中,没有均匀分布,更适合用Huffman编码,因此可以DPCM+熵编码可以提高压缩效率。

猜你喜欢

转载自blog.csdn.net/m0_51333023/article/details/125680949