4 - Filtrage d'une image
Nous allons voir comment modifier les pixels des photos pour obtenir différents effets.
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
RAPPEL
Thonny permet de travailler avec Python dans un environnement qui permet de voir le contenu des variables, et d'avoir accès au même endroit à :
- 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.
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-A (action)° 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.
01-B (action)° Tapez ceci dans la console pour voir si cela déclenche une erreur.
>>> from PIL import Image
Si cela déclenche une erreur, c'est que vous n'avez pas installé la bibliothèque Pillow. Pour l'installer, suivre alors le déroulé suivant :
- 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.
01-C (action)° 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 :
01-D° 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 :
- 1 couche pour une image en nuance de gris uniquement,
- 3 couches RGB pour une image en couleur,
- 4 couches RGBA pour une image en couleur où A est la couche Alpha de transparence.
Tâches à réaliser :
- Enregistrer au même endroit que votre image le programme ci-dessous sous le nom gestion.py, donc dans le répertoire SNT-photographie.
- dans le programme Python, modifier la ligne 5 pour que la variable ref_image fasse référence aux bons nom et extension de votre fichier-image. RAPPEL : le nom doit être placé entre guillemets pour faire comprendre à Python qu'on lui transmet un string, une chaîne de caractère, un texte.
📁 SNT-photographie
📄 gestion.py
📄 votre_image.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
|
Exemple de résultats pouvant s'afficher dans la console :
Pixels en largeur : 1024
Pixels en hauteur : 771
Pixels au total : 789504
Couches : ('R', 'G', 'B')
Nbr de couches : 3
02° Lire le programme en totalité, ligne par ligne, même si vous ne comprennez pas tout pour le moment puis répondre aux question suivantes :
- (rappel de cours : affectation) Lors d'une affectation (comme sur les lignes 3, 7, 8, 9 et 10), va-t-on de la gauche vers la droite ou la droite vers la gauche ?
- (analyse du code): En ligne 3, dans quelle variable a-t-on stocké les données de l'image ? Comment s'appelle la fonction qui permet à Python de mettre en mémoire votre fichier-image ?
- (rappel de cours : instruction conditionnelle) : Pourquoi-a-t-on indenté vers la droite la ligne 19 ? Dans quel cas va-t-on réaliser la ligne 19 au vu de la ligne 18 ?
- Lignes 3-18-19 : Sur quelle ligne demande-t-on d'afficher l'image ? Comment se nomme la fonction qui permet d'afficher l'image ? Expliquer pourquoi l'image s'affiche et comment modifier le programme pour désactiver cet affichage avec la constante.
...CORRECTION...
- L3 : affectation de la droite vers la gauche. On va donc "remplir" ici la variable ref_image avec l'évaluation qu'on trouve du côté droit.
- L3 : la variable se nomme ref_image et la fonction d'ouverture se nomme open().
- On indente les instructions à réaliser si la condition évaluée est True (vraie). Ici, on réalise donc la L19 uniquement si la constante AFFICHAGE contient True.
- Demande d'affichage L19 avec ref_image.show(). Cette ligne s'exécute car AFFICHAGE contient True. Pour ne plus afficher l'image à chaque lancement, il suffit de modifier la constante en L3 en lui mettant False.
PIXELISATION
Nous allons réaliser en deux actions une pixelisation de votre image :
- On commence par réduire la taille de l'image par 10, ce qui entraine une perte d'informations.
- On finit en redonnant la taille initiale à l'image réduite. La perte d'informations va alors clairement apparaître.
03° 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 |
|
Questions
- Sur quelle ligne divise-t-on la taille de l'image par 10 ? Comment se nomme la méthode permettant de modifier la taille d'une image ?
- Sur quelle ligne lui redonne-t-on sa taille initiale ?
- Pourquoi voit-on deux affichages ?
- Sur quelle ligne demande-t-on à Python de sauvegarder l'image ?
...CORRECTION...
- L13 avec la méthode resize().
- L15 avec ref_image = ref_image.resize( (nbr_colonnes, nbr_lignes) )
- Deux affichages car on lui demande d'afficher l'image avant modification en L11 puis après modification en L17.
- L19 avec ref_image.save("image_pixelisée.jpg")
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.
04-A° Si ce n'est pas encore fait car vous reprennez l'activité, 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 :
04-B° Réaliser les deux actions ci-dessous. Inutile de lire le code dans sa totalité pour le moment, nous allons l'analyser par petits bouts.
- Enregistrer avec Thonny le programme ci-dessous au même endroit que votre image, donc dans le répertoire SNT-photographie.
- Modifier le nom du fichier-image en ligne 4 stocké dans la variable originel 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.
- Lancer pour vérifier qu'on obtient bien les intensités de 3 pixels.
📁 SNT-photographie
📄 votre_programme.py
📄 votre_image.png
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 |
|
05° Etude des transferts entre les appels et la fonction. Observer les appels et la déclaration de la fonction pixel puis répondre aux questions..
- Dans quelles variables vont être stockées les valeurs envoyées à la fonction lors de l'appel de la ligne 36 : base, 0, 0
- Pourquoi a-t-on trois affichages ?
- Sur la ligne 15 de la fonction pixel(), str() pourquoi doit-on transformer les entiers x et y qu'on a reçu en string avec str() ?
...CORRECTION...
- Pour répondre, il faut comparer la ligne de la déclaration et la ligne de l'appel :
- Trois affichages car nous avons trois print() correspondant à 3 appels.
- Nous avons vu qu'on ne peut pas concatétener des strings et des entiers : cela provoque une erreur !
9
..
36 |
|
nom reçoit base
x reçoit 0
y reçoit 0
Il faut associer place par place :
35
36
37
38 |
|
>>> "A" + "2"
'A2'
>>> "A" + 2
TypeError: can only concatenate str (not "int") to str
>>> "A" + str(2)
'A2'
06° Etude de la fonction pixel() :
- L14 : que va contenir la variable nbr_couches ?
- L17-21-25 : quel est le cas qui correspond à une image en nuances de gris ? En couleur ? En couleur avec gestion de la transparence ?
- L22 : comment se nomme la méthode permettant de récupérer les intensités lumineuses du pixel de coordonnées (x, y) ?
- L21-L22 : combien y-a-t-il de couches sur ce pixel si on active ce bloc ? Combien a-t-on placé de variables à gauche pour récupérer les valeurs d'intensités du pixel ?
- L32 : quel est le type de la réponse envoyée par la fonction ?
...CORRECTION...
- L14 : nbr_couches contient le nombre de couches sur chaque pixel de cette image.
- L17-21-25 : Une image en nuance de gris n'a qu'une couche donc L17. Une image en couleur RGB possède 3 couches donc ligne 21. Avec la transparence, on atteint 4 couches, donc L25.
- L21-L22 : si on atteint la ligne 22, c'est qu'on a 3 couches sur cette image. On a donc placé trois variables du côté gauche pour récupérer les trois valeurs RGB du pixel.
- La fonction renvoie un string.
r, g, b = ref_image.getpixel( (x,y) )
07° Nous voudrions tenter d'afficher les valeurs des pixels un par un. Il va donc falloir faire varier x progressivement de 0 jusqu'à la dernière valeur possible en x sur la largeur. Ensuite, il faudra passer à la ligne y suivante.
- Remplacer intégralement votre programme par celui-ci : la seule ligne du programme consiste à un appel à la fonction pixels() qui fait varier x et y et, pour chacune des valeurs obtenues, affiche le résultat de la fonction pixel() qui donne les intensités pour le pixel de coordonnées x, y.
- Constater qu'on parvient bien à lire les pixels un par un avec notre double boucle (un for imbriqué dans un for) puis couper le programme en appuyant sur STOP.
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 |
|
08° 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
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 |
|
Exemple avec une image contenant beaucoup de rouge et d'orange :
Et qui devient une image contenant beaucoup de bleu et de cyan :
09° Expliquer ce que renvoie la fonction filtrage() lorsqu'elle reçoit les trois paramètres ancien_r ancien_g ancien_b.
...CORRECTION...
Si on lit le code, on peut se rendre compte qu'elle renvoit le triplet de valeurs mais en intervertissant le rouge et le bleu.
31
32
33
34
35
36
37
38 |
|
Sur ce pixel, les intensités du bleu et du rouge sont donc inversées.
10° En lisant rapidement les lignes 18-19-20 de la fonction filter_image(), comment se nomme la méthode permettant de récupérer les valeurs d'un pixel ? Comment se nomme la méthode qui permet de modifier les valeurs d'un pixel ?
...CORRECTION...
- L18 -> On récupère avec getpixel()
- L20 -> On modifie avec putpixel()
11° En traduisant en français une par une les lignes 9 à 20, expliquer comment la fonction filter_image() parvient à transformer tous les pixels de l'image.
...CORRECTION...
- L9 -> on stocke l'image dans ref_image
- L10 -> on récupère le nombre de colonnes
- L11 -> on récupère le nombre de lignes
- L12 -> on récupère les couches
- L13 -> on récupère le nombre de couches
- L15 -> Si on a bien une image RGB
- L16 -> Pour chaque ligne y de l'image
- L17 -> Pour chaque colonne x de l'image
- L18 -> on récupère les valeurs rgb du pixel en cours
- L19 -> on modifie les valeurs du pixel
- L20 -> on replace le nouveau pixel dans l'image
La fonction filtrage() inverse les valeurs des intensités R et B.
Regardons comment nous pourrions l'utiliser différemment.
3 - Filtrage
Filtrer les couleurs veut dire en laisser passer certaines et pas d'autres.
Pour l'instant, la fonction filtrage() ne provoque qu'une intervertion de couleurs.
12° 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.
Et qui devient une image ne contenant que les intensités rouges :
L'une à côté de l'autre :
...CORRECTION...
31
32
33
34
35
36
37
38 | def filtrage(ancien_r, ancien_g, ancien_b):
"""Fonction qui renvoie des valeurs RGB après les avoir modifiées"""
r = ancien_r # On laisse le rouge
g = 0 # On supprime le vert
b = 0 # On supprime le bleu
return (r, v, b)
|
13° 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.
Et qui devient une image ne contenant que les intensités bleues :
L'une à côté de l'autre :
...CORRECTION...
31
32
33
34
35
36
37
38 | def filtrage(ancien_r, ancien_g, ancien_b):
"""Fonction qui renvoie des valeurs RGB après les avoir modifiées"""
r = 0 # On supprime le rouge
g = 0 # On supprime le vert
b = ancien_b # On laisse le bleu
return (r, v, b)
|
14° 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.
Et qui devient une image ne contenant que les intensités vertes :
L'une à côté de l'autre :
...CORRECTION...
31
32
33
34
35
36
37
38 | def filtrage(ancien_r, ancien_g, ancien_b):
"""Fonction qui renvoie des valeurs RGB après les avoir modifiées"""
r = 0 # On supprime le rouge
g = ancien_g # On laisse le vert
b = 0 # On supprime le bleu
return (r, v, b)
|
15° 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.
Et qui devient une image grise :
L'une à côté de l'autre :
...CORRECTION...
31
32
33
34
35
36
37
38 | def filtrage(ancien_r, ancien_g, ancien_b):
"""Fonction qui renvoie des valeurs RGB après les avoir modifiées"""
r = (ancien_r + ancien_g + ancien_b) // 3
g = (ancien_r + ancien_g + ancien_b) // 3
b = (ancien_r + ancien_g + ancien_b) // 3
return (r, v, b)
|
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.
16° IMAGE GRISE HUMAINE : Remplacer les trois intensités R, G et B par :
red = (21*r + 71*g + 8*b) // 100
La nouvelle version grise à gauche, la moyenne pure à droite :
...CORRECTION...
31
32
33
34
35
36
37
38 | def filtrage(ancien_r, ancien_g, ancien_b):
"""Fonction qui renvoie des valeurs RGB après les avoir modifiées"""
r = (21*ancien_r + 71*ancien_g + 8*ancien_b) // 100
g = (21*ancien_r + 71*ancien_g + 8*ancien_b) // 100
b = (21*ancien_r + 71*ancien_g + 8*ancien_b) // 100
return (r, v, b)
|
17 (en équipe)° Tâche finale complexe :
- choisir une image sur le Web et à l'aide d'un logiciel de dessin, placer un fond totalement VERT (0, 255,0) sur le fond de votre image.
- Sauvegarder cette image en .png (c'est important).
- Sélectionner sur le web une autre image d'un paysage quelconque.
- Créer maintenant un programme qui :
- Place chacune de vos deux images dans une variable différente.
- Redimensionne les images pour qu'elles aient les mêmes dimensions.
- Pour chaque ligne y et chaque colonne x, si le fond de l'image 1 est vert, alors on la modifie en y placant la valeur du pixel de l'image 2.
- On sauvegarde la nouvelle image.
4 - FAQ
Pas de question pour le moment
Activité publiée le 02 12 2019
Dernière modification : 08 12 2019
Auteur : ows. h.