Kodowanie Shannona-Fano

Podobne dokumenty
Kompresja Kodowanie arytmetyczne. Dariusz Sobczuk

AKD Metody słownikowe

mgr inż. Grzegorz Kraszewski SYSTEMY MULTIMEDIALNE wykład 4, strona 1. GOLOMBA I RICE'A

Temat: Algorytm kompresji plików metodą Huffmana

Kody Tunstalla. Kodowanie arytmetyczne

Teoria informacji i kodowania Ćwiczenia

Kodowanie informacji

Przetwarzanie i transmisja danych multimedialnych. Wykład 5 Kodowanie słownikowe. Przemysław Sękalski.

Kodowanie i kompresja Streszczenie Studia dzienne Wykład 9,

Def. Kod jednoznacznie definiowalny Def. Kod przedrostkowy Def. Kod optymalny. Przykłady kodów. Kody optymalne

ZADANIE 1. Rozwiązanie:

Kodowanie Huffmana. Platforma programistyczna.net; materiały do laboratorium 2014/15 Marcin Wilczewski

KODY SYMBOLI. Kod Shannona-Fano. Algorytm S-F. Przykład S-F

teoria informacji Kanały komunikacyjne, kody korygujące Mariusz Różycki 25 sierpnia 2015

Granica kompresji Kodowanie Shannona Kodowanie Huffmana Kodowanie ciągów Kodowanie arytmetyczne. Kody. Marek Śmieja. Teoria informacji 1 / 35

2 Arytmetyka. d r 2 r + d r 1 2 r 1...d d 0 2 0,

Kompresja danych kodowanie Huffmana. Dariusz Sobczuk

pobieramy pierwszą literę komunikatu i wypełniamy nią (wszystkie pozycje tą samą literą) bufor słownikowy.

Teoretyczne Podstawy Informatyki

Wstęp do programowania. Reprezentacje liczb. Liczby naturalne, całkowite i rzeczywiste w układzie binarnym

Kodowanie informacji

Algorytmy kompresji. Kodowanie Huffmana, kodowanie arytmetyczne

Podstawy Informatyki

LZ77 LZ78. Kompresja danych. Tomasz Jurdziński. Wykład 5: kodowanie słownikowe

0 + 0 = 0, = 1, = 1, = 0.

Wygra Polska czy Brazylia, czyli o tym jak zwięźle zapisywać informacje

Metoda znak-moduł (ZM)

0-0000, , , itd

Stan wysoki (H) i stan niski (L)

Kody splotowe. Zastosowanie

Kodowanie i entropia

LABORATORIUM PROCESORY SYGNAŁOWE W AUTOMATYCE PRZEMYSŁOWEJ. Zasady arytmetyki stałoprzecinkowej oraz operacji arytmetycznych w formatach Q

Maszyna Turinga. Algorytm. czy program???? Problem Hilberta: Przykłady algorytmów. Cechy algorytmu: Pojęcie algorytmu

teoria informacji Entropia, informacja, kodowanie Mariusz Różycki 24 sierpnia 2015

Dla człowieka naturalnym sposobem liczenia jest korzystanie z systemu dziesiętnego, dla komputera natomiast korzystanie z zapisu dwójkowego

Kodowanie i kompresja Streszczenie Studia Licencjackie Wykład 11,

Teoria Informacji i Metody Kompresji Danych

Wstęp Statyczne kody Huffmana Dynamiczne kody Huffmana Praktyka. Kodowanie Huffmana. Dawid Duda. 4 marca 2004

Kompresja bezstratna. Entropia. Kod Huffmana

Arytmetyka liczb binarnych

Samodzielnie wykonaj następujące operacje: 13 / 2 = 30 / 5 = 73 / 15 = 15 / 23 = 13 % 2 = 30 % 5 = 73 % 15 = 15 % 23 =

Ćwiczenie nr 4: Kodowanie arytmetyczne, range coder

Kodowanie i kompresja Tomasz Jurdziński Studia Wieczorowe Wykład Kody liniowe - kodowanie w oparciu o macierz parzystości

Kody Huffmana. Konrad Wypyski. 11 lutego 2006 roku

