Vous êtes sur la page 1sur 9

Algorithmique MPSI

2 semaines FFF

TP No VI-A : Manipulations de
fichiers images : Partie No 1
Objectifs : Savoir ouvrir et modifier des fichiers images à l’aide de Python.

Exercice No 1 : Dans un sous-dossier adapté, créer un sous-dossier consacré à ce TP.

Ce TP est dans la continuité du précédent où l’on avait étudié la manipulation de fichiers textes.
On explique maintenant comme manipuler des fichiers images (extension png). Sous Windows, cela
correspond en gros aux fichiers directement lisibles à l’aide du logiciel Paint).

1 Les images « en noir et blanc »

Exercice No 2 : L’objectif de ce premier 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éalité bien
souvent des images en niveaux de gris.
Commencez par récupérer le fichier noir_et_blanc.png se situant sur ma page web et enregistrez-le
dans votre répertoire courant. Regardez l’image en double-cliquant dessus dans l’explorateur de fichiers.
En zoomant sur l’image, on s’aperçoit qu’elle est constituée d’une multitude de pixels organisés en
lignes (y) et colonnes (x). La couleur de chaque pixel est codée sur un octet (c’est-à-dire 8 bits), et
représente donc une nuance de gris parmi 255 valeurs possibles. On peut voir cette valeur comme
la luminosité du pixel : la valeur 0 code la couleur noire, la valeur 255 code la couleur blanche, et
les valeurs intermédiaires codent des nuances de gris de plus en plus claires à mesure que la valeur
augmente.

Figure 1 – Zoom à 150 % de l’image noir_et_blanc.png

Dans la bibliothèque PIL.Image, on dispose des fonctions


— Image.show(image) affiche l’image image. (qui a été chargé au préalable à l’aide de la fonction
open).

1
— Image.getpixel(image,(x,y)) récupère la valeur de la couleur du pixel situé en ligne y et
colonne x de l’image image. (qui a été chargé au préalable à l’aide de la fonction open).
A savoir que les indices des lignes et colonnes commencent à 0.
— Image.putpixel(image,(x,y),valeur) remplace la valeur de la couleur du pixel situé en ligne
y et colonne x de l’image image. (qui a été chargé au préalable à l’aide de la fonction open) par
valeur.

Exercice No 3 :
Afficher l’image noir_et_blanc sous Python puis récupérer la valeur de la couleur du pixel en ligne
36 et colonne 2.

Exercice No 4 :
Écrire une fonction inversion(image) qui prend en entrée une image (qui a été chargé au préalable
à l’aide de la fonction open.) et retourne l’image inversée 1 .
Pour ce faire, on pourra regarder ce que fait la fonction image.size (où image est une image chargée
à l’aide de la fonction open.)
Tester cette fonction avec le fichier noir_et_blanc.png.

Exercice No 5 :
Écrire une fonction noir_et_blanc(image,s) prend en entrée une image (qui a été chargé au préalable
à l’aide de la fonction open.) et un seuil s et qui transforme tous les pixels de valeur inférieure à s en
0 et tous les autres en 255.
Tester cette fonction avec le fichier noir_et_blanc.png.

Exercice No 6 :
Écrire une fonction ligne(image,y,c) qui trace une ligne de couleur de pixel égal à c sur la ligne y
de l’image image (qui a été chargé au préalable à l’aide de la fonction open.).
Tester cette fonction avec le fichier noir_et_blanc.png.

Exercice No 7 :
Écrire une fonction assombrir(image) qui assombri l’image image (qui a été chargé au préalable à
l’aide de la fonction open.) en divisant par 2 la valeur de chaque pixel.
Tester cette fonction avec le fichier noir_et_blanc.png.

Exercice No 8 :
Écrire une fonction eclaircir(image) qui éclaircie l’image image (qui a été chargé au préalable à
l’aide de la fonction open.) en multipliant par 2 la valeur de chaque pixel (en prenant soin de ne pas
dépasser la valeur maximale de 255).
Tester cette fonction avec le fichier noir_et_blanc.png.

2 Les images « en couleur »

Exercice No 9 : Comme précédemment, regardons comment un ordinateur « voit » et manipule des


images couleurs.
Commencez par récupérer le fichier couleurs.png se situant sur ma page web et enregistrer-le dans
votre répertoire courant. Regardez l’image en double-cliquant dessus dans l’explorateur de fichiers. En
zoomant sur l’image, vous devriez voir qu’elle est constituée d’une multitude de pixels organisés en
1. Par image inversée, on entend que les couleurs blanches sont remplacées par du noir et inversement.

2
lignes (y) et colonnes (x), tout comme le sont les images en niveaux de gris.
Pour représenter 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élange de 3 couleurs : rouge, vert, bleu. Chaque couleur est donnée par un nombre entre 0
et 255, on a donc besoin de 3 nombres (qu’on représente chacun sur un octet). Ce codage s’appelle
RGB pour Red Green Blue et où 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 ».

