算术编码(Arithmetic coding)的实现

算术编码例题:

假设信源信号有{A, B, C, D}四个,他们的概率分别为{0.1, 0.4, 0.2, 0.3},如果我们要对CADACDB这个信号进行编码,那么应该怎样进行呢?

准备工作完成之后,我们便可以开始进行编码了。
    那么我们首先读入信号:C——因为C在最初始的间隔中是[0.5, 0.7),所以读入C之后我们的编码间隔就变成[0.5, 0.7)了;
    紧接着,我们读入的是A,A在初始区间内是占整个区间的前10%,因此对应这个上来也是需要占这个编码间隔的前10%,因此编码区间变为:[0.5, 0.52)了;
    再然后是D,因为D占整个区间的70% ~ 100%,所以也是占用这个编码区间的70% ~ 100%,操作后的编码区间为[0.514, 0.52)
    ……
    直到最后将信号量全部读出。

    最后,我们将这个操作过程绘制成为一张表:

 解码例题:

假设信源信号有{A, B, C, D}四个,他们的概率分别为{0.1, 0.4, 0.2, 0.3},当我们得到的编码是0.5143876的时候,问原始的信号串(7位)是怎样的?

准备工作完成之后,我们现在开始解码:
    我们发现,待解码的数据0.5143876在[0.5, 0.7)内,因此,我们解出的第一个码值为C
    同理,我们继续计算0.5143876处于[0.5, 0.7)的第一个10%内因此解出的第二个码值为A
    ……
    这个过程持续直到执行七次全部执行完为止。

    那么以上的过程我们同样可以列表表示:

作业:对任一概率序列,实现算术编码,码长不少于16位,不能固定概率,语言自选。

基于Python实现:

from collections import Counter  #统计列表出现次数最多的元素
import numpy as np

print("Enter a Sequence
")
inputstr = input()
print  (inputstr + "
")

res = Counter(inputstr) #统计输入的每个字符的个数,res是一个字典类型
print (str(res))
# print(res)
#sortlist = sorted(res.iteritems(), lambda x, y : cmp(x[1], y[1]), reverse = True)
#print sortlist

M = len(res)
#print (M)
N = 5
A = np.zeros((M,5),dtype=object)  #生成M行5列全0矩阵

#A = [[0 for i in range(N)] for j in range(M)]

reskeys = list(res.keys())      #取字典res的键,按输入符号的先后顺序排列
# print(reskeys)
resvalue = list(res.values())   #取字典res的值
totalsum = sum(resvalue)        #输入一共有几个字符

# Creating Table

A[M-1][3] = 0
for i in range(M):
   A[i][0] = reskeys[i]      #第一列是res的键
   A[i][1] = resvalue[i]     #第二列是res的值
   A[i][2] = ((resvalue[i]*1.0)/totalsum)    #第三列是每个字符出现的概率
i=0
A[M-1][4] = A[M-1][2]
while i < M-1:                    #倒数两列是每个符号的区间范围,与输入符号的顺序相反
   A[M-i-2][4] = A[M-i-1][4] + A[M-i-2][2]
   A[M-i-2][3] = A[M-i-1][4]
   i+=1
print (A)

# Encoding

print("
------- ENCODING -------
" )
strlist = list(inputstr)
LEnco = []
UEnco = []
LEnco.append(0)
UEnco.append(1)

for i in range(len(strlist)):
    result = np.where(A == reskeys[reskeys.index(strlist[i])])           #满足条件返回数组下标(0,0),(1,0)
    addtollist = (LEnco[i] + (UEnco[i] - LEnco[i])*float(A[result[0],3]))
    addtoulist = (LEnco[i] + (UEnco[i] - LEnco[i])*float(A[result[0],4]))

    LEnco.append(addtollist)
    UEnco.append(addtoulist)

    tag = (LEnco[-1] + UEnco[-1])/2.0           #最后取区间的中点输出

LEnco.insert(0, " Lower Range")
UEnco.insert(0, "Upper Range")
print(np.transpose(np.array(([LEnco],[UEnco]),dtype=object)))  #np.transpose()矩阵转置
print("
The Tag is 
 ")
print(tag)

# Decoding

print("
------- DECODING -------
" )
ltag = 0
utag = 1
decodedSeq = []
for i in range(len(inputstr)):
    numDeco = ((tag - ltag)*1.0)/(utag - ltag)    #计算tag所占整个区间的比例
    for i in range(M):
        if (float(A[i,3]) < numDeco < float(A[i,4])):   #判断是否在某个符号区间范围内

            decodedSeq.append(str(A[i,0]))
            ltag = float(A[i,3])
            utag = float(A[i,4])
            tag = numDeco

print("The decoded Sequence is 
 ")
print("".join(decodedSeq))

Arithmetic coding Code

参考:

https://blog.csdn.net/qq_36752072/article/details/77986159

https://github.com/nishanpoojary/Arithmetic-Coding

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注