Sortowanie zewnętrzne

Systemy liczbowe. 1. Przedstawić w postaci sumy wag poszczególnych cyfr liczbę rzeczywistą R = (10).

Teoria Informacji - wykład. Kodowanie wiadomości

Języki i metodyka programowania. Reprezentacja danych w systemach komputerowych

Założenia i obszar zastosowań. JPEG - algorytm kodowania obrazu. Geneza algorytmu KOMPRESJA OBRAZÓW STATYCZNYCH - ALGORYTM JPEG

Pracownia Komputerowa wykład VI

Nierówność Krafta-McMillana, Kodowanie Huffmana

LICZBY ZMIENNOPRZECINKOWE

Entropia Kodowanie. Podstawy kompresji. Algorytmy kompresji danych. Sebastian Deorowicz

Dane, informacja, programy. Kodowanie danych, kompresja stratna i bezstratna

Symbol, alfabet, łańcuch

Kompresja danych DKDA (7)

ARCHITEKTURA SYSTEMÓW KOMPUTEROWYCH

Podstawowe pojęcia. Teoria informacji

ARYTMETYKA BINARNA. Dziesiątkowy system pozycyjny nie jest jedynym sposobem kodowania liczb z jakim mamy na co dzień do czynienia.

Algorytmy zachłanne. dr inż. Urszula Gałązka

KODY SYMBOLI. Materiały KODA, A.Przelaskowski. Koncepcja przedziałów nieskończonego alfabetu

Metody numeryczne Technika obliczeniowa i symulacyjna Sem. 2, EiT, 2014/2015

12. Wprowadzenie Sygnały techniki cyfrowej Systemy liczbowe. Matematyka: Elektronika:

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Algorytmy i struktury danych Laboratorium Nr 4

Kodowanie informacji. Kody liczbowe

Języki formalne i automaty Ćwiczenia 2

Języki formalne i automaty Ćwiczenia 9

Aproksymacja funkcji a regresja symboliczna

1.1. Pozycyjne systemy liczbowe

Kwantyzacja wektorowa. Kodowanie różnicowe.

Kodowanie transformacyjne. Plan 1. Zasada 2. Rodzaje transformacji 3. Standard JPEG

3. Opracować program kodowania/dekodowania pliku tekstowego. Algorytm kodowania:

Systemy zapisu liczb.

Arytmetyka komputera

Wstęp do informatyki- wykład 1 Systemy liczbowe

Zestaw 3. - Zapis liczb binarnych ze znakiem 1

Teoria przetwarzania A/C i C/A.

Algorytmy kodowania entropijnego

Kod uzupełnień do dwóch jest najczęściej stosowanym systemem zapisu liczb ujemnych wśród systemów binarnych.

Definicja. Jeśli. wtedy

Algorytmy i struktury danych

Wprowadzenie Algorytm ByteRun ByteRun - przykład Algorytm RLE Przykład działania RLE Algorytm LZW Przykład kompresji LZW

Liczby rzeczywiste są reprezentowane w komputerze przez liczby zmiennopozycyjne. Liczbę k można przedstawid w postaci:

Cyfrowy zapis informacji. 5 grudnia 2013 Wojciech Kucewicz 2

Korzystanie z podstawowych rozkładów prawdopodobieństwa (tablice i arkusze kalkulacyjne)

Dane obrazowe. R. Robert Gajewski omklnx.il.pw.edu.pl/~rgajewski

Wprowadzenie do architektury komputerów systemy liczbowe, operacje arytmetyczne i logiczne

Arytmetyka binarna - wykład 6

Wyszukiwanie binarne

Urządzenia Techniki. Klasa I TI. System dwójkowy (binarny) -> BIN. Przykład zamiany liczby dziesiętnej na binarną (DEC -> BIN):

Komunikacja człowiek-komputer

Arytmetyka komputera. Na podstawie podręcznika Urządzenia techniki komputerowej Tomasza Marciniuka. Opracował: Kamil Kowalski klasa III TI

Maciej Piotr Jankowski

Kod IEEE754. IEEE754 (1985) - norma dotycząca zapisu binarnego liczb zmiennopozycyjnych (pojedynczej precyzji) Liczbę binarną o postaci

