01.11.2013 Aufrufe

2 Nachricht, Information und Codierung

2 Nachricht, Information und Codierung

2 Nachricht, Information und Codierung

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

88 3 <strong>Codierung</strong><br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

3.4 Datenkompression<br />

.<br />

.<br />

.<br />

3.4.5 Der LZW-Algorithmus<br />

Kompression von korrelierten Zeichengruppen<br />

Für die verlustfreie Kompression beliebiger Daten hat sich als sehr effizientes Verfahren der<br />

nach seinen Erfindern Lempel, Ziv <strong>und</strong> Welch benannte LZW-Algorithmus durchgesetzt<br />

[Ziv77]. Es handelt sich dabei um ein statistisches Verfahren, das aber anders als das Huffman-Verfahren<br />

oder die arithmetische <strong>Codierung</strong> nicht nur Einzelzeichen codiert, sondern<br />

Zeichengruppen unterschiedlicher Länge. Dadurch lassen sich nicht nur die Häufigkeiten von<br />

Einzelzeichen bei der <strong>Codierung</strong> berücksichtigen, sondern auch durch Korrelationen aufeinander<br />

folgender Zeichen bedingte Red<strong>und</strong>anzen. Der LZW-Algorithmus minimiert also auch<br />

Red<strong>und</strong>anzen, die dadurch entstehen, dass sich identische Zeichenfolgen (Strings) in den<br />

Eingabedaten mehrmals wiederholen. Dies führt zu einer umso besseren Kompressionswirkung,<br />

je häufiger solche Wiederholungen auftreten <strong>und</strong> je länger die sich wiederholenden<br />

Zeichengruppen sind. Das Ergebnis der Kompression besteht dann aus einer weit gehend<br />

unkorrelierten Zeichenfolge, die verlustfrei nicht mehr weiter komprimierbar ist.<br />

Das Prinzip des LZW-Algorithmus<br />

Der LZW-Algorithmus arbeitet mit einer Code-Tabelle in der jeder Eintrag aus einem String<br />

mit Zeichen des Quell-Alphabets <strong>und</strong> dem zugehörigen komprimierten Code besteht. Die<br />

Code-Tabelle wird am Anfang mit allen Einzelzeichen des Quell-Alphabets vorbesetzt <strong>und</strong><br />

während der Kompression nach <strong>und</strong> nach erweitert <strong>und</strong> an die Eingabe angepasst. Wegen<br />

dieser automatischen Anpassung benötigt der LZW im Voraus keinerlei <strong>Information</strong>en über<br />

die Statistik des Eingabetextes; er kann daher als Ein-Schritt-Verfahren realisiert werden.<br />

Auch muss die Code-Tabelle nicht zusammen mit den codierten Daten gespeichert bzw.<br />

übertragen werden, da sie im Decoder aus den codierten Daten in identischer Weise wieder<br />

neu erzeugt werden kann.<br />

Zu Beginn der <strong>Codierung</strong> muss jedes Zeichen des Eingabetextes einzeln codiert werden,<br />

weil ja die Code-Tabelle nur mit den Einzelzeichen des Quell-Alphabets vorbesetzt ist <strong>und</strong><br />

noch keine längeren Strings enthält. Zu Beginn ist also noch kein Kompressionseffekt zu<br />

erwarten. Im Laufe der Verarbeitung sammeln sich aber in der Tabelle immer mehr <strong>und</strong> immer<br />

längere mehrfach aufgetretene Strings an, von denen angenommen werden kann, dass<br />

sie im noch zu komprimierenden Text ebenfalls noch häufig auftreten werden. Dadurch steigt<br />

die Effizienz der Kompression immer weiter an, bis die Code-Tabelle vollständig gefüllt ist.<br />

Danach geht die Anpassungseigenschaft des Algorithmus verloren. Die Kompressionsrate<br />

bleibt dann zunächst gleich, sie kann sich aber auch wieder verschlechtern, wenn sich die<br />

Charakteristika der Eingabedaten ändern. Dem kann man durch Erstellen einer neuen Code-<br />

Tabelle entgegenwirken.<br />

Der Kompressions-Algorithmus<br />

Die <strong>Codierung</strong> einer Zeichenkette Z läuft nun nach folgendem Schema ab: zunächst wird das<br />

nächste Eingabezeichen c des Eingabestrings Z eingelesen <strong>und</strong> an den als Präfix bezeichneten<br />

Anfangs-Teilstring P des Strings Z angehängt, es wird also der String Pc gebildet. Zu<br />

Beginn wird der Präfix P mit dem leeren String vorbesetzt. Ist Pc in der Code-Tabelle bereits


3 <strong>Codierung</strong> 89<br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

vorhanden, so wird P=Pc gesetzt <strong>und</strong> das nächste Zeichen eingelesen. Andernfalls wird P<br />

ausgegeben, Pc in die Code-Tabelle eingetragen <strong>und</strong> der neue Präfix P=c gesetzt. Kommt<br />

der soeben eingetragene Teilstring Pc später im Text nochmals vor, so kann er durch ein<br />

einziges Code-Wort ersetzt werden. Darauf beruht letztlich die komprimierende Wirkung des<br />

