Podstawy kompresji danych
Pojęcie kompresji W ogólności kompresja (kodowanie) jest procedurą (przekształceniem) zmiany reprezentacji wejściowego zbioru danych do postaci wymagającej mniejszej liczby bitów w porównaniu do reprezentacji oryginalnej. Procedura odwrotna do kompresji (dekompresja, dekodowanie) przekształca nową reprezentację zbioru danych do reprezentacji oryginalnej lub rekonstruuje oryginalny zbiór danych. Układ realizujący proces kompresji i dekompresji (rekonstrukcji) nazywany jest kodekiem (codec=compression/decompression). W zależności od ograniczeń nałożonych na rekonstrukcję, algorytmy kompresji można podzielić na dwie podstawowe grupy. Niech X, X C oraz Y oznaczają odpowiednio ciąg wejściowy, ciąg skompresowany oraz ciąg uzyskany po wykonaniu algorytmu rekonstrukcji (dekompresji): Kompresja Dekompresja Kompresja bezstratna (lossless) Kompresja stratna (lossy) Dane po rekonstrukcji są numerycznie identyczne z danymi na wejściu algorytmu. Utrata informacji jest niedopuszczalna. Przykład: kompresja tekstu, obrazów medycznych, numerycznych baz danych, etc. Dopuszczalna jest utrata informacji (nieodwracalna); zrekonstruowane dane stanowią przybliżenie oryginalnego zbioru danych. Dopuszczalny poziom utraty informacji jest zależny od konkretnego zastosowania. Przykład: kompresja wideo, obrazów, mowy, dźwięku, etc.
Sposoby oceny jakości algorytmów kompresji Do podstawowych metryk ilościowej oceny efektywności algorytmów kompresji należą stopień kompresji oraz średnia bitowa. Stopień kompresji (compression ratio) - stosunek liczby bitów potrzebnych do reprezentacji danych przed kompresją do liczby bitów potrzebnych do reprezentacji danych po kompresji. Średnia bitowa (bit-rate) średnia liczba bitów konieczna do reprezentacji pojedynczej próbki danych (np. piksel w przypadku obrazów) w strumieniu skompresowanym. Wartości powyższych metryk są zależne od konkretnej postaci danych wejściowych. Algorytm kompresji może posiadać skrajnie różne wartości stopnia kompresji lub średniej bitowej dla dwóch różnych zbiorów danych wejściowych. W przypadku technik kompresji stratnej definiuje się też metryki oceny jakości obrazu po rekonstrukcji. Można wyróżnić metryki subiektywne oraz obiektywne (liczbowe): Subiektywne metryki oceny najczęściej definiowane są jako średnia ocena obserwatorów MOS (mean observers score): średnia z ocen słownych lub ocen na określonej skali. Metryki liczbowe: błąd MSE, RMSE, SNR, PSNR. Metryki liczbowe nie zawsze dają rezultaty zgodne z oceną subiektywną. Stanowi to wadę metryk liczbowych. Do innych parametrów określających jakość/efektywność algorytmów kompresji należą: Opóźnienie kodowania zdefiniowane jako opóźnienie wprowadzane przez algorytm kompresji. Małe wartości opóźnienia są szczególnie ważne w zastosowaniach czasu rzeczywistego (komunikacja głosowa on-line, przeglądanie on-line, interaktywne wideokonferencje, etc.) Złożoność obliczeniowa/złożoność kodowania.
Model procesu kompresji W procesie kompresji bezstratnej wyróżnić można dwa podstawowe etapy: etap modelowania oraz kodowania. Celem etapu modelowania jest stworzenie skutecznego modelu zbioru danych wejściowych, tak by zapewnić efektywniejszy sposób reprezentowania zbioru danych (usunąć nadmiarowość), a co za tym idzie zapewnić większy stopień kompresji. Do najczęściej wykorzystywanych modeli należą: modele statystyczne (tablica prawdopodobieństw wystąpienia poszczególnych symboli w zbiorze danych wejściowych), modele predykcyjne (przewidywanie wartości następnej próbki na podstawie wartości próbek poprzednich w zbiorze danych), tworzenie słownika (metody słownikowe). Cechą dobrego modelu stworzonego na tym etapie jest usunięcie ze zbioru danych wszelkiego rodzaju nadmiarowości, własności strukturalnych, zależności pomiędzy (niekoniecznie) sąsiednimi próbkami danych. Na tym etapie często wykonywana jest transformacja wejściowego zbioru danych do nowej postaci zgodnie z przyjętym modelem. W przypadku danych obrazowych przekształcenie może polegać na: transformacji do nowej przestrzeni barw w której składowe wektora koloru są mniej skorelowane (do przestrzeni HSV, YCbCR, etc.), reprezentowaniu ciągu wejściowego przez ciąg różnic (metody predykcyjne), wykonaniu przekształceń falkowych, wykonaniu transformacji DCT, etc. Etap kodowania polega na jednoznacznym przypisaniu binarnych słów kodowych poszczególnym symbolom w zbiorze danych wejściowych lub grupom takich symboli. Słowa kodowe stanowią binarną reprezentację symboli lub grup symboli. wejściowy strumień danych Modelowanie zbioru danych / Redukcja nadmiarowości pośrednia reprezentacja danych lub model Usunięcie informacji nieistotnych / Redukcja entropii Kodowanie symboli lub ich grup strumień wyjściowy Rys.. Schemat metod kompresji stratnej i bezstratnej. Funkcjonalność w bloku oznaczonym przerywaną linią jest charakterystyczna dla metod kompresji stratnej. Na takim etapie zachodzi nieodwracalna utrata informacji realizowana najczęściej jako pewien rodzaj kwantyzacji. Pojęcie informacji nieistotnych (kryterium) jest zależne od konkretnego zastosowania.
Proste przykłady modelowania danych - a 2 2 2 23 28 25 26 26 28 28 3 3 3 33 33 33 38 38 38 39 4 b 4 2 2 4 35 3 25 c 5 5 2 Przykład : Na rysunku (a) przedstawiony jest ciąg wejściowy zawierający 2 liczb. Niech ciąg ten stanowi wejściowy zbiór danych. Faza modelowania polega na znajdowaniu własności strukturalnych w zbiorze wejściowym. W tym przypadku okazuje się, że kolejne liczby ciągu układają się wzdłuż prostej o równaniu y(n)=n+2, dla n=,2, 2. Własność tę przedstawia rysunek (c). W tym przypadku zbiór danych wejściowych może być modelowany przez wcześniej podaną zależność funkcyjną, a kodowaniu mogą podlegać jedynie różnice pomiędzy wartością funkcji (znaleziony model) a rzeczywistą wartością odpowiadającego elementu ciągu. Ciąg takich różnic przedstawiony jest na rysunku (b). W tym przypadku oryginalny ciąg zawiera 2 unikalnych symboli, co odpowiada 4 bitom koniecznym do reprezentacji pojedynczego symbolu (razem 84 bity). Ciąg różnic zawiera jedynie 6 unikalnych wartości i wymaga 3 bitów na symbol (razem 63 bity). Pomijając konieczność przesłania informacji o przyjętym modelu oznacza to stopień kompresji 84/63.33. a 2 2 2 23 28 25 26 26 28 28 3 3 3 33 33 33 38 38 38 39 4 b 2 2 5 3 2 2 2 5 Przykład 2: Kompresję ciągu przedstawionego w przykładzie można uzyskać również przez przesyłanie ciągu różnic pomiędzy próbką następną i poprzednią. Pozostawiając pierwszy element ciągu bez zmian otrzymujemy ciąg różnić przedstawiony na rysunku (b). Tak jak w poprzednim przypadku ciąg ten zawiera 6 różnych wartości w stosunku do 2 w ciągu oryginalnym. Przedstawiona w tym przykładzie idea jest podstawą kodowania różnicowego. Przedstawiona idea jest podstawą kodowania predykcyjnego.
Proste przykłady modelowania danych - 2 a b d 5 4 3 2 5 5 2 c e 8 6 4 2-5 5 e Przykład 3: Przykład transformacji zbioru danych obrazowych do reprezentacji pozwalającej zwiększyć stopień kompresji. Na rysunku (a) przedstawiony jest obraz oryginalny. Obraz można podzielić na dwuelementowe bloki, przy czym każdy blok zawiera parę sąsiednich pikseli w obrazie (sąsiadów w wierszu). Tak powstałe bloki można interpretować jako punkty dwuwymiarowej przestrzeni, gdzie pierwszą składową punktu jest wartość pierwszego piksela pary, natomiast drugą składową punktu jest wartość drugiego piksela pary. Wykres takich punktów powstałych przez podział obrazu (a) przedstawiony jest na rysunku (b). Przykładowa transformacja obrazu, której celem jest redukcja nadmiarowości danych może polegać na wykonaniu obrotu każdego punktu w przestrzeni wartości par pikseli o kąt - /4 wokół osi z (w płaszczyźnie ekranu). Wynik takiej transformacji jest przedstawiony na rysunku (c). Punkty po transformacji charakteryzują się mniejszym zakresem zmian drugiej składowej (mniejszą dynamiką, wariancją): w tym przypadku wartości drugiej składowej zmieniają się w zakresie [-5,5] w stosunku do zakresu [,255] dla zbioru danych przed transformacją. Histogram wartości drugiej składowej punktów przed i po transformacji obrotu przedstawiają odpowiednio rysunki (d) oraz (e). Widoczna jest istotna zmiana rozkładu prawdopodobieństwa wartości drugiej składowej! Wykorzystując zmniejszony zakres zmienności drugiej składowej można reprezentować ją na mniejszej liczbie bitów niż pierwszą składową uzyskując w ten sposób kompresję zbioru danych. Rysunek (e) przedstawia przykład bardziej radykalnego podejścia polegającego na wyzerowaniu drugiej składowej każdego punktu (kompresja stratna) po wykonaniu obrotu. Opisana tu transformacja należy do tej samej klasy przekształceń co dyskretna transformacja kosinusowa DCT.
Modele probabilistyczne źródeł danych p(a) p(b) Entropia..9.47.2.8.72.3.7.88.4.6.97.5.5..6.4.97.7.3.88 Rys.. Prawdopodobieństwa i odpowiadająca entropia w zbiorze dwóch symboli {a,b}. Prosty przykład pokazuje, że graniczną wartością entropii jest wartość Log[2,n], gdzie n jest liczbą elementów w zbiorze. Wartość tę entropia osiąga w przypadku, gdy wszystkie symbole mają identyczne prawdopodobieństwa wystąpienia. Podstawowym pojęciem formalnego opisu metod kodowania i kompresji bezstratnej jest pojęcie źródła danych zdefiniowanego jako abstrakcyjny obiekt emitujący analizowany strumień danych. Każde źródło danych można scharakteryzować poprzez zdefiniowanie alfabetu (zbioru symboli podstawowych generowanych przez źródło), prawdopodobieństw wystąpienia poszczególnych symboli oraz entropii. Każdemu symbolowi alfabetu przyporządkować można informację własną (autoinformację, self-information) zdefiniowaną równaniem: Z punktu widzenia binarnego kodowania informacji, informacja własna określa liczbę bitów na jakich można reprezentować konkretny symbol alfabetu. Informacja własna jest wielkością przyporządkowaną konkretnym symbolom alfabetu. Wielkość tę można uśrednić na cały alfabet uzyskując średnią informację własną przypadającą na jeden symbol alfabetu, czyli entropię: Entropia jest miarą określającą średnią liczbę bitów koniecznych do reprezentacji pojedynczego symbolu alfabetu źródła, stanowi więc globalną charakterystykę źródła, w odróżnieniu od informacji własnej charakteryzującej konkretny symbol.
Modele probabilistyczne źródeł danych Przykład. Rozpatrzmy strumień wygenerowany przez pewne źródło. Niech strumień ma postać: a c b b a c b b a c b b b b b b b b a c W pierwszym przypadku przyjmijmy, że źródło generuje symbole z alfabetu S={a,b,c} niezależnie. Prawdopodobieństwo wystąpienia poszczególnych symboli można oszacować następująco: p(a)=p(c)=.2, p(b)=.6. W takim przypadku entropia źródła wynosi: H(S)=.37 bita. Innym modelem źródła może być źródło generujące pary symboli. W tym przypadku wyróżnić można jedynie dwie unikalne pary: (a,c) oraz (b,b). Pary takie można potraktować jako symbole zredukowanego alfabetu S ={(a,c),(b,b)}, w którym symbole występują z prawdopodobieństwem równym odpowiednio:.4 oraz.6. Entropia takiego źródła jest równa H(S )=.97 bita. Wyraźnie mniejsza niż w przypadku pierwszego modelu. Najprostszym modelem probabilistycznym źródła danych jest model niewiedzy zakładający niezależne generowanie symboli alfabetu z jednakowym prawdopodobieństwem. Uogólnieniem powyższego modelu jest często stosowany model zakładający niezależne generowanie symboli alfabetu z różnymi prawdopodobieństwami. Prawdopodobieństwo wystąpienia poszczególnych symboli można szacować na podstawie analizy częstościowej strumienia wygenerowanego przez źródło. Nie zawsze założenie o niezależności generowania symboli jest poprawne. W takich sytuacjach konieczne jest stworzenie modelu wzajemnych zależności pomiędzy elementami ciągu danych. W najprostszym przypadku mogą to być prawdopodobieństwa warunkowe pierwszego rzędu. W innych sytuacjach konstruuje się bardziej złożony kontekst determinujący pojawienie się symboli alfabetu. Stosując modele probabilistyczne źródeł tworzyć można bardzo efektywne sposoby kodowania źródeł danych: kodowanie Huffmana, arytmetyczne. Szacowana wartość entropii, a co za tym idzie średnia minimalna liczba bitów wymaganych do reprezentacji jednego symbolu źródła zmienia się w zależności od przyjętego modelu.
Modele probabilistyczne. Przykład a b Litera Kod Litera Kod A N B O C P D Q E R F S G T H U I V J W K X L Y M Z Rys.. Tworzenie modelu probabilistycznego w najprostszym przypadku polega na określeniu częstości (prawdopodobieństw) wystąpień poszczególnych symboli w ciągu wejściowym. Wiedza na temat prawdopodobieństw wystąpień poszczególnych symboli pozwala reprezentować symbole bardziej prawdopodobne przez krótsze słowa kodowe w stosunku do słów kodowych dla symboli mniej prawdopodobnych. Podejście takie jest podstawą metod entropijnych kodowania strumienia danych, np. bardzo popularnej metody Huffmana. Rysunek (a) przedstawia tablicę częstości wystąpień liter w tekście w języku angielskim. Rysunek (b) przedstawia alfabet Morse a w którym długość sekwencji kodowej zależy od częstości wystąpienia konkretnego symbolu (litery).
Modele probabilistyczne. Przykład. a b c d e f Rys.. Rysunki przedstawiają przykładowe ciągi znaków wygenerowane przez źródła o założonych różnych modelach probabilistyczny. We wszystkich przykładach źródło generuje symbole będące literami alfabetu łacińskiego plus spacja. Rysunki przedstawiają kolejno ciągi wygenerowane przez źródło generujące : (a) symbole niezależnie i z identycznymi prawdopodobieństwami (model niewiedzy); (b) symbole z prawdopodobieństwami ich wystąpienia w języku angielskim; (c) pary liter (digramy) z prawdopodobieństwami ich wystąpień w języku angielskim; (d) trójki liter z prawdopodobieństwami ich wystąpień w języku angielskim. Rysunki (e) i (f) przedstawiają przykładowe ciągi przy założeniu, że źródła generują wyrazy oraz pary wyrazów z prawdopodobieństwami ich występowania w języku angielskim. Przykłady pochodzą z oryginalnej pracy Shannona, 948.
Kodowanie źródeł danych - a b c Symbol Kod C Kod C2 Kod C3 a b c d Rys.. Przykład przedstawia trzy różne sposoby kodowania alfabetu wejściowego S złożonego z symboli: {a,b,c,d}. Kod przedstawiony w drugiej kolumnie (kod C) jest kodem stałej długości, kody w kolumnach trzeciej i czwartej są kodami zmiennej długości. Jedynie kod C2 jest kodem prefiksowym. kod C kod C2 kod C3 bbdc abdb baabb cabb dbb Rys. 2. Dekodowanie przykładowych sekwencji kodowych przy użyciu kodów C, C2 oraz C3 przedstawionych w powyższej tabeli. Kody C oraz C2 są jednoznacznie dekodowalne (kod C2 jest kodem prefiksowym). Kod C3 nie jest kodem prefiksowym. Przykład (c) ilustruje problem dekodowania w przypadku kodu niejednoznacznie dekodowalnego. Z formalnego punktu widzenia kodowanie C jest odwzorowaniem symboli alfabetu wejściowego w ciągi binarne złożone z zer i jedynek: gdzie S jest alfabetem wejściowym, natomiast symbol gwiazdki oznacza skończone ciągi odpowiednich symboli. Binarna sekwencja przyporządkowana danemu symbolowi alfabetu wejściowego nazywana jest słowem kodowym (codeword). Kodem jest zbiór wszystkich słów kodowych. Podstawowym wymaganiem nałożonym na kodowanie jest jego odwracalność. Jednym ze sposobów podziału kodów jest podział na kody stałej (fixed length coding) oraz zmiennej długości (variable length coding). W przypadku kodów pierwszej grupy symbolom alfabetu wejściowego przyporządkowuje się ciągi binarne jednakowej długości. W przypadku kodów zmiennej długości wymaganie to nie jest spełnione. Przykładem popularnego kodu stałej długości jest kod ASCII. Dekodowanie strumienia zakodowanego kodem stałej długości polega na podziale strumienia bitowego (zakodowanego) na bloki o rozmiarze odpowiadającym rozmiarowi słów kodowych i odwzorowaniu słów kodowych na symbole alfabetu. Szczególną klasę kodów zmiennej długości stanowią kody prefiksowe dla których spełnione jest następujące wymagania: żadne ze słów kodowych nie jest prefiksem innego słowa kodowego. Kody prefiksowe posiadają cechę jednoznacznej dekodowalności: każdy ciąg słów kodowych może być zdekodowany tylko w jeden sposób. Kody prefiksowe są pożądane ze względu na możliwość jednoznacznego zdekodowania zakodowanego ciągu w układach bez pamięci są kodami natychmiastowymi.
Kodowanie źródeł danych - 2 Efektywność poszczególnych kodów z punktu widzenia wprowadzanej kompresji ocenić można na podstawie średniej długości kodu, tzn. średniej liczby bitów koniecznych do reprezentacji pojedynczego symbolu źródła. W przypadku modeli źródeł bez pamięci, gdy każdy symbol strumienia kodowany jest niezależnie, średnią długość kodu opisać można równaniem: gdzie p(s k ) określa prawdopodobieństwo wygenerowania przez źródło symbolu s k natomiast l(s k ) jest długością słowa kodowego przyporządkowanego symbolowi s k. Przy założeniu, że symbole są generowane niezależnie, średnia bitowa B C kodu spełnia następującą nierówność: Nierówność ta wskazuje, że średnia bitowa jest ograniczona od dołu przez entropię kodowanego źródła. Najlepszym wynikiem jaki można uzyskać w schemacie kompresji bezstratnej jest zakodowanie ciągu tak, aby średnia liczba bitów była równa entropii źródła (Shannon). Kody spełniające ostatnią nierówność nazywane są kodami optymalnymi. Bezwzględną miarą efektywności algorytmu kodowania (z punktu widzenia kompresji) jest redundancja zdefiniowana jako różnica pomiędzy entropią kodowanego źródła a średnią długością kodu.
Algorytm kodowania długości serii (RLE, run-length encoding) a c {24,8,32} {,,,,5,,,,5,,,,5,,,,5,,,,5,,,,5,,,,5,,,,4} {8,8,8,8,32} {3,2,6,2,6,2,3,6, 3,2,6,2,6,2,3} Rys.. Przykład działania algorytmu RLE dla prostych obrazów binarnych 8x8 pikseli. W przypadku braku kompresji oraz jednobitowej reprezentacji pojedynczego piksela, każdy z obrazów jest reprezentowany na 64 bitach = 8 bajtach. Kolejne rysunki przedstawiają przykłady obrazów dla których algorytm RLE uzyskuje różne wartości stopnia kompresji. Ciągi generowane na wyjściu algorytmu podane są pod rysunkami. Stopień kompresji dla obrazów (a), (b), (c) i (d) wynosi odpowiednio CR=2.67, CR=.6, CR=.24 oraz CR=.53. W dwóch ostatnich przypadkach objętość danych po kompresji jest większa niż przed kompresją! We wszystkich przypadkach algorytm RLE pracuje na spłaszczonym obrazie. b d Algorytm RLE kodowania długości serii (ciągu) jest prostym algorytmem, który można wykorzystać jako algorytm kompresji bezstratnej lub stratnej. W przypadku kompresji bezstratnej algorytm RLE wykorzystuje własność niektórych zbiorów danych (np. binarnych obrazów cyfrowych) polegającą na istnieniu w zbiorze wejściowym długich ciągów jednakowych symboli, np. pikseli o wartościach lub. W takim przypadku zamiast niezależnego kodowania poszczególnych symboli zbioru danych wejściowych długie ciągi jednakowych symboli reprezentowane są przez parę liczb postaci: (ilość_wystąpień_symbolu_w_ciągu, symbol). Przykład :Wejściowy ciąg (5,5,5,5,3,,4,4,4) można reprezentować przez następujący ciąg par { (4,5), (,3), (,), (3,4) }. W przypadku obrazów binarnych, gdzie rozmiar alfabetu wejściowego jest równy 2, można przyjąć konwencję zgodnie z którą bitmapa rozpoczyna się od białego piksela reprezentowanego przez. W takim przypadku efektywność algorytmu RLE dodatkowo wzrasta, ponieważ ciągi jednakowych symboli można reprezentować tylko jedną liczbą: liczbą wystąpień symbolu w ciągu. Przedstawia to poniższy przykład. Przykład 2: Stosując wspomnianą wyżej konwencję przykładowy ciąg wejściowy postaci: (,,,,,,,,,) można zakodować w sposób następujący: (4,5,). Z drugiej strony ciąg postaci: (,,,,,,,,,,) jest reprezentowany przez ciąg: (,,4,5,), tzn. zero białych pikseli, czarny piksel, 4 białe piksele, etc. Algorytm można wykorzystać również do bezstratnej kompresji obrazów reprezentowanych na więcej niż 2 bitach. Efektywność algorytmu RLE zależy od kilku czynników w tym od: złożoności danych wejściowych (patrz rysunek obok), sposobu przeglądania danych (obraz przeglądany po spłaszczeniu, obraz przeglądany niezależnymi wierszami lub kolumnami, zig-zag, etc.), rozmiaru danych wejściowych. W praktyce algorytm RLE kombinowany jest z innymi metodami kodowania/kompresji co dodatkowo zwiększa efektywność kompresji.
Sposoby przeglądania obrazu a b c Rys.. Trzy nietrywialne porządki przeglądania obrazu przez algorytm RLE. W przypadkach przedstawionych na rysunkach (a) oraz (c) wiersze lub kolumny obrazu kodowane są niezależnie. Taki sposób kodowania został przyjęty m. in. w standardach ITU Group 3 oraz Group 4 kompresji danych transmitowanych przez faks. Niezależne przetwarzanie wierszy lub kolumn chociaż może zmniejszyć stopień kompresji to pozwala w prosty sposób zaimplementować korekcję błędów przez stosowanie znacznika końca linii (wiersza).
Algorytm RLE. Przykład Algorytm RLE szczególnie dobrze nadaje się do kodowania obrazów tekstu, które zawierają duże obszary niezajęte przez druk: marginesy boczne, górny, dolny, obszary pomiędzy literami. a b c Rys.. Rysunek (a) przedstawia przykładowy obraz binarny (ramka nie stanowi części obrazu) zawierający 54x35 = 764 pikseli. W przypadku reprezentacji każdego piksela na jednym bicie rozmiar obrazu wynosi 225 bajtów. Po kompresji algorytmem RLE (kompresja bezstratna po spłaszczeniu obrazu w kierunku wierszy) obraz oryginalny jest reprezentowany na 2595 bajtach. W takim przypadku współczynnik kompresji wynosi CR=8.5. W przypadku kompresji fragmentów obrazu oryginalnego przedstawionych na rysunkach (b) i (c), rozmiaru odpowiednio x35 oraz 2x35 pikseli, współczynnik kompresji jest równy odpowiednio CR=7.25 oraz CR=4.5. Dlaczego w drugim przypadku jest on dwukrotnie większy? c.d. na następnej stronie
Algorytm RLE. Przykład (c.d.) d 49524, 4, 4, 5, 3, 3, 3, 7, 2, 2,, 3, 4, 3, 34, 3,, 2, 3, 2,, 3, 2, 2,, 2, 2, 2,, 3, 3, 2,, 3, 3, 2,, 2, 33, 2, 2, 2, 3, 2,, 2, 3, 2, 2, 2,, 2, 2, 2, 4, 4, 3, 2, 2, 3, 3, 2, 3, 2, 3, 2,, 2, 2, 2, 3, 2, 3, 4, 5, 2, 4, 2, 3, 2, 3, 2, 3, 2, 4, 4, 2, 2, 3, 2, 3, 4, 4, 3, 4, 2, 3, 2, 32, 2, 2, 2, 3, 2,, 2, 3, 2, 2, 2, 3,,, 2, 4, 2,,, 3, 2, 3, 2, 32, 6, 2, 3,, 3, 2, 2,, 3, 4, 3, 2, 3, 2, 2, 3, 5, 35, 5,, 2, 2, 3, 3, 3, 6, 4,, 3,, 4, 3, 3, 275, 3, 3, 3, 2, 6, 2, 5, 2, 5, 6, 3, 2, 2, 2, 4, 4, 5,, 3,,, 3, 5, 3,, 6, 8, 8, 6,, 3,, 3,, 6, 5, 7, 3,, 24, 2, 2,,, 2,, 4, 2, 2, 2, 6,, 2,, 3, 6, 2, 2, 3,, 2, 2, 2, 2, 2,, 2, 2, 2,, 3,, 2, 2, 2, 2, 3,, 2, 4, 2, 6, 2,, 2, 2,, 6, 2, 2, 2, 2, 3,, 2, 2,,, 2,, 2, 4, 7, 2, 3, 23,, 2, 2,,, 2, 2,,, 2, 2, 2, 2, 2, 2,, 2,, 2, 8,,, 3, 2, 2, 2, 2,, 2, 2, 2, 5, 2, 2,,,,, 2, 2, 2, 2, 2, 3, 3, 6, 2,,, 3, 2, 5,, 3, 2, 3, 2,, 2, 2,,, 2,, 2, 4,, 2, 2,,, 2, 3, 24, 4, 2, 3, 3, 4, 3, 5,, 2,, 2, 8, 4, 3, 2, 2, 2,, 2, 2, 2, 2, 4,,, 3, 4, 3, 2,, 2, 3, 3, 6, 2, 5, 2, 7, 4, 3, 5, 4, 2,, 2, 4, 3, 23, 3, 3, 3, 4, 4, 3, 5, 3, 3, 8, 3,,, 2, 2, 2, 2,, 2, 2, 2, 3, 2, 2,, 3, 4, 3, 5, 3, 4, 5, 2, 5, 2, 7, 4, 3, 2,, 2, 4, 2,, 2, 3, 5, 22, 2, 2, 3, 3, 3, 2, 2,, 3, 2,, 6,, 8, 2, 2,, 2, 2, 2, 2,, 2, 2, 2, 2, 3,, 2,, 2, 2, 2,, 4,, 2, 2, 2, 2,,, 2, 2, 2,,, 3, 2, 5, 2, 2, 2, 3, 2, 2,, 4, 2,, 2, 3, 2,, 2, 22, 2,, 8,, 3, 3, 4, 7, 2,, 3, 2, 4, 3, 6,, 2, 2,,, 2,, 7, 2, 9,, 4, 6, 7,, 3,, 3, 2, 4, 7, 5,, 3,, 3, 22, 3, 3, 3, 2, 6,,, 2, 3, 3, 4, 7,, 2, 3, 3, 2, 6, 4, 5, 2, 2, 6, 4, 3, 2, 2, 2,, 3, 2,,, 3, 2, 8, 5, 2, 3,, 3, 2, 4, 8,,,, 3,, 3,, 268 c.d. z poprzedniej strony. Rysunek (d) przedstawia ciąg długości 593 elementów (63 bajty) wygenerowany przez algorytm RLE dla obrazu (c). Ciąg ten różni się od ciągu wygenerowanego dla obrazu (b) jedynie wartością pierwszego elementu. Dodatkowy wzrost stopnia kompresji można uzyskać przez zmianę kierunku przeglądania obrazu na pionowy. W takim przypadku stopnie kompresji dla obrazów (a), (b) i (c) wynoszą odpowiednio: CR=9.4, CR=8.3 oraz CR=6.6.
Algorytm Huffmana (David Huffman, 952) Algorytm Huffmana jest popularnym algorytmem generującym optymalny kod w ramach przyjętego probabilistycznego modelu źródła. Oczywiście różne modele mogą prowadzić do kodów o różnej średniej bitowej. Zawsze jednak w ramach przyjętego modelu probabilistycznego kod wygenerowany przez algorytm Huffmana jest optymalny. Algorytm Huffmana wykorzystuje dwa podstawowe fakty dotyczące optymalnych kodów prefiksowych:. Symbolom występującym z większym prawdopodobieństwem odpowiadają w kodzie optymalnym krótsze słowa kodowe niż symbolom występującym rzadziej. 2. Dwa najmniej prawdopodobne symbole są kodowane słowami kodowymi tej samej długości. Algorytm Huffmana rozszerza tę własność optymalnych kodów prefiksowych o dodatkową cechę: słowa kodowe odpowiadające dwóm najmniej prawdopodobnym symbolom różnią się tylko na jednym bicie. Niech dane jest źródło o alfabecie S zawierającym N symboli: S={s, s2, s3,, sn} oraz niech znane jest prawdopodobieństwo wystąpień poszczególnych symboli: p(s)=s, p(s2)=p2,, p(sn)=pn. Algorytm Huffmana znajdowania optymalnego kodu można wówczas sprowadzić do problemu konstrukcji drzewa binarnego zgodnie z poniższym algorytmem:. Ustaw symbole alfabetu S w porządku rosnącym ze względu na prawdopodobieństwo ich wystąpienia. Traktuj symbole alfabetu jako węzły (liście) budowanego drzewa binarnego. Każdemu węzłowi nadaj etykietę równą prawdopodobieństwu wystąpienia symbolu. 2. Znajdź w zbiorze węzłów drzewa dwa węzły o najmniejszym prawdopodobieństwie wystąpienia (nazwijmy je odpowiednio ch oraz ch2) i utwórz dla takich węzłów wspólny węzeł rodzica. Skojarz z węzłem rodzica prawdopodobieństwo będące sumą prawdopodobieństw węzłów ch oraz ch2. Ścieżce od węzła rodzica do lewego potomka nadaj etykietę, ścieżce od węzła rodzica do prawego potomka nadaj etykietę. Nowododany węzeł-rodzic staje się symbolem nowego, zredukowanego alfabetu (alfabet ten nie zawiera symboli będących potomkami nowego węzła). 3. Gdy drzewo zawiera więcej niż jeden węzeł przejdź do punktu algorytmu. W przeciwnym przypadku przejdź do punktu 4. 4. Słowo kodowe dla określonego symbolu tworzone jest przez konkatenację etykiet ścieżek jakie należy przejść od korzenia drzewa do liścia odpowiadającego danemu symbolowi.
Algorytm Huffmana. Przykład. a.5.6.5.9.25.3 b f d c a e b..5.6.5.9.25.3 b f d c a e c.26 d.26..44..5.6.5.9.25.3 b f d c a e.9.25.5.6.5.3 c a b f d e Symbol Prawdopodobieństwo a.25 b.5 c.9 d.5 e.3 f.6 Rys.. Ilustracja konstrukcji drzewa Huffmana dla alfabetu zawierającego 6 symboli o prawdopodobieństwach wystąpień podanych w tabeli obok. Rys. (a) przedstawia fazę inicjalną. Węzły zaznaczone kolorem zielonym odpowiadają symbolom (zredukowanego) alfabetu w bieżącej iteracji algorytmu. Kolejne rysunku przedstawiają kolejne iteracje algorytmu Huffmana. c.d. na następnej stronie
Algorytm Huffmana. Przykład (c.d.) e f..56.56..26.44.44..26.5.6.5.3.9.25 b f d e c a.9.25.5.6.5.3 c a b f d e Symbol Prawdopodo- Słowo kodowe bieństwo a.25 b.5 c.9 d.5 e.3 f.6 Rys.. c.d. z poprzedniej strony. Ostateczne drzewo Huffmana przedstawione jest na rysunku (f). Etykiety ścieżek przechodzonych od korzenia skonstruowanego drzewa do kolejnych liści reprezentujących symbole alfabetu wejściowego odpowiadają słowom kodowym symboli. Postać słów kodowych przedstawiona jest w tabeli obok. Ostateczna postać drzewa binarnego, a co za tym idzie postać słów kodowych zależy od szczegółów konstrukcji drzewa: etykiety ścieżek mogą być nadawane w kolejności przeciwnej niż zaproponowana w przedstawionym algorytmie, ustawianie węzłów w porządku rosnącego prawdopodobieństwa może być pominięte (lub porządek może być zmieniony). Wykorzystując taką dowolność otrzymać można różną postać słów kodowych. Niezależnie jednak od tego wynikowy kod zawsze jest optymalnym kodem prefiksowym.
Cechy kodów Huffmana Prawdopodo- Słowo Symbol bieństwo kodowe a.25 b.5 c.9 d.5 e.3 f.6 Rys.. Model probabilistyczny źródła oraz ciągi kodowe odpowiadające symbolom alfabetu. Cechy kodu Huffmana: Kod Huffmana jest kodem prefiksowym, a przez to jednoznacznie dekodowalnym. Cecha prefiksowości wynika ze sposobu konstrukcji kodu: przez drzewo binarne. Słowa kodowe odpowiadające symbolom najmniej prawdopodobnym mają największą długość (tu: 4 bity) i różnią się na jedynym bicie. Symbole najbardziej prawdopodobne posiadają najkrótsze słowa kodowe (tu: 2 bity). Kod Huffmana jest kodem optymalnym, tzn. H(S)<= B C <=H(S)+. Dla przykładu, entropia źródła kodowanego w przykładzie jest równa: H(S)=2.35, podczas gdy średnia długość skonstruowanego kodu Huffmana jest równa: ceecdaeccddfcadaedeaacadcca edeeaeaacaeceaeacecbcabccac aeeebadeaaaeddaadebaeaaddae adeaeaceecdccddcece Rys.. Rysunek przedstawia przykładowy strumień symboli wygenerowanych przez opisane w przykładzie źródło (model probabilistyczny podany jest w tabeli powyżej). W przypadku stosowania kodu stałe długości, np. kodu 3 bitowego zakodowany strumień zajmować będzie 3 bitów. W przypadku kodowania tego samego ciągu za pomocą wcześniej skonstruowanego kodu Huffmana zakodowany ciąg zajmować będzie 237 bitów, co daje 2.37 bita na symbol. Ten prosty przykład ilustruje jak stosowanie kodów zmiennej długości prowadzi do uzyskania kompresji, w tym przypadku stopień kompresji wynosi CR=.27. Kodowanie Huffmana jest efektywną techniką kodowania entropijnego, ale posiada też pewne ograniczenia: Efektywność kodowania Huffmana zależy od wielu czynników takich jak: rozmiar alfabetu wejściowego oraz rozkład prawdopodobieństw występowania poszczególnych symboli. Kod Huffmana jest optymalny ale tylko w przypadku, gdy znany jest rzeczywisty rozkład prawdopodobieństwa poszczególnych symboli generowanych przez źródło (model źródła). W przypadku, gdy założony rozkład prawdopodobieństwa odbiega od rzeczywistego rozkładu efektywność kodu Huffmana maleje. Z powyższego powodu kodowanie Huffmana nie nadaje się do kodowania źródeł o zmiennej charakterystyce (rozkład prawdopodobieństwa symboli zmienia się w czasie). W takim przypadku stosowanie statycznego kodowania Huffmana może doprowadzić do zwiększenia objętości strumienia zakodowanego w stosunku do wejściowego.
Cechy kodów Huffmana. Przykład Przykład: Niech dane są dwa źródła Ź oraz Ź2 niezależnie generujące symbole z alfabetów odpowiednio S=(,,,9) oraz S2=(,,2). Prawdopodobieństwa z jakimi źródła generują poszczególne symbole są przedstawione na rysunkach obok: rysunek (a) dla Ź, (b) dla Ź2. Jedną z wcześniej wymienionych cech kodów Huffmana jest zależność średniej długości kodu od rozmiaru alfabetu i rozkładu prawdopodobieństw poszczególnych symboli. Można pokazać, że jeśli p max jest prawdopodobieństwem najbardziej prawdopodobnego symbolu generowanego przez źródło, to średnia długość kodu Huffmana opisana jest następującą nierównością: a b.2..8.6.4.2 2 3 4 5 6 7 8 9.8.6.4.2 2 Entropia źródeł jest równa odpowiednio: H(S)=3.29 bita oraz H(S2)=.7 bita. Kody Huffmana skonstruowane niezależnie dla obu źródeł charakteryzują się średnią długością równą odpowiednio: BC(S)=3.32 oraz BC(S2)=.5 bita na symbol. Prosty rachunek pokazuje, że redundancja kodu Huffmana dla pierwszego źródła wynosi.3 bita na symbol, co oznacza że skonstruowany kod potrzebuje średnio dodatkowo.3 bita (.9%) do zakodowania pojedynczego symbolu w stosunku do przypadku idealnego. Redundancja kodu dla drugiego źródła wynosi.44 bita na symbol;.44 bita stanowi 6.2% entropii takiego źródła. stanowiącą dokładniejsze oszacowanie średniej długości kodu Huffmana. Z nierówności tej wynika, średnia długość kodu zbliża się do minimalnej wartości określonej przez entropię źródła w przypadku, gdy maksymalne prawdopodobieństwo w modelu probabilistycznym ma niewielkie wartości. Własność taką mogą posiadać alfabety dużych rozmiarów. W przeciwnym przypadku, gdy alfabet składa się z małej liczby symboli a prawdopodobieństwo jednego z symboli jest wyraźnie większe od pozostałych (duża wartość p max ), średnia długość kodu Huffmana oddala się od minimalnej długości kodu wyznaczonej przez entropię i kod staje się mało efektywny. Pytanie: Jaką średnią długość oraz stopień kompresji osiągają kody Huffmana konstruowane dla źródeł o alfabetach zawierających dokładnie dwa symbole?
Cechy kodów Huffmana. Przykład 2 Kolejną z wymienionych cech kodów Huffmana jest zależność ich średniej długości od przyjętego modelu źródła. Poniższy przykład pokazuje jak zmienia się efektywność kodowania Huffmana w przypadku, gdy model źródła odbiega od rzeczywistej statystyki źródła. a Symbol Źródło Źródło 2 Źródło 3 Źródło 4 a..4.95.25 b.2.3.3.25 c.3.2..25 d.4...25 b.8.6.4.2 2 3 4 c Źródło Źródło 2 Źródło 3 Źródło 4 Entropia.846.846.355 2. Średnia długość kodu.9.9.7 2. Średnia długość kodu przy użyciu kodu wygenerowanego dla źródła..9 2.6 2.97 2.25 Przykład. Rozpatrzmy cztery różne źródła, których modele probabilistyczne przedstawione są w tabeli na rysunku (a). Rozkład prawdopodobieństwa źródeł przedstawiony jest graficznie na rysunku (b). Kod Huffmana jest optymalny przy założeniu dysponowania wiedzą na temat rzeczywistego rozkładu prawdopodobieństwa poszczególnych symboli generowanych przez źródło. W przypadku, gdy wiedza taka jest niedostępna lub niepełna, średnia długość kodu wzrasta w stosunku do przypadku kodu optymalnego. Ilustruje to tabela na rysunku (c). Drugi wiersz tabeli przedstawia średnią długość kodu Huffmana wygenerowanego przy wykorzystaniu rzeczywistego rozkładu prawdopodobieństw symboli danego źródła. Trzeci wiersz przedstawia wartości uzyskanej średniej długości kodu dla kodowania kolejnych źródeł przy użyciu kodu skonstruowanego dla źródła.
Kodowanie strumienia danych Symbol Kod nieuwzględniający EOF a b c d e f EOF - Kod uwzględniający EOF Rys.. Postać kodu Huffmana dla symboli alfabetu źródła rozpatrywanego we wcześniejszych przykładach. Uwzględnienie symbolu EOF powoduje zmianę postaci słów kodowych (ostatnia kolumna tabeli). Rys. 2. Zakodowany ciąg symboli daaefeab uzupełniony znacznikiem EOF oraz dodatkowymi bitami dopełniającymi do 32 bitów (wielokrotność 8 bitów). Zielony blok wskazuje kod znacznika EOF, czerwony blok zawiera bity dopełniające. Kodowanie strumienia danych sprowadza się na mapowaniu kolejnych symboli pojawiających się w strumieniu wejściowym na wcześniej skonstruowane słowa kodowe. Tak powstały strumień kodowy w praktyce musi być rozszerzony o dodatkowe elementy umożliwiające jego poprawne przesłanie lub zapisanie oraz odkodowanie przez dekoder. Pierwszym elementem o jaki należy uzupełnić strumień kodowy jest nagłówek zawierający model probabilistyczny źródła, które wygenerowało pierwotny strumień danych. W takim przypadku pierwszą fazą pracy dekodera jest zbudowanie drzewa binarnego identycznego ze zbudowanym przez koder. W innym przypadku nagłówek może przyjmować postać ciągu par postaci: (symbol, słowo_kodowe). Są to informacje niezbędne dla dekodera do zdekodowania strumienia. Innym problemem jaki należy rozwiązać jest uzupełnienie strumienia kodowego o znak końca danych EOF oraz dopełnienie długości strumienia do wielokrotności 8 bitów. Symbol końca strumienia EOF uwzględnia się już na poziomie konstrukcji drzewa binarnego poprzez rozszerzenie alfabetu wejściowego o symbol EOF o najmniejszej częstości wystąpienia. Dekoder po napotkaniu słowa kodowego reprezentującego EOF ignoruje wszystkie pozostałe bity w strumieniu będące dopełnieniem strumienia do wielokrotności 8 bitów.
Przykłady C R =. C R =.8 C R =.35 C R =. Rys.. Przykładowe obrazy i uzyskane wartości stopnia kompresji dla kodowania Huffmana. C R =6.26