【視頻編解碼·學習筆記】9. 熵編碼算法:指數哥倫布編解碼程序

1、解碼程序:

總體思路:數組

  1. 在數據流中從左向右讀取每個二進制數據
  2. 記錄前綴連零的個數$m$,遇到1中止記錄。並提取後綴信息位(信息位長度與前綴0個數相同)
  3. 將後綴二進制轉換成十進制數$k$
  4. 解碼數值:$decodeNum = 2^m - 1 + k$
  5. 重複步驟1-4,直到數據序列結束

新建一個VS工程,定義數據類型:函數

typedef unsigned char UINT8;

定義一個數組用來存儲待解碼的數據:編碼

UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A };

1. 提取每一位二進制函數:

須要三個參數:待解碼數據序列buf,解碼到第幾個字節bytePosition,第幾位bitPosition (都是從左向右數的,每一個字節自第一位bitPosition=0,最後一位bitPosition=7)spa

static int get_bit_at_position(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
	UINT8 mask = 0, val = 0;
	// mask用來表示提取第幾位的數據,eg:0001 0000,表示提取第5位的數據
	mask = 1 << (7 - bitPosition);
	// 將當前字節數據與mask進行按位與運算,只保留那一位上的數據,總體數據!=0代表那一位數據爲1
	// val保存bytePosition上,第bitPosition的值
	val = ((buf[bytePosition] & mask) != 0);
	// 若是讀到字節末尾,修改兩個Position的值
	if (++bitPosition > 7)
	{
		bytePosition++;
		bitPosition = 0;
	}
	return val;
}

2. 解碼部分:

參照公式:$decodeNum = 2^m - 1 + k$,$m$爲前面0的個數,$k$爲後綴二進制對應十進制的值code

static int get_uev_code_num(UINT8 *buf, UINT8 &bytePosition, UINT8 &bitPosition)
{
	assert(bitPosition < 8);
	UINT8 val = 0, prefixZeroCount = 0;		//存儲每一位的數值; 前綴0的個數
	int prefix = 0, surfix = 0, decodeNum = 0;
	
	//統計前綴0的個數
	while (true)
	{
		val = get_bit_at_position(buf, bytePosition, bitPosition);
		if (val == 0)
		{
			prefixZeroCount++;
		}
		else
		{
			break;
		}
	}
	// 表示計算公式中 2^m - 1 部分
	prefix = (1 << prefixZeroCount) - 1;
	// 計算後綴中二進制轉十進制部分 k
	for (size_t i = 0; i < prefixZeroCount; i++)
	{
		val = get_bit_at_position(buf, bytePosition, bitPosition);
		surfix += val*(1 << (prefixZeroCount - i - 1));
	}

	decodeNum = prefix + surfix;
	return decodeNum;
}

3. 修改主函數

int _tmain(int argc, _TCHAR* argv[])
{
	UINT8 strArray[6] = { 0xA6, 0x43, 0x98, 0xE2, 0x04, 0x8A };
	UINT8 bytePosition = 0, bitPosition = 0;
	// 保存bit數據長度
	UINT8 dataLengthInBits = sizeof(strArray) * 8;

	// 保存解碼後的數據
	int decodeNum = 0;
	while ((bytePosition * 8 + bitPosition) < dataLengthInBits)
	{
		decodeNum = get_uev_code_num(strArray, bytePosition, bitPosition);
		printf("ExpColumb codeNum = %d\n", decodeNum);
	}

    return 0;
}

運行結果以下: 1 解碼結果get

2、編碼程序:

定義待編碼數組,及編碼後存儲的數組:it

UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };    // 帶編碼數組
UINT8 encodeArray[6] = { 0 };	// 存儲指數哥倫布編碼後的結果

總體思路: 以codeNum = 13爲例, ① 前綴0的個數:$prefixLen = floor[log_2(codeNum+1)] = 3$; ② 中間添加一個 1 ③ 後綴部分的二進制:$codeNum+1-2^{prefixLen} = 14-8 = 6 = b(1 1 0)$ 所以13的指數哥倫布編碼碼字爲0 0 0 1 1 1 0。io

1. 編碼部分:

與解碼部分相同,使用了bytePosition和bitPosition表示寫入位置。 【使用按位或的方式,按位寫入每一位數據】 例如:該寫某一字節code的第五位,這一個字節爲 1101 0000,要在第五位上寫入1(0同理), 建立一個mask -> 0000 1000,將code這個字節與mask進行按位或運算,便可將1寫入到第五位上 code | mask = 1101 1000class

static void encode_uev_array(UINT8 *encodeArray, UINT8 codeNum, UINT8 &bytePosition, UINT8 &bitPosition)
{
	// 前綴0
	int preZeroLen = floor(log(codeNum + 1) / log(2));
	bitPosition = bitPosition + preZeroLen;
	if (bitPosition > 7)
	{
		bytePosition++;
		bitPosition = bitPosition % 8;
	}

	// 中間1
	UINT8 mask = 1 << (7 - bitPosition);
	encodeArray[bytePosition] = encodeArray[bytePosition] | mask;
	if (++bitPosition > 7)
	{
		bytePosition++;
		bitPosition = 0;
	}

	// 後綴二進制
	int surDecNum = codeNum + 1 - pow(2, preZeroLen);
	dec_to_bin(encodeArray, surDecNum, bytePosition, bitPosition, preZeroLen);
}

2. 十進制轉二進制:

static void dec_to_bin(UINT8 *encodeArray, UINT8 decNum, UINT8 &bytePosition, UINT8 &bitPosition, int preZeroLen)
{
	if (preZeroLen == 0)
	{
		return;
	}
	// 轉換二進制用的mask
	UINT8 maskBin = 1 << (preZeroLen - 1);
	// 按位寫數據用的mask
	UINT8 maskVal;
	UINT8 val = 0;

	// 寫入二進制後綴
	for (size_t i = 0; i < preZeroLen; i++)
	{
		val = (decNum & maskBin ? 1 : 0);

		maskVal = val << (7 - bitPosition);
		encodeArray[bytePosition] = encodeArray[bytePosition] | maskVal;
		if (++bitPosition > 7)
		{
			bytePosition++;
			bitPosition = 0;
		}
		maskBin = maskBin >> 1;
	}
}

3. 主函數:

UINT8 encodeArray[6] = { 0 };
UINT8 bytePosition = 0, bitPosition = 0;
UINT8 oriNumArray[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
UINT8 oriNumLen = sizeof(oriNumArray) / sizeof(UINT8);

for (size_t i = 0; i < oriNumLen; i++)
{
	encode_uev_array(encodeArray, oriNumArray[i], bytePosition, bitPosition);
	printf("%d \n", bitPosition);*/
}

for (size_t k = 0; k < 6; k++)
{
	printf("%x ", encodeArray[k]);
}

運行結果以下,與第一部分中待解碼數組中數據相同,證實編解碼部分程序能正確執行。 2數據類型

相關文章
相關標籤/搜索