LZW-Verfahrens.<br />

Der Kompressions-Algorithmus lautet damit in Pseudo-Code-Formulierung:<br />

LZW-Algorithmus zur Kompression eines Strings Z<br />

Initialisiere die Code-Tabelle mit den Einzelzeichen<br />

Weise dem Präfix P den Leerstring zu<br />

Wiederhole, solange Eingabezeichen vorhanden sind:<br />

Lies nächstes Eingabezeichen c aus dem Eingabestring Z<br />

Wenn Pc in der Code-Tabelle gef<strong>und</strong>en wird:<br />

setze P=Pc<br />

Sonst:<br />

Trage Pc in die nächste freie Position der Code-Tabelle ein<br />

Gib den Code für P aus<br />

setze P=c<br />

Ende der Schleife<br />

Gib den Code für das letzte Präfix P aus<br />

Beispiel: LZW-Kompression der Zeichengruppe ABABCBABAB.<br />

Als Beispiel wird die Zeichenkette Z=ABABCBABAB betrachtet. Die Code-Tabelle wird mit<br />

den Zeichen A, B, C des Quell-Alphabets <strong>und</strong> den entsprechenden Codes des Ausgabealphabets<br />

vorbesetzt. Wählt man für das Beispiel als maximale Länge der Code-Tabelle sieben<br />

Einträge, so benötigt man in der Ausgabe 3 Bit pro Code-Wort. Die Code-Tabelle wird<br />

also folgendermaßen vorbesetzt:<br />

Tabelle 3.4.6: Vorbesetzung der Code-Tabelle für die Kompression des Strings Z=ABABCBABAB mit<br />

dem LZW-Algorithmus.<br />

Präfix Ausgabe-Code<br />

A 0 = 000<br />

B 1 = 001<br />

C 2 = 010<br />

- 3 = 011<br />

- 4 = 100<br />

- 5 = 101<br />

- 6 = 110<br />

- 7 = 111<br />

Der <strong>Codierung</strong>svorgang läuft damit folgendermaßen ab:


90 3 <strong>Codierung</strong><br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

Tabelle 3.4.7: <strong>Codierung</strong> des Strings Z=ABABCBABAB mit dem LZW-Algorithmus. Das aktuell verarbeitete<br />

Zeichen ist unterstrichen dargestellt. Die codierte <strong>Nachricht</strong> lautet 013247.<br />

Schritt String Z Präfix P Eintrag in die Code-Tabelle Ausgabe<br />

0 ABABCBABAB - Vorbesetzung -<br />

1 ABABCBABAB A - -<br />

2 ABABCBABAB B AB=3 0<br />

3 ABABCBABAB A BA=4 1<br />

4 ABABCBABAB AB - -<br />

5 ABABCBABAB C ABC=5 3<br />

6 ABABCBABAB B CB=6 2<br />

7 ABABCBABAB BA - -<br />

8 ABABCBABAB B BAB=7 4<br />

9 ABABCBABAB BA - -<br />

10 ABABCBABAB BAB - -<br />

11 ABABCBABAB - - 7<br />

Nach Beendigung der <strong>Codierung</strong> hat der Inhalt der Code-Tabelle die Form:<br />

Tabelle 3.4.8: Code-Tabelle nach Beendigung der Kompression des Strings Z=ABABCBABAB.<br />

Präfix Ausgabe-Code<br />

A 0 = 000<br />

B 1 = 001<br />

C 2 = 010<br />

AB 3 = 011<br />

BA 4 = 100<br />

ABC 5 = 101<br />

CB 6 = 110<br />

BAB 7 = 111<br />

Methoden zur Optimierung des Verfahrens<br />

Weil jeder neue Eintrag in der Code-Tabelle nur eine Verlängerung eines bereits in der Code-Tabelle<br />

enthaltenen Strings darstellt, ist es nicht nötig, zu jedem Code den vollständigen<br />

String zu speichern. Es empfiehlt sich statt dessen, nur das letzte Zeichen des Strings zu<br />

speichern <strong>und</strong> einen Verweis auf den String, aus dem er hervorgegangen ist. Der Code ABC<br />

aus dem obigen Beispiel wird dann als 4C abgespeichert. Dadurch erfordert jeder Tabelleneintrag<br />

bei 8 Byte Eingabezeichen <strong>und</strong> 12 bis 16 Bit Code nur drei Byte: ein Byte für das<br />

letzte Zeichen <strong>und</strong> zwei für den Verweis. Meist werden 12 Bit Codes verwendet, entsprechend<br />

4096 Tabelleneinträgen oder 13 Bit Codes, entsprechend 8192 Einträgen. Bei einer<br />

Verlängerung der Code-Tabelle können zwar mehr <strong>und</strong> längere Teilstrings abgespeichert<br />

werden; dies führt jedoch nicht unbedingt zu einer Verbesserung der Kompressionsrate, weil<br />

eine größere Tabelle auch zu längeren Code-Wörtern führt. Insbesondere zu Beginn der<br />

Kompression, wenn noch Einzelzeichen codiert werden, führt dies zunächst nicht zu einer<br />

Kompression, sondern zu einer Verlängerung des Textes.<br />

