2017年的第一篇博文。
本文主要有以下三部分内容:
- 介绍了Golomb编码,及其两个变种:Golomb-Rice和Exp-Golomb的基本原理
- C++实现了一个简单的BitStream库,能够方便在bit流和byte数字之间进行转换
- C++实现了Golomb-Rice和Exp-Golomb的编码,并进行了测试。
在本位的最后给出了源代码的下载地址。
Golomb编码的基本原理
Golomb编码是一种无损的数据压缩方法,由数学家Solomon W.Golomb在1960年代发明。Golomb编码只能对非负整数进行编码,符号表中的符号出现的概率符合几何分布(Geometric Distribution)时,使用Golomb编码可以取得最优效果,也就是说Golomb编码比较适合小的数字比大的数字出现概率比较高的编码。它使用较短的码长编码较小的数字,较长的码长编码较大的数字。
Golomb编码是一种分组编码,需要一个正整数参数m,然后以m为单位对待编码的数字进行分组,如下图:
对于任一待编码的非负正整数N,Golomb编码将其分为两个部分:所在组的编号GroupID以及分组后余下的部分,GroupID实际是待编码数字N和参数m的商,余下的部分则是其商的余数,具体计算如下:
对于得到的组号q使用一元编码(Unary code),余下部分r则使用固定长度的二进制编码(binary encoding)。
一元编码(Unary coding)是一种简单的只能对非负整数进行编码的方法,对于任意非负整数num,它的一元编码就是num个1后面紧跟着一个0。例如:
num | Unary coding |
---|---|
0 | 0 |
1 | 10 |
2 | 110 |
3 | 1110 |
4 | 11110 |
5 | 111110 |
其编解码的伪代码如下:
UnaryEncode(n) {
while (n > 0) {
WriteBit(1);
n--;
}
WriteBit(0);
}
UnaryDecode() {
n = 0;
while (ReadBit(1) == 1) {
n++;
}
return n;
}
使用一元编码编码组号也就是商q后,对于余下的部分r则有根据编码数字大小的不同有不同的处理方法。
- 如果参数m是2的次幂(这也是下面将要介绍的Golomb-Rice编码),则使用取r的二进制表示的低 log2(m) 位,作为r的码字
- 如果参数m不是2的次幂,如果m不是2的次幂,设 b=⌈log2(m)⌉
- 如果 r<2b−m ,则使用b-1位的二进制编码r。
- 如果 r≧2b−m ,则使用b位二进制对 r+2b−m 进行编码
总结,设待编码的非负整数为N,Golomb编码流程如下:
- 初始化正整数参数m
- 取得组号q以及余下部分r,计算公式为: q=N/m,r=N