Figure 2 – Zoom à 150 % de l’image couleurs.png


Voici quelques exemples pour bien comprendre le codage des couleurs :
couleur R G B Octet 1 Octet 2 Octet 3
 0 0 0 00000000 00000000 00000000
255 255 255 11111111 11111111 11111111
 255 0 0 11111111 00000000 00000000
 0 255 0 00000000 11111111 00000000
 0 0 255 00000000 00000000 11111111
 132 122 191 10000100 01111010 10111111
Dans la bibliothèque PIL.Image, on dispose des fonctions
— image.getpixel((x,y)) retourne le tuple (rouge,vert,bleu) qui récupère la valeur des 3
couleurs R,G,B du pixel situé en ligne y et colonne x de l’image image (qui a été chargé au
préalable à l’aide de la fonction open).
— image.putpixel((x,y),(rouge,vert,bleu)) remplace la valeur de la couleur du pixel situé en
ligne y et colonne x par rouge,vert,bleu de l’image image. (qui a été chargé au préalable à
l’aide de la fonction open).

Exercice No 10 :
Écrire une fonction no_rouge(image) qui prend en entrée une image image (qui a été chargé au préa-
lable à l’aide de la fonction open) et qui supprime toute la couleur rouge de chaque pixel.
Tester cette fonction avec le fichier couleurs.png.

L’image couleurs.png que vous avez chargée contient une autre image cachée que vous allez essayer
de découvrir.

3
2.1 Principe pour cacher une image dans une autre
L’image a été cachée par mes soins en changeant légèrement la couleur de certains pixels de l’image
originale. Tout se passe comme si l’image cachée était « sous » l’image visible.

En fait, on mélange les pixels des deux images originales, en privilégiant l’image 1 pour qu’on ne
remarque pas que l’image 2 est cachée dedans. On utilise le fait que modifier légèrement la couleur
des pixels d’une image est difficile à discerner pour l’œil humain. Par exemple, le mot

abracadabra

ne contient pas deux lettres de même couleur, ce qui est difficile à voir. Les couleurs employées sont
trop proches les unes des autres pour pouvoir être distinguées. En résumé, modifier légèrement les
pixels d’une image ne se voit pas facilement.

On utilise le fait que l’œil ne distingue pas les faibles différences 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ême si en fait, on appliquera le même traitement aux trois couleurs).

Prenons 2 images de même dimension. Pour chacune des coordonnées (x, y), on va mélanger une
partie du pixel (x, y) de l’image 1 avec le pixel (x, y) de l’image 2. L’image obtenue sera très proche
de l’image 1, mais l’image 2 sera « cachée » à l’intérieur.
Imaginons que l’on veut mélanger un pixel dans l’image 1 dont l’octet rouge vaut 190, c’est-à-dire

10111110

avec l’octet de l’image 2 qui vaut 121, c’est-à-dire

01111001.

L’idée 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 à
gauche. Au contraire, les unités ne sont pas très importantes pour nous. De nos 2 octets d’origine

10111 110 et 011 11001

4
on ne garde que les chiffres les plus significatifs, en mettant ceux de la première image en tête. Ce
mélange des deux octets d’origine produit l’octet suivant :

10111 011.

On remarque que l’on a peu modifié la valeur par rapport à celle de l’image 1, parce que l’on a gardé
les 5 bits les plus significatifs. Sur notre exemple, la différence 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 comme celui-ci, qui est très proche à l’œil nu. Au pire, on transforme les 3 derniers bits de
000 à 111, ou vice-versa, ce qui fait une différence de 7, au plus. En résumé, la fusion des 2 images
ressemble beaucoup à la première image.
Qu’a-t-on gagné ? Ce que l’on a gagné, c’est que à partir de l’octet que l’on a créé dans l’image
transformée
10111 011,
on n’a pas beaucoup modifié la première image, et on peut retrouver une couleur proche de celle du
pixel de la seconde image grâce 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 com-
pléter la valeur de façon intermédiaire, en ajoutant 16. À partir d’un pixel de l’image modifiée, on
reconstruit donc l’approximation du pixel de l’image cachée :

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. Ça reste suffisant pour retrouver l’image
cachée, même si la perte de précision la dégradera.

2.2 Comment récupérer l’image cachée ?

Exercice No 11 :

Écrire une fonction valeur_derniers_bits(n) qui, à partir d’une valeur n codée sur un octet, re-
tourne la valeur correspondant aux 3 derniers bits.
Par exemple, si on transmet 187 à cette fonction, dont le code en binaire est 10111011, elle devra
garder le code des 3 derniers bits, c’est-à-dire 011 et retourner 3.

Exercice No 12 :

Écrire une fonction décaler(m) qui, à partir d’un entier m dont le code se représente sur 3 bits,
retourne la valeur correspondant à ces 3 bits complétés par 10000.
Par exemple, si on transmet 3 à cette fonction, dont le code binaire est 110, elle retournera 112, codé
par 11010000.

Exercice No 13 :