Relativ einfach zu realisieren ist, dass nicht immer die volle Länge der Codes übertragen<br />

werden muss. Solange in der Tabelle nicht mehr als 512 Einträge sind, reichen 9 Bit für die<br />

Darstellung der Code-Wörter aus, zwischen 513 <strong>und</strong> 1024 Einträgen genügen 10 Bit usw.<br />

Sowohl der Kompressor als auch der Dekompressor (siehe unten) können anhand ihrer Code-Tabelle<br />

feststellen, mit welcher Wortlänge gerade gearbeitet wird <strong>und</strong> die Wortlänge erhöhen,<br />

sobald ein längerer Code in die Tabelle eingetragen wird. Oft wird auch die Erhöhung<br />

der Wortlänge durch ein eigenes, dafür reserviertes Code-Wort signalisiert, weil dann nicht<br />

schon beim Eintragen eines längeren Code-Wortes in die Tabelle umgeschaltet werden<br />

muss, sondern erst dann, wenn tatsächlich das erste längere Code-Wort verwendet wird.<br />

Wenn die Code-Tabelle vollständig gefüllt ist, kann man entweder mit dieser Tabelle weiterarbeiten<br />

oder aber die Tabelle löschen <strong>und</strong> mit einer neu initialisierten Tabelle fortfahren. Bei


3 <strong>Codierung</strong> 91<br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

der zweiten Strategie sinkt zwar die Kompressionsrate zunächst, aber die Code-Tabelle<br />

kann dafür wieder neu an die Eigenschaften der Eingabedaten angepasst werden. Dies erweist<br />

sich dann als sinnvoll, wenn damit zu rechnen ist, dass sich die Charakteristik der Daten<br />

ändern wird. Dies ist insbesondere bei der Kompression von Bilddaten der Fall. Eine<br />

Neuinitialisierung der Code-Tabelle muss in den komprimierten Daten allerdings durch Einfügen<br />

eines dafür reservierten Code-Worts kenntlich gemacht werden.<br />

Bei der Komprimierung der Daten muss bei jedem Schritt nach dem String Pc gesucht werden,<br />

also dem aktuellen Präfix plus nächstes Eingabezeichen. Eine sequentielle Suche würde<br />

sehr viel Zeit benötigen, so dass sich die Verwendung einer Hash-Tabelle (siehe Kapitel<br />

11.3) empfiehlt. Dazu wird neben der Code-Tabelle noch eine Hash-Tabelle zur Speicherung<br />

von Verweisen auf die Code-Tabelle aufgebaut.<br />

Eine weitere Verbesserung, allerdings auf Kosten der Ausführungszeit, kann erzielt werden,<br />

wenn man das Verfahren nicht einschrittig auslegt, sondern eine statistische Analyse vorschaltet.<br />

Besonders häufig auftretende Strings können so vorab ermittelt <strong>und</strong> bereits bei der<br />

Initialisierung der Code-Tabelle berücksichtigt werden.<br />

Der Dekompressions-Algorithmus<br />

Die Dekompression ist zunächst etwas unanschaulicher, aber auch nicht schwieriger zu implementieren<br />

als die Kompression. Zunächst wird wie bei der Kompression eine Code-Tabelle<br />

angelegt, <strong>und</strong> mit den Eingabezeichen vorbesetzt. Der Dekompressor liest nun ein Zeichen<br />

nach dem anderen ein, sucht den zugehörigen String in der Code-Tabelle auf <strong>und</strong> gibt ihn<br />

aus. Zusätzlich wird an den im vorherigen Schritt decodierten String das erste Zeichen des<br />

aktuell decodierten Strings angehängt <strong>und</strong> das Ergebnis in die nächste freie Position der<br />

Code-Tabelle eingetragen. Auf diese Weise wird schrittweise dieselbe Code-Tabelle aufgebaut,<br />

mit der auch der Kompressor gearbeitet hat. Es gibt dabei jedoch eine Komplikation:<br />

Wenn bei der Kompression ein String in die Code-Tabelle eingetragen <strong>und</strong> im nächsten<br />

Schritt bereits wieder verwendet wurde, so kann er bei der Dekompression an dieser Stelle<br />

noch nicht in der Tabelle enthalten sein. In diesem Fall ist aber klar, dass der fehlende Code<br />

einfach durch Verlängerung des Präfix um das erste Zeichen des zuvor ausgegebenen<br />

Strings entsteht. Der in die Code-Tabelle einzutragende String ist in diesem Sonderfall mit<br />

dem auszugebenden String identisch. Der Algorithmus lautet damit als Pseudo-Code:<br />

LZW-Algorithmus zur Dekompression einer <strong>Nachricht</strong><br />

Initialisiere die Code-Tabelle mit den Einzelzeichen<br />

Weise dem Präfix P den Leerstring zu<br />

Wiederhole, solange Eingabezeichen vorhanden sind:<br />

Lies nächstes Eingabezeichen c<br />

Wenn c in der Code-Tabelle enthalten ist:<br />

Gib den zu c gehörenden String aus<br />

Setze k = erstes Zeichen dieses Strings<br />

Trage Pk in die Code-Tabelle ein, falls noch nicht vorhanden<br />

