Les couleurs et filtres

Nous allons utiliser le langage de programmation Python afin de directement travailler sur les pixels d'une image. Par travailler sur les pixels, j'entends déterminer la valeur du canal rouge, la valeur du canal et la valeur du canal bleu pour un pixel donné ou bien encore modifier carrément la couleur d'un pixel.

Avant de commencer à écrire un programme qui nous permettra de travailler sur les pixels d'une image, il est nécessaire de préciser que chaque pixel a des coordonnées x,y.

pixel

Comme vous pouvez le constater sur le schéma ci-dessus, le pixel de coordonnées (0,0) se trouve en haut à gauche de l'image. Si l'image fait 800 pixels de large et 600 pixels de haut, le pixel ayant pour coordonnées (400,300) sera au milieu de l'image.

Dans un premier temps nous allons utiliser une simple photo de pomme pour faire nos premiers essais, ensuite, vous pourrez travailler avec l'image de votre choix. L'image de la pomme est téléchargeable ici. Cette image devra se trouver dans le même dossier que vos programmes Python.

Voici un premier programme :

Après avoir ouvert l'éditeur edupython, saisissez et testez le programme suivant :


from PIL import Image
img = Image.open("pomme.jpg")
r,v,b=img.getpixel((100,250))
print("canal rouge : ",r,"canal vert : ",v,"canal bleu : ",b)
			

Ce programme vous donne le canal rouge, le canal vert et le canal bleu du pixel de coordonnées (100,250) de l'image "pomme.jpg"

Quelles sont les trois valeurs?


Voici une analyse ligne par ligne du programme ci-dessus :

  • "from PIL import Image" : pour travailler sur les images nous avons besoin d'une extension de Python (appelé bibliothèque). Cette bibliothèque se nomme PIL.
  • "img = Image.open("pomme.jpg")" c'est grâce à cette ligne que nous précisons que nous allons travailler avec l'image "pomme.jpg". Pour travailler avec une autre image, il suffit de remplacer "pomme.jpg" par un autre nom (attention, votre fichier image devra se trouver dans le même dossier que le ficher de votre programme Python).
  • "r,v,b=img.getpixel((100,250))" cette ligne récupère les valeurs du canal rouge (r), du canal vert (v) et du canal bleu (b) du pixel de coordonnées (100,250). Dans la suite du programme, r correspondra à la valeur du canal rouge, v correspondra à la valeur du canal vert et b correspondra à la valeur du canal bleu
  • "print("canal rouge : ",r,"canal vert : ",v,"canal bleu : ",b)" permet d'imprimer le résultat

Modifiez le programme de l'exercice 1 pour qu'il affiche les valeurs du canal rouge, du canal vert et du canal bleu du pixel de coordonnées (250,300), notez votre réponse.

Il est possible de modifier les canaux RVB d'un pixel :

Saisissez et testez le programme suivant :


from PIL import Image
img = Image.open("pomme.jpg")
img.putpixel((250,250),(255,0,0))
img.show()
			

Regardez attentivement le centre de l'image, vous devriez voir un pixel rouge à la place d'un pixel vert.


Voici une analyse ligne par ligne du programme ci-dessus :

  • "img.putpixel((250,250),(255,0,0))" permet de colorier le pixel de coordonnées (250,250) en rouge (255,0,0).
  • "img.show()" permet d'afficher l'image modifiée

Modifiez le programme de l'exercice précédent afin de colorier le pixel de coordonnées (100,250) en bleu.


Modifiez un pixel c'est déjà bien, mais comment faire pour modifier plusieurs pixels ? La réponse est simple, nous allons utiliser des boucles "for". Le but ici n'est pas de détailler le fonctionnement des boucles "for" en Python, vous devez juste comprendre que grâce à ces boucles nous allons pouvoir balayer toute l'image et ne plus nous contenter de modifier les pixels un par un.

