天天看點

資料壓縮實驗4——DPCM編碼一、DPCM原理二、代碼實作三、實驗結果

資料壓縮實驗3——DPCM編碼

  • 一、DPCM原理
  • 二、代碼實作
    • 1、重要代碼講解
    • 2、整體代碼展示
  • 三、實驗結果

一、DPCM原理

預測編碼是根據某一模型利用以往的樣本值對于新樣本值進行預測,然後将樣本的實際值與其預測值相減得到一個誤內插補點,對于這一誤內插補點進行編碼。如果模型足夠好且樣本序列在時間上相關性較強,那麼誤差信号的幅度将遠遠小于原始信号,進而得到較大的資料壓縮結果。

預測編碼方法分線性預測和非線性預測編碼方法。線性預測編碼方法,也稱內插補點脈沖編碼調制法,簡稱DPCM。

encoder圖中輸入信号Xn是某一像素點的實際灰階值,Pn是對該像素點的預測值,在本實驗中就是與它相鄰的前一個像素點的重建值。dn 是預測誤差。(dn)是量化預測誤差,(Xn)=量化預測誤差^(dn)+預測灰階值Pn,得到目前像素點的重建值,作為下一個像素點的預測值。

預測器的輸入是已經解碼以後的樣本,因為在解碼端隻能得到存在誤差的樣本。

由圖可見,encoder中包含了一個decoder

編碼框圖(encoder)

資料壓縮實驗4——DPCM編碼一、DPCM原理二、代碼實作三、實驗結果

解碼框圖(decoder)

資料壓縮實驗4——DPCM編碼一、DPCM原理二、代碼實作三、實驗結果

二、代碼實作

在這裡我實作了左向預測8bit

1、重要代碼講解

因為是左向預測,是以圖檔中每一行的左側第一個值沒有前面的值,是以直接将預測值設為本身的值,插值設為0。

if (j == 0)
			{
				yForecastBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];
				yDifferenceBuf[j + i * frameWidth] = 0;
			}
           

如果不是每一行的第一個值,那就需要先先計算插值a,将這個像素值減去它左邊像素的預測值。但是因為圖像是8bit有256個值,是以如果相減值就會變為512個值,是以如果想進行8bit量化,需要将插值進行變換,本像素插值d=a/2+127(量化插值b=a/2)。之後需要進行反量化值c,将量化插值b乘2(c=b*2)。之後再将反量化值c與左側像素預測值相加得到本像素預測值

a = yBuf[j + i * frameWidth] - yForecastBuf[j + i * frameWidth - 1];//計算插值
				b = a / 2;//進行量化
				c = b * 2;//進行反量化
				d = b + 128;//進行+128
				yDifferenceBuf[j + i * frameWidth] = d;
				yForecastBuf[j + i * frameWidth] = yForecastBuf[j + i * frameWidth - 1] + c;

           

2、整體代碼展示

#include "iostream"
#include"stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include"math.h"
#pragma warning (disable:4996)
using namespace std;
#define u_int8_t	unsigned __int8
#define u_int		unsigned __int32


int main(int argc, char** argv)
{
	char* yuvFileName = NULL;
	char* yuceFileName = NULL;
	char* chazhiFileName = NULL;
	u_int8_t* yBuf = NULL;
	u_int8_t* yuvBuf = NULL;
	u_int8_t* yForecastBuf = NULL;
	u_int8_t* yDifferenceBuf = NULL;
	u_int8_t* Buf128 = NULL;
	FILE* yuvFile = NULL;
	FILE* differenceFile = NULL;
	FILE* forecastFile = NULL;
	u_int frameWidth = 0;
	u_int frameHeight = 0;
	int a = 0;//量化前插值
	int b = 0;//量化後值
	int c = 0;//反量化後值
	int d = 0;//+128之後值

	//讀取資料yuv檔案資料
	yuvFileName = argv[1];
	yuceFileName = argv[2];
	chazhiFileName = argv[3];
	frameWidth = atoi(argv[4]);
	frameHeight = atoi(argv[5]);
	yuvFile = fopen(yuvFileName, "rb");
	yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3 / 2);
	yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	yForecastBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	yDifferenceBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	Buf128 = (u_int8_t*)malloc(frameWidth * frameHeight / 2);

	fread(yuvBuf, 1, frameWidth * frameHeight * 3 / 2, yuvFile);

	forecastFile = fopen(yuceFileName, "wb");
	differenceFile = fopen(chazhiFileName, "wb");

	//給Buf128全指派為128
	for (int i = 0; i < frameWidth * frameHeight / 2; i++)
	{
		Buf128[i] = 128;
	}

	//讀取y資料
	for (int i = 0; i < frameWidth * frameHeight; i++)
	{
		yBuf[i] = yuvBuf[i];
	}

	//計算內插補點與預測值
	for (int i = 0; i < frameHeight; i++)
	{
		for (int j = 0; j < frameWidth; j++)
		{
			if (j == 0)
			{
				yForecastBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];
				yDifferenceBuf[j + i * frameWidth] = 0;
			}
			else
			{
				a = yBuf[j + i * frameWidth] - yForecastBuf[j + i * frameWidth - 1];//計算插值
				b = a / 2;//進行量化
				c = b * 2;//進行反量化
				d = b + 128;//進行+128
				yDifferenceBuf[j + i * frameWidth] = d;
				yForecastBuf[j + i * frameWidth] = yForecastBuf[j + i * frameWidth - 1] + c;
			}
		}
	}
	fwrite(yForecastBuf, frameWidth * frameHeight, 1, forecastFile);
	fwrite(yDifferenceBuf, frameWidth * frameHeight, 1, differenceFile);
	fwrite(Buf128, frameWidth * frameHeight / 2, 1, differenceFile);
	fwrite(Buf128, frameWidth * frameHeight / 2, 1, forecastFile);
	fclose(differenceFile);
	fclose(forecastFile);
	fclose(yuvFile);
	free(yBuf);
	free(yuvBuf);
	free(yForecastBuf);
	free(yDifferenceBuf);
	free(Buf128);

	return 0;
}
           

三、實驗結果

預測圖像

資料壓縮實驗4——DPCM編碼一、DPCM原理二、代碼實作三、實驗結果

插值圖像

資料壓縮實驗4——DPCM編碼一、DPCM原理二、代碼實作三、實驗結果

通過插值圖像可以看出,在模特肩膀部位插值圖像為一條黑色曲線,這是因為右側像素比左側像素黑,也就是右側像素值小于左側像素值,是以右像素-左像素為負值是以為黑。這樣也就能根據插值圖像知到為左向預測。

繼續閱讀