Setze P auf den zu dem Code c gehörigen String<br />

Sonst (Sonderfall):<br />

setze k = erstes Zeichen von P<br />

Gib Pk aus<br />

Trage Pk in die Code-Tabelle ein<br />

Setze P=Pk<br />

Ende der Schleife<br />

Gib letztes Präfix aus


92 3 <strong>Codierung</strong><br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

Beispiel: Dekompression<br />

Als Beispiel wird nun das weiter oben gewonnene Kompressions-Ergebnis 013247 des<br />

Strings ABABCBABAB wieder dekomprimiert. Zunächst wird die leere Code-Tabelle mit den<br />

Zeichen A, B <strong>und</strong> C vorbesetzt. Der Dekompressor liest dann das erste Code-Zeichen (=0)<br />

ein, sucht das zugehörige Zeichen des Quell-Alphabetes in der Code-Tabelle (=A) <strong>und</strong> gibt<br />

dieses Zeichen aus. Anschließend wird das nächste Zeichen (=1) eingelesen, decodiert (=B)<br />

<strong>und</strong> ausgegeben. Zusätzlich wird jetzt der String AB, bestehend aus dem zuvor decodierten<br />

Zeichen A <strong>und</strong> dem soeben decodierten Zeichen B auf die Nächste freie Position, hier also<br />

3, der Code-Tabelle eingetragen. Das als Nächstes eingelesene Zeichen (=3) ergibt den<br />

Ausgabestring AB, der soeben erst in die Code-Tabelle eingetragen wurde. Zusätzlich wird<br />

der String BA, bestehend aus dem Zeichen B des vorhergehenden Schritts <strong>und</strong> dem ersten<br />

Zeichen des Strings AB, in die Code-Tabelle eingetragen. Die weiteren Schritte der Decodierung<br />

ergeben sich aus der nachstehenden Tabelle.<br />

Tabelle 3.4.9: Decodierung der komprimierten <strong>Nachricht</strong> 013247 mit dem LZW-Algorithmus. Das<br />

aktuell verarbeitete Zeichen ist jeweils unterstrichen dargestellt. Es wird wieder die ursprüngliche<br />

<strong>Nachricht</strong> ABABCBABAB aufgebaut.<br />

Schritt Code-String Eintrag in Code-Tabelle Ausgabe-String=Präfix<br />

0 013247 Vorbesetzung -<br />

1 013247 - A<br />

2 013247 AB B<br />

3 013247 BA AB<br />

4 013247 ABC C<br />

5 013247 CB BA<br />

6 013247 BAB BAB<br />

Man erkennt, dass der Dekompressor tatsächlich dieselben Strings in die Code-Tabelle einträgt<br />

wie der Kompressor, allerdings immer einen Schritt später. Der Dekompressor kann<br />

beispielsweise den String AB erst dann eintragen, wenn er auch den Code für B bereits verarbeitet<br />

hat, weil erst dann bekannt ist, dass bei der Komprimierung auf das Zeichen A ein B<br />

folgte. Dieses Nachhinken kann zu dem oben bereits erwähnten Sonderfall führen, dass ein<br />

benötigter Code in der Code-Tabelle noch nicht enthalten ist. In dem betrachteten Beispiel ist<br />

dies in Schritt 6 der Fall. Dort trifft der Dekompressor auf den Code 7, den er in der Code-<br />

Tabelle nicht findet, weil dafür noch kein String eingetragen worden ist. Wenn dieser Fall<br />

eintritt, ist aber bekannt, dass der fehlende String mit demselben Zeichen beginnen muss,<br />

wie der unmittelbar zuvor decodierte <strong>und</strong> ausgegebene String.


3 <strong>Codierung</strong> 93<br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

3.4.6 Datenreduktion durch unitäre Transformationen (JPEG)<br />

Die Fourier-Transformation<br />

In vielen technischen Anwendungen werden Daten, insbesondere Messdaten <strong>und</strong> Bilder, mit<br />

Hilfe der Fourier-Transformation in eine Frequenzdarstellung transformiert. In diesem Kapitel<br />

wird gezeigt, dass auf diese Weise auch eine sehr effiziente Datenkompression erreicht werden<br />

kann. Die Fourier-Transformation wird durch Integrale vermittelt, die im Falle diskreter<br />

Daten durch Summen ersetzt werden können; man spricht dann von der diskreten Fourier-<br />

Transformation, für die es sehr effiziente Algorithmen gibt. Der bekannteste ist der DFFT-<br />

Algorithmus (von Diskrete Fast Fourier Transform). Damit kann man eine aus N Punkten bestehende<br />

Datenmenge f n in ihre Entsprechung F n im Frequenzraum transformieren:<br />

F<br />

u<br />

=<br />

1<br />

N<br />

N<br />

∑ − 1<br />

f<br />

n<br />

n=<br />

0<br />

e<br />

−2πinu/N<br />

Fourier-Transformation<br />

Die Formel für die Rücktransformation lautet:<br />

N−1<br />

2 /N<br />

f<br />

n<br />

= ∑ Fue<br />

πinu Fourier-Rücktransformation<br />

u=<br />

0<br />

