MANIPULATION DES FICHIERS IMAGES
Objectifs :Savoir ouvrir et modifier des fichiers images `a l’aide de Python.
Ce TP est dans la continuit´e du pr´ec´edent o`u l’on avait ´etudi´e la manipulation de fichiers textes. On explique maintenant comme manipuler des fichiers images (extensionpng). Sous Windows, cela correspond en gros aux fichiers directement lisibles `a l’aide du logiciel Paint).
Exercice 1.
Dans votre dossier personnel de votre PC portable (pas besoin d’Internet), cr´eer un dossier Informatique, puis un sous dossier TP11 consacr´e `a ce TP. Il commencera par TP11, contiendra le nom du TP actuel et respectera les r`egles classiques ci-dessous. (Donner des noms de dossiers sans accent, ni espace, ni caract`ere sp´ecial. De pr´ef´erence, utilisez le tiret-bas au lieu du tiret - et de l’espace.)
A la fin du TD, copier le contenu du dossier TP11 sur votre cl´e USB ou sur votre dossier partag´e dans sous- dossier Informatiqueavec les TP pr´ec´edents.
I LES IMAGES « EN NOIR ET BLANC »
Exercice 2.
L’objectif de cet exercice est de comprendre comment un ordinateur «voit» et manipule des images que l’on appelle abusivement en noir et blanc, mais qui sont en r´ealit´e bien souvent des images en niveaux de gris.
Commencez par r´ecup´erer les fichiers noir_et_blanc.png etcouleurs.png(dans votre Drive, dans le dossier partag´eAAA - Classe enti`erepuisInformatique, aller dans le dossierTP11) et enregistrez-le dans le dossier
`
a votre nom sur le bureau de l’ordinateur.
Regardez l’image en double-cliquant dessus dans l’ex- plorateur de fichiers.
En zoomant sur l’image, on s’aper¸coit qu’elle est consti- tu´ee d’unemultitude de pixels organis´es en lignes (y) et colonnes (x). La couleur de chaque pixel est cod´ee sur un octet (c’est-`a-dire 8 bits), et repr´esente donc une nuance de gris parmi 255 valeurs possibles. On peut voir cette valeur commela luminosit´e du pixel : la valeur 0 code la couleur noire, la valeur 255 code la couleur blanche, et les valeurs interm´ediaires codent des nuances de gris de plus en plus claires `a me- sure que la valeur augmente.
On importe la biblioth`equePillowou PIL, plus pr´ecis´ement la partie d’affichage d’image de la fa¸con suivante : from PIL.Image import *
Si cela ne fonctionne pas, utiliser la syntaxe suivante ´equivalente : from PIL import Image
from PIL.Image import *
Dans la biblioth`eque PIL.Image, on dispose des fonctions :
— Image.show(image) affiche l’image image. (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen).
— Image.getpixel(image,(x,y)) r´ecup`ere la valeur de la couleur du pixel situ´e en ligne yet colonne x de l’imageimage. (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen).
A savoir que les indices des lignes et colonnes commencent `a 0.
— Image.putpixel(image,(x,y),valeur) remplace la valeur de la couleur du pixel situ´e en ligne y et colonnexde l’imageimage. (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen) par valeur.
Rappel : pour ouvrir un fichier en mode lecture, ´ecriture ou ajout : image=open("fichier_image",options `a ajouter)
Exercice 3.
1. Afficher l’imagenoir_et_blanc sous Python.
2. R´ecup´erer puis afficher la valeur de la couleur du pixel en ligne 36 et colonne 2. Que vaut-elle ?
. . . . 3. Tester la commandeimage.sizeet faire afficher ce qu’elle renvoie. Que repr´esentent ces nombres ?
. . . . Exercice 4.
Ecrire une fonction´ inversion(image) qui prend en entr´ee une image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonction open.) et retourne l’image invers´ee (on entend que les couleurs blanches sont remplac´ees par du noir et inversement). Tester cette fonction avec le fichier noir_et_blanc.png.
Exercice 5.
Ecrire une fonction´ noir_et_blanc(image,s)prend en entr´ee une image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonction open.) et un seuil s et qui transforme tous les pixels de valeur inf´erieure `a s en 0 et tous les autres en255. Tester cette fonction avec le fichier noir_et_blanc.png.
Exercice 6.
Ecrire une fonction´ ligne(image,y,c) qui trace une ligne de couleur de pixel ´egal `a csur la ligneyde l’image image(qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen.).
Tester cette fonction avec le fichiernoir_et_blanc.png.
Exercice 7.
Ecrire une fonction´ assombrir(image) qui assombri l’imageimage(qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen.) en divisant par 2 la valeur de chaque pixel. Tester cette fonction avec le fichiernoir_et_blanc.png.
Exercice 8.
Ecrire une fonction´ eclaircir(image)qui ´eclaircie l’image image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonction open.) en multipliant par 2 la valeur de chaque pixel (en prenant soin de ne pas d´epasser la valeur maximale de 255). Tester cette fonction avec le fichiernoir_et_blanc.png.
II LES IMAGES « EN COULEUR »
II.1 Codage RGB d’une image en couleur
Comme pr´ec´edemment, regardons comment un ordinateur «voit» et manipule des images couleurs. Re- gardez l’image du fichier couleurs.png en double-cliquant dessus dans l’explorateur de fichiers. En zoomant sur l’image, vous devriez voir qu’elle est constitu´ee d’une multitude de pixels organis´es en lignes (y) et colonnes (x), tout comme le sont les images en niveaux de gris. Pour repr´esenter assez finement pour l’œil humain un pixel en niveaux de gris, on n’a besoin que d’une seule valeur entre 0 et 255 (0 : noir, 255 : blanc).
Dans une image couleur, on indique pour chaque pixel un m´elange de 3 couleurs : rouge, vert, bleu.
Chaque couleur est donn´ee par un nombre entre 0 et 255, on a donc besoin de 3 nombres (qu’on repr´esente cha- cun sur un octet).
Ce codage s’appelle RGB pour Red Green Blue et o`u pour chacune de ces couleurs
— la valeur 0 indique qu’on met 0% du«pot de cette couleur».
— la valeur 255 indique qu’on met 100% du «pot de cette couleur».
Chaque pixel est donc repr´esent´e par un triplet d’octets codant un entier entre 0 et 255.
Voici quelques exemples pour bien comprendre le codage des couleurs :
couleur R G B Octet 1 Octet 2 Octet 3
noir 0 0 0 0000 0000 0000 0000 0000 0000 blanc 255 255 255 1111 1111 1111 1111 1111 1111 rouge 255 0 0 1111 1111 0000 0000 0000 0000 vert 0 255 0 0000 0000 1111 1111 0000 0000 bleu 0 0 255 0000 0000 0000 0000 1111 1111 violet 132 122 191 1000 0100 0111 1010 1011 1111 Dans la biblioth`eque PIL.Image, on dispose des fonctions
— image.getpixel((x,y)) retourne le tuple (rouge,vert,bleu) qui r´ecup`ere la valeur des 3 couleurs R,G,B du pixel situ´e en lignexet colonneyde l’image image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen).
— image.putpixel((x,y),(rouge,vert,bleu)) remplace la valeur de la couleur du pixel situ´e en ligne x et colonneyparrouge,vert,bleude l’imageimage. (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonction open).
Exercice 9.
Ecrire une fonction´ no_rouge(image) qui prend en entr´ee une image image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen) et qui supprime toute la couleur rouge de chaque pixel.
Tester cette fonction avec le fichiercouleurs.png. L’imagecouleurs.png que vous avez charg´ee contient une autre image cach´ee que vous allez essayer de d´ecouvrir.
II.2 Principe pour cacher une image dans une autre L’image a ´et´e cach´ee par mes soins en changeant l´eg`ere-
ment la couleur de certains pixels de l’image originale.
Tout se passe comme si l’image cach´ee ´etait «sous» l’image visible.
En fait, on m´elange les pixels des deux images originales, en privil´egiant l’image 1 pour qu’on ne remarque pas que l’image 2 est cach´ee dedans. On utilise le fait que mo- difier l´eg`erement la couleur des pixels d’une image est difficile `a discerner pour l’œil humain. Par exemple, le mot
a b r a c a d a b r a
ne contient pas deux lettres de mˆeme couleur, ce qui est difficile `a voir. Les couleurs employ´ees sont trop proches les unes des autres pour pouvoir ˆetre distingu´ees. En r´esum´e, modifier l´eg`erement les pixels d’une image ne se voit pas facilement.
On utilise le fait que l’œil ne distingue pas les faibles diff´erences de couleur pour cacher une image dans une autre. Pour simplifier, voyons ce qui se passe sur une seule composante de couleur, disons le rouge (mˆeme si en fait, on appliquera le mˆeme traitement aux trois couleurs).
Prenons 2 images de mˆeme dimension. Pour chacune des coordonn´ees (x,y), on va m´elanger une partie du pixel (x,y) de l’image 1 avec le pixel (x,y) de l’image 2. L’image obtenue sera tr`es proche de l’image 1, mais l’image 2 sera «cach´ee» `a l’int´erieur. Imaginons que l’on veut m´elanger un pixel dans l’image 1 dont l’octet rouge vaut 190, c’est-`a-dire
10111110 avec l’octet de l’image 2 qui vaut 121, c’est-`a-dire
01111001.
L’id´ee est de recombiner les 5 chiffres les plus significatifs du premier pixel avec les 3 chiffres les plus significatifs de l’image 2. Les chiffres significatifs sont les plus importants, ceux qui se trouvent `a gauche. Au contraire, les unit´es ne sont pas tr`es importantes pour nous. De nos 2 octets d’origine
10111 110 et 011 11001
on ne garde que les chiffres les plus significatifs, en mettant ceux de la premi`ere image en tˆete. Ce m´elange des deux octets d’origine produit l’octet suivant :
10111 011.
On remarque que l’on a peu modifi´e la valeur par rapport `a celle de l’image 1, parce que l’on a gard´e les 5 bits les plus significatifs. Sur notre exemple, la diff´erence est seulement de 3 : la nouvelle valeur est 187, ce qui donne un rouge comme ce texte, au lieu de 190 dans l’image originale, ce qui donne un rouge qui est tr`es proche `a l’œil nu.
Au pire, on transforme les 3 derniers bits de 000 `a 111, ou vice-versa, ce qui fait une diff´erence de 7, au plus.
En r´esum´e, la fusion des 2 images ressemble beaucoup `a la premi`ere image.
Qu’a-t-on gagn´e ? Ce que l’on a gagn´e, c’est que `a partir de l’octet que l’on a cr´e´e dans l’image transform´ee 10111 011.
on n’a pas beaucoup modifi´e la premi`ere image, et on peut retrouver une couleur proche de celle du pixel de la seconde image grˆace aux 3 derniers bits, 011. On sait donc que la valeur du pixel original de la seconde image se situe entre 011 00000 et 011 11111.
L’erreur est au maximum de 32. Pour reconstruire approximativement le pixel original, on peut compl´eter la valeur de fa¸con interm´ediaire, en ajoutant 16. `A partir d’un pixel de l’image modifi´ee, on reconstruit donc l’approximation du pixel de l’image cach´ee :
01110000
Ce nombre vaut 112 au lieu de 121 dans l’image 2 qu’on voulait cacher. On a donc fait une erreur de 9 qui reste acceptable. Au pire, on fera une erreur de 16. ¸Ca reste suffisant pour retrouver l’image cach´ee, mˆeme si la perte de pr´ecision la d´egradera.
II.3 Comment r´ecup´erer l’image cach´ee ? Exercice 10.
1. ´Ecrire une fonctionbinaire(n)qui prend en entr´ee une valeurncod´ee sur un octet et retourne une liste contenant son code en binaire.
V´erifier que cette fonction renvoie bien la liste [1,0,1,1,1,1,1,0]pour le rouge dont l’octet vaut 190.
2. En d´eduire une fonction valeur_derniers_bits(n) qui, `a partir d’une valeur n cod´ee sur un octet, retourne la valeur correspondant aux 3 derniers bits.
Par exemple, si on transmet 187 `a cette fonction, dont le code en binaire est 10111011, elle devra garder le code des 3 derniers bits, c’est-`a-dire 011 et retourner 3.
Exercice 11.
Ecrire une fonction´ d´ecaler(m) qui, `a partir d’un entier m dont le code se repr´esente sur 3 bits, retourne la valeur correspondant `a ces 3 bits compl´et´es par 10000. Par exemple, si on transmet 3 `a cette fonction, dont le code binaire est 011, elle retournera 112, cod´e par 01110000.
Exercice 12.
Ecrire une fonction´ decoder(image) qui d´ecode l’image image (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen). Tester cette fonction avec le fichier couleurs.png.
Exercice 13.
Ecrire une fonction´ cache(image_illusion,image_cacher)qui cache l’imageimage_cacher(qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen) dans l’imageimage_illusion (qui a ´et´e charg´e au pr´ealable `a l’aide de la fonctionopen).
Exercice 3.
1 fr om PIL i m p o r t I m a g e
2 fr om PIL . I m a g e i m p o r t *
3
4 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
5 I m a g e . sh ow ( i m a g e )
6 p r i n t( I m a g e . g e t p i x e l ( image , ( 3 6 , 2 ) ) )
7 p r i n t( i m a g e . s ize )
8 i m a g e . c l o s e ()
Exercice 4.
1 def i n v e r s i o n ( i m a g e ):
2 ( l , h ) = i m a g e . s ize
3 for y in r a n g e( h ):
4 for x in r a n g e( l ):
5 c = I m a g e . g e t p i x e l ( image ,( x , y ))
6 inv = 255 - c
7 I m a g e . p u t p i x e l ( image ,( x , y ) , inv )
8 r e t u r n i m a g e
9
10 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
11 I m a g e . sh ow ( i n v e r s i o n ( i m a g e ))
12 i m a g e . c l o s e ()
Exercice 5.
1 def n o i r _ e t _ b l a n c ( image , s ):
2 ( l , h ) = i m a g e . s ize
3 for y in r a n g e( h ):
4 for x in r a n g e( l ):
5 c = I m a g e . g e t p i x e l ( image ,( x , y ))
6 if c <= s :
7 c =0
8 el se:
9 c =2 55
10 I m a g e . p u t p i x e l ( image ,( x , y ) , c )
11 r e t u r n i m a g e
12
13 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
14 I m a g e . sh ow ( n o i r _ e t _ b l a n c ( image , 1 2 5 ) )
15 i m a g e . c l o s e ()
Exercice 6.
1 def l i g n e ( image , y , c ):
2 ( l , h ) = i m a g e . s ize
3 for x in r a n g e( l ):
4 I m a g e . p u t p i x e l ( image ,( x , y ) , c )
5 r e t u r n i m a g e
6
7 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
8 I m a g e . sh ow ( l i g n e ( image , 125 ,0 ))
9 i m a g e . c l o s e ()
Exercice 7.
1 def a s s o m b r i r ( i m a g e ):
2 ( l , h ) = i m a g e . s ize
3 for x in r a n g e( l ):
4 for y in r a n g e( h ):
5 c = I m a g e . g e t p i x e l ( image ,( x , y ))
6 I m a g e . p u t p i x e l ( image ,( x , y ) , c // 2)
7 r e t u r n i m a g e
8
9 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
10 I m a g e . sh ow ( a s s o m b r i r ( i m a g e ))
11 i m a g e . c l o s e ()
Exercice 8.
1 def e c l a i r c i r ( i m a g e ):
2 ( l , h ) = i m a g e . s ize
3 for x in r a n g e( l ):
4 for y in r a n g e( h ):
5 c = I m a g e . g e t p i x e l ( image ,( x , y ))
6 if 2* c > 255 :
7 I m a g e . p u t p i x e l ( image ,( x , y ) ,255)
8 el se:
9 I m a g e . p u t p i x e l ( image ,( x , y ) ,2* c )
10 r e t u r n i m a g e
11
12 i m a g e =op en(" n o i r _ e t _ b l a n c . png "," r ")
13 I m a g e . sh ow ( e c l a i r c i r ( i m a g e ))
14 i m a g e . c l o s e ()
Exercice 9.
1 def n o _ r o u g e ( i m a g e ):
2 ( l , h ) = i m a g e . s ize
3 for x in r a n g e( l ):
4 for y in r a n g e( h ):
5 ( rouge , vert , b leu )= i m a g e . g e t p i x e l (( x , y ))
6 i m a g e . p u t p i x e l (( x , y ) ,(0 , vert , b leu ))
7 r e t u r n i m a g e
8
9 i m a g e =op en(" c o u l e u r s . png "," r ")
10 I m a g e . sh ow ( n o _ r o u g e ( i m a g e ))
11 i m a g e . c l o s e ()
Exercice 10.
1 def b i n a i r e ( n ):
2 s =[0 ,0 ,0 ,0 ,0 ,0 ,0 ,0]
3 y = n
4 for i in r a n g e(8 ):
5 s [ -1 - i ]= y %2
6 y = y //2
7 r e t u r n s
8
9 def v a l e u r _ d e r n i e r s _ b i t s ( n ):
10 s =[0 ,0 ,0 ,0 ,0 ,0 ,0 ,0]
11 y = n
12 for i in r a n g e(8 ):
13 s [ -1 - i ]= y %2
14 y = y //2
15 r e t u r n s [ -1]+2* s [ -2]+4* s [ -3]
Exercice 11.
1 def d e c a l e r ( m ):
2 s =[0 ,0 ,0 ,0 ,0 ,0 ,0 ,0]
3 y = m
4 for i in r a n g e(8 ):
5 s [ -1 - i ]= y %2
6 y = y //2
7 r e t u r n 2 * * 5 * s [ - 1 ] + 2 * * 6 * s [ - 2 ] + 2 * * 7 * s [ - 3 ] + 2 * * 4
Exercice 12.
1 def d e c o d e r ( i m a g e ):
2 ( l , h ) = i m a g e . s ize
3 for x in r a n g e( l ):
4 for y in r a n g e( h ):
5 ( rouge , vert , ble u )= i m a g e . g e t p i x e l (( x , y ))
6 r o u g e = d e c a l e r ( v a l e u r _ d e r n i e r s _ b i t s ( r o u g e ))
7 ve rt = d e c a l e r ( v a l e u r _ d e r n i e r s _ b i t s ( ver t ))
8 bl eu = d e c a l e r ( v a l e u r _ d e r n i e r s _ b i t s ( ble u ))
9 i m a g e . p u t p i x e l (( x , y ) ,( rouge , vert , bl eu ))
10 r e t u r n i m a g e
11
12 i m a g e =op en(" c o u l e u r s . png "," r ")
13 I m a g e . sh ow ( d e c o d e r ( i m a g e ))
14 i m a g e . c l o s e ()
Exercice 13.
1 def c a c h e ( i m a g e _ i l l u s i o n , i m a g e _ c a c h e r ):
2 ( l , h ) = i m a g e _ i l l u s i o n . si ze
3 for x in r a n g e( l ):
4 for y in r a n g e( h ):
5 ( rouge_1 , vert_1 , b l e u _ 1 )= i m a g e _ i l l u s i o n . g e t p i x e l (( x , y ))
6 ( rouge_2 , vert_2 , b l e u _ 2 )= i m a g e _ c a c h e r . g e t p i x e l (( x , y ))
7 u , v = b i n a i r e ( r o u g e _ 1 ) , b i n a i r e ( r o u g e _ 2 )
8 r o u g e = u [ 4 ] * 2 * * 3 + u [ 3 ] * 2 * * 4 + u [ 2 ] * 2 * * 5 + u [ 1 ] * 2 * * 6 + u [ 0 ] * 2 * * 7 + v [ 2 ] + 2 * v [ 1 ] + 4 * v [0]
9 u , v = b i n a i r e ( v e r t _ 1 ) , b i n a i r e ( v e r t _ 2 )
10 ve rt = u [ 4 ] * 2 * * 3 + u [ 3 ] * 2 * * 4 + u [ 2 ] * 2 * * 5 + u [ 1 ] * 2 * * 6 + u [ 0 ] * 2 * * 7 + v [ 2 ] + 2 * v [ 1 ] + 4 * v [0]
11 u , v = b i n a i r e ( b l e u _ 1 ) , b i n a i r e ( b l e u _ 2 )
12 bl eu = u [ 4 ] * 2 * * 3 + u [ 3 ] * 2 * * 4 + u [ 2 ] * 2 * * 5 + u [ 1 ] * 2 * * 6 + u [ 0 ] * 2 * * 7 + v [ 2 ] + 2 * v [ 1 ] + 4 * v [0]
13 i m a g e _ i l l u s i o n . p u t p i x e l (( x , y ) ,( rouge , vert , bl eu ))
14 r e t u r n i m a g e _ i l l u s i o n