日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

向极限挑战:算术编码 (转)

發(fā)布時(shí)間:2023/12/18 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 向极限挑战:算术编码 (转) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

向極限挑戰(zhàn):算術(shù)編碼

(轉(zhuǎn)) http://blog.csdn.net/hhf383530895/archive/2009/08/24/4478605.aspx

我們?cè)谏弦徽轮幸呀?jīng)明白,Huffman 編碼使用整數(shù)個(gè)二進(jìn)制位對(duì)符號(hào)進(jìn)行編碼,這種方法在許多情況下無法得到最優(yōu)的壓縮 效果。假設(shè)某個(gè)字符的出現(xiàn)概率為 80%,該字符事實(shí)上只需要 -log2 (0.8) = 0.322 位編碼,但 Huffman 編碼一定會(huì)為其分配一位 0 或一位 1 的編碼??梢韵胂?#xff0c;整個(gè)信息的 80% 在壓縮后都幾乎相當(dāng)于理想長度的 3 倍左右,壓縮效果可想而知。

難道真的能只輸出 0.322 個(gè) 0 或 0.322 個(gè) 1 嗎?是用剪刀把計(jì)算機(jī) 存儲(chǔ) 器中的二進(jìn)制位剪開嗎?計(jì)算機(jī)真有這樣的特異功能嗎?慢著慢著,我們不要被表面現(xiàn)象所迷惑,其實(shí),在這一問題上,我們只要換一換腦筋,從另一個(gè)角度……哎呀,還是想不通,怎么能是半個(gè)呢?好了,不用費(fèi)心了,數(shù)學(xué)家們也不過是在十幾年前才想到了算術(shù)編碼這種神奇的方法,還是讓我們虛心地研究一下他們究竟是從哪個(gè)角度找到突破口的吧。

輸出:一個(gè)小數(shù)

更神奇的事情發(fā)生了,算術(shù)編碼對(duì)整條信息(無論信息有多么長),其輸出僅僅是一個(gè)數(shù),而且是一個(gè)介于 0 和 1 之間的二進(jìn)制小數(shù)。例如算術(shù)編碼對(duì)某條信息的輸出為 1010001111,那么它表示小數(shù) 0.1010001111,也即十進(jìn)制數(shù) 0.64。

咦?怎么一會(huì)兒是表示半個(gè)二進(jìn)制位,一會(huì)兒又是輸出一個(gè)小數(shù),算術(shù)編碼怎么這么古怪呀?不要著急,我們借助下面一個(gè)簡單的例子來闡釋算術(shù)編碼的基本原理。為了表示上的清晰,我們暫時(shí)使用十進(jìn)制表示算法中出現(xiàn)的小數(shù),這絲毫不會(huì)影響算法的可行性。

考慮某條信息中可能出現(xiàn)的字符僅有 a b c 三種,我們要壓縮保存的信息為 bccb。

在沒有開始?jí)嚎s進(jìn)程之前,假設(shè)我們對(duì) a b c 三者在信息中的出現(xiàn)概率一無所知(我們采用的是自適應(yīng)模型),沒辦法,我們暫時(shí)認(rèn)為三者的出現(xiàn)概率相等,也就是都為 1/3,我們將 0 - 1 區(qū)間按照概率的比例分配給三個(gè)字符,即 a 從 0.0000 到 0.3333,b 從 0.3333 到 0.6667,c 從 0.6667 到 1.0000。用圖形表示就是:

??????????????????? +-- 1.0000
??????????????????? |
?? Pc = 1/3??? |
??????????????????? |
??????????????????? +-- 0.6667
??????????????????? |
?? Pb = 1/3??? |
??????????????????? |
??????????????????? +-- 0.3333
??????????????????? |
?? Pa = 1/3??? |
??????????????????? |
??????????????????? +-- 0.0000現(xiàn)在我們拿到第一個(gè)字符 b,讓我們把目光投向 b 對(duì)應(yīng)的區(qū)間 0.3333 - 0.6667。這時(shí)由于多了字符 b,三個(gè)字符的概率分布變成:Pa = 1/4,Pb = 2/4,Pc = 1/4。好,讓我們按照新的概率分布比例劃分 0.3333 - 0.6667 這一區(qū)間,劃分的結(jié)果可以用圖形表示為:

+-- 0.6667 Pc = 1/4 | +-- 0.5834 | | Pb = 2/4 | | | +-- 0.4167 Pa = 1/4 | +-- 0.3333

接著我們拿到字符 c,我們現(xiàn)在要關(guān)注上一步中得到的 c 的區(qū)間 0.5834 - 0.6667。新添了 c 以后,三個(gè)字符的概率分布變成 Pa = 1/5,Pb = 2/5,Pc = 2/5。我們用這個(gè)概率分布劃分區(qū)間 0.5834 - 0.6667:

+-- 0.6667 | Pc = 2/5 | | +-- 0.6334 | Pb = 2/5 | | +-- 0.6001 Pa = 1/5 | +-- 0.5834

現(xiàn)在輸入下一個(gè)字符 c,三個(gè)字符的概率分布為:Pa = 1/6,Pb = 2/6,Pc = 3/6。我們來劃分 c 的區(qū)間 0.6334 - 0.6667:

+-- 0.6667 | | Pc = 3/6 | | | +-- 0.6501 | Pb = 2/6 | | +-- 0.6390 Pa = 1/6 | +-- 0.6334

輸入最后一個(gè)字符 b,因?yàn)槭亲詈笠粋€(gè)字符,不用再做進(jìn)一步的劃分了,上一步中得到的 b 的區(qū)間為 0.6390 - 0.6501,好,讓我們?cè)谶@個(gè)區(qū)間內(nèi)隨便選擇一個(gè)容易變成二進(jìn)制的數(shù),例如 0.64,將它變成二進(jìn)制 0.1010001111,去掉前面沒有太多意義的 0 和小數(shù)點(diǎn),我們可以輸出 1010001111,這就是信息被壓縮后的結(jié)果,我們完成了一次最簡單的算術(shù)壓縮過程。

怎么樣,不算很難吧?可如何解壓縮呢?那就更簡單了。解壓縮之前我們?nèi)匀患俣ㄈ齻€(gè)字符的概率相等,并得出上面的第一幅分布圖。解壓縮時(shí)我們面對(duì)的是二進(jìn)制流 1010001111,我們先在前面加上 0 和小數(shù)點(diǎn)把它變成小數(shù) 0.1010001111,也就是十進(jìn)制 0.64。這時(shí)我們發(fā)現(xiàn) 0.64 在分布圖中落入字符 b 的區(qū)間內(nèi),我們立即輸出字符 b,并得出三個(gè)字符新的概率分布。類似壓縮時(shí)采用的方法,我們按照新的概率分布劃分字符 b 的區(qū)間。在新的劃分中,我們發(fā)現(xiàn) 0.64 落入了字符 c 的區(qū)間,我們可以輸出字符 c。同理,我們可以繼續(xù)輸出所有的字符,完成全部解壓縮過程(注意,為了敘述方便,我們暫時(shí)回避了如何判斷解壓縮結(jié)束的問題,實(shí)際應(yīng)用中,這個(gè)問題并不難解決)。

現(xiàn)在把教程拋開,仔細(xì)回想一下,直到你理解了算術(shù)壓縮的基本原理,并產(chǎn)生了許多新的問題為止。

真的能接近極限嗎?

現(xiàn)在你一定明白了一些東西,也一定有了不少新問題,沒有關(guān)系,讓我們一個(gè)一個(gè)解決。

首先,我們?cè)磸?fù)強(qiáng)調(diào),算術(shù)壓縮可以表示小數(shù)個(gè)二進(jìn)制位,并由此可以接近無損壓縮的熵極限,怎么從上面的描述中沒有看出來呢?