Die Summen in diesen Gleichungen lassen sich durch Multiplikation einer die Exponentialterme<br />

enthaltenden Matrix mit einem Vektor darstellen, dessen Komponenten die zu transformierenden<br />

Daten sind. Die einzelnen Komponenten des transformierten Vektors ergeben<br />

sich also durch Berechnung des Skalarproduktes aus der entsprechenden Matrixzeile mit<br />

dem Datenvektor. Betrachtet man die Zeilen der Matrix als Basisvektoren, so wird durch das<br />

Skalarprodukt diejenige Komponente des Datenvektors transformiert, die in Richtung des<br />

entsprechenden Basisvektors zeigt.<br />

Unitäre <strong>und</strong> orthogonale Transformationen<br />

Dieses Prinzip soll nun verallgemeinert werden. Dazu wird bei der Fourier-Transformation<br />

die Exponentialfunktion e -i2πnu/N durch eine zunächst beliebige, als Kern der Transformation<br />

bezeichnete Matrix K der Dimension N mit den Komponenten K nu ersetzt <strong>und</strong> bei der Rücktransformation<br />

durch die zu K inverse Matrix K -1 :<br />

F<br />

f<br />

1<br />

=<br />

N<br />

N−1<br />

∑<br />

fK<br />

u n nu<br />

n=0<br />

N−1<br />

−1<br />

n<br />

= ∑ FuK nu<br />

u=0<br />

allgemeine unitäre Transformation<br />

unitäre Rück-Transformation<br />

Damit sich eine sinnvolle Transformation ergibt, müssen die Basisvektoren des Kerns, also<br />

die Zeilen der Matrix K, einen Vektorraum mit Dimension N aufspannen. Dies ist dann der<br />

Fall, wenn alle N Zeilenvektoren (Basisvektoren) linear unabhängig, also in einer geometrischen<br />

Betrachtungsweise nicht parallel zueinander sind. Besonders einfach wird die mathematische<br />

Beschreibung, wenn die Basisvektoren nicht nur linear unabhängig, sondern orthogonal<br />

sind, also - geometrisch interpretiert - aufeinander senkrecht stehen. Für komplexe<br />

Matrizen bedeutet dies, dass (bis auf den vorgezogenen Normierungsfaktor 1/N) die inverse<br />

Matrix K -1 mit der konjugiert komplexen <strong>und</strong> transponierten Matrix K *T übereinstimmt:<br />

K<br />

− 1 T<br />

= K<br />

*


94 3 <strong>Codierung</strong><br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

Komplexe Matrizen mit dieser Eigenschaft werden als unitäre Matrizen bezeichnet, dementsprechend<br />

heißen auch die durch sie vermittelten Transformationen unitäre Transformationen.<br />

Insbesondere gehört auch die Fourier-Transformation zur Klasse dieser Transformationen.<br />

Im Falle reeller Matrizen stimmt die inverse Matrix mit der transponierten Matrix überein,<br />

man spricht dann von orthogonalen Matrizen <strong>und</strong> orthogonalen Transformationen. Ist die<br />

orthogonale Transformationsmatrix außerdem noch symmetrisch, so ist sie mit ihrer Inversen<br />

bzw. Transponierten identisch. Da das Rechnen mit komplexen Zahlen doch einen gewissen<br />

Aufwand bedeutet, werden in der Praxis orthogonale Transformationen mit reellen, möglichst<br />

auch noch symmetrischen Matrizen bevorzugt verwendet. Das bekannteste Beispiel für eine<br />

orthogonale Transformation ist wohl die Drehung von Koordinatensystemen, was bei der<br />

Robotersteuerung oder in CAD-Anwendungen zum täglichen Brot gehört.<br />

Im allgemeinen Fall ist die Berechnung der inversen Matrix recht aufwendig, die Bestimmung<br />

der transponierten Matrix dagegen trivial: man erhält die transponierte Matrix einfach durch<br />

Spiegelung an der Hauptdiagonalen. Damit ist auch sofort klar, dass orthogonale, symmetrische<br />

Matrizen zu sich selbst invers sind, so dass für die Hintransformation <strong>und</strong> die Rücktransformation<br />

identische Matrizen verwendet werden können.<br />

Hat man einen Datensatz durch eine unitäre bzw. orthogonale Transformation in eine andere<br />

Darstellung überführt, so ist noch stets die gleiche Datenmenge zu speichern, eine Kompression<br />

wurde dadurch also nicht bewirkt. Eine sehr effiziente Möglichkeit zur Datenreduktion<br />

liegt aber darin, dass bei geeigneter Wahl der Transformation manche Komponenten nur<br />

wenig <strong>Information</strong> tragen <strong>und</strong> daher weggelassen werden können (siehe Abbildung 3.4.4).<br />

Der Gr<strong>und</strong> dafür ist, dass man orthogonale Transformationen angeben kann, bei denen die<br />

Komponenten des Ergebnisses weitgehend unkorreliert sind, während die zu transformierenden<br />

Daten in der Regel sehr stark miteinander korreliert sind, da sie sich für gewöhnlich<br />

stetig ändern. Anders ausgedrückt: kennt man einige aufeinanderfolgende Werte der zu<br />

transformierenden Ausgangsdaten, so lässt sich der Wert des nächsten Wertes mit hoher<br />

Wahrscheinlichkeit voraussagen; für das Ergebnis einer geeigneten orthogonalen Transformation<br />

gilt das aber nicht mehr.<br />

f<br />

f 2<br />

f 1<br />

X<br />

f’<br />

f 1<br />

f 2<br />

X’<br />

Abbildung 3.4.4:<br />

Durch eine geeignete Koordinatentransformation<br />

wird erreicht, dass die X’-<br />

Komponenten für die beiden Daten f 1 <strong>und</strong> f 2<br />

zu 0 werden <strong>und</strong> daher nicht gespeichert<br />

werden müssen. Dies entspricht einer Datenkompression.<br />

Ordnet man den Zeilen des Kerns als Basisfunktionen Schwingungen mit ansteigender Frequenz<br />

zu, so wird ein Datenvektor durch Überlagerungen dieser Basisfunktionen ausgedrückt.<br />

Hohe Frequenzanteile in Daten entstehen durch scharfe Kanten <strong>und</strong> durch Rauschen.<br />

Werden nun die den hohen Frequenzanteilen entsprechenden Komponenten vernachlässigt,<br />

so führt dies zu einer Rauschunterdrückung, aber – da es sich hierbei im Gr<strong>und</strong>e<br />

um einen Tiefpass-Filter handelt – auch zu einer Kantenverschmierung.


3 <strong>Codierung</strong> 95<br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

Die Hadamard-Transformation<br />

Die Effizienz des Verfahrens hängt in erster Linie von den gewählten Basisfunktionen ab. Die<br />

einfachste Möglichkeit ergibt sich, wenn man als Basisfunktionen Rechteckschwingungen<br />

wählt, die in diesem Zusammenhang auch als Walsh-Funktionen bezeichnet werden. Die<br />

zugehörige Transformation ist als Hadamard-Transformation bekannt <strong>und</strong> besonders einfach<br />

<strong>und</strong> extrem schnell ausführbar, weil die Transformationsmatrix nur die Werte 1 <strong>und</strong> -1 enthält,<br />

so dass man bei der Transformation völlig ohne Multiplikationen auskommt. Als günstiger<br />

hat sich allerdings die Wahl von Sinus- oder Kosinusfunktionen als Basis erwiesen, da<br />

dann die Resultate in noch höherem Maße unkorreliert sind als bei der Hadamard-<br />

Transformation, so dass höhere Kompressionsraten erreichbar sind.<br />

Die Kosinus-Transformation<br />

Bei der Fourier-Transformation besteht der Kern aus einer komplexen Exponentialfunktion<br />

exp(i2πnu/N), die sich in einen reellen Kosinus-Anteil <strong>und</strong> einen imaginären Sinus-Anteil zerlegen<br />

lässt:<br />

e i2πnu/N = cos(2πnu/N) + i . sin(2πnu/N)<br />

Die Kosinus- oder Sinus-Funktionen alleine bilden in diesem Fall jedoch keine Basis, da die<br />

Kosinus-Funktionen gerade Funktionen <strong>und</strong> die Sinus-Funktionen ungerade Funktionen sind.<br />

Mit den Kosinus-Funktionen alleine kann man also nur gerade Funktionen darstellen, das<br />

Ergebnis ist dann rein reell. Mit den Sinus-Funktionen alleine sind nur ungerade Funktionen<br />

darstellbar, <strong>und</strong> zwar mit rein imaginärem Ergebnis. Für Funktionen bzw. Daten ohne diese<br />

besonderen Symmetrien wird also die komplexe Kombination aus Kosinus- <strong>und</strong> Sinus-<br />

Termen benötigt.<br />

Weil ein reelles Ergebnis in den meisten Anwendungsfällen bequemer zu handhaben ist,<br />

greift man zu einem Kunstgriff: Man symmetrisiert die zu transformierenden Daten durch<br />

Spiegeln an der vertikalen Koordinatenachse. Nun wird eine Fourier-Transformation über<br />

diesen um den Faktor zwei vergrößerten Datenvektor durchgeführt, wobei sich die Summation<br />

nun über 2N Terme erstreckt. Das Ergebnis ist jetzt aber rein reell <strong>und</strong> enthält nur Kosinus-Funktionen.<br />

Wegen der künstlich erzeugten geraden Symmetrie lassen sich viele Summanden<br />

zusammenfassen, so dass sich schließlich wieder nur genau so viele Terme ergeben,<br />

wie man bei Summation über die ursprünglichen Daten erhalten hätte, wobei sich aber<br />

die Wellenlängen der Kosinus-Funktionen verglichen mit der Fourier-Transformation verdoppelt<br />

haben. Das Ergebnis ist die rein reelle Kosinus-Transformation [Str02], die in der<br />

Praxis größte Bedeutung erlangt hat. Die Transformations-Formeln lauten:<br />

N−1<br />

u<br />

=<br />

u n [ + ]<br />

F c 2/N∑ fcos(2n 1) π u/2N)<br />

Kosinus-Transformation<br />

n=<br />

0<br />

N−1<br />

∑ [ π ]<br />

