算術編碼(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\n")
inputstr = input()
print  (inputstr + "\n")

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("\n------- ENCODING -------\n" )
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("\nThe Tag is \n ")
print(tag)

# Decoding

print("\n------- DECODING -------\n" )
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 \n ")
print("".join(decodedSeq))
Arithmetic coding Code

 

 

參考:

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM