TP – Image

Dans ce TP nous aurons besoin de la bibliothèque Pillow. C’est une bibliothèque permettant de travailler sur les images.

Cette bibliothèque est déjà installée avec EduPython.

Maintenant créez un dossier TP_image. Nous travaillerons dans ce dossier.

Dans cette activité, nous allons travailler avec l’image ci-dessous « IMAGE.jpg ».

Télécharger cette image et la copier dans un répertoire « TP_image »

 Lenna

Lenna

Pour en savoir plus sur l’origine de cette photo : https://fr.wikipedia.org/wiki/Lenna

1. Quelques rappels sur les images :

  • Une image est constituée de pixels (points), la définition d’une image L x H (par exemple 330 x 330 pour l’image considérée correspond au nombre de pixels de l’image (L : la largeur de l’image en pixel, H : la hauteur de l’image en pixel).
  • Chaque pixel est constitué de 3 éléments (chacun est appelé aussi canal) : un rouge, un vert et un bleu (RVB). C’est la somme de ces 3 couleurs qui permet d’obtenir un grand nombre de couleurs (synthèse additive).
  • Classiquement, à chaque canal, on associe un nombre binaire codé sur 8 bits (soit donc 24 bits par pixel).
  • Pour chaque pixel, on aura donc une valeur pour le rouge (comprise entre 0 et 255 puisque codé sur 8 bits), une valeur pour le vert (comprise entre 0 et 255) et une valeur pour le bleu (comprise entre 0 et 255).
    Quelques exemples : (0,0,0) => noir ; (255,0,0) => rouge ; (255,255,255) => blanc ; (0,255,0) => vert…

Remarque : Il peut exister un 4e canal en plus du canal rouge, canal vert et canal bleu, le canal « alpha » qui permet de gérer la transparence du pixel (par exemple, les images au format .png gèrent la transparence). Chaque pixel est donc codé sur 32 bits (4 x 8).

Partant du principe que l’image que vous avez copiée possède une définition de 508*512, que chaque pixel est constitué de 3 éléments (RVB) chacun codé sur 8 bits = 1 octet, calculez la taille (ou poids) de cette image en kilo octet (ko).
Rappel : 1 ko = 1024 octets ; 1 octet = 8 bits
Si vous regardez la taille réelle de l’image en ko, vous allez sans doute trouver une valeur inférieure à celle que vous venez de calculer. Ceci est tout à fait normal, car le .jpeg est un format compressé (le taux de compression est compris entre 10 : 1 et 25 : 1).
Vous pouvez convertir cette image en .PNG avec « paint » ou « photofiltre » et comparer sa nouvelle taille à la taille précédente.

2. Fonctions de base

  1. Voici le code minimal vous permettant d’ouvrir une image et de l’afficher :
    from PIL import Image
    image =  Image.open("IMAGE.jpg")
    image.show()

    Attention ! Pour que cela fonctionne votre fichier .py doit se trouver dans le même dossier que votre image !
    La première ligne permet d’indiquer que nous utiliserons les outils de la bibliothèque Pillow.
    La deuxième ligne permet d’ouvrir l’image et de l’enregistrer dans variable (pour simplifier) « image »
    La troisième ligne permet d’afficher l’image à l’écran.

  2. Plutôt que d’afficher l’image on peut plutôt en enregistrer une copie:
    from PIL import Image
    image = Image.open("IMAGE.jpg")
    image.save("resultat.jpg", "JPEG")

    La ligne « image.save(« resultat.jpg », »JPEG ») » permet de sauvegarder une image. L’image sera sauvegardée dans le dossier courant (le même dossier que « IMAGE.jpg ») et aura pour nom « resultat.jpg ».

  3. La méthode getpixel((x,y)) renvoie un tuple (un tuple ressemble beaucoup à une liste, à l’exception près, qu’un tuple, une fois créé, n’est pas modifiable.) contenant les trois composantes : rouge, verte et bleue du pixel situé aux coordonnées x, y (sachant que le pixel de coordonnées 0, 0 se situe en haut à gauche de l’image).
    Pixel de coordonnées (3, 1)

    Pixel de coordonnées (3, 1)

    Saisissez, analysez et testez ce code :

    from PIL import Image
    image = Image.open("IMAGE.jpg")
    (r, v, b) = image.getpixel((100, 100))
    print(r, v, b)

    Si tout se passe correctement, vous devriez avoir à l’écran (dans la console) : (175, 68, 76). Nous pouvons donc affirmer que le pixel de l’image « IMAGE.jpg », ayant pour coordonnées (100, 100), a pour composantes : Rouge=>175 ; Vert=>68 ; Bleu=>76. Encore une chose importante sur les tuples : si vous voulez récupérer une valeur du tuple, cela se passe exactement comme avec les listes. Si vous reprenez l’exemple ci-dessus, tu [0] est égal à 175 et tu [2] est égal à 68. Vous remarquerez que la méthode getpixel prend en paramètre un tuple : (100,100).

  4. Autre fonction très utile : putpixel. Cette méthode permet de modifier les canaux Rouge, Vert et Bleu d’un pixel. La méthode putpixel prend deux paramètres (2 tuples) : le premier paramètre correspond aux coordonnées du pixel que nous voulons modifier (tuple avec 2 éléments : (x, y)). Le second paramètre correspond aux valeurs à attribuer aux canaux R, V, B (tuple avec 3 éléments : (255,255,255), ici un pixel blanc).Saisissez, analysez et testez ce code :
    from PIL import Image
    image = Image.open("IMAGE.jpg")
    image.putpixel((312, 444), (0, 0, 255))
    image.save("resultat.jpg", "JPEG")

    Cherchez maintenant le pixel bleu sur l’image. (vers l’épaule 🙂 )

  5. Récupérer la définition d’une photo
    (L, H) = image.size
  6. Redimensionner une photo
    image = image.resize((L, H))

    L et H étant les nouvelles dimensions de « image »

  7. Visualiser une image
    image.show() 

3. Pixel art

Nous allons construire un petit drapeau français sur 6 pixels :

Voici le programme en question :

from PIL import Image
image = Image.new('RGB', (3, 2))
image.putpixel((0, 0), (5, 20, 64))
image.putpixel((0, 1), (5, 20, 64))
image.putpixel((1, 0), (255, 255, 255))
image.putpixel((1, 1), (255, 255, 255))
image.putpixel((2, 0), (236, 25, 32))
image.putpixel((2, 1), (236, 25, 32))
image.save("image.png")

Pensez à zoomer, le drapeau est tout petit 🙂

Si vous le souhaitez vous pouvez redimensionner l’image avec :

image = image.resize((300,200))

Exercice :

  • Modifiez le programme pour obtenir le drapeau allemand.

Exercice :

  • Une fois ce drapeau réalisé essayez de réaliser un dessin de votre choix. (une lettre, un smiley, etc )

Exercice supplémentaire (Exercice un peu difficile, vous pouvez le passer si vous êtes en seconde) :

  1. Ecrivez une procédure qui permet de colorier un rectangle d’une certaine longueur, d’une certaine largeur et d’une certaine couleur.
    Compléter :
    from PIL import Image
    def rectangle(origine, image, longueur, largeur, couleur):
    # A vous de complèter ici
    # test de la procédure :
    image = Image.new('RGB', (50, 50))
    rectangle((2,2), image, 20, 30, (0, 0, 250))

    Le programme précédent devrait dessiner un rectangle bleu de 20 pixels sur 30 pixels. Le coin en haut à gauche de ce rectangle se situe sur le pixel de coordonnées (2;2)

  2. Utilisez la fonction précédente pour faire un drapeau français de 500 pixels de côté.

4. Modification d’une photo

Très souvent il est nécessaire de parcourir les pixels d’une image. Voyons un exemple permettant de transformer tous les pixels en bleu :

from PIL import Image
image = Image.open("IMAGE.jpg")
(L, H)= image.size
for i in range(H): # On parcours les lignes de pixels de l'image
for j in range(L): #  Pour chaque ligne on parcours les pixels de la ligne i
image.putpixel((j, i), (0, 0, 255))
image.save("resultat.jpg", "JPEG")
image.show()

Le résultat n’est pas très intéressant… Avant d’aller plus loin assure toi d’avoir bien compris ce petit programme.

Regardons des manipulations plus intéressantes :

(Avant de consulter les corrigés tu peux essayer un peu quand même… Et si tu es amené à consulter le corriger assure toi de bien le comprendre)

1) Écrire et commenter le programme permettant de d’assombrir l’image. (soustraire 50 à chaque canal, par exemple)
Indication : Il faut penser à utilise get.pixel pour récupérer les couleurs de ce pixel.

2) Écrire et commenter un programme en Python qui permettra de transformer une image couleur en son négatif.

3) Écrire et commenter un programme en Python qui permettra de transformer une image couleur en une image en niveau de gris (souvent improprement appelée « noir et blanc », car une image « noir et blanc » est uniquement composée de pixel noir et de pixel blanc).
Une des façons d’obtenir du gris est de prendre les fractions suivantes pour les composantes RVB : (rouge=0.299 ;
verte=0.587 ; bleue=0.144), la somme faisant 1.

Remarque : en Python, int(x) permet de prendre la valeur entière de x.

4) Transformer une image en sa symétrique par rapport à l’axe de symétrie « vertical » (principal) de la fenêtre graphique.

5) (Attention, cette question est optionnelle en seconde) Faite tourner l’image d’un quart de tour dans le sens des aiguilles d’une montre. (Et sans dupliquer l’image si vous souhaitez faire la question en mode Iron Man)

Corrigés

1) Assombrir l’image

Solution

from PIL import Image
image = Image.open("IMAGE.jpg")
(L, H) = image.size
for i in range(H): 
for j in range(L): 
(r, v, b) = image.getpixel((j, i))
image.putpixel((j, i), (r-50, v-50, b-50))
image.save("resultat.jpg", "JPEG")
2) Négatif de l'image

Solution

from PIL import Image
image = Image.open("IMAGE.jpg")
(L, H) = image.size
for i in range(H):
for j in range(L):
(r, v, b) = image.getpixel((j, i))
image.putpixel((j, i), (255 - r, 255 - v, 255 - b))      
image.save("resultat.jpg", "JPEG")
3) Niveau de gris

Solution

from PIL import Image
image = Image.open("IMAGE.jpg")
(L, H) = image.size
for i in range(H):
for j in range(L):
(r, v, b) = image.getpixel((j, i))
image.putpixel((j, i), (int(0.299 * r), int(0.587 * v), int(0.144 * b)))      
image.save("resultat.jpg", "JPEG")
4) Symétries

Solution

from PIL import Image
image = Image.open("IMAGE.jpg")
(L, H) = image.size
# On utilise une nouvelle image
nouvelle_image = Image.new("RGB", (L, H))
for i in range(H):
for j in range(L):
(r, v, b) = image.getpixel((j, i))
nouvelle_image.putpixel((j, -i+H-1), (r, v, b))     
nouvelle_image.save("resultat.jpg", "JPEG")

Exemple de mini-projet : Exemples de mini-projets sur les images numériques

Exercice :

Pour la future application FaceSturm, pourriez vous écrire un programmequi change la couleur du rouge à lèvre de cette dame.

Faite la même chose pour la deuxième photo mais en faisant attention de ne pas modifier la couleur du fond !

5. Variations autour d’une pomme

Pour commencer, télécharger cette image de pomme :

Maintenant testez le code qui permet de coller l’image de pomme dans une image de fond :

from PIL import Image
# On ouvre l'image de pomme
image = Image.open("pomme.jpg")
# On réccupère la définition de l'image de pomme
(L, H) = image.size
# Je crée une nouvelle image pouvant contenir 4 fois l'image de pomme
fond = Image.new("RGB", (L * 2, H * 2))
# Je colle l'image en (0, 0) (coin en haut à gauche
fond.paste(image, (0, 0))
fond.save("resultatf.jpg", "JPEG")
fond.show() 

Maintenant modifiez ce code pour obtenir l’image suivante :

Quatre pommes

Solution

from PIL import Image
# On ouvre l'image de pomme
image = Image.open("pomme.jpg")
# On réccupère la définition de l'image de pomme
(L, H) = image.size
# Je crée une nouvelle image pouvant contenir 4 fois l'image de pomme
fond = Image.new("RGB", (L * 2, H * 2))
# Je colle l'image en (0, 0) (coin en haut à gauche
fond.paste(image, (0, 0))
fond.paste(image, (L, 0))
fond.paste(image, (0, H))
fond.paste(image, (L, H))
fond.save("resultatf.jpg", "JPEG")
fond.show() 

En vous inspirant de ce code :

from PIL import Image
# On ouvre l'image de pomme
pomme1 = Image.open("pomme.jpg")
#On crée une copie de la pomme
pomme2 = pomme1.copy()
# On réccupère la définition de l'image de pomme
(L, H) = pomme1.size
# Je crée une nouvelle image pouvant contenir 4 fois l'image de pomme
fond = Image.new("RGB", (L * 2, H * 2))
# Je modifie ma copie de pomme
for i in range(H): # On parcours les lignes de pixels de l'image
for j in range(L): # On parcours les pixels de la ligne i
(r, v, b)=pomme1.getpixel((j, i))
pomme2.putpixel((j, i), (255 - r, 255 - v, 255 - b))
fond.paste(pomme1, (0, 0))
fond.paste(pomme2, (L, H))
fond.save("resultatf.jpg", "JPEG")
fond.show() 

et en réutilisant tout ce que vous avez vu dans ce TP, écrivez un programme permettant d’obtenir l’image suivante :

(Pour chaque image une couleur a été supprimée)

Et maintenant, laissez libre cours à votre imagination ! Réalisez votre œuvre d’art.