f = 2/ N c F cos (2n+<br />

1) u/2N)<br />

n u u<br />

u=<br />

0<br />

mit: u,n = 0,1,...N-1, c u = 1/√2 für u=0, c u = 1 für u>0.<br />

Kosinus-Rücktransformation<br />

Der Transformationskern enthält nun nicht mehr nur die Werte 1 <strong>und</strong> -1 wie bei der Hadamard-Transformation.<br />

Die Berechnung ist daher wegen der jetzt nötigen Multiplikationen entsprechend<br />

aufwendiger. Der Aufwand lohnt jedoch, da wie schon erwähnt, die Ergebnisse<br />

der Kosinus-Transformation noch weniger korreliert sind als bei der Hadamard-<br />

Transformation <strong>und</strong> somit eine noch effizientere Datenreduktion ermöglichen. Wegen der<br />

Verfügbarkeit von Signalprozessoren, die in der Lage sind, die nötigen Berechnungen sehr<br />

schnell durchzuführen, hat sich die Kosinus-Transformation als Standard durchgesetzt. Häufig<br />

verwendet man Kerne mit N=8:


96 3 <strong>Codierung</strong><br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

C<br />

un<br />

= 0.5 ⋅ c cos[(2n + 1) πu /16]<br />

=<br />

u<br />

⎛1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 ⎞<br />

1.3870 1.1759 0.7857 0.2759 -0.2759 -0.7857 -1.1759 -1.3870<br />

1.3066 0.5412 -0.5412 -1.3066 -1.3066 -0.5412 0.5412 1.3066<br />

1.1759 -0.2759 -1.3870 -0.7857 0.7857 1.3870 0.2759 -1.1759<br />

= 1.0000 -1.0000 -1.0000 1.0000 1.0000 -1.0000 -1.0000 1.0000<br />

0.7857 -1.3870 0.2759 1.1759 -1.1759 -0.2759 1.3870 -0.7857<br />

0.5412 -1.3066 1.3066 -0.5412 -0.5412 1.3066 -1.3066 0.5412<br />

⎝0.2759 -0.7857 1.1759 -1.3870 1.3870 -1.1759 0.7857 -0.2759⎠<br />

Die Transformation entspricht dann einer Multiplikation der Matrix C mit dem Vektor der Bilddaten<br />

(Zeile bzw. Spalte) f:<br />

u<br />

N<br />

=∑ −1<br />

F f C<br />

Fourier-Transformation<br />

n<br />

n=0<br />

N<br />

∑ − 1<br />

c<br />

u<br />

u=<br />

0<br />

nu<br />

f = F C Fourier-Rücktransformation<br />

n<br />

u<br />

−1<br />

nu<br />

Bei der Ausführung der Transformation, geht man am besten durch Erweiterung der Koeffizienten<br />

mit einer Potenz von 2, beispielsweise 4096, zu einer Integer-Darstellung über, so<br />

dass für alle Berechnungen Integer-Arithmetik genügt.<br />

JPEG-Kompression durch Quantisierung der Koeffizienten<br />

Die Kosinustransformation liefert als Ausgabe quadratische Matrizen mit einer zuvor festgelegten<br />

Komponentenzahl, üblicherweise 8×8. Es wird nun angestrebt, diese Einträge möglichst<br />

Platz sparend abzuspeichern, wozu ein Teil der <strong>Information</strong> so zu entfernen ist, dass<br />

es in den rekonstruierten Daten nur zu geringen, nicht relevanten Änderungen kommt. Bei<br />

der Entscheidung, welche Matrixkomponenten übertragen werden <strong>und</strong> mit wie vielen Bits sie<br />

dargestellt werden sollen, gibt es prinzipiell zwei verschiedene Möglichkeiten:<br />

Ein Ansatz besteht darin, die Entscheidung von der Position der Komponenten in der Matrix<br />

abhängig zu machen. Man geht dabei von der Überlegung aus, dass die niederfrequenten<br />

Anteile mehr zur <strong>Information</strong> beitragen als die zu höheren Frequenzen gehörenden Komponenten.<br />

Die Ergebnismatrix wird dementsprechend in verschiedene Zonen aufgeteilt, für die<br />

in einer Bit-Zuordnungstabelle oder Quantisierungstabelle festgelegt wird, wie viele Bits für<br />

die <strong>Codierung</strong> der Matrixkomponenten in den jeweiligen Zonen zu verwenden sind. Dabei<br />

werden für die niederfrequenten Matrixkomponenten mehr Bits reserviert als für die höherfrequenten<br />

<strong>und</strong> die höchsten Frequenzen werden oft ganz unterdrückt, was durch den Eintrag<br />

Null gekennzeichnet wird. Die folgende Tabelle zeigt eine mögliche Bit-Zuordnung für<br />

eine 8×8 Matrix, entsprechend einer Datenreduktion um etwa den Faktor 3.<br />

Tabelle 3.4.10: Eine datenkomprimierende Bitzuordnungstabelle (Quantisierungstabelle) für die 8×8<br />

Kosinus-Transformation. Der Kompressionsfaktor beträgt für dieses Beispiel ca. 3.<br />

