Implementation and analysis of DPCM compression system

Posted by dcalladi on Thu, 17 Feb 2022 16:47:21 +0100

Implementation and analysis of DPCM compression system

I Experimental purpose

Master the basic principle of DPCM codec system. Preliminarily master the experiment, program the DPCM encoder with C/C++/Python and other languages, and analyze its compression efficiency.

II Experimental content


DPCM is the abbreviation of differential predictive coding modulation. It is a typical predictive coding system. In DPCM system, it should be noted that the input of predictor is the decoded sample. The reason why the original samples are not used for prediction is that the original samples cannot be obtained at the decoding end, and only the samples with errors can be obtained. Therefore, a decoder is actually embedded in the DPCM encoder, as shown in the dotted box in the encoder.
In a DPCM system, two factors need to be designed: predictor and quantizer. Ideally, the predictor and quantizer should be jointly optimized. In practice, a suboptimal design method is adopted: the optimal design of linear predictor and quantizer is carried out respectively.
2. Design of DPCM coding system
In this experiment, we use fixed predictor and uniform quantizer. The predictor adopts both left and upper prediction.
The quantizer adopts 8-bit uniform quantization. The goal of this experiment is to verify the coding efficiency of DPCM coding. Firstly, a 256 level gray image is read, the prediction error is calculated by using the prediction method set by ourselves, and the prediction error is uniformly quantized by 8 bits (basic requirements). The prediction error can also be quantized by 1-bit, 2-bit and 4-bit (improve the requirements). During the implementation of DPCM encoder, the prediction error image and reconstructed image can be output at the same time. Write the prediction error image into the file and input the file into Huffman encoder to obtain the output code stream, give the probability distribution diagram and calculate the compression ratio. Input the original image file into Huffman encoder, get the output code stream, give the probability distribution diagram and calculate the compression ratio. Finally, the coding efficiency (compression ratio and image quality) between the two systems (1.DPCM + entropy coding and 2. Entropy coding only) is compared. The compression mass is calculated in PSNR

III code implementation

  1. Left prediction
//Left prediction//
void DPCMLeft(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)//DPCM left prediction
{
	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 is the error between the current value and the predicted value, and P2 is the error after quantization
	unsigned char P3;//P3 is the error after inverse quantization

	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			if(j == 0)//When predicting to the left, the pixel values of the leftmost column of the image are directly output without differential prediction
			{
				*(recB+j+i*Width)=*(yB+j+i*Width);//The current value is the reconstruction value, which is used as the reference value of the next pixel
				*(errB+j+i*Width)=0;//The error is 0
			}
			else//DPCM is performed when the pixels are not in the leftmost column
			{
				P1=*(yB+j+i*Width)-*(recB+(j-1)+i*Width);//Find the difference between the current value and the reference value
				if(P1%2==0)//The difference is evenly quantized by 8bit and offset by + 128 to output
					P2=P1/2+128;
				else
					P2=(P1-1)/2+128;
				*(errB+j+i*Width)=unsigned char(P2);//Write error to errB cache area
				P3=unsigned char(P2*2);//Inverse quantization of quantized error
				*(recB+j+i*Width)=*(recB+(j-1)+i*Width)+P3;
				//Add the reference value and the error obtained by inverse quantization as the reconstruction value of the current pixel, that is, the reference value of the next pixel
			}
		}
	}
}
  1. Upward prediction
void DPCMUp(int Width,int Height,void *yBuff,void *recBuff,void *errBuff)//DPCM upward prediction
{
	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 is the error between the current value and the predicted value, and P2 is the error after quantization
	unsigned char P3;//P3 is the error after inverse quantization

	for(int i=0;i<Height;i++)
	{
		for(int j=0;j<Width;j++)
		{
			if(i == 0)//When making up prediction, the pixel value of the uppermost column of the image is directly output without differential prediction
			{
				*(recB+j+i*Width)=*(yB+j+i*Width);//The current value is the reconstruction value, which is used as the reference value of the next pixel
				*(errB+j+i*Width)=0;//The error is 0
			}
			else//DPCM is performed when the pixels are not in the top column
			{
				P1=*(yB+j+i*Width)-*(recB+j+(i-1)*Width);//Find the difference between the current value and the reference value
				if(P1%2==0)//The difference is evenly quantized by 8bit and offset by + 128 to output
					P2=P1/2+128;
				else
					P2=(P1-1)/2+128;
				*(errB+j+i*Width)=unsigned char(P2);//Write error to errB buffer area
				P3=unsigned char(P2*2);//Inverse quantization of quantized error
				*(recB+j+i*Width)=*(recB+j+(i-1)*Width)+P3;
				//Add the reference value and the error obtained by inverse quantization as the reconstruction value of the current pixel, that is, the reference value of the next pixel
			}
		}
	}
}
  1. psnr calculation
//PSNR//
int simplest_yuv420_psnr(void *yBuff1,void *yBuff2, int w, int h, int num)//Calculate PSNR of Y component
{
	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);//Take the square of each difference and add it up
			}
		}
		mse = mse_sum / (w * h); //Calculate mse according to the formula
		psnr = 10 * log10(255.0 * 255.0 / mse); //Calculate psnr according to the formula
		printf("%5.3f\n", psnr);
	}
	system("pause");
	return 0;
}
  1. Header file
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. Main function
#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;//Width and height of image
	int frameHeight;

	/* internal variables */
	char* yFileName = NULL;//Original document
	char* recFileName = NULL;//Rebuild value file
	char* errFileName = NULL;//Quantized prediction error

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


	/*Write 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;
		}
	}

	/*Write reconstruction and error images*/
	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);
}

IV experimental result

  1. psnr/db result:

  2. original image


Upward prediction: error image & reconstructed image

3.y-channel probability statistics

-Original image:

  • Error image:

    Approximate Gaussian distribution, good quantization effect

4. Compression ratio analysis:

  1. Generate file summary:


The image after 8bit quantization is basically the same as the original image