COMPRESSION BINAIRE Compression et décompression d une image binaire suivant la recommandation T.4 de l ITU-T Auteurs: KASTTET Ahmed, SALIM Eliass ENSEIRB. T2. 2007/2008
SOMMAIRE I.Introduction... 3 II.Codage... 3 II.1.Détection... 3 II.2. Codage... 3 II.3.Ecriture dans un fichier... 4 III. Décodage... 5 III.1. Lecture dans un fichier... 5 III.2. Décodage... 5 III.3. Reconstruction... 6 IV.Simulation... 6 V.Conclusion... 7 VI.Annexes : Scripts matlab... 7
I.INTRODUCTION La recommandation T4 de l ITU définit le format standard de l'image transmise par fax. Cette recommandation est particulièrement adaptée aux images monochromes, car il offre un bon taux de compression, entre 5:1 et 8:1 selon les images, ainsi qu une compression sans pertes de données. Ce codage qui est basé sur le codage de Huffman, convient donc parfaitement aux transmissions type fax. Le but du projet était de simuler sous Matlab, l encodage et le décodage d une image, en respectant les recommandations T4, puis de tester l algorithme de compression sur une image noir et blanc et de comparer la sortie avec l image d origine. II.CODAGE II.1.DETECTION Tout d abord, nous transformons les séquences de bits 0 (pixel noir) et 1 (pixel blanc) par des entiers représentant la longueur de ces séquences. Cette opération est effectuée par la fonction «detect.m» Cepant, la norme nous impose de commencer par une séquence de blancs. Ainsi nous obtenons alternativement un entier correspondant aux pixels blancs, puis un entier correspondant aux pixels noirs, etc Pour la ligne suivante : 000110001111100000111111 (1) Nous obtenons : 0 3 2 3 5 5 6 II.2. CODAGE Dans une seconde étape nous codons chaque élément de la séquence obtenue précédemment, selon des codes qui proviennent de la table de Huffman prédéfinie par les spécifications T.4. Elle est issue d études statistiques sur la fréquence moyenne des séquences de 1 et de 0 dans des documents typiques.
Les codes sont de deux types : - Les codes Terminating - Les codes Make Up. Pour les longueurs inférieures à 64 le code est de type Terminating, pour trouver le codage équivalent il suffit de regarder à la ligne correspondant à la longueur dans la table de Huffman et l on récupère le code associé. Pour les longueurs supérieures ou égales à 64 le code est une concaténation des deux codes Make Up et Terminating. Le code Make Up correspondant au multiple de 64 le plus proche (par valeur inférieure) de la longueur de la séquence, le code Terminating étant la différence entre la longueur de la séquence et Make Up multiple obtenu.( Cf.codage_ligne.m) On obtient alors : 0011010110011110110000111110 (3) Afin de distinguer les différentes lignes dans le fichier complet, la norme précise de rajouter à la fin de chaque ligne le code EOL suivant : 000000000001 Nous avons alors : 0011010110011110110000111110000000000001 (4) Le code obtenu dans notre exemple est plus long que le code initial, ceci vient du fait que ce codage de Huffman est spécifique aux documents qui contiennent de plus longues séquences de 1 et de 0 que la séquence prise dans cet exemple. II.3.ECRITURE DANS UN FICHIER Pour finir, nous stockons le code obtenu précédemment dans un fichier ASCII (Cf. «ecriture.m») Cette étape consiste simplement à découper le code binaire obtenu en (4) en groupe de 8 bits, que l on va transformer en décimal puis enregistrer en tant que codes de caractères ASCII dans un fichier. Si le dernier groupe ne possède pas un nombre de bits multiple de 8, on complète par des zéros. On obtient le code ASCII suivant : 53 158 195 224 1 (5)
III. DECODAGE III.1. LECTURE DANS UN FICHIER Pour retrouver la séquence de bits émise initialement il est nécessaire de décoder le fichier obtenu. La première chose à faire dans notre cas, est de convertir les codes ASCII stockés dans le fichier en code binaire. Tout en tenant compte du nombre de bits de padding à retirer du dernier code ASCII lu dans le fichier (Cf. «lecture.m»). On obtient le code binaire suivant : 0011010110011110110000111110000000000001 (6) III.2. DECODAGE L étape de décodage la plus délicate consiste à transformer cette suite de bits en nombre entier représentant la longueur. Pour ce faire on utilise un arbre de décodage (sous forme de tableau), qui s inspire des arbres de décodage de Huffman. Le principe de décodage est le suivant. Si le contenu d une case du tableau est égale a -1, on doit continuer à parcourir notre suite de bits car on ne se trouve pas sur une feuille de l arbre. L indice du tableau se calcule de la façon suivante : - initialisé à 1 pour tout nouveau code - multiplié par 2 si on trouve un 0 dans la suite de bits - multiplié par 2 puis sommé à 1 si on trouve un 1 Lorsque l on a trouvé une feuille, soit un élément différent de -1, on récupère la valeur et l écrit à la suite de notre vecteur. Cette valeur représente en fait le nombre de bits à 0 ou 1 à écrire dans le fichier de destination. Il ne faut pas oublier de changer de tableau à chaque nouveau code, sauf si la valeur retournée par le tableau est supérieure à 64 et différente de 8193 (8193 correspond au code EOL), dans ce cas on considère que le premier code correspond au make up, on reste sur le même arbre pour le code suivant, le Terminating.
De même il ne faut pas oublier qu après un code EOL il faut nécessairement recommencer avec l arbre des blancs («decodage.m ). On obtient le code suivant : 0 3 2 3 5 5 6 8193 (7) III.3. RECONSTRUCTION La dernière étape du décodage consiste donc à retrouver le code initial à partir du code obtenu précédemment. Le fonctionnement est très basique, puisqu il ne s agit que d écrire le nombre de pixels noirs ou blancs donné par la séquence (7) alternativement dans une matrice, et de changer de ligne à chaque fois qu on tombe sur le code 8193. Sans oublier que le premier nombre représente toujours le nombre de blancs en début de ligne (Cf. «recostruction.m»). On obtient ainsi notre image initiale. 000110001111100000111111 IV.SIMULATION Le processus décrit ci-dessus peut se résumer sur le schéma suivant : Image initiale Image codée RLE Image codée selon table de Huffman Ecriture du fichier codée (ASCII) Codage Image en reception Decodage RLE Décodage selon table de Huffman Lecture du fichier codée (ASCII) Décodage
Ce processus va être appliqué à l image monochrome «test_bin.tif» de taille 15.5ko. (Cf. «main.m»). En comparant les taills du fichier initial et celui genéré par la méthode, il est possible de mesurer le taux de compression obtenu. Il est également possible de comparer le résultat obtenu avec celui de la fonction imwrite qui implémente des compressions analogues (fax3,fax4) On peut également vérifier que le processus opère sans perte car la somme de la différence des deux images (initiale est finale) est nulle. Perte=sum(sum(image-image_decompresse)) =0 Voici les résultats obtenus : i. taux de compression de notre chaine= 58,77 % ii. taux de compression de imwrite(fax3)=50,77 % iii. taux de compression de imwrite(fax4)=64,87 % on constate que notre chaine donne un rement acceptable et dans le même ordre de grandeur de celui de la fonction matlab imwrite. V.CONCLUSION Le but de ce projet était de mettre en pratique, à l aide de Matlab, la compression / décompression d une image binaire selon les recommandations T4. Il était intéressant de se concentrer sur chaque étape du codage et du décodage, puis de tout mettre en commun afin de réaliser la compression/décompression. Cette mise en commun ne fut pas évidente, et fut source de beaucoup d erreurs. Elle nous a permis de constater que certaines de nos fonctions comportait des erreurs pour certains cas auxquels nous n avions pas pensés. L encodage utilisé ici est un encodage à une dimension, nous aurions pu obtenir encore de meilleurs résultat avec un encodage à deux dimensions. VI.ANNEXES : SCRIPTS MATLAB ------------------------------------------------ % main.m ------------------------------------------------ clear all load('arbres_codes.mat') image=imread('test_bin.tif'); image_compresse=codage('test_bin.tif','codes.txt'); recus=lecture('transmis.txt'); sequence=decodage(recus,black_tree,white_tree); image_decompresse=recostruction(sequence);
taille_initiale=size(image,1)*size(image,2); taille_finale=size(image_decompresse,1)*size(image_decompresse,2); taux_compression=taille_initiale/taille_finale; disp('taux de compression :'); disp(taux_compression); imwrite(image,'image_fax3.tif','tif','compression','fax3'); image_fax3=imread('image_fax3.tif'); taille_fax3=size(image_fax3,1)*size(image_fax3,2); taux_fax3=taille_fax3/taille_finale; disp('taux de compression fax3 :'); disp(taux_fax3); imwrite(image,'image_fax4.tif','tif','compression','fax4'); image_fax4=imread('image_fax4.tif'); taille_fax4=size(image_fax4,1)*size(image_fax4,2); taux_fax4=taille_fax4/taille_finale; disp('taux de compression fax4 :'); disp(taux_fax4); %detect.m % function [y] = detect (x) t=0; i=1; k=1; if (x(1)=='0') y(k)=0; k=2; while (i<length(x)+1) if (x(i)=='0') while (i<length(x)+1 && x(i)=='0') t=t+1; i=i+1; else while (i<length(x)+1 && x(i)=='1') t=t+1; i=i+1; y(k)=t; k=k+1; t=0; %codage_mot.m % function [code]= codage_mot(num,color) fid=fopen('codes.txt'); k=1; table=cell(91,3); while 1 tline = fgetl(fid); if ~ischar(tline), break, numero=sscanf(tline,'%d %*s %*s'); noir=sscanf(tline,'%*d %s %*s'); blanc=sscanf(tline,'%*d %*s %s');
noir=char(noir)'; blanc=char(blanc)'; table{k,1}=numero; table{k,2}=noir; table{k,3}=blanc; k=k+1; fclose(fid); if (num<64) t=table(num+1,color); else first_num=mod(num,64); term=table(first_num+1,color); scnd_num=floor(num/64); make=table(64+scnd_num,color); t=[make term]; code=t; ----------------------------------------------% %codage_ligne.m % ----------------------------------------------% function [y] = codage_ligne(x) i=1; y=''; EOL='000000000001'; while(i<length(x)+1) if (mod(i,2)==1) t=codage_mot(x(i),3); else t=codage_mot(x(i),2); i=i+1; y=[y t]; y=[y EOL]; %codage.m % function code=codage(image,table_huff) table=lecture(table_huff); A=imread(image); [l c]=size(a); code=[]; EOL='000000000001'; for i=1:l ligne=num2str(a(i,:)')'; code=[code codage_ligne(detect(ligne))]; code=[code EOL EOL EOL EOL EOL]; ecriture(code,'codage.txt'); %ecriture.m % function fichier=ecriture(code,file) l=length(code); pad=mod( 8-mod(l,8),8); padding=dec2bin(zeros(1,pad))'; code=[code padding]; l=length(code)/8;
bits_8=reshape(code,[8,l])'; [h,w]=size(bits_8); fid = fopen('transmis.txt', 'w'); for i=1:h fwrite(fid,bin2dec(bits_8(i,:))); fclose(fid); %lecture.m % function recus=lecture(fichier) fid=fopen(fichier); i=1; recus=[]; while 1 recus=dec2bin(fread(fid)); if ~ischar(fgetl(fid)), break, recus=reshape(recus',[1,numel(recus)]); fclose(fid); %decodage.m % function sequence=decodage(recus,black_tree,white_tree) index=1; val=-1; buffer=0; code=[]; sequence=[]; EOL='000000000001'; color=1 ; for i=1:numel(recus) if (val==-1) code=[code recus(i)]; bit=str2num(recus(i)); index=bit*(2*index+1)+not(bit)*(2*index); index=2*index+1; index=2*index; if(color==1) val=white_tree(index); else val=black_tree(index); % cas des EOL if( strcmp(code,eol) ) sequence=[sequence -1]; color=1; buffer=0; val=-1; index=1; code=[]; % cas <63 elseif (val~=-1 && val<=63) sequence=[sequence val+buffer];
color=mod(color+1,2) ; index=1; val=-1; buffer=0; code=[]; % cas >63 elseif (val~=-1 && val>63) buffer=val; index=1; val=-1; i=i+1; %reconstruction.m % function [image]=recostruction(sequence) l=length(sequence); image=[]; ligne=[]; color=1; firsteol=1; for i=1:l-5 if (sequence(i)~=-1) if(sequence(i)==0) color=0; elseif(color==1) ligne=[ligne ones(1,sequence(i))]; color=0; elseif(color==0) ligne=[ligne zeros(1,sequence(i))]; color=1; else if(firsteol) image=[ligne;ligne]; firsteol=0; ligne=[]; color=1; if(~firsteol) image=[image;ligne]; ligne=[]; color=1; image(1,:)=[];