8 8 7 7 6 5 4 4<br />

8 7 6 5 4 3 2 2<br />

7 6 5 3 2 2 1 1<br />

7 5 3 2 1 1 0 0<br />

6 4 2 1 1 0 0 0<br />

5 3 2 1 0 0 0 0<br />

4 2 1 0 0 0 0 0<br />

4 2 1 0 0 0 0 0


3 <strong>Codierung</strong> 97<br />

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯<br />

Der zweite Ansatz zur Datenkompression besteht darin, die Quantisierung nicht nach der<br />

Lage der Matrixelemente zu entscheiden, sondern nach deren Größe. Man geht hier von der<br />

Annahme aus, dass Matrixeinträge mit großen Beträgen auch viel <strong>Information</strong> tragen. Dies<br />

trägt der Tatsache Rechnung, dass scharfe Kanten in Messdaten oder Bildern im Verlauf der<br />

Daten auch zu signifikanten hochfrequenten Komponenten führen, deren Unterdrückung zu<br />

einer Kantenverschmierung führen würde. Alle Matrixelemente werden daher mit einem voreinstellbaren<br />

Schwellwert verglichen <strong>und</strong> nur übertragen, wenn sie größer sind als dieser<br />

Schwellwert. Allerdings muss dann auch die Position der Matrixelemente mit codiert werden.<br />

Fehlende Einträge werden bei der Rücktransformation wie beim ersten Verfahren durch Null<br />

ergänzt.<br />

Beide Methoden können zu Problemen führen. Das erste Verfahren berücksichtigt nicht,<br />

dass auch hochfrequente Matrixelemente wichtige <strong>Information</strong> tragen können. Das zweite<br />

Verfahren vermeidet zwar diesen Fehler, codiert aber statt dessen niederfrequente Anteile<br />

nur dann, wenn sie über dem Schwellwert liegen. Erinnert man sich daran, dass die erste<br />

Matrixkomponente den Mittelwert der codierten Daten repräsentiert, so wird deutlich, dass<br />

diese Komponente auch dann nicht ohne Qualitätsverlust weggelassen werden darf, wenn<br />

sie klein ist. Eine optimale Lösung muss demnach beide Methoden kombinieren <strong>und</strong> die Anzahl<br />

der Bits für die <strong>Codierung</strong> der einzelnen Matrix-Komponenten in Abhängigkeit von deren<br />

Position <strong>und</strong> Größe entscheiden.<br />

Die Kosinus-Transformation mit 8×8-Matritzen ist wesentlicher Bestandteil des genormten<br />

JPEG-Standards für die datenreduzierende <strong>Codierung</strong> von Bilddaten, bei der nach den oben<br />

beschriebenen Strategien kleine <strong>und</strong>/oder hochfrequente Komponenten auf 0 gesetzt werden.<br />

Dadurch ergeben sich häufig längere Sequenzen von Nullen, die durch eine Lauflängen-<strong>Codierung</strong><br />

komprimiert werden. Zusätzlich werden die Koeffizienten aufeinander folgender<br />

8×8-Bereiche mittels Differenz-<strong>Codierung</strong> weiter komprimiert. Im letzten Schritt steht<br />

dann eine Huffman-<strong>Codierung</strong> oder eine arithmetische <strong>Codierung</strong>, mit der die verbleibende<br />

Einzelzeichen-Red<strong>und</strong>anz eliminiert wird. Für Bilder ergeben sich dann bei Kompressionsraten<br />

um ca. den Faktor 10 gute visuelle Eindrücke, obwohl der <strong>Information</strong>sgehalt wesentlich<br />

reduziert wurde. Besonders für Internet-Anwendungen hat dieses Verfahren der Bildkompression<br />

weite Verbreitung gef<strong>und</strong>en.<br />

Weitere Kompressionsverfahren<br />

Von großer praktischer Bedeutung ist die Kompression bewegter Bilder nach dem MPEG-<br />

Standard (siehe [Wat01] <strong>und</strong> [Sym98]) Die Kompression von Einzelbildern erfolgt dabei wie<br />

beim JPEG-Verfahren durch Kosinustransformation [Str02]. Es werden jedoch nicht alle Bilder,<br />

sondern nur Stützbilder (beispielsweise jedes vierte) vollständig komprimiert, Zwischenbilder<br />

aber nur aus den Stützbildern interpoliert. Zusätzlich wird durch die Übernahme örtlich<br />

verschobener, aber sonst unveränderter Bildbereiche von einem Bild zum nächsten ein weiterer<br />

Kompressionseffekt erzielt. Insgesamt sind Kompressionsraten bis ca. um den Faktor<br />

100 möglich.<br />

Weitere Methoden der Bilddatenkompression sind die Kompression mit Hilfe der Wavelet-<br />

Transformation [Str02], bei der die zur Bildbeschreibung benötigte Funktionsbasis aus den<br />

Bildern selbst gewonnen wird sowie die fraktale Bildkompression [Fis96], bei der Bilder durch<br />

typische, kleine Bildausschnitte <strong>und</strong> deren Kombination zu fraktalen Mustern durch Überlagerung<br />

sowie unter Verwendung affiner Abbildungen approximiert werden.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!