Python - Manipulation d'images

Dans cette page tu trouveras :

LE FONCTIONNEMENT DES COULEURS ET DES PIXELS

 

Avant de commencer à parler de PIL, voici un petit préambule explicatif sur le fonctionnement des pixels et des couleurs en programmation 🙂 ET une seconde partie sur la manipulation d’images en programmation (à lire avant de commencer à programmer !!)

Qu’est ce qu’un pixel ?

Les pixels, ce sont ces touts petites lumières qui composent ton écran et qui changent de couleur en fonction de ce qu’ils doivent afficher. C’est le composant principal de l’écran de ton ordi, de ton téléphone, de ta télé, etc…

D’ailleurs, quand on parle de résolution d’écran, on parle du nombre de pixels sur ce dernier ! Une résolution de 1920×1080 correspond à 1920 pixels de large pour 1080 pixels de haut sur ton écran !

Le pixel est aussi l’unité de mesure par défaut pour les images numériques ! 🙂 Une image de 200×200 mesure 200 pixels de côté !

 De nos jours, les pixels peuvent afficher une palette d’à peu près 16 millions de couleurs. On garde cette info en tête pour un peu plus tard 😉

Cependant, un pixel n’affiche pas 16 millions de couleurs comme par magie !

Pour ça, il est décomposé en 3 parties, une pour chaque couleur primaire :

  • Une partie qui affiche le Rouge (Red)
  • Une partie qui affiche le Vert (Green)
  • Une partie qui affiche le Bleu (Blue)

C’est ce qui nous donne ce qu’on appelle un code RGB (ou RVB en français) !

 

On ne peut pas voir à l’œil nu les trois couleurs primaires d’un pixel, mais en se mélangeant, ces trois couleurs peuvent former n’importe quelle couleur ! On va voir ça plus en détail dans le paragraphe en dessous 😉

Le code RGB

Comme expliqué au dessus, les pixels d’un écran sont composés des trois couleurs primaires, et en se mélangeant peuvent former n’importe quelle couleur. C’est le code RGB (Red Green Blue) !

Chaque couleur d’un pixel est codée sur 256 valeurs, allant de 0 à 255.

Comme on a trois couleurs, et que chacune peut prendre 256 valeurs, si on calcule le nombre total de couleurs qu’on peut faire : 256 * 256 * 256 = 16 777 216 couleurs différentes !

Donc un peux plus de 16 millions de couleurs différentes, comme on le disait juste un peu avant 😉

Voici quelques exemples de couleurs basiques avec leur code RGB pour que tu puisses te donner une idée !

Un code RGB s’écrit comme ceci : (R, G, B), où les lettres correspondent à la valeur de chaque couleur primaire 🙂

MANIPULER DES IMAGES EN PROGRAMMATION​

Quand tu manipules des images en Python, tu vas noter dans ton code le chemin pour accéder à une image que tu as envie d’ouvrir. Si tu notes juste le nom de l’image, le programme va aller chercher dans le même dossier que le code pour trouver ton image. Il faut donc que ton image soit enregistré sur ton ordinateur au bon endroit pour l’ouvrir facilement ! 

Sur Repl.it, c’est pareil ! Il faut que ton image soit dans le même dossier que ton code pour l’ouvrir facilement. Il faut donc que tu l’importes dans Repl.it.

On va ouvrir une image avec le mot clé « open » (expliqué dans le bloc suivant). Voici deux exemples :

si tu es sur ton ordinateur et que tu programmes sur un éditeur comme SublimeText ou Atom

si tu utilises l’outil en ligne repl.it

ET voici comment importer une image sur l’outil Repl.it :

Si l’image n’est pas bien rangée (ou que tu as mal écrit son nom), tu auras ce message d’erreurs :

Python Imaging Library, est une bibliothèque pour Python qui permet de manipuler des images.

N’oublie pas d’importer le module avant chaque programme que tu crées !

/!\ Attention, avec l’outil Repl.it tu ne pourras pas montrer l’image avec « show », il te faudra sauvegarder l’image pour voir le rendu 😉

LES BASES DE PIL

Importer le module !!

Avant de faire quoi que ce soit, il est très important d’importer le module PIL en haut de ton programme Python !!

from PIL import Image

 

Afficher une image

Pour afficher une image, on doit d’abord la récupérer avec Image.open(« nomDeTonImage »), la stocker dans une variable. Puis on peut l’afficher avec image.show().

from PIL import Image # importe le module

 

image = Image.open(« nom_image.png ») # recupere l’image

 

image.show() # ouvre l’image

 

Sauvegarder une image