Języki formalne i automaty Ćwiczenia 7

1 Podstawy c++ w pigułce.

Technologie Informacyjne

Systemy liczbowe używane w technice komputerowej

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 2 WSTĘP DO INFORMATYKI

Wykład z Technologii Informacyjnych. Piotr Mika

Transkrypt:

Kodowanie Shannona-Fano Kodowanie Shannona-Fano znane było jeszcze przed kodowaniem Huffmana i w praktyce można dzięki niemu osiągnąć podobne wyniki, pomimo, że kod generowany tą metodą nie jest optymalny. Zasada: Symbolom przypisujemy wagi proporcjonalne do prawdopodobieństwa ich wystąpienia w ciągu wejściowym. Następnie budujemy binarne drzewo kodowe, dzieląc zbiór przypisany do danej gałęzi na dwa podzbiory, które mają w przybliżeniu jednakową sumaryczną wagę. Przykład: Poniżej podaną mamy przykładową charakterystykę źródła, uzyskane kody oraz drzewo kodowe z wyszczególnionymi kolejnymi podziałami zbioru symboli: Symbol Waga (prawopodobieństwo) Kod s 1 0,05 000 s 2 0,1 100 s 3 0,1 110 s 4 0,15 101 s 5 0,15 111 s 6 0,2 001 s 7 0,25 01 0 s 1, s 2, s 3, s 4, s 5, s 6, s 7 sumaryczna waga: 1 1 s 1, s 6, s 7 s 2, s 3, s 4, s 5 sumaryczna waga: 0,5 sumaryczna waga: 0,5 0 1 0 1 s 1, s 6 sumaryczna waga: 0,25 s 7 s 2, s 4 sumaryczna waga: 0,25 s 3, s 5 sumaryczna waga: 0,25 0 1 0 1 0 1 s 1 s 6 s 2 s 3 s 5 s 4

Algorytm Lempela-Ziva Algorytm Lempela-Ziva (w skrócie LZ) jest, w odróżnieniu do algorytmów Huffmana i Shannona- Fano, algorytmem pobierającym bloki o zmiennej długości, kodując je za pomocą kodów o stałej lub zmiennej długości. Należy on do grupy algorytmów słownikowych. Zaletą w porównaniu do Huffmana jest to, że chcąc zakodować dane algorytmem LZ nie musimy znać lub przewidywać rozkładu prawdopodobieństw występowania poszczególnych symboli w ciągu wejściowym. Sam algorytm LZ występuje w dwóch wersjach - LZ77 i LZ78 (poniżej opisana jest ta druga z nich). Dodatkowo, zarówno LZ77 jak i LZ78 doczekały się licznych modyfikacji, z których jedna (LZW) również opisana jest w niniejszym opracowaniu. Podsumowanie istniejących wariantów algorytmu LZ zawiera tabelka: Warianty LZ77 LZR LZSS LZB LZH Warianty LZ78 LZW LZC LZT LZMW LZJ LZFG Algorytm LZ78 Zasada: dzielimy ciąg wejściowy na części, które są najkrótszymi podciągami (blokami) nie napotkanymi do tej pory. Innymi słowy, dzieląc ciąg na bloki zatrzymujemy się po pierwszym elemencie, który sprawia, że nasz blok nie pasuje do żadnego napotkanego wcześniej. Załóżmy, że mamy ciąg symboli o dwuelementowym alfabecie D={a, b} a a a b a b b b a a a b a a a a a a a b a a b b Zgodnie z powyższą zasadą pierwszym blokiem naszego ciągu będzie a, następnym aa, później b, ab itd. W rezultacie otrzymamy następujący podział: a a a b a b b b a a a b a a a a a a a b a a b b Chcąc zakodować ciąg, indeksujemy kolejno bloki od 1 do n, dodając dodatkowo pusty blok o indeksie 0.