Saisissez et testez le programme suivant (ATTENTION : l'exécution de ce programme n'est pas très intéressante en soi, vous pouvez l'arrêter à tout moment en appuyant simultanément sur la touche Ctrl et sur la touche C):


from PIL import Image
img = Image.open("pomme.jpg")
largeur_image=500
hauteur_image=500
for y in range(hauteur_image):
    for x in range(largeur_image):
        r,v,b=img.getpixel((x,y))
        print("rouge : ",r,"vert : ",v,"bleu : ",b)
print("fin")
			

Quelques commentaires sur ce programme :

  • Nous commençons par définir les variables "largeur_image" et "hauteur_image" ("largeur_image=500" et "hauteur_image=500"). Je pense que vous aurez compris que notre image "pomme.jpg" fait 500 pixels de large et 500 pixels de haut. Si vous désirez travailler avec une autre image, il faudra veiller à bien modifier la valeur de ces deux variables.
  • Les 2 boucles "for" nous permettent de parcourir l'ensemble des pixels de l'image :
    
    for y in range(hauteur_image):
        for x in range(largeur_image):
    		 	   ...
    				 
    Le plus important ici est de bien comprendre que dans la suite du programme, les variables x et y vont nous permettre de parcourir l'ensemble des pixels de l'image : nous allons commencer avec le pixel de coordonnées (0,0), puis le pixel de coordonnées (1,0), puis le pixel de coordonnées (2,0)...jusqu'au pixel de coordonnées (499,0). Ensuite, nous allons changer de ligne avec le pixel de coordonnées (0,1), puis le pixel de coordonnées (1,1)...bref, le dernier pixel sera le pixel de coordonnées (499,499), tout cela grâce à la double boucle "for" !
  • "r,v,b=img.getpixel((x,y))" cette ligne ne devrait pas poser de problème, nous avons juste remplacé les coordonnées des pixels par (x,y) afin de considérer l'ensemble des pixels de l'image.
  • "print("rouge : ",r,"vert : ",v,"bleu : ",b)" nous imprimons les valeurs des canaux RVB pour chaque pixel de l'image.
  • "print("fin")" ATTENTION cette ligne n'est pas dans la double boucle (pas de décalage), le mot "fin" ne sera donc affiché qu'une seule fois (après avoir parcouru l'ensemble des pixels).

Compliquons un peu la chose en modifiant tous les pixels de l'image :

Saisissez et testez le programme suivant :


from PIL import Image
img = Image.open("pomme.jpg")
largeur_image=500
hauteur_image=500
for y in range(hauteur_image):
    for x in range(largeur_image):
        r,v,b=img.getpixel((x,y))
        n_r=v
        n_v=b
        n_b=r
        img.putpixel((x,y),(n_r,n_v,n_b))
img.show()
		

Expliquez en quelques mots ce que fait ce programme.

Comment pourraient se nommer les variables r, v, b, n_r, n_b et n_v pour être plus explicite ?

En vous inspirant de ce qui a été fait à l'exercice 6 , écrivez un programme qui inverse les valeurs des canaux bleu et rouge sans changer la valeur du canal vert.


Après avoir fait quelques recherches sur le "négatif d'une image", écrivez un programme qui donne le négatif d'une image.


Après avoir fait quelques recherches sur les "images en niveau de gris", écrivez un programme qui transforme une "image couleur" en une "image en niveau de gris".

Petite astuce qui pourrait vous aider : en Python pour avoir une division entière (le résultat est un entier), il faut utiliser l'opérateur // à la place de l'opérateur /


Testez les programmes écrient dans le à l'exercice 8" et le à l'exercice 9" avec une image de votre choix (attention aux variables "largeur_image" et "hauteur_image").


Pour l'instant nous avons modifié tous les pixels de l'image. Avec l'instruction "if", il est possible de modifier seulement certains pixels.

Saisissez et testez le programme suivant :


from PIL import Image
img = Image.open("pomme.jpg")
largeur_image=500
hauteur_image=500
for y in range(hauteur_image):
    for x in range(largeur_image):
        r,v,b=img.getpixel((x,y))
        if b<200:
            n_b=255-b
        else :
            n_b=b
        img.putpixel((x,y),(r,v,n_b))
img.show()
		

Expliquez en quelques mots ce que fait ce programme.


Il est même possible de combiner plusieurs conditions :

Saisissez et testez le programme suivant :


from PIL import Image
img = Image.open("pomme.jpg")
largeur_image=500
hauteur_image=500
for y in range(hauteur_image):
    for x in range(largeur_image):
        r,v,b=img.getpixel((x,y))
        if v>100 and y>250:
            n_v=0
        else :
            n_v=255
        img.putpixel((x,y),(r,n_v,b))
img.show()
		

Expliquez en quelques mots ce que fait ce programme.

Transformez Mario en Luigi, vous pouvez lui laisser le M, il s'appelera Muigi!😜

voici l'image à télécharger:


En résumé..

Voici un programme qui reprend les différents traitements.



from PIL import Image        #Importe le module Image de la bibliothèque PIL


def CreationImage(image0):   # Création de la fonction qui permet de créer l'image demandée
    dimx = image0.size[0]    # largeur de l'image
    dimy = image0.size[1]    # hauteur de l'image
    image1 = Image.new('RGB', (3*dimx, 4*dimy), (250, 250, 250)) # Création d'une nouvelle image 3 fois plus large et 4 fois plus haute
    for i in range(dimx):    # parcours des deux dimensions pour modifier chaque pixel
        for j in range(dimy):
            r, v, b = image0.getpixel((i, j))    # On récupère la couleur du pixel (i,j) sous la forme d'un tuple (r, g, b)
            image1.putpixel((i, j), (r,v,b))     # On recopie cette image dans le coin en haut à gauche
            image1.putpixel((dimx+i, j), (b,r,v)) #Etape 2 : permutation de (r,v,b)
            image1.putpixel((2*dimx+i, j), (v,b,r)) #Etape 3 : permutation de (r,v,b)
            image1.putpixel((i, dimy+j), (255-r,255-v,255-b)) #Etape 4 : passage au négatif de l'image
            #Etape 5 : elle représente l'image en niveaux de gris en faisant la moyenne des composantes (r,v,b) de l'image initiale
            g=int((r+v+b)/3)
            image1.putpixel((dimx+i, dimy+j), (g,g,g))
            image1.putpixel((2*dimx+i, dimy+j), (255-g,255-g,255-g)) #Etape 6 : passage au négatif de l'image de l'étape 5
            image1.putpixel((i, 2*dimy+j), (r,v,0))   # Etape 7 : image initiale en supprimant la composante bleue.
            image1.putpixel((dimx+i, 2*dimy+j), (0,v,b)) # Etape 8 :image initiale en supprimant la composante rouge
            image1.putpixel((2*dimx+i, 2*dimy+j), (r,0,b)) # Etape 9 :image initiale  en supprimant la composante verte
            image1.putpixel((i, 3*dimy+j), (r,0,0))   # Etape 10 :image initiale en supprimant la composante bleue et verte.
            image1.putpixel((dimx+i, 3*dimy+j), (0,v,0)) #Etape 11 :image initiale en supprimant la composante rouge et bleue
            image1.putpixel((2*dimx+i, 3*dimy+j), (0,0,b)) #Etape 12 :image initiale  en supprimant la composante rouge et verte
    return image1





image_initiale = "gateau.jpeg"
image_ini = Image.open(image_initiale)  # Ouverture du fichier image source et création de l'objet Image

image_finale = CreationImage(image_ini) # On crée l'image
image_finale.save("Etape2.jpg")         # on sauvegarde sous un autre nom
image_finale.show()



		
Téléchargez l'image

Testez le programme, modifiez-le , vous pouvez aussi changer l'image...