[Experiment 4] implementation and analysis of DPCM compression system

Combined with experiment 2 code

1, 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.

2, Experimental principle

1.DPCM encoding and decoding principle


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. Peak signal-to-noise ratio

3, Experimental code

1.main.cpp:

(1) Open up space

int main(int argc, char** argv)
{
	/* variables controlable from command line */
	u_int frameWidth = 352;			/* --width=<uint> */
	u_int frameHeight = 240;		/* --height=<uint> */
	unsigned int i;

	/* internal variables */
	char* yuvFileName = NULL;
	char* reFileName = NULL;
	char* qFileName = NULL;
	FILE* yuvFile = NULL;
	FILE* reFile = NULL;
	FILE* qFile = NULL;
	u_int8_t* fileBuf = NULL;
	u_int8_t* yBuf = NULL;
	u_int8_t* reBuf = NULL;
	u_int8_t* qBuf = NULL;
	u_int32_t videoFramesWritten = 0;

	yuvFileName = argv[1];
	qFileName = argv[2];
	reFileName = argv[3];
	frameWidth = atoi(argv[4]);
	frameHeight = atoi(argv[5]);//atoi string to number

(2) Open the imported yuv file

	yuvFile = fopen(yuvFileName, "rb");
	if (yuvFile == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}
	else
	{
		printf("The input yuv file is %s\n", yuvFileName);
	}

(3) Open the output (to be written) reconstruction image and residual image

	qFile = fopen(qFileName, "wb");
	reFile = fopen(reFileName, "wb");
	qBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	reBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	fileBuf = (u_int8_t*)malloc(frameWidth * frameHeight / 2);
	fread(yBuf, 1, frameWidth * frameHeight, yuvFile);
	DPCM(frameHeight, frameWidth, yBuf, qBuf, reBuf);
	for (int i = 0; i < frameWidth * frameHeight / 2; i++)
	{
		fileBuf[i] = 128;
	}

	fwrite(qBuf, 1, frameWidth * frameHeight, qFile);
	fwrite(fileBuf, 1, frameWidth * frameHeight / 2, qFile);
	fwrite(reBuf, 1, frameWidth * frameHeight, reFile);
	fwrite(fileBuf, 1, frameWidth * frameHeight / 2, reFile);

(4) Shut down

	free(yBuf);
	free(qBuf);
	free(reBuf);
	free(fileBuf);
	fclose(qFile);
	fclose(reFile);
	fclose(yuvFile);

2.dpcm.cpp

(1)8bit

void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
    int size = width * height;
    for (int i = 0; i < size; i++) {
            if (i % width == 0) {           //Determine whether it is the first pixel of each line

                qBuf[i] = yuvBuf[i];
                reBuf[i] = yuvBuf[i];
            }
            else {
                int dn = yuvBuf[i] - reBuf[i - 1];//    The range of dn is - 255-255
                //8-bit quantization, 0-255
                dn >>= 1;//-127 - 127
                int temp = dn + 128;//0 - 255
                qBuf[i] = temp;
                reBuf[i] = qBuf[i] * 2 + reBuf[i - 1];

            }
        }
}

(2)4bit

void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
    int size = width * height;
    for (int i = 0; i < size; i++) {
            if (i % width == 0) {           //Determine whether it is the first pixel of each line
                int k = 256 / pow(2, 4);
                qBuf[i] = int(yuvBuf[i] / k);
                reBuf[i] = int(yuvBuf[i] / k);
            }
            else {
                int dn = yuvBuf[i] - reBuf[i - 1];//    The range of dn is - 255-255
                //4-bit quantization
                dn >>= 5;//-7 - 7
                int temp = dn + 8;//0 - 15
                qBuf[i] = temp;
                reBuf[i] = qBuf[i] * 32 + reBuf[i - 1];

            }
        }
}

(3)2bit

void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
    int size = width * height;
     for (int i = 0; i < size; i++) {
        if (i % width == 0) {           //Determine whether it is the first pixel of each line
            int k = 256 / pow(2, 6);
            qBuf[i] = int(yuvBuf[i] / k);
            reBuf[i] = int(yuvBuf[i] / k);
        }
        else {
            int dn = yuvBuf[i] - reBuf[i - 1];//    The range of dn is - 255-255
            //2-bit quantization
            dn >>= 7;//-1 - 1
            int temp = dn + 2;//0 - 3
            qBuf[i] = temp;
            reBuf[i] = qBuf[i] * 128 + reBuf[i - 1];

        }
    }
}

(4)1bit

void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
    int size = width * height;
    for (int i = 0; i < size; i++) {
        if (i % width == 0) {           //Determine whether it is the first pixel of each line
            int k = 256 / pow(2, 7);
            qBuf[i] = int(yuvBuf[i] / k);
            reBuf[i] = int(yuvBuf[i] / k);
        }
        else {
            int dn = yuvBuf[i] - reBuf[i - 1];//    The range of dn is - 255-255
            //1-bit quantization
            dn >>=8;
            int temp = dn + 1;
            qBuf[i] = temp;
            reBuf[i] = qBuf[i] * 256 + reBuf[i - 1];

        }
    }
}

4, Experimental results

Original drawing:

1.8bit:


2.4bit:


3.2bit:


4.1bit:

5, Experimental analysis

1. Compare coding quality:

Calculate the peak signal-to-noise ratio between the original image and the reconstructed image under their respective quantization standards:
psnr.cpp:

#include <math.h>
double psnr(unsigned char* ybuf, unsigned char* rebuf, int height, int width)
{

	double mse = 0;
	double div = 0;
	double psnr = 0;

	for (int v = 0; v < height; v++)
	{
		for (int u = 0; u < width; u++)
		{
			div = rebuf[v * width + u] - ybuf[v * width + u];
			mse += div * div;
		}
	}
	mse = mse / (width * height);
	psnr = 10 * log10(255 * 255 / mse);
	return psnr;
}

In main CPP add before closing the file:

	double ps = psnr(yBuf, reBuf, frameHeight, frameWidth);
	cout << ps;

8bit: 51.7761

4bit: 23.1471

2bit: 14.8853

1bit: 10.0007

2. Compare coding efficiency:

Using the executable program encoded by Huffman, we get two huff file
(1) Write the prediction error image to a file and input the file into Huffman encoder
(2) Input the original image file into Huffman encoder

Compare the coding efficiency (compression ratio and image quality) between the two systems (1.DPCM + entropy coding and 2. Entropy coding only)
Former: (96-32.6) / 96
Latter: (96-80.7) / 96

summary

It's hard

Added by rodolp13 on Thu, 17 Feb 2022 11:53:03 +0200