Pour sauvegarder une image, il suffit d’écrire image.save(« nomImage.png »)

image.save(« chat.png »)

 

Changer le mode

Il existe plusieurs modes de couleur d’une image:

  • nuance de gris: l’image est grisée, les composantes des couleurs (rouge, vert & bleu) sont toutes égales
  • en couleur: le mélange des couleurs rouge, verte & bleue forment un pixel de l’image
  • en noir et blanc: chaque pixel est soit noir, soit blanc
image = image.convert(« L ») # convertir en nuance de gris

image = image.convert(« RGB ») # convertir en RGB

image = image.convert(« 1 ») # convertir en noir et blanc

Modifier la taille

La fonction ancienneimage.resize() permet de modifier la taille de l’image

image = image.resize((28,28)) # modifie la taille en 28 par 28 pixels

Tourner l’image

On peut effectuer des rotations en degré avec la fonction ancienneimage.rotate().

image = image.rotate(90) # tourne de 90 degres

Les coordonnées d’une image en Python

En Python, mais plus généralement en programmation, les coordonnées sont un peu différentes de ce qu’on connaît en maths classiques.

Comme tu peux le voir sur l’image de gauche, l’axe des ordonnées (Y) vas vers le bas au lieu d’aller vers le haut 🙂

L’origine de l’image est donc le point en haut à gauche de celle-ci !

C’est très important de savoir ça pour la suite, car on se sert des coordonnées des images dans les prochaines fonctions

Recadrer l’image

Pour recadrer une image, on utilise la fonction ancienneimage.crop() où on indique le point en haut à gauche (x,y) et le point en bas à droite (x,y) du nouveau cadre de la photo.

# On recupere la taille de l’image : w = largeur, h = hauteur

w,h = image.size

image = image.crop((100,100,w,h))

Intégrer une image dans une autre image

Pour copier une image dans une autre, on va utiliser la fonction image1.paste(image2, endroit). L’endroit doit être un rectangle dont on spécifie le coin supérieur gauche (x,y) et le coin inférieur droit (x,y).

image = Image.open(« chat.jpg ») # la première image

image2 = Image.open(« plage.jpg ») # la deuxième image

# Pour mettre la deuxième image sur la première, je dois lui donner une taille

# correspondant à la zone que je veux recouvrir sur la première image.

image2 = image2.resize((200,200))

 
# Enfin, je précise quelle image je veux mettre par dessus ma première image,

# ainsi que la « box », c’est à dire la taille de la zone à recouvrir avec la deuxième image

image.paste(image2, box=(200,200))

Attention ! la fonction paste ne renvoie pas d’image, il ne faut donc pas faire image = image.paste(…) mais juste image.paste(…)

LES FILTRES

Module ImageFilter

Ce module te permet d’ajouter toutes sortes de filtres à tes images ! Modification des couleurs, de la netteté, ajout de flou, etc… Bref, tu vas t’amuser 😉

Sur tous les prochains exemples, tu verras un comparatif de l’image originale (à gauche) et de l’image modifiée (à droite) !

Penses à importer le module en haut de ton code 😉

from PIL import ImageFilter

Filtre Contour

Le filtre Contour permet de mettre en valeur les contours repérés dans ton image.

image = image.filter(ImageFilter.CONTOUR)

Filtre Edge_Enhance

Le filtre Edge_Enhance permet d’accentuer les contours de ton image.

image = image.filter(ImageFilter.EDGE_ENHANCE)

Filtre Edge_Enhance_More

Le filtre contour fort permet d’accentuer fortement les contours de ton image.

image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)

Le filtre Edge_Enhance permet d‘accentuer les contours de ton image.

image = image.filter(ImageFilter.EDGE_ENHANCE)

Filtre Detail

Le filtre détail permet d’augmenter les détails de ton image.

image = image.filter(ImageFilter.DETAIL)

Filtre Find_Edges

Le filtre Find_Edges permet de repérer où sont les contrastes forts entre 2 pixels, et les met en valeur.

image = image.filter(ImageFilter.FIND_EDGES)

Filtre Sharpen

Le filtre Sharpen permet d’augmenter la netteté d’une image.

image = image.filter(ImageFilter.SHARPEN)

Filtre Blur (flou)

Le filtre Blur permet de rendre ton image un peu floue.

image = image.filter(ImageFilter.BLUR)

Filtre Smooth (Flou)

Le filtre Smooth permet de lisser ton image.

image = image.filter(ImageFilter.SMOOTH)

Filtre Smooth_More (Flou)

Le filtre Smooth_More permet de lisser fortement ton image.

