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. Fallera- Gallagera)
Przykład: drzewo mające własność rodzeństwa
r 2
d 1 c
1 a
5
b
2 2
4 6
11
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
Przykład: kodujemy ciąg abrr, wstawienie symbolu b 0
a
1
a 1 0
b
1
a 1 1
b 1 0
2
a 1 1
b 1 0
p
p
q
q
r
wstawienie symbolu r (przywróć własność rodzeństwa) r
2
a 1 1
b 1
0 1
r 1 0
p
2
a 1 2
b
1 1
r 1 0
p
2
a 1 2
b 1
wstawienie symbolu r 1
r 1 0
p
2
a 1 2
b 1
2
a 1
1
r 1 0
2
b 1
p
3
a 1
1
r 1 0
2
b 1 r
3
a 1
1
r 1 0
2
b 1 r
3
a 1
1
r 2 0
2
b 1
p
3
a 1
1
r 2 0
2
b 1
p
ponowne wstawienie symbolu r (przywróć własność rodzeństwa)
3
a 1
1
r 2 0
2
b 1
p
4
r 2
1
a 1 0
2
b 1 p
ponowne wstawienie symbolu r (przywróć własność rodzeństwa)
4
r 2
1
a 1 0
2
b 1
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 Alfabet
0 .. 4 0 .. 5 0 .. 6 0 .. 7
0 . 0 0 . 0 0 . 0 0 . 0 0 0
1 . 0 1 . 0 1 . 0 1 0 . 0 0 1
2 . 1 0 . 1 0 0 . 0 1 1 . 0 1 0
3 . 1 1 0 . 1 0 1 . 1 0 0 . 0 1 1
4 . 1 1 1 . 1 1 0 . 1 0 1 . 1 0 0
5 . 1 1 1 . 1 1 0 . 1 0 1
6 . 1 1 1 . 1 1 0
7 . 1 1 1
(długość słowa kodowego kodu binarnego dla alfabetu j symboli to log(j) )
◦ 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 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
◦ 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/ 2k zakodowane unarnie (kod α Eliasa) x >> k
sufiks słowa: x mod 2k 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 2N
• dla rodziny Golomba kody o m > 2N-1 mają słowa kodowe
wszystkich symboli alfabetu dłuższe od kodu o m = 2 N-1
• sensowne jest używanie początkowych 2 N-1
kodów
• dla kodów Golomba- Rice’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 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.
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 Idea
◦ 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)
Idea kodowania arytmetycznego
Koncepcja implementacji dla liczb o ograniczonej precyzji
Wybrane algorytmy
◦ MQ-Coder
◦ Range-Coder
◦ Szybki model dla kodera arytmetycznego
Warto się zapoznać