indeks 0 1 2 3 4 5 6 7 8 9 10 ø a a a b a b b b a a a b a a a a a a a b a a b b Ciąg wyjściowy kodujemy w formie dwuelementowej indeks symbol, gdzie indeks jest numerem bloku napotkanego wcześniej, a symbol ostatnim elementem bloku. W tym przypadku kod pierwszego bloku a będzie miał postać 0a (pusy ciąg + a ), nastęnego bloku aa - 1a (blok o indeksie 1 + a ) itd. W rezultacie otrzymujemy ciąg wyjściowy: indeks 0 1 2 3 4 5 6 7 8 9 10 ciąg wyjściowy 0a 1a 0b 1b 3b 2a 3a 6a 2b 9b Jak widać, słownikiem w algorytmie LZ jest sam zakodowany ciąg symboli, nie ma więc konieczności dodatkowego przesyłania słownika do dekodera. Dodatkowo zauważmy, że nie musimy zakładać stałej liczby bitów na zakodowanie indeksu (przy długich ciągach musiałaby być duża), ponieważ liczba bitów może rosnąć wraz z kolejnym indeksem. Zauważmy, że indeks na pozycji n może być równy co najwyżej n-1, więc liczba bitów potrzebna do jego zakodowania wynosi log 2 n 1 zaokrąglone w górę do najbliższej liczby całkowitej. Uwaga do przykładu: Podany przykładowy ciąg wejściowy jest zbyt krótki, a przede wszystkim dysponuje zbyt ubogim (bo tylko dwuelementowym) alfabetem, przez co kodowanie LZ nie zaowocuje w tym przypadku realną kompresją danych, chociaż już na tak prostym przykładzie można zaobserwować zasadę zastępowania coraz dłuższych ciągów symboli zestawem indeks/symbol. W realnych implementacjach stosuje się najczęściej symbole o rozmiarze jednego bajtu, a sam ciąg wejściowy ma przynajmniej kilka kb długości. W takim przypadku kod LZ jest zazwyczaj wydajniejszy od kodu Huffmana, zwłaszcza w przypadku ciągów, w których istnieją zależności międzysymbolowe (takich jak np. tekst w języku naturalnym), których kod Huffmana ze swojej natury nie jest w stanie uwzględnić.

Algorym LZW Jest to modyfikacja algorytmu LZ78 zwana od nazwisk twórców Lempel-Ziv-Welch. Stosowana jest ona m.in. W popularnym formacie plików graficznych gif, a także w kompresorach spotykanych w systemie UNIX. Algorytm: 1. Zainicjuj słownik wszystkimi blokami o długości jeden (tj. wszystkimi symbolami z podstawowego alfabetu źródła) 2. Wyszukaj w ciągu wejściowym jak najdłuższy blok W, który występuje w słowniku 3. Zakoduj W za pomocą jego indeksu w słowniku 4. Dodaj W z dołączonym pierwszym symbolem następnego bloku do słownika 5. Idź do punktu 2 Dekodowanie odbywa się w odwrotnej kolejności. Dekoder wie, że ostatni symbol z najświeższego wpisu do słownika jest pierwszym symbolem z następnego bloku do zdekodowania. Wiedza ta umożliwia rozwiązanie potencjalnych konfliktów w dekoderze i zbudowanie słownika na bieżąco. Przykład: Załóżmy, że mamy ciąg o dwuelementowym alfabecie D={a,b}, taki sam jak ten, który służył za ilustrację algorytmu LZ. a a a b a b b b a a a b a a a a a a a b a a b b Słownik, zainicjowany wstępnie blokami o długości jeden, wygląda natępująco: indeks 0 1 blok a b Przeglądamy ciąg wejściowy. Pierwszym symbolem jest a, które oczywiście istnieje w słowniku na pozycji 0. Kodujemy więc a za pomocą 0, następnie blok wraz z następnym symbolem (również a - zaznaczony podkreśleniem) dodajemy do słownika.

