SNT Photo Filtrage

Identification

Infoforall

4 - Filtrage d'une image


Nous allons voir comment modifier les pixels des photos pour obtenir différents effets.

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Mise en évidence d'une couleur, transformation en noir et blanc, détection de contour ...

Cela vous permettra de voir ce qu'on peut faire avec un langage de programmation comme Python.

1 - Prise en main des images avec Python

Thonny permet de travailler avec Python dans un environnement qui permet de voir le contenu des variables, et d'avoir dans la même fenêtre

  • la fenêtre de programmation où on tape des instructions qu'on pourra exécuter plusieurs fois. C'est la partie en haut à gauche ci-dessous qui contient les mots largeur et hauteur.
  • la console où on écrit des instructions qui seront exécutées immédiatement. C'est la partie en bas à gauche qui contient 3 chevrons >>>. Ces chevrons forment l'invite de commande : le système précise qu'il est prêt à exécuter ce qu'on va taper.
  • la zone de visualisation des variables à droite. Elle permet de voir ce qui est en mémoire, ou pas.
Thonny

Nous allons maintenant manipuler des images et changer les valeurs RGB des différents pixels.

Nous avons vu dans l'activité précédente qu'une image n'est qu'une succession de nombres.

Pour manipuler les images avec Python et Thonny, il faut possèder un module spécifique, qui gère les images : Pillow.

01° Ouvrir Thonny. Dans le menu Affichage ou View, sélectionner variables.

Cela devrait ouvrir une zone à droite qui vous montrera les choses en mémoire.

Commençons par voir si vous disposez (ou pas) du module Pillow.

02° Tapez ceci dans la console pour voir si cela déclenche une erreur.

>>> from PIL import Image

Si c'est le cas :

  • Ouvrir le menu Tool/Outils en haut vers la droite dans Thonny
  • Sélectionner Manage Packages/Gérer les Paquets
  • Faire une recherche sur Pillow puis installer la bibliothèque. Ca peut être un peu long.
Vue Manage Packages

03° Téléchargez une image de type .png ou jpg sur le Web et placez la dans un dossier nommé SNT-photographie. Choisissez une image possèdant pas mal de couleurs différentes si possible.

Par exemple, pour illustrer ce cours, j'ai choisi ceci :

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

