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 !!)
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 1920x1080 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 200x200 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 :
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 😉
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 🙂
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 😉
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
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
Pour sauvegarder une image, il suffit d'écrire image.save("nomImage.png")
image.save("chat.png")
Il existe plusieurs modes de couleur d'une image:
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
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
On peut effectuer des rotations en degré avec la fonction ancienneimage.rotate().
image = image.rotate(90) # tourne de 90 degres
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
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))
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))
image = image.paste(...)
mais juste image.paste(...)
Dans cette section, tu vas découvrir plusieurs filtres de PIL que tu peux appliquer à tes images !
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) !
from PIL import ImageFilter
Le filtre Contour permet de mettre en valeur les contours repérés dans ton image.
image = image.filter(ImageFilter.CONTOUR)
Le filtre Edge_Enhance permet d'accentuer les contours de ton image.
image = image.filter(ImageFilter.EDGE_ENHANCE)
Le filtre contour fort permet d'accentuer fortement les contours de ton image.
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)
Le filtre détail permet d'augmenter les détails de ton image.
image = image.filter(ImageFilter.DETAIL)
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)
Le filtre Sharpen permet d'augmenter la netteté d'une image.
image = image.filter(ImageFilter.SHARPEN)
Le filtre Blur permet de rendre ton image un peu floue.
image = image.filter(ImageFilter.BLUR)
Le filtre Smooth permet de lisser ton image.
image = image.filter(ImageFilter.SMOOTH)
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 :
Le filtre Gaussian_Blur permet de mettre du flou gaussien sur une image. On peut paramétrer la puissance du flou en changeant le chiffre envoyé en paramètre !
image = image.filter(ImageFilter.GaussianBlur(10))
Voici l'image après avoir appliqué le flou gaussien avec un argument égal à 20 !
image = image.filter(ImageFilter.GaussianBlur(20))
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))
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) !
from PIL import ImageOps
La fonction ImageOps.flip(ancienneimage) permet de faire une symétrie horizontale de ton image.
image = ImageOps.flip(image)
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")
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)
Cet effet permet d'inverser les couleurs de ton image: le noir devient blanc et le blanc devient noir.
image = ImageOps.invert(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)
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)
Dans cette section, tu vas découvrir comment mélanger des images avec PIL !
On peut coller une image sur une autre avec la fonction monImage.alpha_composite().
Le fonctionnement est assez simple :
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()
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")
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
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)
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)
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)
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)
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)
Dans cette section, tu vas découvrir comment ajouter du texte ou des formes sur tes images avec PIL !
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
Pour aller chercher des polices sympas, tu peux aller sur ces deux sites qui proposent des polices gratuites :
Une fois ta police téléchargée, tu dois placer le fichier de la police dans le dossier de ton code !
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()
Pour dessiner une image, c'est le même cheminement que pour le texte !
On doit créer un objet pour dessiner sur l'image, et ensuite utiliser les différentes fonctions de ImageDraw pour dessiner les formes 🙂
La fonction line() nous permet de dessiner une ligne.
Il y a 3 paramètres à fournir :
# 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 "line" pour dessiner une ligne drawObj.line(xy=(0,0,100,100), fill=(255,0,0), width=40) # Pour finir, on montre l'image ! image.show()
La fonction ellipse() nous permet de dessiner un cercle ou un ovale.
Il y a 3 paramètres à fournir :
# 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()
La fonction rectangle() nous permet de dessiner un carré ou un rectangle.
Il y a 3 paramètres à fournir :
# 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()
La fonction point() nous permet de dessiner un point à des coordonnées précises.
Il y a 2 paramètres à fournir :
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()
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 /!\
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
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")
Pour finir, un exemple de montage pour t’inspirer 🙂
Avec le code ci-dessous :