【数据压缩6】DPCM压缩系统的实现和分析

实验原理

一、DPCM编解码

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

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

二、PSNR峰值信号噪声比

PSNR:“Peak Signal to Noise Ratio”的缩写,即峰值信噪比,是一种评价图像的客观标准,它具有局限性,一般是用于最大值信号和背景噪音之间的一个工程项目。

首先计算均方误差 MSE(Mean Square Error):
在这里插入图片描述

其中M , N M,NM,N为图像的宽和高,f ( i , j ) , f ’ ( i , j ) f(i,j),f’(i,j)f(i,j),f’(i,j)为原图像和重建图像在( i , j ) 的像素值。PSNR(单位:dB)以如下方式计算:
在这里插入图片描述

PSNR ≥ 40dB时,图像质量非常好,接近于原图像;
30dB ≤ PSNR < 40dB时,图像有可察觉的失真,但质量仍可接受;
20dB ≤ PSNR < 30dB时,图像质量较差;
PSNR < 20dB时,图像质量已经无法接受。

实验步骤

1.读取BMP文件,转化为yuv格式,提取y分量
2. 对该灰度图像进行预测,预测器的输入为上一个样点的重建值,计算预测误差
3. 对预测误差进行8bit均匀量化
4. 对量化后的预测误差进行反量化,求重建值
5. 将预测误差图像和原始灰度图像输入Huffman编码器,得到码字必要信息并比较两种系统(DPCM+熵编码和仅进行熵编码)之间的编码效率。

实验代码

1.DPCM

 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;
		}
	}
}

2.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);

3.计算信源符号概率分布

	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]);
	}

4.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);

	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;
}

5.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

6.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;
		}
	}
}

实验结果

量化比特数 原图 预测误差 重建图 PSNR
8 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 51.153
4 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 13.957
2 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 8.743

随着量化bit数减少,PSNR值逐渐降低,图像出现明显失真,已经无法有效重建图像。

猜你喜欢

转载自blog.csdn.net/ppinecone/article/details/125792624