Formation I.S.N.

Module PIL - Exercices

Le module PIL manipule tout type de fichier image, des plus classiques (.jpg, .png, .gif) au moins courants (comme le Portable Bitmap). Les informations récupérées sur l'image sont :

  • soit des chaînes de caractères (extension du fichier, encodage des couleurs, ...) ;
  • soit des tuples de nombres, que l'on peut interpréter grossièrement comme des listes de nombres non modifiables (dimensions de l'image, intensité des composantes RVB).

Les exercices ci-dessous permettent de manipuler les images dans différentes situations. Certains ont été donnés à des élèves.

Extraction de composantes


  1. Cliquer sur l'image ci-contre pour télécharger le logo ISN-IREM au format .jpg.
  2. Concevoir un unique programme permettant d'afficher trois images distinctes, chacune représentant les composantes rouge, vert et bleu de l'image d'origine :
Composante rouge Composante verte Composante bleue
  • Une piste
  • Une solution classique
  • Une solution plus originale

Les dimensions des images sont celles de l'image d'origine, l'encodage couleur des images est celui de l'image d'origine...

On parcourt chaque pixel de l'image d'origine et on enregistre les composantes r, v, b de ce pixel. La lère image créée ne reçoit que la composante rouge. Quelle valeur peut-on alors donner aux composantes vertes et bleues ?


##----- Importation des Modules -----##
from PIL import Image                             # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size

##----- Conception de la nouvelle image -----##
im_rouge = Image.new(couleur, (l, h))             # Composante rouge
im_verte = Image.new(couleur, (l, h))             # Composante verte
im_bleue = Image.new(couleur, (l, h))             # Composante bleue

for x in range(l):
    for y in range(h):                            # On parcourt chaque pixel de l'image analysée plus haut
        r, v, b = im.getpixel((x, y))             # On récupère le triplet de couleur
        
        im_rouge.putpixel((x, y), (r, 0, 0))      # Il faut un tuple pour les intensités de couleur 
        im_verte.putpixel((x, y), (0, v, 0)) 
        im_bleue.putpixel((x, y), (0, 0, b))

im_rouge.save('Logo_ISN-IREM_Rouge.jpg')
im_verte.save('Logo_ISN-IREM_Vert.jpg')
im_bleue.save('Logo_ISN-IREM_Bleu.jpg')
im_rouge.show()
im_verte.show()
im_bleue.show()

##----- Importation des Modules -----##
from PIL import Image                              # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size

##----- Conception de la nouvelle image -----##
liste=[0, 0, 0]                                    # Future liste des images_composantes

for i in range(3):
    liste[i] = Image.new(couleur, (l, h))          # Chaque élément de la liste est une image en devenir
    
for x in range(l):
    for y in range(h):
        triplet = im.getpixel((x, y))              # Composantes sous forme de liste
        
        for i in range(3):
            a=[0, 0]                               # On insère la composante R, V ou B dans la liste selon la valeur de i
            a.insert(i, triplet[i])
            liste[i].putpixel((x, y), tuple(a))    # Il faut un tuple pour les intensités de couleur 

for i in range(3):
    liste[i].save('Logo_ISN-IREM_{0}.jpg'.format(i))
    liste[i].show()

Quelques nuances de gris

Dans une image en couleur, un pixel dispose des trois composantes RVB. Un pixel dont les trois valeurs RVB sont identiques sera affiché dans une nuance de gris. Pour convertir une image couleur en niveaux de gris, on peut :

  1. utiliser la moyenne des trois composantes RVB : \(G = \frac {R+V+B} {3}\).
  2. utiliser la formule recommandée (recommandation 601) par la C.I.E (Commission Internationale de l'Éclairage) pour les couleurs non-linéaires (image vue à partir d'un écran vidéo) : \(G = 0,299 R + 0,587 V + 0,114 B\).
  • Une piste
  • Une solution

Il y a deux possibilités pour l'image à concevoir :

  • Ou bien on la définit avec le mode couleur 'RGB' et les trois composantes du triplet doivent prendre la même valeur ;
  • Ou bien on la définit avec le mode couleur 'L' et il suffit de donner une unique valeur pour la nuance de gris.

##----- Importation des Modules -----##
from PIL import Image                               # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
l, h = im.size

##----- Conception de la nouvelle image -----##
im_gris = Image.new('L', (l, h))

for x in range(l):
    for y in range(h):                              # On parcourt chaque pixel de l'image ouverte plus haut
        r, v, b = im.getpixel((x, y))               # On récupère le triplet de couleur
        # g=(r+v+b)//3                              # Quotient pour obtenir une valeur entière...
        g = int(0.299*r + 0.587*v + 0.114*b)
                
        im_gris.putpixel((x, y), g)

im_gris.save('Logo_ISN-IREM_Gris.jpg')
im_gris.show()

Création d'un sigle

L'image ci-contre représente le sigle d'une célèbre marque de voiture inscrit dans un carré de 400 px de côté.
Les cercles ont pour rayon 130 px et 180 px.

Pour concevoir un programme en langage Python permettant de créer le fichier au format JPEG de ce logo, on pourra suivre les étapes suivantes :

  1. Commencer par colorier en noir toute la zone extérieure au petit cercle et en blanc la zone intérieure.
  2. Compléter le programme en coloriant en blanc la zone extérieure au grand cercle.
  3. Finir par tracer les deux zones bleues à l'intérieur du petit cercle.
  • Une piste
  • Une solution