算術(shù)編碼實(shí)際上采用了化零為整的思想來表示小數(shù)個(gè)二進(jìn)制位,我們確實(shí)無法精確表示單個(gè)小數(shù)位字符,但我們可以將許多字符集中起來表示,僅僅允許在最后一位有些許的誤差。

結(jié)合上面的簡單例子考慮,我們每輸入一個(gè)符號(hào),都對(duì)概率的分布表做一下調(diào)整,并將要輸出的小數(shù)限定在某個(gè)越來越小的區(qū)間范圍內(nèi)。對(duì)輸出區(qū)間的限定是問題的關(guān)鍵所在,例如,我們輸入第一個(gè)字符 b 時(shí),輸出區(qū)間被限定在 0.3333 - 0.6667 之間,我們無法決定輸出值得第一位是 3、4、5 還是 6,也就是說,b 的編碼長度小于一個(gè)十進(jìn)制位(注意我們用十進(jìn)制講解,和二進(jìn)制不完全相同),那么我們暫時(shí)不決定輸出信息的任何位,繼續(xù)輸入下面的字符。直到輸入了第三個(gè)字符 c 以后,我們的輸出區(qū)間被限定在 0.6334 - 0.6667 之間,我們終于知道輸出小數(shù)的第一位(十進(jìn)制)是 6,但仍然無法知道第二位是多少,也即前三個(gè)字符的編碼長度在 1 和 2 之間。等到我們輸入了所有字符之后,我們的輸出區(qū)間為 0.6390 - 0.6501,我們始終沒有得到關(guān)于第二位的確切信息,現(xiàn)在我們明白,輸出所有的 4 個(gè)字符,我們只需要 1 點(diǎn)幾個(gè)十進(jìn)制位,我們唯一的選擇是輸出 2 個(gè)十進(jìn)制位 0.64。這樣,我們?cè)谡`差不超過 1 個(gè)十進(jìn)制位的情況下相當(dāng)精確地輸出了所有信息,很好地接近了熵值(需要注明的是,為了更好地和下面的課程接軌,上面的例子采用的是 0 階自適應(yīng)模型,其結(jié)果和真正的熵值還有一定的差距)。

小數(shù)有多長?

你一定已經(jīng)想到,如果信息內(nèi)容特別豐富,我們要輸出的小數(shù)將會(huì)很長很長,我們?cè)撊绾卧趦?nèi)存 中表示如此長的小數(shù)呢?

其實(shí),沒有任何必要在內(nèi)存中存儲(chǔ)要輸出的整個(gè)小數(shù)。我們從上面的例子可以知道,在編碼的進(jìn)行中,我們會(huì)不斷地得到有關(guān)要輸出小數(shù)的各種信息。具體地講,當(dāng)我們將區(qū)間限定在 0.6390 - 0.6501 之間時(shí),我們已經(jīng)知道要輸出的小數(shù)第一位(十進(jìn)制)一定是 6,那么我們完全可以將 6 從內(nèi)存中拿掉,接著在區(qū)間 0.390 - 0.501 之間繼續(xù)我們的壓縮進(jìn)程。內(nèi)存中始終不會(huì)有非常長的小數(shù)存在。使用二進(jìn)制時(shí)也是一樣的,我們會(huì)隨著壓縮的進(jìn)行不斷決定下一個(gè)要輸出的二進(jìn)制位是 0 還是 1,然后輸出該位并減小內(nèi)存中小數(shù)的長度。

靜態(tài)模型如何實(shí)現(xiàn)?

我們知道上面的簡單例子采用的是自適應(yīng)模型,那么如何實(shí)現(xiàn)靜態(tài)模型呢?其實(shí)很簡單。對(duì)信息 bccb 我們統(tǒng)計(jì)出其中只有兩個(gè)字符,概率分布為 Pb = 0.5,Pc = 0.5。我們?cè)趬嚎s過程中不必再更新 此概率分布,每次對(duì)區(qū)間的劃分都依照此分布即可,對(duì)上例也就是每次都平分區(qū)間。這樣,我們的壓縮過程可以簡單表示為:

輸出區(qū)間的下限 輸出區(qū)間的上限 -------------------------------------------------- 壓縮前 0.0 1.0 輸入 b 0.0 0.5 輸入 c 0.25 0.5 輸入 c 0.375 0.5 輸入 b 0.375 0.4375

我們看出,最后的輸出區(qū)間在 0.375 - 0.4375 之間,甚至連一個(gè)十進(jìn)制位都沒有確定,也就是說,整個(gè)信息根本用不了一個(gè)十進(jìn)制位。如果我們改用二進(jìn)制來表示上述過程的話,我們會(huì)發(fā)現(xiàn)我們可以非常接近該信息的熵值(有的讀者可能已經(jīng)算出來了,該信息的熵值為 4 個(gè)二進(jìn)制位)。

為什么用自適應(yīng)模型?

既然我們使用靜態(tài)模型可以很好地接近熵值,為什么還要采用自適應(yīng)模型呢?

要知道,靜態(tài)模型無法適應(yīng)信息的多樣性,例如,我們上面得出的概率分布沒法在所有待壓縮信息上使用,為了能正確解壓縮,我們必須再消耗一定的空間保存靜態(tài)模型統(tǒng)計(jì)出的概率分布,保存模型所用的空間將使我們重新遠(yuǎn)離熵值。其次,靜態(tài)模型需要在壓縮前對(duì)信息內(nèi)字符的分布進(jìn)行統(tǒng)計(jì),這一統(tǒng)計(jì)過程將消耗大量的時(shí)間,使得本來就比較慢的算術(shù)編碼壓縮更加緩慢。

另外還有最重要的一點(diǎn),對(duì)較長的信息,靜態(tài)模型統(tǒng)計(jì)出的符號(hào)概率是該符號(hào)在整個(gè)信息中的出現(xiàn)概率,而自適應(yīng)模型可以統(tǒng)計(jì)出某個(gè)符號(hào)在某一局部的出現(xiàn)概率或某個(gè)符號(hào)相對(duì)于某一上下文的出現(xiàn)概率,換句話說,自適應(yīng)模型得到的概率分布將有利于對(duì)信息的壓縮(可以說結(jié)合上下文的自適應(yīng)模型的信息熵建立在更高的概率層次上,其總熵值更小),好的基于上下文的自適應(yīng)模型得到的壓縮結(jié)果將遠(yuǎn)遠(yuǎn)超過靜態(tài)模型。

自適應(yīng)模型的階

我們通常用“階”(order)這一術(shù)語區(qū)分不同的自適應(yīng)模型。本章開頭的例子中采用的是 0 階自適應(yīng)模型,也就是說,該例子中統(tǒng)計(jì)的是符號(hào)在已輸入信息中的出現(xiàn)概率,沒有考慮任何上下文信息。

如果我們將模型變成統(tǒng)計(jì)符號(hào)在某個(gè)特定符號(hào)后的出現(xiàn)概率,那么,模型就成為了 1 階上下文自適應(yīng)模型。舉例來說,我們要對(duì)一篇英文文本進(jìn)行編碼,我們已經(jīng)編碼了 10000 個(gè)英文字符,剛剛編碼的字符是 t,下一個(gè)要編碼的字符是 h。我們?cè)谇懊娴木幋a過程中已經(jīng)統(tǒng)計(jì)出前 10000 個(gè)字符中出現(xiàn)了 113 次字母 t,其中有 47 個(gè) t 后面跟著字母 h。我們得出字符 h 在字符 t 后的出現(xiàn)頻率是 47/113,我們使用這一頻率對(duì)字符 h 進(jìn)行編碼,需要 -log2 (47/113) = 1.266 位。

對(duì)比 0 階自適應(yīng)模型,如果前 10000 個(gè)字符中 h 的出現(xiàn)次數(shù)為 82 次,則字符 h 的概率是 82/10000,我們用此概率對(duì) h 進(jìn)行編碼,需要 -log2 (82/10000) = 6.930 位??紤]上下文因素的優(yōu)勢顯而易見。

我們還可以進(jìn)一步擴(kuò)大這一優(yōu)勢,例如要編碼字符 h 的前兩個(gè)字符是 gt,而在已經(jīng)編碼的文本中 gt 后面出現(xiàn) h 的概率是 80%,那么我們只需要 0.322 位就可以編碼輸出字符 h。此時(shí),我們使用的模型叫做 2 階上下文自適應(yīng)模型。

最理想的情況是采用 3 階自適應(yīng)模型。此時(shí),如果結(jié)合算術(shù)編碼,對(duì)信息的壓縮效果將達(dá)到驚人的程度。采用更高階的模型需要消耗的系統(tǒng) 空間和時(shí)間至少在目前還無法讓人接受,使用算術(shù)壓縮的應(yīng)用程序 大多數(shù)采用 2 階或 3 階的自適應(yīng)模型。

轉(zhuǎn)義碼的作用

使用自適應(yīng)模型的算術(shù)編碼算法必須考慮如何為從未出現(xiàn)過的上下文編碼。例如,在 1 階上下文模型中,需要統(tǒng)計(jì)出現(xiàn)概率的上下文可能有 256 * 256 = 65536 種,因?yàn)?0 - 255 的所有字符都有可能出現(xiàn)在 0 - 255 個(gè)字符中任何一個(gè)之后。當(dāng)我們面對(duì)一個(gè)從未出現(xiàn)過的上下文時(shí)(比如剛編碼過字符 b,要編碼字符 d,而在此之前,d 從未出現(xiàn)在 b 的后面),該怎樣確定字符的概率呢?

比較簡單的辦法是在壓縮開始之前,為所有可能的上下文分配計(jì)數(shù)為 1 的出現(xiàn)次數(shù),如果在壓縮中碰到從未出現(xiàn)的 bd 組合,我們認(rèn)為 d 出現(xiàn)在 b 之后的次數(shù)為 1,并可由此得到概率進(jìn)行正確的編碼。使用這種方法的問題是,在壓縮開始之前,在某上下文中的字符已經(jīng)具有了一個(gè)比較小的頻率。例如對(duì) 1 階上下文模型,壓縮前,任意字符的頻率都被人為地設(shè)定為 1/65536,按照這個(gè)頻率,壓縮開始時(shí)每個(gè)字符要用 16 位編碼,只有隨著壓縮的進(jìn)行,出現(xiàn)較頻繁的字符在頻率分布圖上占據(jù)了較大的空間后,壓縮效果才會(huì)逐漸好起來。對(duì)于 2 階或 3 階上下文模型,情況就更糟糕,我們要為幾乎從不出現(xiàn)的大多數(shù)上下文浪費(fèi)大量的空間。

我們通過引入“轉(zhuǎn)義碼”來解決這一問題。“轉(zhuǎn)義碼”是混在壓縮數(shù)據(jù)流中的特殊的記號(hào),用于通知解壓縮程序下一個(gè)上下文在此之前從未出現(xiàn)過,需要使用低階的上下文進(jìn)行編碼。

舉例來講,在 3 階上下文模型中,我們剛編碼過 ght,下一個(gè)要編碼的字符是 a,而在此之前,ght 后面從未出現(xiàn)過字符 a,這時(shí),壓縮程序輸出轉(zhuǎn)義碼,然后檢查 2 階的上下文表,看在此之前 ht 后面出現(xiàn) a 的次數(shù);如果 ht 后面曾經(jīng)出現(xiàn)過 a,那么就使用 2 階上下文表中的概率為 a 編碼,否則再輸出轉(zhuǎn)義碼,檢查 1 階上下文表;如果仍未能查到,則輸出轉(zhuǎn)義碼,轉(zhuǎn)入最低的 0 階上下文表,看以前是否出現(xiàn)過字符 a;如果以前根本沒有出現(xiàn)過 a,那么我們轉(zhuǎn)到一個(gè)特殊的“轉(zhuǎn)義”上下文表,該表內(nèi)包含 0 - 255 所有符號(hào),每個(gè)符號(hào)的計(jì)數(shù)都為 1,并且永遠(yuǎn)不會(huì)被更新,任何在高階上下文中沒有出現(xiàn)的符號(hào)都可以退到這里按照 1/256 的頻率進(jìn)行編碼。

“轉(zhuǎn)義碼”的引入使我們擺脫了從未出現(xiàn)過的上下文的困擾,可以使模型根據(jù)輸入數(shù)據(jù)的變化快速 調(diào)整到最佳位置,并迅速減少對(duì)高概率符號(hào)編碼所需要的位數(shù)。

存儲(chǔ)空間問題

在算術(shù)編碼高階上下文模型的實(shí)現(xiàn)中,對(duì)內(nèi)存的需求量是一個(gè)十分棘手的問題。因?yàn)槲覀儽仨毐3謱?duì)已出現(xiàn)的上下文的計(jì)數(shù),而高階上下文模型中可能出現(xiàn)的上下文種類又是如此之多,數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)將直接影響到算法實(shí)現(xiàn)的成功與否。

在 1 階上下文模型中,使用數(shù)組來進(jìn)行出現(xiàn)次數(shù)的統(tǒng)計(jì)是可行的,但對(duì)于 2 階或 3 階上下文模型,數(shù)組大小將依照指數(shù)規(guī)律增長,現(xiàn)有計(jì)算機(jī)的內(nèi)存滿足不了我們的要求。

比較聰明的辦法是采用樹結(jié)構(gòu)存儲(chǔ)所有出現(xiàn)過的上下文。利用高階上下文總是建立在低階上下文的基礎(chǔ)上這一規(guī)律,我們將 0 階上下文表存儲(chǔ)在數(shù)組中,每個(gè)數(shù)組元素包含了指向相應(yīng)的 1 階上下文表的指針,1 階上下文表中又包含了指向 2 階上下文表的指針……由此構(gòu)成整個(gè)上下文樹。樹中只有出現(xiàn)過的上下文才擁有已分配的節(jié)點(diǎn),沒有出現(xiàn)過的上下文不必占用內(nèi)存空間。在每個(gè)上下文表中,也無需保存所有 256 個(gè)字符的計(jì)數(shù),只有在該上下文后面出現(xiàn)過的字符才擁有計(jì)數(shù)值。由此,我們可以最大限度地減少空間消耗。

資源

關(guān)于算術(shù)壓縮具體的設(shè)計(jì)和實(shí)現(xiàn)請(qǐng)參考下面給出的示例程序。

程序 Arith-N 由 League for Programming Freedom 的 Mark Nelson 提供,由王笨笨在 Visual C++ 5.0 環(huán)境下編譯、調(diào)試 通過。

Arith-N 包含 Visual C++ 工程 ArithN.dsp 和 ArithNExpand.dsp,分別對(duì)應(yīng)了壓縮和解壓縮程序 an.exe 與 ane.exe。

Arith-N 是可以在命令行指定階數(shù)的 N 階上下文自適應(yīng)算術(shù)編碼通用壓縮、解壓縮程序,由于是用作教程示例,為清晰起見,在某些地方并沒有刻意進(jìn)行效率 上的優(yōu)化 。

所有源程序包裝在文件 .NET /wangyg/tech/benben/src/Arith-N.zip">Arith-N.zip 中。

?

本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/pyramide/archive/2010/01/12/5172334.aspx

總結(jié)

以上是生活随笔為你收集整理的向极限挑战:算术编码 (转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。