image = image.filter(ImageFilter.SMOOTH_MORE)

Plus on applique le filtre sur une image, plus on la transforme !

Voici le résultat après avoir appliqué le filtre trois fois d’affilée :

Filtre Smooth_More (Flou)

Le filtre Smooth_More permet de lisser fortement ton image.

image = image.filter(ImageFilter.SMOOTH_MORE)

Voici l’image après avoir appliqué le flou gaussien avec un argument égal à 20 !

image = image.filter(ImageFilter.GaussianBlur(20))

Filtre ModeFilter (Flou)

Le filtre ModeFilter permet de modifier les couleurs dans un rayon que l’on donne en paramètre. Ainsi on obtient un rendu très flou avec de belles couleurs !

image = image.filter(ImageFilter.ModeFilter(15))

Module ImageOps

Ce module contient quelques fonctions de traitement d’images toutes faites, qui te permettront d’ajouter des effets cools à tes images, que des filtres ne pourraient pas faire ! 🙂

Sur tous les prochains exemples, tu verras un comparatif de l’image originale (à gauche) et de l’image modifiée (à droite) !

Penses à importer le module en haut de ton code 😉

from PIL import ImageOps

Flip une image

La fonction ImageOps.flip(ancienneimage) permet de faire une symétrie horizontale de ton image.

image = ImageOps.flip(image)

Miroir

Pour faire un effet « miroir » sur ton image, il suffit de commencer par la retourner avec la fonction Flip (juste au dessus), et ensuite de la tourner de 180 degrés 🙂

image = Image.open(« chat.jpg »)

image = ImageOps.flip(image)

image = image.rotate(180)

image.show()

image.save(« chatMiroir.jpg »)

Ajouter un bord

Avec le sous-module ImageOps de PIL, on peut dessiner un contour à notre image. On définit la largeur du contour en argument (à la place du « 10 » dans notre exemple).

image = ImageOps.expand(image, border=10)

image.show()

image.save(« chatMiroir.jpg »)

Inverser les couleurs de l’image

Cet effet permet d’inverser les couleurs de ton image: le noir devient blanc et le blanc devient noir.

image = ImageOps.invert(image)

image.save(« chatMiroir.jpg »)

Inverser certaines couleurs de l’image

L’effet solarize te permet d’inverser les couleurs de l’image, mais seulement à partir d’un certain point.

Comme les couleurs sont codées sur 255 valeurs, on peut choisir la valeur à partir de laquelle la couleur sera inversée.

Sur le code ci-dessous, on inverse les couleurs qui ont une valeur supérieure à 128 🙂

image = ImageOps.solarize(image, threshold=128)

Modifier le contraste

Cet effet te permet d’augmenter les contrastes d’une image : il enlèvera un pourcentage (donné en paramètre) des pixels les plus sombres et les plus clairs d’une image 🙂

Dans cet exemple, on enlève 10% des pixels sombres et clairs !

image = ImageOps.autocontrast(image, cutoff=10)

FUSION D’IMAGES

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.

Coller une image sur une autre

On peut coller une image sur une autre avec la fonction monImage.alpha_composite().

Le fonctionnement est assez simple :

  • Premièrement, l’image de base et celle qu’on veut coller par dessus doivent être en mode RGBA.
  • Ensuite, il suffit d’utiliser la fonction alpha_composite() de l’image sur laquelle on veut faire le collage. En l’occurrence, je veux mettre imageChat par dessus imagePlage, j’écris donc imagePlage.alpha_composite()
  • Enfin, on doit choisir le pixel de destination de l’image à coller sur l’image de base. Sur l’exemple, je l’envoie en (0, 0), donc tout en haut à gauche (cf. le récap sur les coordonnées d’une image si tu ne te rappelles plus trop comment ça marche !).

 

imagePlage = Image.open(« plage.jpg »)
imageChat = Image.open(« chat.jpg »)
imagePlage = imagePlage.convert(« RGBA »)
imageChat = imageChat.convert(« RGBA »)
imagePlage.alpha_composite(imageChat, dest=(0, 0))
imagePlage.save(« result.png »)
imagePlage.show()

Mélanger deux images

Pour mélanger 2 images, il faut qu’elles aient le même mode et la même taille.

Puis on utilise Image.blend(image1, image2, pourcentage). Le pourcentage correspond à la visibilité de l’image 1 à l’intérieur de l’image 2: plus il est élevé, plus on verra l’image 1.

image1 = Image.open(« chat.jpg »)
image2 = Image.open(« happy.png »)


