Zalety o prosty o szybki Wady o nieefektywny, gdy
Transkrypt
Zalety o prosty o szybki Wady o nieefektywny, gdy
Zalety o prosty o szybki Wady o nieefektywny, gdy prawdopodobieństwo wystąpienia jednego z symboli alfabetu źródła jest duże (ale można kodować ciągi symboli) o dwuprzebiegowy (koszt transmisji modelu może być duży, nie do zastosowania wprost do kodowania on-line) Użycie algorytmu Huffmana w adaptacyjnym modelu jest możliwe Metoda brute-force – każdorazowo po zakodowniu symbolu buduj od nowa drzewo Huffmana ( Uwaga na Zero Frequency Problem ) ... ale w praktyce zbyt kosztowne Ale mamy algorytm generujący kod zbliżony do kodu Huffmana, nadający się do zastosowania w algorytmie adaptacyjnym. Drzewo Huffmana budowane jest przyrostowo – możliwa jest „aktualizacja modelu” •został wynaleziony niezależnie przez Fallera i Gallagera • udoskonalony przez Cormacka i Horspoola oraz (niezależnie) przez Knutha • następnie udoskonalony przez Vittera Na czym polega? Budujemy przyrostowo drzewo binarne, którego węzły zawierają liczniki częstości, a liście są dodatkowo skojarzone z symbolami alfabetu źródła Drzewo ma własność rodzeństwa, gdy: 1. każdy węzeł nie będący liściem ma 2 potomków; 2. przechodząc węzły w kolejności z góry do dołu, a na danym poziomie od prawej do lewej, otrzymamy ciąg węzłów o nierosnących licznikach. Drzewo mające własność rodzeństwa jest drzewem Huffmana (tw. FalleraGallagera) Przykład: drzewo mające własność rodzeństwa 11 6 5 a 2 4 r 2 2 b 1 1 c d Budowane drzewo zawiera liść (0-węzeł) reprezentujący wszystkie symbole, które jeszcze nie wystąpiły w kodowanym ciągu Kodowanie rozpoczynamy od drzewa składającego się wyłącznie z 0- węzła Używamy pomocniczej struktury węzły, listy dwukierunkowej zawierającej węzły drzewa uporządkowane w kolejności przeglądania drzewa z góry do dołu, a na danym poziomie od prawej do lewej Podlistę listy węzły składającą się z wszystkich węzłów o wartości licznika i nazywamy blokiem-i , a pierwszy węzeł takiego bloku liderem DynamiczneKodowanieHuffmanaFGK(symbol s) p = liść zawierający symbol s; wyprowadź słowo kodowe dla s (*); if p jest 0-węzłem utwórz nowy węzeł q dla symolu s; q.licznik = 1; p = nowy węzeł w miejscu 0-węzła będący rodzicem 0-węzła i węzła q; p.licznik = 1; else p.licznik++; endif while p nie jest korzeniem if p narusza własność rodzeństwa if lider bloku-i zawierającego p nie jest rodzicem p zamień p z liderem; endif endif p = rodzic(p); p.licznik++; endwhile a p r b 0 1 1 2 p 0 1 1 q 1 1 a 1 a 0 1 q b Przykład: kodujemy ciąg abrr, wstawienie symbolu b a 0 1 b r 2 2 2 p 1 a 0 2 1 2 1 1 a p 1 a 1 1 b 1 1 b 0 1 b 0 r wstawienie symbolu r (przywróć własność rodzeństwa) 1 r r 2 3 2 p p 2 1 1 a a 1 1 1 r wstawienie symbolu r 2 a 1 1 1 1 b 0 1 2 b b 0 1 r 0 1 r r 3 1 3 1 2 a 3 a 1 1 b 1 r 2 a 1 1 0 1 2 1 1 b 0 2 p r b 0 2 p r ponowne wstawienie symbolu r (przywróć własność rodzeństwa) 3 4 p 1 2 2 a 2 r 1 1 1 1 b 0 2 p r b 0 1 a ponowne wstawienie symbolu r (przywróć własność rodzeństwa) 4 2 2 r 1 1 b 0 1 a postać drzewa po przetworzeniu ciągu abrr Dodatkowe założenie: w bloku-i węzłów najpierw znajdują się węzły wewnętrzne, później liście minimalizujemy głębokość drzewa bardziej złożone staje się przywracanie własności rodzeństwa ciąg o długości s zakodujemy na nie więcej niż h+s bitach, gdzie h to liczba bitów dla kodowania statycznego Huffmana Algorytm adaptacyjny można zbudować z kilku stałych modeli Ale po kolei ... ◦ ◦ ◦ ◦ Zmodyfikowane kody binarne Rodzina kodów Golomba Rodzina kodów Golomba-Rice’a Model danych dla parametrycznej rodziny kodów (model algorytmu FELICS) Prefiksowy kod dla skończonego alfabetu, np. dla liczb 0 .. j-1 ◦ słowa kodowe o długości log(j) lub log (j) bitów, gdzie j to rozmiar alfabetu ◦ właściwie to rodzina kodów Symbol (długość słowa kodowego kodu binarnego dla alfabetu j symboli to log(j) ) Alfabet 0 .. 4 0 .. 5 0 .. 6 0 .. 7 0 .00 .00 .00 .000 1 .01 .01 .010 .001 2 .10 .100 .011 .010 3 .110 .101 .100 .011 4 .111 .110 .101 .100 .111 .110 .101 .111 .110 5 6 7 .111 Generowanie słowa kodowego kodujemy liczbę i zmodyfikowanym kodem binarnym dla liczb 0 .. j – 1, przyjmijmy N = log(j) i n = 2 N jeżeli i < n – j zakoduj i za pomocą N – 1 -bitowego kodu binarnego else zakoduj i + n – j za pomocą N -bitowego kodu binarnego Własności zmodyfikowanego kodu binarnego ◦ długość słowa kodowego: log(j) lub log (j) ◦ dla j = 2 N kod staje się N -bitowym kodem binarnym ◦ liczba dłuższych słów kodowych jest zawsze parzysta ◦ parametryczna rodzina kodów przeznaczona do kodowania nieujemnych liczb całkowitych nieskończona parametrem kodu jest całkowite m, m > 0 ◦ zawiera kody optymalne dla wykładniczego rozkładu prawdopodobieństwa symboli (dla niektórych parametrów rozkładu) (nadaje się do źródeł o rozkładzie nierosnącym) ◦ słowa kodowe łatwe w generacji i dekodowaniu Generowanie słowa kodowego kodujemy liczbę x kodem Golomba z parametrem m prefiks słowa: x/ m zakodowane unarnie (kod α Eliasa) sufiks słowa: x mod m zakodowane zmodyfikowanym kodem binarnym dla przedziału [0, m – 1] np. 8 kodem Golomba z parametrem 3 8/3 = 2 110 8 mod 3 = 2 11 Jest to szczególny przypadek kodu Golomba zauważony już przez Golomba i niezależnie od niego odkryty przez Rice’a. Kody Golomba są szczególnie proste, gdy m = 2 k kodujemy liczbę x kodem Golomba-Rice’a z parametrem k prefiks słowa: x/ 2 k sufiks słowa: x mod 2 k zakodowane unarnie (kod α Eliasa) x >> k zakodowane zmodyfikowanym kodem binarnym dla przedziału [0, m – 1] k najmniej znaczących bitów x Dla skończonego alfabetu używamy tylko części nieskończonej rodziny. Przyjmijmy rozmiar alfabetu 2 N • dla rodziny Golomba kody o m > 2 N-1 mają słowa kodowe wszystkich symboli alfabetu dłuższe od kodu o m = 2 N-1 • dla kodów GolombaRice’a kody o k > N – 1 mają słowa wszystkich symboli alfabetu dłuższe od kodu o k = N – 1 • sensowne jest używanie początkowych 2 N-1 kodów • sensowne jest używanie początkowych N kodów (k = 0 .. N – 1 ) Rodziny Golomba-Rice’a można użyć do kodowania ciągów symboli o wykładniczym rozkładzie prawdopodobieństwa. (rozkład często spotykany w kompresji obrazów, dźwięków ... ) Jeżeli parametr rozkładu jest nieznany, lub zmienia się w trakcie pracy źródła to parametr kodu Golomba-Rice’a trzeba dobierać adaptacyjnie. Jak to zrobić? Wybierajmy ten kod, który jest najlepszy dla już przetworzonych symboli Jak to zrobić? Algorytm modelowania zastosowany przez Howarda i Vittera w algorytmie bezstratnej kompresji obrazów FELICS. Idea Dla każdego kodu z rodziny utrzymuj licznik (tablica liczników) ◦ licznik liczby bitów, którą by uzyskano, kodując dotychczas przetworzoną część ciągu tym kodem. Po zakodowaniu symbolu zwiększ licznik każdego z kodów o długość słowa kodowego właśnie zakodowanego symbolu w kodzie odpowiadającym licznikowi Do kodowania symbolu użyj kodu o najmniejszym liczniku ◦ Udoskonalenie: okresowo, gdy wartość najmniejszego z liczników przekroczy pewien próg, podziel wszystkie liczniki przez 2 unikniemy przepełnienia zwiększymy znaczenie symboli kodowanych niedawno ◦ Ww. metoda to tylko część całego algorytmu (i tylko część modelu) ◦ Metoda z FELICS nadaje się do każdej rodziny ◦ Jeszcze prostsza metoda istnieje dla rodziny Golomba-Rice’a zastosowana przez Weinberger, Seroussi, Sapiro w algorytmie LOCO(JPEG-LS) niezależnie od rozmiaru alfabetu mamy 2 liczniki (licznik zakodowanych symboli i licznik sumy wartości tych symboli) Warto się zapoznać Idea kodowania arytmetycznego Koncepcja implementacji dla liczb o ograniczonej precyzji Wybrane algorytmy ◦ MQ-Coder ◦ Range-Coder ◦ Szybki model dla kodera arytmetycznego