對一幅BMP格式的灰度圖像進行二元霍夫曼編碼和譯碼


對一幅BMP格式的灰度圖像進行二元霍夫曼編碼和譯碼

信息論的實驗終於結束了,才開始寫python,寫的比較亂,僅供參考


主要思想

霍夫曼編碼關鍵在於樹的構造,其構造要達到的目的為權重越大越靠近葉子結點,權重越小越靠近根,即使出現次數越多的值的碼長越短。
構造時每次去權重最小的兩個點合並為一個點n,這兩個點為點n的左右子結點,這兩個點的權重的和為結點n的權重,然后重復上述操作直至剩下一個點。如:

 

 

程序說明

1、還原程序直接將圖像大小寫死了為256* 256
2、程序中編碼效率的計算為信源熵除以平均碼長
3、了解了python中的pillow庫
Image.open(圖像)打開圖像
getpixel((x,y))得到圖像x,y處像素值
Image.fromarry(數組,astype('uint8')).convert('L')將一個數組還原為圖像,其中L表示灰度圖
show()展示圖像
save()保存圖像
4、統計一個列表中各數值的個數

#需要導入from collections import Counter c = Counter() for num in list: c[num] = c[num] + 1 #list為一個列表,比如list=[11,11,22,22,22,33],則運行結果c={11:2,22:3,33:1}

5、np.arrry(矩陣)可以將矩陣變為數組
需要導入import numpy as np
程序還原時發現圖像是鏡像的,不知哪有問題,后來干脆把得到的二維數組轉置一下,發現可以
轉置有兩種方法:
(1)T: 數組.T
(2)reshape:np.reshape(數組)

編碼程序

import os import math from PIL import Image from collections import Counter #定義樹的結構 class BinaryTree: def __init__(self,weight,name=None): self.name=name self.weight = weight self.leftChild = None self.rightChild = None #讀取圖像,將像素存入一個列表im_list image_name=input('請輸入需要編碼的圖像') im = Image.open(image_name) width = im.width height = im.height im_list = [] for x in range(width): raw_list = [] for y in range(height): pixel = im.getpixel((x, y)) raw_list.append(pixel) im_list.extend(raw_list) sum=len(im_list)#計算像素個數總和 #統計各像素的的個數,將像素及對應次數存入字典c c = Counter() for num in im_list: c[num] = c[num] + 1 sum_v=[]#各像素的概率 H=0#信源熵 for i in range(0,256): if i in c: sum_v.append(c[i]/sum) H=H+c[i]/sum*math.log(sum/c[i],2) else: sum_v.append(0) #先將字典c中的各對元素轉化為Binarytree類,即將各對元素變為結點,並存到Node列表中 node=[] for i in range(0,len(c)): temp_key=min(c,key=c.get) temp_num=c[temp_key] node.append(BinaryTree(temp_num,temp_key)) del c[temp_key] #對表內元素按照權重排序的函數 def sort_weight(elem): return elem.weight node.sort(key=sort_weight) #構造哈夫曼樹 while len(node)!=1: small_1=node.pop(0) small_2=node.pop(0) newnode=BinaryTree(0) newnode.weight=small_1.weight+small_2.weight newnode.rightChild=small_1 newnode.leftChild=small_2 node.append(newnode) node.sort(key=sort_weight) tree=node.pop(0) #進行編碼 huffcode={}#最后像素和所對應的的字典都存放在這里 bin_str=[]#想當於一個棧結構,用於存放編碼 bin_str.append('') #迭代遍歷函數 def coding (tree): Left(tree) Right(tree) bin_str.pop(-1) #左樹遍歷 def Left(tree): tree1=tree.leftChild bin_str.append(bin_str[-1] + '0') if tree1.name!=None: huffcode[tree1.name] = bin_str.pop(-1) return coding(tree1) #右樹遍歷 def Right(tree): tree2 = tree.rightChild bin_str.append(bin_str[-1] + '1') if tree2.name != None: huffcode[tree2.name]=bin_str.pop(-1) return coding(tree2) #對各像素編碼,並將得到的編碼表寫入文件 coding(tree) filehuff=open('huffcode.txt',mode='w') filehuff.write(str(huffcode)) #對圖像進行編碼,並將編碼寫入文件imcode.txt im_code=[] while len(im_list)!=0 : im_code.append(huffcode[im_list.pop(0)]) filecode=open('imcode.txt',mode='w') filecode.write(str(im_code)) print('編碼成功!') sum_l=[]#各像素碼長 for i in range(0,256): if i in huffcode: sum_l.append(len(huffcode[i])) else: sum_l.append(0) L=0#平均碼長 while(len(sum_l)!=0): L=sum_l.pop(0)*sum_v.pop(0)+L print('編碼效率為') print(H/L)

還原程序

import os import re import numpy as np from PIL import Image #定義樹的結構 class BinaryTree: def __init__(self,name=None): self.name=name self.leftChild = None self.rightChild = None #得到哈夫曼編碼表,保存為一個列表 file=open('huffcode.txt') c={} for each_word in file: a=re.split(r'[\{\}\:\,\'\s+]+', each_word) a.pop(0) a.pop(-1) #構造哈夫曼編碼的樹 def encode(nodeser,tree_leave,strlen,str_len): if str[strlen] == '0': if str_len==1: nodeser.leftChild=tree_leave return elif nodeser.leftChild==None: newnode=BinaryTree() nodeser.leftChild =newnode encode(nodeser.leftChild,tree_leave,strlen+1,str_len-1) else: if str_len == 1: nodeser.rightChild = tree_leave return elif nodeser.rightChild == None: newnode = BinaryTree() nodeser.rightChild = newnode encode(nodeser.rightChild, tree_leave, strlen + 1, str_len - 1) return tree=BinaryTree() while len(a)!=0: name=a.pop(0) str=a.pop(0) tree_leave=BinaryTree(name) encode(tree,tree_leave,0,len(str)) #讀取經過哈夫曼編碼后的圖片的文檔 file2=open('imcode.txt') for each_word in file2: im=re.split(r'[\[\]\,\'\s+]+', each_word) im.pop(0) im.pop(-1) strcode='' #先轉化為一串01串 while len(im)!=0: strcode=strcode+im.pop(0) tree_copy=tree reimg=[] #遍歷樹,得到相對應的像素值 for i in range(0,len(strcode)): if strcode[i]=='0': tree_copy=tree_copy.leftChild else: tree_copy=tree_copy.rightChild if tree_copy.name!=None: reimg.append(tree_copy.name) tree_copy=tree #變為二維列表存儲 reimage=[] for i in range(0,256): reimage.append([]) for j in range(0,256): reimage[i].append(reimg.pop(0)) #變為數組形式,並轉置 iii=np.array(reimage) iii=iii.T #變為圖像 image=Image.fromarray(iii.astype('uint8')).convert('L') #展示並保存為dd.bmp image.show() image.save('dd.bmp')

運行結果

對如下圖像編碼(大小為256* 256,因為不能上傳bmp圖像,所以示例如下)


得到的兩個文件,一個是像素值與編碼的對應關系,一個為圖像的編碼結果



免責聲明!

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



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