Écrire une fonction decoder(image) qui décode l’image image (qui a été chargé au préalable à l’aide
de la fonction open).
Tester cette fonction avec le fichier couleurs.png.

Exercice No 14 :

5
Écrire une fonction cache(image_illusion,image_cacher) qui cache l’image image_cacher (qui a
été chargé au préalable à l’aide de la fonction open) dans l’image image_illusion (qui a été chargé
au préalable à l’aide de la fonction open).

6
Correction des exercices
Correction Exercice No 3

from PIL.Image import *

image=open("noir_et_blanc.png","r")
Image.show(image)
print(Image.getpixel(image,(2,36)))
image.close()

Correction Exercice No 4

def inversion(image):
(l,h) = image.size
for y in range(h):
for x in range(l):
c = Image.getpixel(image,(x,y))
inv = 255 - c
Image.putpixel(image,(x,y), inv)
return image

image=open("noir_et_blanc.png","r")
Image.show(inversion(image))
image.close()

Correction Exercice No 5

def noir_et_blanc(image,s):
(l,h) = image.size
for y in range(h):
for x in range(l):
c = Image.getpixel(image,(x,y))
if c<=s:
c=0
else:
c=255
Image.putpixel(image,(x,y),c)
return image

image=open("noir_et_blanc.png","r")
Image.show(noir_et_blanc(image,125))
image.close()

Correction Exercice No 6

def ligne(image,y,c):
(l,h) = image.size
for x in range(l):
Image.putpixel(image,(x,y),c)
return image

image=open("noir_et_blanc.png","r")
Image.show(ligne(image,125,0))
image.close()

Correction Exercice No 7

7
def assombrir(image):
(l,h) = image.size
for x in range(l):
for y in range(h):
c = Image.getpixel(image,(x,y))
Image.putpixel(image,(x,y),c/2)
return image

image=open("noir_et_blanc.png","r")
Image.show(assombrir(image))
image.close()

Correction Exercice No 8

def eclaircir(image):
(l,h) = image.size
for x in range(l):
for y in range(h):
c = Image.getpixel(image,(x,y))
if 2*c > 255:
Image.putpixel(image,(x,y),255)
else:
Image.putpixel(image,(x,y),2*c)
return image

image=open("noir_et_blanc.png","r")
Image.show(eclaircir(image))
image.close()

Correction Exercice No 9

def no_rouge(image):
(l,h) = image.size
for x in range(l):
for y in range(h):
(rouge,vert,bleu)=image.getpixel((x,y))
image.putpixel((x,y),(0,vert,bleu))
return image

image=open("couleurs.png","r")
Image.show(no_rouge(image))
image.close()

Correction Exercice No 10

def valeur_derniers_bits(n):
s=[0,0,0,0,0,0,0,0]
y=n
for i in range(8):
s[-1-i]=y%2
y=y//2
return s[-1]+2*s[-2]+4*s[-3]

Correction Exercice No 11

def decaler(m):
s=[0,0,0,0,0,0,0,0]
y=m
for i in range(8):
s[-1-i]=y%2
y=y//2
return 2**5*s[-1]+2**6*s[-2]+2**7*s[-3]+2**4

Correction Exercice No 12

8
def decoder(image):
(l,h) = image.size
for x in range(l):
for y in range(h):
(rouge,vert,bleu)=image.getpixel((x,y))
rouge=decaler(valeur_derniers_bits(rouge))
vert=decaler(valeur_derniers_bits(vert))
bleu=decaler(valeur_derniers_bits(bleu))
image.putpixel((x,y),(rouge,vert,bleu))
return image

image=open("couleurs.png","r")
Image.show(decoder(image))
image.close()

Correction Exercice No 13

def binaire(n):
s=[0,0,0,0,0,0,0,0]
y=n
for i in range(8):
s[-1-i]=y%2
y=y//2
return s

def cache(image_illusion,image_cacher):
(l,h) = image_illusion.size
for x in range(l):
for y in range(h):
(rouge_1,vert_1,bleu_1)=image_illusion.getpixel((x,y))
(rouge_2,vert_2,bleu_2)=image_cacher.getpixel((x,y))
u,v=binaire(rouge_1),binaire(rouge_1)
rouge=16+u[-4]*2**3+u[-5]*2**4+u[-6]*2**5+u[-7]*2**6+u[-8]*2**7+v[-5]+2*v[-6]+4*v[-7]
u,v=binaire(vert_1),binaire(vert_2)
vert=16+u[-4]*2**3+u[-5]*2**4+u[-6]*2**5+u[-7]*2**6+u[-8]*2**7+v[-5]+2*v[-6]+4*v[-7]
u,v=binaire(bleu_1),binaire(bleu_2)
bleu=16+u[-4]*2**3+u[-5]*2**4+u[-6]*2**5+u[-7]*2**6+u[-8]*2**7+v[-5]+2*v[-6]+4*v[-7]
image_illusion.putpixel((x,y),(rouge,vert,bleu))
return image_illusion

Vous aimerez peut-être aussi