ciąg wejściowy: ciąg wyjściowy: 0 a a a b a b b b a a a b a a a a a a a b a a b b słownik: indeks 0 1 2 ciąg a b aa Przeglądając dalej ciąg wejściowy napotykamy na istniejący już w słowniku ciąg aa, który również kodujemy za pomocą jego indeksu, tym razem 2, a do słownika dodajemy aab. ciąg wejściowy: ciąg wyjściowy: 0 2 a a a b a b b b a a a b a a a a a a a b a a b b słownik: indeks 0 1 2 3 ciąg a b aa aab Postępując tak dalej otrzymujemy zakodowany ciąg: ciąg wejściowy: a a a b a b b b a a a b a a a a a a a b a a b b ciąg wyjściowy: 0 2 1 0 1 6 2 5 8 10 4 5 0 słownik: indeks 0 1 2 3 4 5 6 7 8 9 10 11 12 ciąg a b aa aab ba ab bb bba aaa aba aaaa aaaab baa

Teoretycznie słownik może osiągać dowolnie duże rozmiary, w praktyce ogranicza się go np. do 4096 elementów (12 bitów/indeks). Po przekroczeniu tej liczby kolejne wpisy przestają być dodawane. Zmieniając rozmiar słownika możemy regulować stopień kompresji kosztem jej szybkości. Tak samo jak w algorytmie LZ możemy zastosować zmienną długość indeksu, co pozwoli zaoszczędzić dokładnie 2 m 1 bitów przy słowniku o rozmiarze 2 m. Jak widać, algorytm LZW dokonuje nieco innego (można powiedzieć: mniej optymalnego) podziału ciągu wejściowego niż LZ, za to w ciągu wyjściowym występują tylko same indeksy, co w praktyce czyni algorytm LZW nieco bardziej wydajnym od LZ. Metoda arytmetyczna Metoda arytmetyczna należy, podobnie jak kodowanie Huffmana, do grupy metod statystycznych, czyli opiera się na statystycznym rozkładzie prawdopodobieństwa źródła. Jednak w przeciwieństwie do Huffmana metoda arytmetyczna nie przydziela każdemu z symboli kodu o długości wyrażonej w bitach, ale dąży do obliczenia na podstawie statystyki źródła liczby kodowej opisującej dane źródło - cały ciąg wejściowy kodujemy za pomocą jednej liczby rzeczywistej. Brzmi to efektownie, jednak należy mieć na uwadze, że liczba ta może wymagać bardzo dużej precyzji - dokładność zwykle używanych liczb typu double skończy się po zakodowaniu góra kilkunastu symboli (jednak i z tym można sobie poradzić stosując notację stałoprzecinkową). W rezultacie efektywna długość kodu dla pojedynczego symbolu może wynosić nawet ułamek bita! Osiągnięte to zostało poprzez całkowicie odmienne podejście do kodowania. Niech X = {x(i)} będzie dyskretną zmienną losową, której wartościami będą symbole z alfabetu źródła (w najbardziej typowym przypadku, dla symboli będących bajtami x(i) = i = 0, 1,.., 255). Zaczynamy od podziału przedziału [0, 1) na rozłączne podprzedziały o długości równej prawdopodobieństwu wystąpienia każdego z symboli. Znając statystykę zmiennej X, możemy w tym celu posłużyć się się dystrybuantą: S i =[ F X i 1, F X i, (1) gdzie S i jest podprzedziałem odpowiedzialnym za symbol o indeksie i. Każda liczba z tego przedziału będzie arytmetyczną reprezentacją danego symbolu. Pobierając teraz symbole ze strumienia wejściowego, korzystając z wyznaczonych podprzedziałów, dla każdego symbolu dokonujemy sukcesywnego zawężania przedziału głównego, w którym mieści się poszukiwania liczba kodowa, będąca wynikiem kodowania.

Algorytm kodowania: 1. Dokonaj podziału przedziału [0, 1) na podstawie statystyki źródła za pomocą wzoru (1). Niech S [i] będzie tablicą rekordów o polach beg i end, opisujących przedział dla symbolu o indeksie i, 2. zmiennym m_beg oraz m_end opisującym przedział główny przypisz wartości początkowe odpowiednio 0 i 1, 3. wczytaj symbol z wejścia (oznaczmy go c) i dokonaj korekty górnej i dolnej granicy przedziału głównego za pomocą wzorów: m_beg := m_beg + (m_end m_beg) * S [c].beg, m_end := m_end + (m_end m_beg) * S [c].end, 4. powtarzaj punkt 3 aż do wyczerpania się źródła, 5. zapisz do strumienia wyjściowego statystykę źródła oraz liczbę z przedziału [m_beg, m_end), będzie to poszukiwana liczba kodowa. Uwaga: Aby dekoder mógł rozpoznać miejsce, w którym należy przerwać dekodowanie, należy w dodatkowo w strumieniu wyjściowym umieścić informację o liczbie zakodowanych symboli, albo wydzielić w alfabecie dodatkowy symbol EOF. Przykład: Zakodujmy za pomocą podanego powyżej algorytmu ciąg ARYTMETYKA. Oto statystyka tekstu i przypisane na jej podstawie podprzedziały dla kolejnych symboli: Znak Prawd. wystąpienia Podprzedział A 0,2 [0; 0.2) E 0,1 [0,2; 0,3) K 0,1 [0,3; 0,4) M 0,1 [0,4; 05) R 0,1 [0,5; 0,6) T 0,2 [0,6; 0,8) Y 0,2 [0,8; 1) Zawężanie przedziału głównego w kolejnych krokach algorytmu:

Ciąg wejściowy m_beg Start 0 1 A 0 0,2 R 0,1 0,12 Y 0,16 0,12 T 0,1184 0,1192 M 0,11872 0,1188 m_end E 0,118736 0,118744 T 0,1187408 0,1187424 Y 0,11874208 0,1187424 K 0,118742176 0,118742208 A 0,118742176 0,1187421824 Zatem w rezultacie mamy przedział główny do którego należy poszukiwana liczba kodowa: [0,118742176, 0,1187421824). Możemy przyjąć dla uproszczenia, że poszukiwaną liczbą będzie dolna granica przedziału, czyli K = 0,118742176 (w praktycznej realizacji opłaca się poszukać w przedziale liczby, dla zapisania której potrzeba jak najmniej miejsc po przecinku). Algorytm dekodowania: 1. Dokonaj podziału przedziału [0, 1), na podstawie odczytanej ze strumienia wejściowego statystyki źródła, za pomocą wzoru (1). Niech S [i] będzie tablicą rekordów o polach beg i end, opisujących przedział dla symbolu o indeksie i (identycznie jak przy kodowaniu), 2. wczytaj liczbę kodową K, 3. zdekoduj symbol opisywany przez K (poprzez sprawdzenie, do jakiego podprzedziału należy K, jeśli K S c to zdekodowanym symbolem jest c). 4. Zmodyfikuj K tak by wyeliminować wpływ zdekodowanego symbolu K S [c].beg K = S [c]. end S [c].beg 5. Powtarzaj kroki 3 i 4 aż do zdekodowania wszystkich znaków (lub napotkania symbolu EOF). Przykład: Korzystając z wyników poprzedniego przykładu:

Liczba kodowa K (kolejne modyfikacje) Przedział do którego należy K Symbol odpowiadający przedziałowi 0,118742176 [0; 0,2) A 0,59371088 [0,5; 0,6) R 0,9371088 [0,8; 1) Y 0,685544 [0,6; 0,8) T 0,42772 [0,4; 0,5) M 0,2772 [0,2; 0,3) E 0,772 [0,6; 0,8) T 0,86 [0,8; 1) Y 0,3 [0,3; 0,4) K 0 [0; 0,2) A Jak widać, dysponując tylko jedną liczbą (oraz statystyką źródła, która jednak zajmuje zawsze tyle samo miejsca, niezależnie od długości ciągu) można dokonać jednoznacznego zdekodowania i otrzymać źródłowy ciąg symboli. Zauważmy, że część całkowita liczby K jest zawsze równa 0, wystarczy więc zapamiętać część ułamkową, do reprezentacji której z kolei można wykorzystać notację stałoprzecinkową (kolejne bity odpowiadają za wartości 2-1, 2-2, 2-3 itd.). Ma to tą dodatkową zaletę, że taki ciąg bitów można wydłużać w nieskończoność, w przeciwieństwie do liczby zmiennoprzecinkowej, która ma zawsze skończoną i z góry określoną precyzję. Opracowanie: Łukasz Wołowiec