Proseminar WS 2002/2003

Werbung
Technische Universität Chemnitz
Fakultät für Informatik
Professur Theoretische Informatik
Proseminar WS 2002/2003
Thema: Datenkompression
Dynamisches / Adaptives Huffman-Verfahren
Danny Grobe
Rainer Kuhn
Dynamisches / Adaptives Huffman-Verfahren
Huffman-Kode:
Von David A. Huffman stammt ein Algorithmus, welcher zu einer gegebenen Nachricht einen
Präfixkode erzeugt, der die Länge einer kodierten Nachricht unter der Annahme einer
shannonschen Quelle minimiert. Der durch diesen Algorithmus konstruierte Kode wird als
Huffman-Kode zu einer Nachricht bezeichnet. Die Huffman- Kodierung einer Nachricht ist
eine binäre Kodierung der Nachricht, deshalb sei im folgenden angenommen, dass die
Zeichen der Nachricht durch den Huffman-Kode über dem Alphabet {0, 1} kodiert werden.
Der Algorithmus wurde im Jahre 1952 von Huffman in "A method for the construction of
minimum redundancy codes" veröffentlicht.
Arten der Huffmankodierung:
Die Huffman-Kodierung kann statisch, dynamisch oder adaptiv vorgenommen werden.
Bei der statischen Kodierung ist die Codetabelle dem Coder und dem Decoder bekannt.
Bei der dynamischen Kodierung wird der Prefixcode für den jeweiligen Datenstrom (Block)
neu berechnet. In diesem Fall muss neben dem kodierten Signal jedoch zusätzlich die gültige
Codeworttabelle übertragen werden.
Die adaptive Variante geht von einer initialen Codetabelle (oftmals leer) aus, aktualisiert diese
aber während des Kodierens. Der Decoder aktualisiert seine Codetabelle entsprechend.
Minimaleigenschaft:
Bei der der Huffman-Kodierung will man unter der Annahme der shannonschen Quelle die
Länge der kodierten Nachricht möglichst gering halten. Bezeichnet h(x) die absolute
Häufigkeit des Zeichens x in der Nachricht N über dem Alphabet A und l(x) die Länge der
Kodierung des Zeichens, dann ist die Länge l(N) der kodierten Nachricht offenbar durch
gegeben. Betrachtet man zum Beispiel die Nachricht "baa", so gilt: h(a)= 2 und h(b)= 1. Wird
dabei "a" mit einer Länge von 3 und "b" mit einer Länge von 4 kodiert, so erhält man:
Die kodierte Nachricht hat also eine Länge von 10. Ziel bei der Konstruktion eines HuffmanKodes zu einer endlichen Nachricht ist die Minimierung der Länge l(N) durch geeignete Wahl
der l(x). Unter der Annahme einer shannonschen Quelle ist für jedes Zeichen, welches in der
Nachricht auftreten kann, also aus dem Alphabet A, über welchem die Nachricht kodiert ist,
stammt, die relative Auftrittswahrscheinlichkeit durch Abzählung oder Abschätzung
ermittelbar. Mithilfe dieser Wahrscheinlichkeiten p(x) ermittelt man die Entropie H, den
mittleren Informationsgehalt pro Zeichen, der Nachr icht zu
wobei ld der Logarithmus zur Basis zwei ist. Unter der Betrachtung der Entropie lässt sich die
Minimaleigenschaft des gesuchten Kodes anders formulieren: Die durchschnittliche
Kodierungslänge D des Kodes, welche durch
gegeben ist, wobei l(x) die Kodierungslänge des Zeichens x und p(x) die
Auftrittswahrscheinlichkeit des Zeichens x aus dem Alphabet A sei, soll minimiert werden.
Man sucht also den Kode derart, dass es keinen Kode gibt, welche eine geringere
durchschnittliche Kodierungslänge der Zeichen hat. Dabei kann die durchschnittliche
Kodierungslänge D nicht geringer als die theoretische Grenze der Entropie H werden. Im
Idealfall hat also der gesuchte Kode eine durchschnittliche Kodierungslänge, welche der
Entropie entspricht, wobei dieser Fall auftritt, wenn die Wahrscheinlichkeiten Potenzen von
zwei sind.
Betrachtet man dabei speziell eine endliche Nachricht und setzt die
Auftrittswahrscheinlichkeiten zu den Häufigkeiten der Zeichen in der Nachricht, so ergibt
sich die zuerst betrachtete Festlegung der Minimalbedingung, welche die kodierte Länge der
Nachricht minimieren soll.
Baumdarstellung:
Kodes lassen sich sehr anschaulich mithilfe von Bäumen darstellen. Jeder Knoten hat eine
bestimmte Anzahl von Nachfolger, wobei diese Anzahl durch die Anzahl der Zeichen im
Kodealphabet beschränkt ist. Nachrichten werden sehr oft über dem Alphabet {0, 1} kodiert,
in diesem Fall entsteht ein binärer Baum. Jede Kante des Baumes wird derart mit einem
Zeichen aus dem Kodealphabet versehen, dass jeder Knoten höchstens eine abgehende Kante
mit einem bestimmten Zeichen des Kodealphabets besitzt. Hätte ein Knoten zwei abgehe nde
Kanten mit gleicher Bezeichnung, so könnte man die Knoten, an welchen die Kanten enden,
zu einem Knoten zusammenfassen. Dies könnte aber dazu führen, dass eine bestimmte Folge
von Kodezeichen mehrere Zeichen kodiert, was natürlich nicht zugelassen ist.
Binäre Kodierung in Baumdarstellung
Die Zuordnung des Kodes zu einem Zeichen ist einfach gegeben durch die Folge der Kanten,
wenn man von der Wurzel aus zu dem Zeichen geht, dabei ist der Weg eindeutig, denn ein
Baum ist frei von Zyklen.
Finden des Kodes eines bestimmten Zeichens,
"C" wird durch "110" kodiert
Durch die Darstellung mithilfe eines Baumes hat man offenbar eine weitere Charakterisierung
für die Erfüllung der Präfixbedingung gewonnen: Eine Zuordnung ist genau dann ein
Präfixkode, falls alle Knoten, welche zu Zeichen gehören, Blätter des Baumes sind, also keine
Nachfolger haben.
Aufwandsbetrachtung:
Eine für die Konstruktion eines Huffman-Kodes günstige Datenstruktur ist die Halde, welche
bei einer Größe von m Elementen für Einfügen und Löschen nur O(log(m)) Schritte benötigt.
Mithilfe einer Halde lässt sich die Konstruktion des Huffman-Kodes wie folgt durchführen
Man speichert in der Halde nur die noch zu betrachtenden Knoten mit deren Häufigkeiten ab,
so sind zu Anfang die n in der Nachricht vorkommenden, verschiedenen Zeichen in der
Halde. In jedem Schritt werden die beiden Knoten mit minimaler Gewichtung von der Halde
entfernt und zu einem neuen Knoten, welcher in die Halde eingefügt wird, zusammengefasst.
Da jedes Einfügen und Löschen in O(log(n)) Schritten durchgeführt werden kann und O(n)
Schritte ausreichen, da anfangs n Elemente vorhanden sind und in jedem Schritt eines weniger
auf der Halde bleibt, kann man den Huffman-Kode in O(n*log(n)) Schritten konstruieren,
wenn man annimmt, dass die Häufigkeiten der n Zeichen bekannt sind.
Anwendung von Huffman-Kodes:
Für Kodierungen von Zeichen verwendet ma n im Allgemeinen keine Kodes, welche
verschiedene Längen haben, weil diese einen sehr hohen Aufwand zur Folge haben. Deshalb
werden Huffman-Kodes nur in Ausnahmefällen eingesetzt, um eine geeignete Kodierung für
Zeichen
zu
finden,
wie
zum
Beispiel
beim
Morsealphabet.
Eine weitere Einsatzmöglichkeit von Huffman-Kodes eröffnet sich durch ihre Eigenschaft, die
Länge kodierter Nachrichten zu minimieren. Dabei werden Huffman-Kodes nur im Verbund
mit anderen Methoden zur Kompression eingesetzt, vor allem bei Bild- oder Audiodaten. Dies
ist darauf zurückzuführen, dass bei der Kodierung mit Huffman-Kodes angenommen wird,
dass eine shannonsche Nachricht vorliegt. Da dies fast nie gegeben ist und darüber hinaus für
häufig vorkommende Daten, wie zum Beispiel Text, Bilder oder Musik, wesentlich bessere
Methoden zur Kompression zur Verfügung stehen, wird der Huffman-Kode nie alleine zur
Kompression von Daten verwendet. Huffman-Kodes sind als Ergänzung der Kompression in
verschiedenen Dateiformaten aufzufinden. Im JPEG-Format (Joint Graphic Experts Group)
für Bilddaten kommt neben einer diskreten Kosinustransformation (DCT) auch die HuffmanKodierung zum Einsatz, um Bilder mit möglichst wenig Speicherverbrauch zu speichern.
Im PNG-Format (Portable Network Graphic-Format) wird die Huffman-Kodierung eingesetzt,
um Bilder ohne Verlust zu komprimieren. Im MP3-Format für Audiodaten kommt neben
einigen anderen Verfahren die Huffman-Kodierung zum Einsatz, um schon verlustbehaftete
Daten weiter ohne Verlust zu komprimieren (circa 20% Kompression möglich). Bei diesem
Format ergänzen sich die Huffman-Kodierung und andere Verfahren derart, dass oft immer
ein Verfahren eine gute Kompression leistet. Im MPEG-Format für Bilddaten ist neben
verlustbehafteten Methoden die Huffman-Kodierung zur nachträglichen Reduktion der Daten
eingesetzt. Die verbreiteten Komprimierungsprogramme bzip und bzip2 verwenden neben
einem Burrows-Wheeler-Algorithmus ebenfalls die Huffman-Kodierung, um Daten
beliebigen Typs ohne Verlust zu komprimieren.
Dynamisches Huffman-Verfahren:
Der Text wird in Blöcke unterteilt, welche mit dem normalen Huffman-Verfahren
komprimiert werden. Dabei wird für jeden Block eine eigene Codetabelle ermittelt, mit dieser
dann der Block komprimiert wird. Beides (Codetabelle und komprimierter Block) werden
zusammen übermittelt. Beim Dekomprimieren wird die jeweilige Codetabelle benutzt um den
dazugehörigen Block zu entschlüsseln. Die dekomprimierten Blöcke ergeben in der richten
Reihenfolge aneinandergereiht wieder den Ausgangstext.
Komprimieren eines Blockes nach Standard-Huffman:
-
Ermitteln der absoluten Zeichenhäufigkeiten über den ganzen Block
Wald erstellen mit Zeichen und zugehörigen Häufigkeiten
Solange bis nur noch 1 fertiger Baum entstanden ist
o immer die zwei Bäume mit den minimalen Häufigkeiten durch einen Parentknoten verknüp fen, dem die Summe der Häufigkeiten der beiden Teilbäume
zugewiesen wird.
è Baum aus dem man die Kodes für jedes Zeichen ablesen kann
è Kodetabelle
è Kodetabelle abspeichern und ersetzen der Zeichen durch den erhaltenen Bitcode
Vorteil der Unterteilung in Blöcke:
Die dynamische Huffmancodierung bildet das Verfahren auf eine Blocklänge größer als eins
ab. Der einfache Ansatz kann bei einer ungleichmäßigen Wahrscheinlichkeitsverteilung, also
wenn auf ein Symbol ein großes Gewicht fällt und andere dafür kaum vorkommen, stark von
der Entropie abweichen. Diesem kann man entgegenwirken, wenn man Blöcke aus mehreren
Symbolen zur Codelänge benutzt. Allgemein kann man so eine durchschnittliche Codelänge
erreichen, die näher an der Entropie liegt.
Beispiel für das Komprimieren eines Blockes:
Inhalt des Blockes:
„halloballo“
Ermittelte Zeichen, die im Text vorkommen und deren absolute Häufigkeit:
Zeichen
Habsolut
h
1
a
2
l
4
o
2
b
1
o
111
b
101
Resultierender Huffmanbaum:
10
6
2
4
1
2
4
2
1
h
a
l
o
b
Resultierende Codetabelle:
Zeichen
Code
h
100
a
110
l
0
Komprimierter Text:
100 110 0 0 111 101 110 0 0 111
Länge: 22 bit
Bei der 7bit-ASCII-Codierung hätte sich eine Länge von 10 Zeichen * 7 bit = 70 bit ergeben.
Komprimierungsleistung: 69 % (bei Vernachlässigung der Codetabelle)
Adaptives Huffman-Verfahren:
Bei diesem Verfahren kennt man die Häufigkeiten der Symbole zuerst nicht, allerdings wird
beim enkodieren der Codebaum adaptiv aus den vorkommenden Symbolen aufgebaut,
ausgehend von dem Fall der Gleichverteilung. So passen sich die Codes im Laufe der Datei
immer besser an die Häufigkeiten an. Da derselbe Prozess auch beim Decodieren verwendet
wird, kann dieser Prozess auch eindeutig Rückgängig gemacht werden.
Der Huffmanbaum wird folgendermaßen aufgebaut:
-
-
-
Anfangsbaum der nur aus NYT (Escape)-Knoten besteht, der Gewicht NULL hat
Zeichen einlesen
wenn Zeichen noch nicht im Baum enthalten dann:
o Suche NYT und erhöhe dessen Wichtung und die der Knoten auf dem Pfad
dort hin um 1
o Anhängen von 2 Blättern an das NYT-Blatt à wird zum Knoten und ist daher
unmarkiert
o linkes Blatt = neues NYT mit Wichtung 0
o rechtes Blatt = neues Zeichen mit Wichtung 1
o Ausgabe des Bitcodes der zum neuen Zeichen führt, gefolgt vom neuen
Zeichen
sonst:
o suche Zeichen
o alle Knotenwichtungen auf dem Pfad zwischen Wurzel und Zeichen um 1
erhöhen
o Ausgabe des Bitcodes
Überprüfung der Wichtungen:
o Die Knotenwichtungen einer Ebene müssen immer kleiner sein als die der
übergeordneten Ebene, sonst tausche die Teilbäume !
o Wichtungen von Knoten einer Ebene müssen von links nach rechts aufsteigend
sortiert sein, sonst sortierendes Tauschen!
NYT bedeutet „not yet transmitted“, das heißt, dass an seiner Stelle Zeichen eingefügt
werden, die bis jetzt noch nicht aufgetreten sind.
Im Folgenden soll anhand des Textes „halloballo“ die Funktionsweise des adaptiven
Huffmanverfahrens nahe gebracht werden.
NYT
Begonnen wird mit einem Baum, der nur aus dem NYT-Knoten mit der Wichtung 0 besteht.
Als erstes Zeichen wurde das „h“ transferiert. Jedes neue Zeichen wird rechts an den NYTKnoten gehangen mit der Wichtung 1. Außerdem wird links ein neues Blatt angehangen, das
der neue NYT-Knoten mit der Wichtung 0 wird. Der alte NYT-Knoten verliert seine
Markierung und erhält die Summe der Wichtungen seiner Söhne.
Ausgabe: h
Wieder wird ein neues Zeichen eingefügt, das „a“. Damit der Decoder weiß, dass ein neues
Zeichen folgt, wird ihm der Pfad zum NYT-Knoten übermittelt, gefolgt vom neuen Zeichen.
Die Wichtungen aller Knoten werden von unten nach oben aktualisiert, so dass jeder Knoten
die Summe der Wichtungen seiner Söhne als Wichtung erhält. Dieser Schritt wird nach jeder
Änderung am Baum durchgeführt.
Ausgabe: 0 a
Nach dem Einfügen des „l“ am NYT-Knoten und der Aktualisierung der Wichtungen erweist
es sich als notwendig, die beiden Teilbäume zu vertauschen, da rechts immer der Sohn mit der
höheren Wichtung hängen muss.
Ausgabe: 0 0 l
Ein weiteres „l“ wurde übermittelt. Da das Zeichen im Baum bereits vorhanden ist, wird die
Wichtung des „l“-Knotens um 1 erhöht. Der Weg zum „l“-Knoten wird ausgegeben und die
Wichtungen aktualisiert. Da der „l“-Knoten nun die Wichtung 2 hat, somit „schwerer“ ist als
der „h“-Knoten, und die Regel „ Für jeden Knoten k1 und k2 mit dem Level l1 und l2 muss gelten,
wenn l1<l2, dann w(k1)>=w(k2).“ beachtet werden muss, war es notwendig den „l“-Knoten mit
dem „h“-Knoten zu vertauschen.
Ausgabe: 1 0 1
Das „o“ wird als neues Zeichen am NYT-Knoten angefügt und die Wichtungen aktualisiert.
Danach ist es erforderlich den Knoten „a“ mit seinem linken Bruder zu vertauschen, da dieser
nun eine höhere Wichtung besitzt als er. Es gilt: „Die Wichtung eines rechten Sohnes muss
immer größer gleich der Wichtung des linken Sohnes sein.“
Ausgabe: 1 0 0 o
Da nun alle Regeln erläutert wurden, beschränken wir uns nun nur noch auf die Ausgabe.
Ausgabe: 1 1 0 0 b
Ausgabe: 1 1 0
Ausgabe: 1 1
Ausgabe: 1 1
Ausgabe: 1 0 1
Komprimierter Text:
h 0 a 0 0 l 1 0 1 1 0 0 o 1 1 0 0 b 1 1 0 1 1 0 1 1 1 1 1 0 1
Länge (ohne Buchstaben1 ): 26 bit
Bei der 7bit-ASCII-Codierung hätte sich eine Länge von 10 Zeichen * 7 bit = 70 bit ergeben.
Komprimierungsleistung: 63 %
Vergleich der beiden Verfahren:
Dynamisches Verfahren
Adaptives Verfahren
Vorteile
einfaches Verfahren zur Erzeugung des
Huffmanbaumes
bei Beschädigung eines Blockes ist nur
dieser beschädigt
Daten müssen nur einmal eingelesen werden
Nachteile
zweimaliges Einlesen der Daten notwendig
1
stark anfällig für Fehler
aufwendige Verwaltung des Huffmanbaumes
Die Buchstaben werden nicht mit gezählt, da sie jeweils nur ein mal auftreten und dadurch bei längeren Texten
nicht ins Gewicht fallen.
Quellenverzeichnis:
Sedgewick, R., Algorithmen, Addison-Wesley, Bonn, München, Paris [u.a.], 1992.
Heun, V., Grundlegende Algorithmen, Vieweg, 1. Auflage, Oktober 2000
Internetquellen:
Übersicht über Varianten von Huffmans Algorithmen
http://www.dbg.rt.bw.schule.de/lehrer/ritters/info/kompr/huffman.htm
Algorithmen à Datenkompression an der FH Flensburg
http://www.iti.fh- flensburg.de/lang/algorithmen/code/huffman/huffman.htm
Applet zum dynamischen Huffman-Verfahren
http://www.cs.sfu.ca/cs/CC/365/li/squeeze/Huffman.html
Applet zum adaptiven Huffman-Verfahren
http://www.cs.sfu.ca/cs/CC/365/li/squeeze/AdaptiveHuff.html
Funktions weise des adaptiven Huffman-Verfahrens
http://www.cs.cf.ac.uk/Dave/Multimedia/node212.html
http://www.cs.duke.edu/csed/curious/compression/adaptivehuff.html#encoding
Herunterladen