LZW編碼演算法詳解
LZW(Lempel-Ziv & Welch)編碼又稱字串表編碼,是Welch將Lemple和Ziv所提出來的無損壓縮技術改進後的壓縮方法。GIF影像檔採用的是一種改良的LZW壓縮演算法,通常稱為GIF-LZW壓縮演算法。下面簡要介紹GIF-LZW的編碼與解碼方程
解:例 現有來源於二色系統的映像資料來源(假設資料以字串表示):aabbbaabb,試對其進行LZW編碼及解碼。
1)根據映像中使用的顏色數初始化一個字串表(如表1),字串表中的每個顏色對應一個索引。在初始字串表的LZW_CLEAR和LZW_EOI分別為字串表初始化標誌和編碼結束標誌。設定字串變數S1、S2並初始化為空白。
2)輸出LZW_CLEAR在字串表中的索引3H(見表2第一行)。
3)從映像資料流中第一個字元開始,讀取一個字元a,將其賦給字串變數S2。判斷S1+S2=“a”在字元表中,則S1=S1+S2=“a”(見表2第二行)。
4)讀取映像資料流中下一個字元a,將其賦給字串變數S2。判斷S1+S2=“aa”不在字串表中,輸出S1=“a”在字串表中的索引0H,並在字串表末尾為S1+S2="aa"添加索引4H,且S1=S2=“a”(見表2第三行)。
5)讀下一個字元b賦給S2。判斷S1+S2=“ab”不在字串表中,輸出S1=“a”在字串表中的索引0H,並在字串表末尾為S1+S2=“ab”添加索引5H,且S1=S2=“b”(見表2第四行)。
6)讀下一個字元b賦給S2。S1+S2=“bb”不在字串表中,輸出S1=“b”在字串表中的索引1H,並在字串表末尾為S1+S2=“bb”添加索引6H,且S1=S2=“b”(見表2第五行)。
7)讀字元b賦給S2。S1+S2=“bb”在字串表中,則S1=S1+S2=“bb”(見表2第六行)。
8)讀字元a賦給S2。S1+S2=“bba”不在字串表中,輸出S1=“bb”在字串表中的索引6H,並在字串表末尾為S1+S2=“bba”添加索引7H,且S1=S2=“a”(見表2第七行)。
9)讀字元a賦給S2。S1+S2=“aa”在字串表中,則S1=S1+S2=“aa”(見表2第八行)。
10)讀字元b賦給S2。S1+S2=“aab”不在字串表中,輸出S1=“aa”在字串表中的索引4H,並在字串表末尾為S1+S2=“aab”添加索引8H,且S1=S2=“b”(見表2第九行)。
11)讀字元b賦給S2。S1+S2=“bb”,在字串表中,則S1=S1+S2=“b”(見表2第十行)。
12)輸出S1中的字串"b"在字串表中的索引1H(見表2第十一行)。
13)輸出結束標誌LZW_EOI的索引3H,編碼完畢。
最後的編碼結果為"30016463“。
下面對上述編碼結果"30016463"進行解碼。同樣先初始化字串表,結果如表1所示。
1)首先讀取第一個編碼Code=3H,由於它為LZW_CLEAR,無輸出(見表3第一行)。
2)讀入下一個編碼Code=0H,由於字串表中存在該索引,因此輸出字串表中0H對應的字串"a",同時使OldCode=Code=0H(見表3第二行)。
3)讀下一個編碼Code=0H,字串表中存在該索引,輸出0H所對應的字串"a",然後將OldCode=0H所對應的字串"a"加上Code=0H所對應的字串的第一個字元"a",即"aa"添加到字串表中,其索引為4H,同時使OldCode=Code=0H(見表3第三行)。
4)讀下一個編碼Code=1H,字串表中存在該索引,輸出1H所對應的字串"b",然後將OldCode=0H所對應的字串"a"加上Code=1H所對應的字串的第一個字元"b",即"ab"添加到字串表中,其索引為5H,同時使OldCode=Code=1H(見表3第四行)。
5)讀入下一個編碼Code=6H,由於字串表中不存在該索引,因此輸出OldCode=1H所對應的字串"b"加上OldCode的第一個字元"b“,即"bb",同時將"bb"添加到字串表中,其索引為6H,同時使OldCode=Code=6H(見表3第五行)。
6)讀下一個編碼Code=4H,字串表中存在該索引,輸出4H所對應的字串"aa",然後將OldCode=6H所對應的字串"bb"加上Code=4H所對應的字串的第一個字元"a",即"bba"添加到字串表中,其索引為7H,同時使OldCode=Code=4H(見表3第六行)。
7)讀下一個編碼Code=6H,字串表中存在該索引,輸出6H所對應的字串"bb",然後將OldCode=4H所對應的字串"aa"加上Code=6H所對應的字串的第一個字元"b",即"aab"添加到字串表中,其索引為8H,同時使OldCode=Code=6H(見表3第七行)。
8)讀下一個編碼Code=3H,它等於LZW_EOI,資料解碼完畢(見表3第八行)。
最後的解碼結果為aabbbaabb。
由此可見,LZW編碼演算法在編碼與解碼過程中所建立的字串表是一樣的,都是動態產生的,因此在壓縮檔中不必儲存字串表。
1.LZW的全稱是什麼?
Lempel-Ziv-Welch (LZW).
2. LZW的簡介和壓縮原理是什麼。
LZW壓縮演算法是一種新穎的壓縮方法,由Lemple-Ziv-Welch 三人共同創造,用他們的名字命名。它採用了一種先進的串表壓縮,將每個第一次出現的串放在一個串表中,用一個數字來表示串,壓縮檔只存貯數字,則不存貯串,從而使圖象檔案的壓縮效率得到較大的提高。奇妙的是,不管是在壓縮還是在解壓縮的過程中都能正確的建立這個串表,壓縮或解壓縮完成後,這個串表又被丟棄。
LZW演算法中,首先建立一個字串表,把每一個第一次出現的字串放入串表中,並用一個數字來表示,這個數字與此字串在串表中的位置有關,並將這個數字存入壓縮檔中,如果這個字串再次出現時,即可用表示它的數字來代替,並將這個數字存入檔案中。壓縮完成後將串表丟棄。如"print" 字串,如果在壓縮時用266表示,只要再次出現,均用266表示,並將"print"字串存入串表中,在圖象解碼時遇到數字266,即可從串表中查出266所代表的字串"print",在解壓縮時,串表可以根據壓縮資料重建。
3.在詳細介紹演算法之前,先列出一些與該演算法相關的概念和詞彙
1)'Character': 字元,一種基礎資料元素,在普通文字檔中,它佔用1個單獨的byte,而在映像中,它卻是一種代表給定像素顏色的索引值。
2)'CharStream':資料檔案中的字元流。
3)'Prefix':首碼。如這個單詞的含義一樣,代表著在一個字元最直接的前一個字元。一個前置詞字元長度可以為0,一個prefix和一個character可以組成一個字串(string),
4)'Suffix': 尾碼,是一個字元,一個字串可以由(A,B)來組成,A是首碼,B是尾碼,當A長度為0的時候,代表Root,根
5)'Code:碼,用於代表一個字串的位置編碼
6)'Entry':一個Code和它所代表的字串(string)
4.壓縮演算法的簡單樣本,不是完全實現LZW演算法,只是從最直觀的角度看lzw演算法的思想
對未經處理資料ABCCAABCDDAACCDB進行LZW壓縮
未經處理資料中,只包括4個字元(Character),A,B,C,D,四個字元可以用一個2bit的數表示,0-A,1-B,2-C,3-D,從最直觀的角度看,原始字串存在重複字元:ABCCAABCDDAACCDB,用4代表AB,5代表CC,上面的字串可以替代表示為:45A4CDDAA5DB,這樣是不是就比原資料短了一些呢。
5.LZW演算法的適用範圍
為了區別代表串的值(Code)和原來的單個的資料值(String),需要使它們的數範圍不重合,上面用0-3來代表A-D,那麼AB就必須用大於3的數值來代替,再舉另外一個例子,原來的數值範圍可以用8bit來表示,那麼就認為原始的數的範圍是0~255,壓縮程式產生的標號的範圍就不能為0~255(如果是0-255,就重複了)。只能從256開始,但是這樣一來就超過了8位的表示範圍了,所以必須要擴充資料的位元,至少擴充一位,但是這樣不是增加了1個字元佔用的空間了麼。但是卻可以用一個字元代表幾個字元,比如原來255是8bit,但是現在用256來表示254,255兩個數,還是划得來的。從這個原理可以看出LZW演算法的適用範圍是未經處理資料串最好是有大量的子串多次重複出現,重複的越多,壓縮效果越好。反之則越差,可能真的不減反增了。
6.LZW演算法中特殊標記
隨著新的串(string)不斷被發現,標號也會不斷地增長,如果原資料過大,產生的標號集(string table)會越來越大,這時候操作這個集合就會產生效率問題。如何避免這個問題呢?Gif在採用lzw演算法的做法是當標號集足夠大的時候,就不能增大了,乾脆從頭開始再來,在這個位置要插入一個標號,就是清除標誌CLEAR,表示從這裡我重新開始構造字典,以前的所有標記作廢,開始使用新的標記。
這時候又有一個問題出現,足夠大是多大。這個標號集的大小為比較合適呢。理論上是標號集大小越大,則壓縮比率就越高,但開銷也越高。 一般根據處理速度和記憶體空間連個因素來選定。GIF規範規定的是12位,超過12位的表達範圍就推倒重來,並且GIF為了提高壓縮率,採用的是變長的字長。比如說未經處理資料是8位,那麼一開始,先加上一位再說,開始的字長就成了9位,然後開始加標號,當標號加到512時,也就是超過9為所能表達的最大資料時,也就意味著後面的標號要用10位字長才能表示了,那麼從這裡開始,後面的字長就是10位了。依此類推,到了2^12也就是4096時,在這裡插一個清除標誌,從後面開始,從9位再來。
GIF規定的清除標誌CLEAR的數值是未經處理資料字長表示的最大值加1,如果未經處理資料字長是8,那麼清除標誌就是256,如果未經處理資料字長為4那麼就是16。另外GIF還規定了一個結束標誌END,它的值是清除標誌CLEAR再加1。由於GIF規定的位元有1位(單色圖),4位(16色)和8位(256色),而1位的情況下如果只擴充1位,只能表示4種狀態,那麼加上一個清除標誌和結束標誌就用完了,所以1位的情況下就必須擴充到3位。其它兩種情況初始的字長就為5位和9位。
7、用lzw演算法壓縮未經處理資料的樣本分析
輸入資料流,也就是原始的資料為:255,24,54,255,24,255,255,24,5,123,45,255,24,5,24,54..................
這個正好可以看到是gif檔案中像素數組的一部分,如何對它進行壓縮
因為未經處理資料可以用8bit來表示,故清除標誌Clear=255+1 =256,結束標誌為End=256+1=257,目前標號集為
0 1 2 3 .................................................................................255 CLEAR END
第一步,讀取第一個字元為255,在標記表裡面尋找,255已經存在,我們已經認識255了,不做處理
第二步,取第二個字元,此時首碼為A,形成當前的Entry為(255,24),在標記集合不存在,我們並不認識255,24好,這次你小子來了,我就記住你,把它在標記集合中標記為258,然後輸出首碼A,保留尾碼24,並作為下一次的首碼(尾碼變首碼)
第三步,取第三個字元為54,當前Entry(24,54),不認識,記錄(24,54)為標號259,並輸出24,尾碼變首碼
第四部:取第四個字元255,Entry=(54,255),不認識,記錄(54,255)為標號260,輸出54,尾碼變首碼
第五步 取第5個字元24,entry=(255,24),啊,認識你,這不是老258麼,於是把字串規約為258,並作為首碼
第六步 取第六個字元255,entry=(258,255),不認識,記錄(258,255)為261,輸出258,尾碼變首碼
.......
一直處理到最後一個字元,
用一個表記錄處理過程
CLEAR=256,END=257
第幾步 首碼 尾碼 Entry 認識(Y/N) 輸出 標號
1 255 (,255)
2 255 24 (255,24) N 255 258
3 24 54 (24,54) N 24 259
4 54 255 (54,255) N 54 260
5 255 24 (255,24) Y
6 258 255 (258,255) N 258 261
7 255 255 (255,255) N 255 262
.....
上面這個樣本有些不能完整體現,另外一個例子是
原輸入資料為:A B A B A B A B B B A B A B A A C D A C D A D C A B A A A B A B .....
採用LZW演算法對其進行壓縮,壓縮過程用一個表來表述為:
注意原資料中只包含4個character,A,B,C,D
用兩bit即可表述,根據lzw演算法,首先擴充一位變為3為,Clear=2的2次方+1=4; End=4+1=5;
初始標號集因該為
0 1 2 3 4 5
A B C D Clear End
而壓縮過程為:
第幾步 首碼 尾碼 Entry 認識(Y/N) 輸出 標號
1 A (,A)
2 A B&