Les pixels situés à l'extérieur d'un cercle de centre A de coordonnées (a,b) et de rayon r sont des points M de coordonnées (x,y) telles que la distance de A à M est supérieure à r, ce qui s'écrit (x-a)**2+(y-b)**2>r**2


##----- Importation des Modules -----##
from PIL import Image                              # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
couleur = 'RGB'
l, h = 400, 400

##----- Conception de la nouvelle image -----##
wbm = Image.new(couleur, (l, h))                    # création nouvelle image vierge

for x in range(l):
    for y in range(h):                              # On parcourt chaque pixel
        if (x-200)**2+(y-200)**2>16900:             # si on est au-delà du petit cercle
			if (x-200)**2+(y-200)**2<32400:         # mais à l'interieur du grand
				wbm.putpixel((x,y),(0,0,0))         # on colorie en noir
			else:									# sinon
				wbm.putpixel((x,y),(255,255,255))	# on colorie en blanc
		else:										# si on est à l'intérieur du petit cercle
			if x>200 and y>200 or x<200 and y<200:	# et si on est dans le quart inférieur droit ou supérieur gauche
				wbm.putpixel((x,y),(0,0,255))		# on colorie en bleu
			else:									# sinon
				wbm.putpixel((x,y),(255,255,255))	# on colorie en blanc
			

wbm.save('sigle.jpg')		# on sauvegarde
wbm.show()					# on affiche l'image créée
							

Symétrie(s)

  1. L'image ci-contre représente le logo ISN-IREM après une symétrie horizontale. Un pixel du logo d'origine a pour coordonnées (x, y). Quelles sont les coordonnées du pixel correspondant dans l'image à obtenir ?
  2. En déduire le programme permettant d'obtenir cette image.
  3. Améliorer ce programme pour que, selon la valeur d'un unique paramètre, la symétrie soit verticale ou horizontale.
  • Une illustration
  • Une solution
  • Une amélioration

##----- Importation des Modules -----##
from PIL import Image                             # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size

##----- Conception de la nouvelle image -----##
im_hori = Image.new(couleur, (l, h))              # Symetrie horizontale

for x in range(l):
    for y in range(h):                            # On parcourt chaque pixel de l'image analysée plus haut
        triplet = im.getpixel((x, y))             # On récupère le triplet de couleur
        
        im_hori.putpixel((x, h-1-y), triplet)     # La ligne du bas a pour ordonnée h-1...

im_hori.save('Logo_ISN-IREM_sym_hori.jpg')
im_hori.show()

##----- Importation des Modules -----##
from PIL import Image                               # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size

##----- Conception de la nouvelle image -----##
param = 1                                           # Lorsque param prend la valeur 0, la symétrie sera horizontale
                                                    # Lorsque param prend la valeur 1, la symétrie sera verticale
im_sym = Image.new(couleur, (l, h))

for x in range(l):
    for y in range(h):                              # On parcourt chaque pixel de l'image ouverte plus haut
        triplet = im.getpixel((x, y))               # On récupère le triplet de couleur
                                                    # avec param = 1, on a (1-param) = 0 et vice-versa...
        
        im_sym.putpixel(((l-1)*param + x*(-1)**param, (h-1)*(1-param) + y*(-1)**(1-param)), triplet)

im_sym.save('Logo_ISN-IREM_sym.jpg')
im_sym.show()

Rotation d'image

La transposition c'est bien, la rotation c'est mieux. Le programme à réaliser doit :

  1. Récupérer les informations d'une image existante ;
  2. Créer une nouvelle image avec le même encodage couleur, de largeur et hauteur échangées ;
  3. Faire en sorte que l'image obtenue soit l'image d'origine soumise à une rotation de 90° dans le sens direct ;
  4. Afficher l'image ainsi «tournée».

Pour les élèves ayant des difficultés à concevoir ce genre de transformation, leur faire illustrer par un dessin peut les amener à avoir une bonne piste de réflexion pour la suite.

  • Une illustration
  • Une solution

L'image n'est pas modifiée, elle est simplement tournée. Ce ne sont donc pas les composantes couleur qu'il faut modifier mais plutôt les coordonnées de chaque pixel. Pour trouver les opérations méthématiques à effectuer, le plus simple est de faire un schéma de l'image dans lequel on place un pixel de coordonnées (x, y) avant la rotation, puis le même pixel après la rotation. En déterminant ses nouvelles coordonnées à partir du pixel haut-gauche de l'image tournée, on peut en déduire les calculs à effectuer sur les coordonnées (x, y) d'origine.

On en déduit l'illustration ci-dessous. Les figures de couleurs représentent les pixels des 4 coins de l'image, avec leurs coordonnées avant pui après la rotation. Le pixel quelconque de coordonnées (x, y) est représenté par la carré rouge «évidé».


##----- Importation des Modules -----##
from PIL import Image                             # Ne pas oublier de l'importer pour un programme indépendant

##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size

##----- Conception de la nouvelle image -----##
im2 = Image.new(couleur, (h, l))                  # Création d'une image encodée en RGB, de largeur h et de hauteur l

for x in range(l):
    for y in range(h):                            # On parcourt chaque pixel de l'image analysée plus haut
        triplet = im.getpixel((x, y))             # On récupère son "code couleur"
        im2.putpixel((y, l-1-x), triplet)         # Attention à la numérotation des pixels, de 0 à l-1 en abscisses...

im2.save('Logo_ISN-IREM_tourne.jpg')
im2.show()