# Attention : Les images doivent avoir la meme taille et le meme mode !
image1 = image1.convert(« RGB »)
image1 = image1.resize((300,300))
image2 = image2.convert(« RGB »)
image2 = image2.resize((300,300))


image3 = Image.blend(image1, image2, 0.5)


image3.show()
image3.save(« chatHappy.jpg »)

Module ImageChops

Le module ImageChops te permet de fusionner deux images avec des effets de fusion différents 🙂

Sur tous les prochains exemples, tu verras un comparatif des deux images originales, puis du résultat de la fusion !

Penses à importer le module en haut de ton code 😉

from PIL import ImageChops

Fusionner en ajoutant les couleurs

La fonction ImageChops.add(image1, image2) te permet de fusionner deux images en ajoutant les couleurs de tous leurs pixels.

Par exemple, si un pixel est gris sur la première image (100,100,100) et turquoise sur la deuxième (0,200,200), le nouveau pixel sera égal à la somme des deux (avec toujours un max de 255 par valeur).

Le nouveau pixel sera donc égal à (0,255,100) ! C’est pour ça que le résultat des deux images ci-dessous est si blanc : comme l’image de chat a beaucoup de pixels blancs de base (255,255,255), avec la somme de la deuxième photo, le rendu final est très blanc 🙂

image3 = ImageChops.add(image,image2)

Darker

La fonction ImageChops.darker(image1, image2) va parcourir chaque pixel des deux images, et ne va garder que le pixel le plus sombre pour le rendu final.

image3 = ImageChops.darker(image,image2)

Lighter

La fonction ImageChops.lighter(image1, image2) va parcourir chaque pixel des deux images, et ne va garder que le pixel le plus clair pour le rendu final.

image3 = ImageChops.lighter(image,image2)

Difference

La fonction ImageChops.difference(image1, image2) va parcourir chaque pixel des deux images, et va faire la différence des couleurs des deux pixels pour le rendu final.

Par exemple, si un pixel est blanc (255, 255, 255) et l’autre est bleu (0, 0, 255), le pixel final sera jaune (255, 255, 0) !

image3 = ImageChops.difference(image,image2)

Multiply

La fonction ImageChops.multiply(image1, image2) va fusionner les deux images en gardant toutes les couleurs principales des deux images, pour un rendu final le plus propre possible 🙂

image3 = ImageChops.multiply(image1, image2)

AJOUTER DU TEXTE ET DES DESSINS

Ajouter du texte dans une image

Pour commencer, il ne faut pas oublier d’importer les deux modules ImageFont et ImageDraw en haut de ton code.

ImageFont te permettra d’importer une police de caractères personnelle.

ImageDraw te permettra de dessiner et d’écrire sur ton image.

from PIL import ImageFont

 

from PIL import ImageDraw

Une fois ta police téléchargée, tu dois placer le fichier de la police dans le dossier de ton code !

Pour aller chercher des polices sympas, tu peux aller sur ces deux sites qui proposent des polices gratuites :

Au niveau du code, c’est très simple !

Tu dois d’abord charger la police grâce à ImageFont, puis tu dois créer une variable ImageDraw qui te servira à écrire sur l’image que tu veux.

Pour finir, grâce à cette variable, tu pourras écrire ton texte en précisant les coordonnées où tu veux le placer sur l’image, le texte en lui même, la police que tu veux utiliser, ainsi que la couleur du texte !

# Imports

from PIL import ImageFont

from PIL import ImageDraw

# On ouvre l’image

image = Image.open(« chat.jpg »)

# On charge la police de caractère présente dans le même dossier, avec la taille qu’on veut

police = ImageFont.truetype(‘airstream.ttf’, 69)

# Ici, on crée l’objet nous permettant d’écrire le texte sur l’image

drawObj = ImageDraw.Draw(image)

# On définit l’emplacement du texte sur l’image, le texte, la police et la couleur !

drawObj.text((0,0), « Hey ! », font=police, fill=(255,0,0))

# Pour finir, on sauvegarde l’image et on la montre

image.save(« chatTexte.png »)

image.show()

ellipse()

La fonction ellipse() nous permet de dessiner un cercle ou un ovale.

Il y a 3 paramètres à fournir :

  • xy, qui correspond à 4 coordonnées. Les deux premières sont le X et le Y du point le plus en haut à gauche du cercle ; Les deux dernières sont le X et le Y du point le plus en bas à droite du cercle.
  • outline, qui correspond à la couleur de la ligne extérieure du cercle
  • fill, qui correspond à la couleur intérieure du cercle
# Imports

 

from PIL import ImageDraw

 

 
# On ouvre l’image

 

