La compression de données (Généralités)
Les méthodes de compression sans perte
Un exemple simple.
Étudions dabord un exemple très simple.
Supposons que nous devions essayer de compresser la série doctets
suivante :
0001 0100 0011 1111 0101 0101 0101 0101 0101 0101
0101 0101 1110 1111 0000 1111 1111 1111 1111 1111
1111 1111 1111 1111 1111 1111 0110 0111 0111 0000
0111 0000 1010 1111 0000 0000 0001 1111 0001 1111
0001 1111
Elle compte 21 octets. (Vous pouvez linterpréter comme une suite de caractères ou comme les niveaux de gris dune suite de pixels, cela na pas dimportance pour ce qui nous préoccupe ici).
Nous allons coder cette chaîne en utilisant les répétitions doctets pour gagner de la place.
Commençons par écrire un octet de signalisation, pour le repérer, nous lécrirons en gras.
0000 0010
Convenons que le premier bit indique si loctet de donnée qui suit se répète, si cest le cas le bit sera mis à 1 (ce nest pas le cas ici), si ce nest pas le cas il sera mis à 0. Les 7 bits qui suivent indiqueront le nombre de répétitions dans le premier cas ou le nombre doctets sans répétition qui suivent (ici on a écrit 0000 0010 car on va faire suivre loctet de signalisation par deux octets différents qui ne se répètent pas).
Notons quavec ces 7 bits, nous pouvons coder 127 répétitions. On voit léconomie réalisée si beaucoup doctets sont identiques (un masque dans Photoshop
).
Notre chaîne codée commence donc par :
0000 0010 0001 0100 0011 1111
Ça commence mal ! Nous avons utilisé 3 octets pour en coder 2, mais ça va saméliorer. Continuons. Les 4 octets qui suivent sont identiques, ce que nous indiquons par loctet de signalisation :
1000 0100
Le premier bit à 1 annonce une répétition, la valeur 0000100 (4 en binaire) indique le nombre de répétitions.
Nous pouvons compléter notre chaîne codée :
0000 0010 0001 0100 0011 1111 1000 0100 0101 0101
Vous vérifierez quen continuant nous obtenons la chaîne suivante qui code lensemble du message :
0000 0010 0001 0100 0011 1111 1000 0100 0101 0101
0000 0010 1110 1111 0000 1111 1000 0101 1111 1111
0000 0001 0110 0111 1000 0010 0111 0000 0000 0010
1010 1111 0000 0000 1000 0011 0001 1111
Cette chaîne fait 19 octets soit 2 de moins que la chaîne initiale, nous avons un taux de compression de 21/19 = 1,1
Le décodage ne pose aucun problème à condition que le décodeur soit informé de la méthode utilisée, il interprètera dans ce cas le premier octet comme un octet de signalisation et tout ira bien
Cette méthode est séduisante parce quelle est facile à comprendre mais elle est malheureusement peu efficace. Elle nest plus utilisée seule mais seulement comme méthode complémentaire.
Les méthodes statistiques.
Lidée est la suivante : nous avons lhabitude de coder toutes les valeurs que nous avons à stocker avec le même nombre de bits, généralement un ou plusieurs octets. Nous utilisons un octet par caractère quand nous travaillons avec du texte, un ou deux octets par pixel et par couche quand nous travaillons avec des images. Est-ce la meilleure solution ? La théorie nous apprend que non.
Il est en effet plus efficace dutiliser des codes plus courts pour des valeurs fréquentes et de réserver des codes plus longs pour les valeurs moins fréquentes. Lintérêt de cette méthode dépendra bien entendu de la distribution des valeurs à coder telle quon peut létudier en construisant lhistogramme des valeurs à coder. Pour une image, Photoshop sait faire ça très bien comme vous le savez.
En fait lexamen des histogrammes de quelques images comme celles que nous utilisons journellement est assez encourageant : il y a toujours dans les images naturelles des variations de fréquence significatives.
On va donc sintéresser aux VLC (Variable Length Code), on dit aussi au codage entropique.
Nous voyons bien lintérêt de la méthode mais la mise en oeuvre est un peu plus délicate. Prenons un petit exemple.
Supposons que nous ayons à traiter un message qui ne contient que 4 caractères que nous nommerons A, B, C et D. et que les fréquence de ces caractères dans notre message soient les suivantes :
A : 60 %
B : 30 %
C : 5 %
D : 5 %
On peut imaginer le code suivant :
A : 0 B : 00 C : 01 D : 10
Il nous permettra assurément de gagner de la place mais si nous recevons le message suivant : 00001, comment linterpréter ?
4 A ? 2 B ? 2 A et 1 B? 1 B et 2 A ? Ça ne marche pas ! Nous venons de découvrir le problème de la synchronisation.
Comment le résoudre ?
Utiliser des caractères séparateurs ? cest contradictoire avec lobjectif de compression.
La solution cest le VLC préfixé.
Un code est préfixé sil nest le début daucun autre. Le VLC que nous avions tenté dutiliser tout à lheure nétait pas préfixé.
Revenons à notre exemple et essayons de corriger.
A : 0 B : 10 C : 110 D : 111 Ça marche ! Est-ce la solution optimale ? Comme nous lavons optenue par tatonnement, on nen sait rien mais rassurez-vous la théorie permet daffirmer que oui.
Nous allons maintenant prendre un exemple un peu plus complexe et présenter une méthode permettant de déterminer un VLC efficace (même sil nest pas toujours optimal).
Supposons que nous voulions transmettre le message suivant :
LE PRESIDENT EST ENTRE DANS LA SALLE
Il compte 36 caractères et occupe dans un logiciel comme XPress ou WordPerfect 36 octets.
Nous allons compter les occurences des différents caractères de lalphabet utilisés et les classer par fréquences décroissantes, nous obtenons la liste suivante :
E : 7
Espace : 6
L : 4
S : 4
N : 3
T : 3
A : 3
R : 2
D : 2
P : 1
I : 1
Nous allons maintenant regrouper les caractères en deux groupes dont les fréquences dapparition sont aussi proches que possibles puis diviser chacun de ces groupes de la même façon jusquà parvenir à chacune des fréquences de départ (il est équivalent de travailler avec le nombre doccurences ou les fréquences). Voici le développement du calcul sous forme de schéma :
|
|
On numérote les branches de larborescence en binaire et on parcourt chaque branche pour déterminer les codes qui figurent dans la colonne de droite.
On peut vérifier que lon obtient bien un VLC préfixé.
Mesurons son efficacité.
Nous sommes parti dun message de 36 caractères soit 36 x 8 = 288 bits
si lon avait codé chaque caractère sur 4 bits (cétait suffisant), on utilisait 144 bits.
En utilisant le codage que nous venons de réaliser nous utiliserons :
(2 x 7) + (3 x 6) + (3 x 4)+ (3 x 4) + (4 x 3) + (4 x 3) +(4 x 3) + (4 x 2) + (4 x 2) + (5 x 1) + (5 x 1) = 14 + 18 +12 + 12 + 12 + 12 + 12 + 8 + 8 + 5 + 5 = 118 bits
Le taux de compression par rapport à la représentation sur 4 bits est s = 144/118 = 1,22.
Lalgorithme que nous venons dutiliser pour déterminer un VLC préfixé est appelé du nom de ses auteurs, lalgorithme de Shanon-Fano.
On lui préfère souvent un algorithme voisin qui est un peu plus complexe mais qui parvient au même résultat, celui de Huffman.
Ces méthodes sont utilisées directement dans les photocopieurs et elles interviennent en PAO comme méthode complémentaires. Il y a par exemple un codage de Huffman dans la méthode de compression JPEG.
Les algorithmes de type dictionnaire
Les méthodes statistiques, en particulier lalgorithme de Huffman, ont été très employées jusquen 78. Cest alors que sont apparues les méthodes de type dictionnaire .
Nous avons commencé, tout à lheure, à compresser en tenant compte des répétitions doctets mais dans les images que nous manipulons ce sont souvent des séquences doctets, des motifs qui se répètent. Pourquoi ne pas utiliser ces répétitions pour compresser les données ?
Prenons un petit exemple pour faire comprendre lintérêt de la méthode.
Combien la langue française comporte-t-elle de mots de 10 lettres ? environ 10 000.
Combien peut-on faire de mots différents de 10 lettres aves les 26 lettres de lalphabet ?
2610 soit 1,4.1014 ce qui fait tout de même 140 000 milliards de mots. Autrement dit, les mots de 10 lettres qui ont un sens représentent 1 quatorze milliardième de lensemble des mots de 10 lettres.
Il est donc très judicieux si lon veut coder efficacement ces mots, den dresser une liste et de les numéroter, on dit plutôt de les indexer.
Les algorithmes LZ**
Cest en 1977 que Jacob Ziv et Abraham Lempel ont publié un article qui est à la base de tous les algorithmes à dictionnaire que nous utilisons actuellement.
En 1984, laméricain Terry Welch améliore lalgorithme précédent et dépose un brevet. Cest la naissance de lalgoritme LZW. Il est plus performant que les méthodes statistiques. IL sert de base à la norme V42bis du CCITT que nous utilisons dans nos modems.
Le principe de lalgorithme LZW, cest dutiliser un dictionnaire dynamique qui contient des motifs du fichier traité.
Linconvénient des algorithmes à dictionnaire, cest quil est à priori nécessaire de transmettre le dictionnaire avec les données, ce nest pas le cas avec LZW. Le dictionnnaire est construit à la compression et reconstruit à la décompression.
Ce qui est également intéressant, cest quil est inutile de lire et détudier le fichier avant de le compresser. La compression seffectue au fur et à mesure de la lecture, le compresseur détectant au fur et à mesure les séquences qui se répètent.
Nous nexpliciterons pas cet algorithme mais nous retiendrons deux points :
dune part, il sagit dun algorithme sophistiqué et « pilotable ». Il est possible par exemple de remettre à zéro le dictionnaire ou de modifier sa taille.
dautre part, on peut combiner LZW et algorithme de codage statistique. Cest ce que font des programmes comme ARJ ou PKZIP qui utilisent LZW puis Shanon-Fano.
|
|