04° Réaliser les deux actions ci-dessous qui vont permettre à Python de vous donner certaines informations sur votre image : sa taille et son nombre de couches (par exemple 1 pour une image en nuance de gris, 3 pour une image en couleurs RGB, 4 pour une image en couleurs RGBA où A est la couche Alpha de transparence

Tâches à réaliser :

  1. Enregistrer sous le nom getion.py le programme ci-dessous au même endroit que votre image, donc dans le répertoire SNT-photographie.
  2. 📁 SNT-photographie

    📄 gestion.py

    📄 votre_image.png

  3. Modifier le nom du fichier-image en ligne 5 stocké dans la variable base de façon à ce qu'il corresponde à celui de votre image. Attention, le nom doit être placé entre guillemets pour faire comprendre à Python qu'on lui transmet un string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from PIL import Image AFFICHAGE = True base = Image.open("image.jpeg") largeur = base.width # width veut dire largeur en anglais hauteur = base.height # height veur dire hauteur en anglais couches = base.getbands() # pour récupérer les couches nb = len(couches) # pour récupérer le nombre nb de couches (len pour length, longueur) print("Nbr de pixels : ", largeur, "x", hauteur, "=", largeur*hauteur) print("Couches : ", couches) print("Nbr de couches : ", nb) if AFFICHAGE: base.show()

Exemple de résultats pouvant s'afficher dans la console :

Nbr de pixels : 1024 x 771 = 789504 Couches : ('R', 'G', 'B') Nbr de couches : 3

05° Répondre aux question suivantes :

  • Sur quel nom a-t-on stocké les données de l'image ?
  • Sur quelle ligne demande-t-on d'afficher l'image à l'écran ?
  • Expliquer pourquoi l'image s'affiche.

Nous allons maintenant réaliser en deux temps une pixelisation de votre image :

  1. On commence par réduire la taille de l'image par 10, ce qui va entrainer une perte d'informations.
  2. On finit en redonnant la taille initiale à l'image réduite. La perte d'informations va alors clairement apparaître.

06° Utiliser ce nouveau programme puis répondre aux questions..

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
from PIL import Image AFFICHAGE = True base = Image.open("image.jpeg") largeur = base.width # width veut dire largeur en anglais hauteur = base.height # height veur dire hauteur en anglais couches = base.getbands() # pour récupérer les couches nb = len(couches) # pour récupérer le nombre nb de couches (len pour length, longueur) print("Nbr de pixels : ", largeur, "x", hauteur, "=", largeur*hauteur) print("Couches : ", couches) print("Nbr de couches : ", nb) if AFFICHAGE: base.show() base = base.resize( (largeur//10, hauteur//10) ) # On divise la taille par k base = base.resize( (largeur, hauteur) ) # On remet la taille initiale if AFFICHAGE: base.show() base.save("image_pixelisée.jpg") # On sauvegarde l'image obtenue en modifiant le nom

Questions

  1. Sur quelle ligne divise-t-on la taille de l'image par 10&nbs?
  2. Sur quelle ligne lui redonne-t-on sa taille initiale ?
  3. Sur quelle ligne demande-t-on à Python de sauvegarder l'image ?

2 - Gestion des pixels avec Python

Nous allons maintenant changer les valeurs RGB des différents pixels.

Nous avons vu dans l'activité précédente qu'une image n'est qu'une succession de nombres.

07° Si ce n'est pas encore fait, téléchargez une image de type .png ou jpg sur le Web et placez la dans un dossier nommé SNT-photographie. Choisissez une image possèdant pas mal de couleurs différentes si possible.

Par exemple, pour illustrer ce cours, j'ai choisi ceci :

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

08° Réaliser les deux actions ci-dessous. Inutile de lire le code dans sa totalité, nous n'allons qu'en utiliser une petite partie.

  1. Enregistrer avec Thonny le programme ci-dessous au même endroit que votre image, donc dans le répertoire SNT-photographie.
  2. 📁 SNT-photographie

    📄 votre_programme.py

    📄 votre_image.png

  3. Modifier le nom du fichier-image en ligne 4 stocké dans la variable base de façon à ce qu'il corresponde à celui de votre image. Attention, le nom doit être placé entre guillemets pour faire comprendre à Python qu'on lui transmet un string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
from PIL import Image # Nom du fichier-image original base = "nom_a_modifier.png" # Nom voulu pour l'image après modification sauvegarde = "modification.png" def pixel(nom, x, y): '''Fonction qui renvoie un string contenant les intensité du pixel (x,y) de l'image''' # Création de l'objet-image propre à Python ref_image = Image.open(nom) # Si image avec 3 couches : R G B if len(ref_image.getbands()) == 3: # On récupère les valeurs RGB du pixel de coordonnées (x,y) rouge, vert, bleu = ref_image.getpixel( (x,y) ) return(f"Pixel de coordonnées ({x}, {y}) : R = {rouge} - G = {vert} - B = {bleu}") # Si image avec 4 couches : R G B et transparence (alpha) if len(ref_image.getbands()) == 4: # On récupère les valeurs RGB du pixel de coordonnées (x,y) rouge, vert, bleu, alpha = ref_image.getpixel( (x,y) ) return(f"Pixel de coordonnées ({x}, {y}) : R = {rouge} - G = {vert} - B = {bleu} - A = {alpha}") # Si image grise avec 1 couche : if len(ref_image.getbands()) == 1: # On récupère la valeur du pixel de coordonnées (x,y) intensite = ref_image.getpixel( (x,y) ) return(f"Pixel de coordonnées ({x}, {y}) : Intensité = {intensite}") def filtrer_image(nom): '''Fonction qui renvoie un objet-image après l'avoir filtré pixel par pixel''' # Création de l'objet-image propre à Python ref_image = Image.open(nom) # Lecture et action sur les pixels, un par un largeur, hauteur = ref_image.size # Si image avec 3 couches : R G B if len(ref_image.getbands()) == 3: for x in range(largeur): for y in range(hauteur): # On récupère les valeurs RGB du pixel de coordonnées (x,y) rouge, vert, bleu = ref_image.getpixel( (x,y) ) # On transforme les valeurs RGB avec la fonction de filtrage rouge, vert, bleu = filtrage(rouge, vert, bleu) # On transforme l'image-Python en mémoire ref_image.putpixel( (x, y) , (rouge, vert, bleu) ) # Sinon, si image avec 4 couches : R G B + Transparence(alpha) if len(ref_image.getbands()) == 4: for x in range(largeur): for y in range(hauteur): # On récupère les valeurs RGB du pixel de coordonnées (x,y) rouge, vert, bleu, alpha = ref_image.getpixel( (x,y) ) # On transforme les valeurs RGB avec la fonction de filtrage rouge, vert, bleu = filtrage(rouge, vert, bleu) # On transforme l'image-Python en mémoire ref_image.putpixel( (x,y), (rouge, vert, bleu, alpha) ) return ref_image def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = b # On place la valeur b dans rouge vert = g # On laisse la valeur g dans vert bleu = r # On place la valeur r dans bleu return (rouge, vert, bleu) # Création d'une nouvelle image à partir de la source originale nouvelle = filtrer_image(base) # Affichage de l'objet-image Python à l'écran nouvelle.show() # Sauvegarde de l'image dans un nouveau fichier-image nouvelle.save(sauvegarde)

Vous n'aurez qu'à gérer que les lignes suivantes du programme :

  • Ligne 1 : on importe les fonctionnalités liées aux images
  • Ligne 4 : on déclare le nom du fichier-image à traiter.
  • Ligne 6 : on déclare le nom donné à l'image modifiée.
  • Ligne 64 et plus : on déclare une fonction qui va modifier les couleurs de l'image
1 2 3 4 5 6 .. 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
from PIL import Image # Nom du fichier-image original base = "maisons.jpg" # Nom voulu pour l'image après modification sauvegarde = "modification.png" def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = b # On place la valeur b dans rouge vert = g # On laisse la valeur g dans vert bleu = r # On place la valeur r dans bleu return (rouge, vert, bleu) # Création d'une nouvelle image à partir de la source originale nouvelle = filtrer_image(base) # Affichage de l'objet-image Python à l'écran nouvelle.show() # Sauvegarde de l'image dans un nouveau fichier-image nouvelle.save(sauvegarde)
  • Ligne 72 : on crée une nouvelle image-python en utilisant la fonction filtrer_image() qui va utiliser la fonction filtrage()
  • Ligne 75 : on affiche l'image sur l'ordinateur.
  • Ligne 77 : on sauvegarde la nouvelle image sous le nom donné en L6.

09° Lancer votre programme. Si une erreur apparaît (en rouge), lire le message.

Souvent :

  • soit vous n'avez pas installé le module Pillow !
  • soit vous n'avez pas modifié le nom associé à la variable base
  • soit vous n'avez pas mis votre image et votre fichier Python dans le même répertoire

Si vous bloquez, faire appel à l'enseignant.

Vous devriez avoir une image à l'écran, mais une image où les intensités bleu et le rouge ont été inversées : voir les lignes suivantes

66 67 68
rouge = b # On place la valeur b dans rouge vert = g # On laisse la valeur g dans vert bleu = r # On place la valeur r dans bleu

Exemple avec une image contenant beaucoup de rouge et d'orange :

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Et qui devient une image contenant beaucoup de bleu et de cyan :

Image contenant beaucoup de bleu
Même image en intervertissant Bleu et Rouge

Pour obtenir les intensités RGB des différents pixels, nous allons utiliser la fonction pixel() qu'on déclare en ligne 8. Inutile de comprendre son code : nous allons simplement l'utiliser.

10° Utiliser les commandes suivantes dans la console pour voir les valeurs des intensités R, G et B sur le pixel de coordonnées x=50 et y=100 par exemple.

>>> pixel(base, 50, 100) 'Pixel de coordonnées (50, 100) : R = 160 - G = 174 - B = 3' >>> pixel(sauvegarde, 50, 100) 'Pixel de coordonnées (50, 100) : R = 3 - G = 174 - B = 160'

Visualiser que le programme est bien parvenu à intervertir les deux valeurs sur ce pixel.

Image JPEG : les images JPEG prennent moins de place en mémoire car on réduit le nombre de couleurs disponibles. Il est donc possible que les deux valeurs interverties ne soient pas exactement les mêmes si vous avez utilisé ce format pour le fichier de sauvegarde.

11° Comparer l'appel à la fonction et la déclaration de la fonction (son prototype)

L'appel :

>>> pixel(base, 50, 100)

La déclaration :

8
def pixel(nom, x, y):

Questions

  • Dans quel paramètre va se stocker la variable base ?
  • Dans quel paramètre va se stocker la valeur 50 ?
  • Dans quel paramètre va se stocker la valeur 100 ?

...CORRECTION...

Il faut associer place par place :

On voit donc qu'on stocke base dans nom, 50 dans x et 100 dans y.

C'est comme si cet appel précis avait été fait en notant ceci en début de la fonction :

  1. nom = base
  2. x = 50
  3. y = 100

12° Comparer l'appel à la fonction et la déclaration de la fonction (son prototype)

L'appel :

>>> pixel(sauvegarde, 300, 40)

La déclaration :

8
def pixel(nom, x, y):
  • Dans quel paramètre va se stocker la variable sauvegarde ?
  • Dans quel paramètre va se stocker la valeur 300 ?
  • Dans quel paramètre va se stocker la valeur 40 ?

...CORRECTION...

C'est comme si cet appel précis avait été fait en notant ceci en début de la fonction :

  1. nom = sauvegarde
  2. x = 300
  3. y = 40

Que fait la fonction filtrage() ? Pour l'instant, elle inverse les valeurs des intensités R et B.

Regardons comment nous pourrions l'utiliser.

3 - Filtrage

Filtrer les couleurs veut dire en laisser passer certaines et pas d'autres.

Pour l'instant, nous intervertissons le rouge et le bleu sur chaque pixel dans la fonction filtrage() :

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = b # On place la valeur b dans rouge vert = g # On laisse la valeur g dans vert bleu = r # On place la valeur r dans bleu return (rouge, vert, bleu)

13° CREER UN FILTRE ROUGE : cela veut dire que la fonction filtrage ne doit renvoyer que la bonne intensité rouge de départ et mettre les autres à 0.

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Et qui devient une image ne contenant que les intensités rouges :

Image avec uniquement la couche Rouge
La couche Rouge

L'une à côté de l'autre :

Image contenant beaucoup de rouge Image avec uniquement la couche Rouge

...CORRECTION...

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = r vert = 0 bleu = 0 return (rouge, vert, bleu)

14° CREER UN FILTRE BLEU : cela veut dire que la fonction filtrage() ne doit renvoyer que la bonne intensité bleue de départ et mettre les autres à 0.

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Et qui devient une image ne contenant que les intensités bleues :

Image avec uniquement la couche Bleue
La couche Bleue

L'une à côté de l'autre :

Image contenant beaucoup de rouge Image avec uniquement la couche Bleue

...CORRECTION...

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = r vert = 0 bleu = 0 return (rouge, vert, bleu)

15° CREER UN FILTRE VERT : cela veut dire que la fonction filtrage() ne doit renvoyer que la bonne intensité verte de départ et mettre les autres à 0.

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Et qui devient une image ne contenant que les intensités vertes :

Image avec uniquement la couche Verte
La couche Verte

L'une à côté de l'autre :

Image contenant beaucoup de rouge Image avec uniquement la couche Verte

...CORRECTION...

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = 0 vert = g bleu = 0 return (rouge, vert, bleu)

16° IMAGE GRISE : Remplacer les trois intensités R, G et B par la moyenne des trois. On pourra utiliser la division euclidienne en Python en utilisant // plutôt que simplement /.

Par exemple rouge = (r+g+b) // 3

Si les trois intensités RGB ont la même valeur, votre oeil percevra du gris.

Image contenant beaucoup de rouge
Image de base libre de droit : le Palais des congrès de Montréal

Et qui devient une image grise :

Image grise
Image grise

L'une à côté de l'autre :

Image contenant beaucoup de rouge Image grise

...CORRECTION...

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = (r + g + b) // 3 vert = (r + g + b) // 3 bleu = (r + g + b) // 3 return (rouge, vert, bleu)

Si on veut transformer une image en couleur en réelle perception grisée pour un oeil humain, il faut utiliser des formules particulières pour avoir un rendu correct car nos yeux ne sont pas sensibles de la même manière à la lumière rouge, verte ou bleue. ils sont beaucoup plus sensibles à la lumière verte qu'aux lumières bleues et rouges.

17° IMAGE GRISE HUMAINE : Remplacer les trois intensités R, G et B par :

red = (21*r + 71*g + 8*b) // 100

Image grise
Nouvelle version

La nouvelle version grise à gauche, la moyenne pure à droite :

Image grise version 2 Image grise

...CORRECTION...

64 65 66 67 68 69
def filtrage(r, g, b): '''Fonction qui renvoie des valeurs r, g, b après les avoir modifiées''' rouge = (21*r + 71*g + 8*b) // 100 vert = (21*r + 71*g + 8*b) // 100 bleu = (21*r + 71*g + 8*b) // 100 return (rouge, vert, bleu)

4 - FAQ

Pas de question pour le moment

Comme vous pouvez le voir, il est assez facile de modifier les couleurs d'une image ou d'en tirer des informations supplémentaires.

Dans une prochaine activité, nous verrons même qu'il est parfois possible d'y laisser votre nom ou vos coordonnées GPS. C'est dire ...

Prochaine activité : nous allons voir comment trouver les contours d'une image.

Activité publiée le 02 12 2019
Dernière modification : 08 12 2019
Auteur : ows. h.