image = Image.open(« chat.jpg »)

 

 
# On crée l’objet pour dessiner sur l’image

 

drawObj = ImageDraw.Draw(image)

 

 
# Ensuite, on utilise la fonction « ellispe » pour dessiner un cercle

 

drawObj.ellipse(xy=(0,0,200,200), outline=(0,0,255), fill=(255,0,0))

 

 
# Pour finir, on montre l’image !

 

image.show()

rectangle()

La fonction rectangle() nous permet de dessiner un carré ou un rectangle.

Il y a 3 paramètres à fournir :

  • xy, qui correspond à 4 coordonnées. Les deux premières sont le X et le Y du point le plus en haut à gauche du rectangle ; Les deux dernières sont le X et le Y du point le plus en bas à droite du rectangle
  • outline, qui correspond à la couleur de la ligne extérieure du rectangle
  • fill, qui correspond à la couleur intérieure du rectangle
# Imports

from PIL import ImageDraw

 
# On ouvre l’image

image = Image.open(« chat.jpg »)

 
# On crée l’objet pour dessiner sur l’image

drawObj = ImageDraw.Draw(image)

 
# Ensuite, on utiliser la fonction « rectangle » pour dessiner un carré

drawObj.rectangle(xy=(0,0,100,100), outline=(0,0,255), fill=(255,0,0))

 
# Pour finir, on montre l’image !

image.show()

point()

La fonction point() nous permet de dessiner un point à des coordonnées précises.

Il y a 2 paramètres à fournir :

  • xy, qui correspond à 2 coordonnées : Le X et le Y du point
  • fill, qui correspond à la couleur du point

Si on combine cette fonction à une boucle, on peut par exemple tracer une diagonale de plein de points 🙂

# Imports

from PIL import ImageDraw

 
# On ouvre l’image

image = Image.open(« chat.jpg »)

 
# On crée l’objet pour dessiner sur l’image

drawObj = ImageDraw.Draw(image)

 
# Ensuite, grâce à une boucle « for … in range », on va pouvoir tracer plein de points sur l’image 🙂

# Dans cette boucle, position va prendre les valeurs de 1 à 100 avec des pas de 5 (0, 5, 10, 15, etc…)

# Du coup, on va utiliser cette valeur comme coordonnées pour le point au fur et à mesure de la boucle !

for position in range(0,100,5):

   drawObj.point(xy=(position,position), fill=(255,0,0))

 
# Pour finir, on montre l’image !

image.show()

SCREENSHOT & WEBCAM

Dans cette section, tu vas découvrir comment faire une capture d’écran avec PIL ou utiliser la webcam avec OpenCV ! 

/!\ Attention, avec l’outil Repl.it tu ne pourras pas accéder à la webcam /!\

Faire une capture d’écran

 

from PIL import ImageGrab

image = ImageGrab.grab() # tout l’ecran

image = ImageGrab.grab((0,0,500,500)) # part du haut gauche de l’ecran et prend une image de 500 par 500

 

Utiliser la Webcam avec OpenCV

Pour prendre une photo, on va se servir d’une autre module: cv2 !

Voici un code exemple pour récupérer l’image et la préparer pour toutes les transformations avec PIL !

import cv2


cam = cv2.VideoCapture(0) # accede a la webcam


ret, image = cam.read() # prend une photo


image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # convertit la photo dans un format OK pour PIL


image = Image.fromarray(image) # charge l’image convertie dans PIL avec la methode « fromarray »


Attention ! Sur certains ordinateurs, il faut doubler la ligne qui prend une photo (ret, image = cam.read()). Sinon la caméra n’a pas le temps de prendre la photo et on obtient juste une image noire !

Et après, le fun c’est de modifier le selfie !

###########

# IMPORTS #

###########

from PIL import ImageFilter

from PIL import Image

import cv2

############################

# UTILISATION DE LA WEBCAM #

############################

cam = cv2.VideoCapture(0) # accède à la webcam

ret, image = cam.read() # prend une photo

###########################

# MANIPULATION DE L’IMAGE #

###########################

image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # convertit la photo dans un format OK pour PIL

image = Image.fromarray(image) # charge l’image convertie dans PIL avec la methode « fromarray »

image = image.filter(ImageFilter.EDGE_ENHANCE)

image = image.filter(ImageFilter.ModeFilter(15))

######################################

# SAUVEGARDE DE L’IMAGE ET AFFICHAGE #

######################################

image.show()

image.save(« customSelfie.png »)

VERS L’INFINI ET AU-DELA !

Pour finir, un exemple de montage pour t’inspirer 🙂

Avec le code ci-dessous :

Retour en haut