Range coder的原理部分可以参考熵编码算法Range encoding工程原理和实现
比特流原理参考Range Coder编码比特流
本篇文章谈一谈range-coder的使用问题
代码参考
根据range coder的原理,我们在编码前需要提前知道编码数据的累计概率分布
from range_coder import RangeEncoder, RangeDecoder
from range_coder import prob_to_cum_freq, cum_freq_to_prob
prob = [4, 6, 8]
prob = np.asarray(prob, dtype=np.float64) / np.sum(prob)
cumFreq = prob_to_cum_freq(prob, 128)
cumFreq[-1] = 2**32
sequence = [2, 2]
这里自定了一个pmf作为频率统计,后做了一个归一化,然后使用prob_to_cum_freq将概率做了一个累计概率密度处理,注意这里处理后输出的结果为
print(cumFreq)
[0, 29, 72, 4294967296]
cumFreq 中只有4位数其代表的是只有三个概率区间,因此只能编0,1,2三个数。
如果需要改变累计概率密度函数,则重新输入累计概率密度函数,这样在编码区间划分时会按照这个区间进行划分。
filepath = mkstemp()[1]
# encoding one sequence should require 1 byte
cumFreq0 = [0, 4, 6, 8]
cumFreq1 = [0, 2, 5, 7, 10, 14]
data0 = [random.randint(0, len(cumFreq0) - 2) for _ in range(10)]
data1 = [random.randint(0, len(cumFreq1) - 2) for _ in range(17)]
encoder = RangeEncoder(filepath)
encoder.encode(data0, cumFreq0)
encoder.encode(data1, cumFreq1)
encoder.close()
完整的编解码示意
random.seed(0)
filepath = mkstemp()[1]
for _ in range(20):
numSymbols = np.random.randint(1, 6)
cumFreq = [0] + np.cumsum(np.random.randint(1, 10, size=numSymbols)).tolist()
data = np.random.randint(numSymbols, size=np.random.randint(20)).tolist()
encoder = RangeEncoder(filepath)
encoder.encode(data, cumFreq)
encoder.close()
decoder = RangeDecoder(filepath)
dataRec = decoder.decode(len(data), cumFreq)
decoder.close()
assert data == dataRec
os.remove(filepath)