十六算术编码_2算术编码举例实现

Posted 叮咚咕噜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十六算术编码_2算术编码举例实现相关的知识,希望对你有一定的参考价值。

基本原理

在一次算术编码的执行前,为简便起见,首先假设输入的信源为0/1的二进制信源,0和1的概率比为7:3。即二者的概率为:

p(0) = 0.7;
p(1) = 0.3;

假设输入的待编码信息为[0, 0, 1],在编码每一个符号时,都需要对概率区间进行分割,并通过与编码区间进行比较,判断是否输出码流的bit位,以及更新编码下一个符号的上下文。

在第一次进行分割之后,概率区间和编码区间的关系如下图所示:
在这里插入图片描述
第一个字符的概率区间分割之后,不满足输出码流的条件,因此结束这个字符的编码,准备开始编码下一个字符。

第二个字符依然为0,此时概率区间和编码区间的关系为:
在这里插入图片描述
此时概率区间已经完全处于编码区间的下半区,因此应输出一个bit-0。而后,编码区间的下半区间扩展2倍到原有的完整编码区间继续进行下一个编码。(因为每次我们比较的还是0-5000,但是我们下一次比对的是前半段区间,所以需要扩展)该过程由下图所示:
在这里插入图片描述
当前的编码区间是0-9800,我们设定的最后一个待编码符号为1,因此最后一次分割概率区间,选取上30%作为结果。此时的概率区间分割结果如下图所示:
在这里插入图片描述
由于当前的编码区间变为6860-9800,归一化之后超出了0-10000,所以需要在归一化之前需要先减去50000

代码实现

//<2>程序在概率模型为0.7、0.3最终输出0110
int main()
{
	unsigned int input_data[] = { 0, 0, 1};
	unsigned int input_length = sizeof(input_data) / sizeof(unsigned int);

	for (int idx = 0; idx < input_length; idx++)
	{
		//<1>编码每一个元素
		Encode_one_symbol(input_data[idx]);
	}

	//<1>收尾操作
	Encode_stop();

	return 0;
}
/*
	|0-------------------7000|-------10000|
	如果我们输入的要编码的数据是0,则概率区间是0-7000这部分,如果是1则是7000-10000
*/
static unsigned int probability_model[3] = { 0, 7000, 10000 };	//<2>概率模型,0出现的概率是7,1出现的概率是3
static unsigned int upper_bound = 10000;		//<2>概率上限

//<2>编码器的实例
ARITHMETIC_ENCODER encoder = { 0, FULL_VALUE, 0 };

void output_bits(int bit)
{
	printf("%d", bit);
	while (encoder.bits_to_follow > 0)		//<2>bits_to_follow在输出的时候使用,有几个待输出的bit
	{
		printf("%d", !bit);
		encoder.bits_to_follow--;
	}
}

//<2>实现元素编码:循环编码每一个传入的值,通过这个值不断的分割编码区间按照7:3的比例,最终在满足几种条件时输出
int Encode_one_symbol(unsigned int symbol)
{
	long range = encoder.high - encoder.low + 1;	//<2>编码区间长度,传入数据之前的长度
	//<2>然后每编码一个这样的符号,需要将这个区间按照概率模型对区间进行再次分割
	encoder.high = encoder.low + (range * probability_model[symbol + 1] / upper_bound) - 1;
	encoder.low = encoder.low + (range * probability_model[symbol] / upper_bound);

	while (1)
	{
		//<2>整个区间在左侧,应当输出一个0
		if (encoder.high < HALF_VALUE)
		{
			// Output 0;
			output_bits(0);
		}//<2>整个区间再右侧输出一个1
		else if (encoder.low >= HALF_VALUE)
		{
			// Output 1;
			output_bits(1);	
			encoder.high -= HALF_VALUE;//<2>将这个在右侧的区间减半是为了能够在归一化*2之后仍在0-FULL_VALUE之间
			encoder.low -= HALF_VALUE;	
		}//<2>大于1/4小于3/4,即小于整体的一半,应该输出,由于跨过了中点不知道是输出0还是1
		else if (encoder.low >= FIRST_QUATER && encoder.high < THIRD_QUATER)
		{
			encoder.bits_to_follow++;	//<2>无法判断输出的是0还是1
			encoder.high -= FIRST_QUATER;
			encoder.low -= FIRST_QUATER;
		}
		else    //<2>进行一次区间长度更新之后,low和high依然大于整体区间的一半,不进行任何输出,直接break
		{
			break;
		}

		//<2>为了实现归一化,将这个放大一倍
		encoder.low = 2 * encoder.low;
		encoder.high = 2 * encoder.high + 1;
	}

	return 0;
}

//<2>收尾
int Encode_stop()
{
	encoder.bits_to_follow++;	//<2>待编码增加1
	if (encoder.low < FIRST_QUATER)		//<2>协议要求
	{
		output_bits(0);
	} 
	else
	{
		output_bits(1);
	}
	printf("\\n");
	return 0;
}

例二

输入:011
输出:10101

该例子中点阐述的是编码第二个1时,4900~7000,跨过了中点,这种情况4900-2500 ~ 7000-2500,其实是将2500-7500归一化为0-10000
在这里插入图片描述

以上是关于十六算术编码_2算术编码举例实现的主要内容,如果未能解决你的问题,请参考以下文章

十七熵编码_CABAC语法元素的二值化

H264熵编码之CABAC

H264熵编码之CABAC

H.264---CABAC---第四步--算术编码

H.264/AVC视频编解码技术详解十八:算术编码的基本原理与实现

CABAC