algorithme glouton

.

La photographie numérique

.

Une image est composée de petits points appelés pixel. La définition d’une image vous donne le nombre de pixels qui compose l’image, par exemple une image de définition 800 x 600 (800 par 600), signifie que cette image est composée de 800 pixels en largeur et de 600 pixels en hauteur, soit en tout 800 x 600 = 480000 pixels.

Un pixel est composé de trois parties : une partie rouge, une partie verte et une partie bleue. À chaque pixel on associe donc 3 couleurs : le rouge, le vert et le bleu. On parle du canal rouge, du canal vert et du canal bleu d’un pixel (on parle de système RVB ou RGB en anglais). La théorie physique de la synthèse additive des couleurs (pour plus d’informations sur cette théorie, voir ici) montre que la variation de l’intensité lumineuse de chaque canal permet d’obtenir un très grand nombre de couleurs. La valeur de l’intensité lumineuse associée à chaque canal de chaque pixel d’une image est très souvent comprise entre 0 et 255 (256 valeurs possibles). On codera donc un pixel à l'aide d'un triplet de valeur (par exemple "247,56,98"). La première valeur donnant l'intensité du canal rouge, la deuxième valeur donnant l'intensité du canal vert et la troisième valeur donnant l'intensité du canal bleu.

pixel
pixel
pixel
pixels

Quand on observe un pixel "à la loupe", on peut constater que le pixel est bien constitué de trois parties : une partie rouge, une partie verte, et une partie bleue (voir schéma ci-dessus). Et là, je suis sûr que vous vous posez une question fondamentale : quand nous regardons une image sur un écran d'ordinateur, nous "voyons" des pixels de différentes couleurs (jaune, mauve,...) et pas des pixels constitués de rouge, de vert et de bleu, pourquoi ?

Cela est dû à une limitation de notre oeil : son pouvoir séparateur !

pixel
pouvoir séparateur de l'oeil

Quand vous regardez 2 points très proches l'un de l'autre, l'oeil "voit" deux points si l'angle α (voir le schéma ci-dessus) est supérieur à 0,017°. En dessous de cette valeur, votre oeil "superposera" les 2 points, il ne verra pas deux, mais un seul point.

Un pixel est tellement petit que notre oeil superposera la partie rouge, la partie verte et la partie bleue du pixel, voilà pourquoi nous voyons des pixels de différentes couleurs.

À faire vous-même 1

Combien de couleurs différentes est-il possible d’obtenir avec ce système RVB ?


À faire vous-même 2

À l'aide de l'application proposée sur ce site, faites varier les canaux rouge, vert et bleu (à l'aide des boutons + et des boutons -) afin d'obtenir différentes couleurs.

Comment obtenir du rouge ?

Comment obtenir du blanc ?

Comment obtenir du noir ?

Comment obtenir du jaune ?

Que se passe-t-il quand les trois canaux ont la même valeur (par exemple 125,125,125) ?


La taille est une autre caractéristique d'une image, elle correspond à la taille de l'image en cm ou en pouce (inch en anglais), toujours en utilisant la largeur et la longueur de l'image. Le papier photo vendu dans le commerce que l'on trouve le plus couramment fait 15 cm en largeur et 10 cm en hauteur. En cas d'impression sur ce papier, on obtiendra des photos de taille 15x10.

En combinant la taille et la définition d'une image, l'on obtient la résolution de cette image. La résolution d'une image est définie par le nombre de pixels par unité de longueur : nombre de pixels par cm ou plus couramment nombre de pixels par pouce (ppp ou dpi).

À faire vous-même 3

Soit une image de définition 800x533 que l'on imprime sur du papier photo de taille 15x10 (en cm), calculez la résolution de cette image en ppp (rappel 1 pouce = 2,54 cm).

À faire vous-même 4

Sachant que l'on estime que pour avoir une impression de qualité il faut atteindre une résolution de 300 ppp, calculez la définition minimale d'une image dans le cas d'une impression sur du papier photo 15 x 10.

À faire vous-même 5

L'écran d'un smartphone a une résolution de 458 ppp, il affiche des images de résolution 2436 x 1125. Calculez la taille de cet écran (largeur, hauteur) en cm.

Nous allons utiliser le langage de programmation 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 :

À faire vous-même 1

Après avoir ouvert l'éditeur Spyder, 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"


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

À faire vous-même 2

Modifiez le programme du "À faire vous-même 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 :

À faire vous-même 3

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

À faire vous-même 4

Modifiez le programme du "À faire vous-même 3" 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.

À faire vous-même 5

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 :

À faire vous-même 6

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.

À faire vous-même 7

En vous inspirant de ce qui a été fait au "À faire vous-même 6", écrivez un programme qui inverse les valeurs des canaux bleu et rouge sans changer la valeur du canal vert.


À faire vous-même 8

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


À faire vous-même 9

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 /


À faire vous-même 10

Testez les programmes écrient dans le "À faire vous-même 8" et le "À faire vous-même 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.

À faire vous-même 11

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.


Il est même possible de combiner plusieurs conditions :

À faire vous-même 12

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

        img.putpixel((x,y),(r,v,n_b))

img.show()

Expliquez en quelques mots ce que fait ce programme.


Au siècle dernier on trouvait dans tous les appareils photo des pellicules. Une pellicule est une surface photosensible (surface qui réagit à la lumière) qui capte les informations lumineuses. Une fois la pellicule terminée (avec une pellicule on peut faire un nombre variable de photos : 6, 12, 24 ou 36), elle était extraite (je parle au passé, mais certains photographes utilisent encore des appareils photo avec pellicule) de l'appareil photo puis développée dans un laboratoire spécialisé grâce à des procédés chimiques, bref, tout cela était quelque peu complexe et quelque peu contraignant (par exemple une photo ratée, était tout de même développée et donc facturée...). Aujourd'hui, fini ces contraintes, on peut prendre autant de photos que l'on veut (dans la limite des capacités mémoires de l'appareil), effacer une photo si elle ne nous convient pas, imprimer uniquement certaines photos sur l'imprimante familiale. Cela a été rendu possible grâce au progrès de l'informatique et de l'électronique et plus particulièrement grâce à l'arrivée dans l'électronique grand public des capteurs photo.

Le capteur photo remplace la pellicule, un capteur photo est donc une surface photosensible. Le capteur photo est composé d'un grand nombre de photosites, chaque photosite va recevoir de la lumière, l'intensité lumineuse va être "convertie" en tension électrique grâce à un effet physique très complexe qui ne sera pas abordé ici : l'effet photoélectrique. Plus l'intensité lumineuse reçue par le photosite est importante plus le photosite produira une tension électrique importante.

photosite
capteur photo et photosites

La tension électrique produite par un photosite sera ensuite "converti" en nombre (on parle de numérisation), à chaque photosite on associera donc un nombre qui sera fonction de la quantité de lumière reçue par ce même photosite. C'est ces nombres qui seront "stockés" dans la mémoire de l'appareil photo.

Si l'on se contentait de ce système, nous aurions uniquement des images en niveau de gris (souvent appelé à tort image en "noir et blanc"). Afin de pouvoir gérer les couleurs, on rajoute donc un filtre coloré devant chaque photosite. Nous avons vu, dans la partie consacrée aux images, qu'il est possible de générer un grand nombre de couleurs uniquement à partir du rouge, du vert et du bleu, nous allons donc trouver 3 types de filtres : des filtres "rouges" (qui laisseront uniquement passer la lumière rouge), des filtres "verts" (qui laisseront uniquement passer la lumière verte) et des filtres "bleus" (qui laisseront uniquement passer la lumière bleue). À chaque photosite on associera soit un filtre rouge, soit un filtre vert, soit un filtre bleu. Il existe différentes façons d'agencer les filtres sur le capteur photo, mais nous ne rentrerons pas dans ces détails ici.

filtres et photosites
filtres et photosites

Comme vous pouvez le constater sur l'image ci-dessus, les filtres dits "Bayer" sont constitués de 50% de filtres vert, de 25% de filtre rouge et de 25% de filtre bleu afin d'imiter la physiologie de l'oeil humain (notre oeil est plus sensible au vert qu'au bleu et au rouge). Dans ce genre de capteur, 50% des photosites enregistrent uniquement la lumière verte, 25% des photosites enregistrent uniquement la lumière rouge et 25% des photosites enregistrent uniquement la lumière bleue.

Précédemment nous avons vu qu'une image est constituée de pixels, mais dans le cas d'une photo d'où vient l'information (canal rouge, canal vert et canal bleu) associée à chaque pixel de la photo ?

La réponse est simple : des photosites du capteur photo. L'association de 4 photosites (deux verts, un rouge et un bleu) donnera les informations qui permettront de créer un pixel de l'image.

photosites et pixels
photosites et pixels

Comme vous pouvez le constater sur le schéma ci-dessus, l'information produite par un photosite pourra être utilisée pour "construire" 2 pixels se trouvant l'un à côté de l'autre dans l'image finale.

Un fichier "image" issu d'un appareil photo numérique contient plus qu'une simple image. On trouve en effet des informations sur l'image elle-même (définition, résolution...) mais aussi des informations sur la prise de vue (date et heure, lieu...). Cette spécification des fichiers "image" d'un appareil photo numérique s'appelle EXIF (EXchangeable Image file Format). Ces données contenues dans un fichier "image" d'un appareil photo s'appellent des métadonnées.

La plupart des logiciels de retouche photo permettent de lire ces métadonnées. Nous n'allons pas utiliser ce type de logiciel, nous allons plutôt écrire un petit programme Python (plus précisément, nous utiliserons la bibliothèque Python "PIL").

À faire vous-même 1

Créez un dossier nommé "exif", enregistrez l'image suivante : "photo.jpg"(clic droit, "Enregistrer sous") dans ce dossier "exif".

À faire vous-même 2

En utilisant le logiciel Spyder, saisissez et testez le programme suivant (il faudra enregistrer le fichier contenant ce programme dans le dossier "exif" ) :

 

 

import PIL.Image

img = PIL.Image.open('photo.jpg')

exif_data = img._getexif()

Après avoir exécuté le programme, utilisez l'"Explorateur de variables" de Spyder, pour analyser le contenu de la variable "exif_data", vous devriez avoir quelque chose qui ressemble à cela :

pixel

À faire vous-même 3

Comme vous pouvez le constater, nous avons un système clé:valeur (à chaque clé correspond une valeur). Les clés sont "codées" par des nombres, pour comprendre la signification de ces nombres, consultez le site http://www.exiv2.org/tags.html.

En vous aidant du site web cité ci-dessus, essayez de trouver les informations suivantes pour l'image "photo.jpg" :

  • la largeur de l'image en pixel
  • la hauteur de l'image en pixel
  • le fabricant du matériel
  • la date et l'heure de la prise de vue

La clé "34853" n'est pas tout le temps présente puisqu'il s'agit des coordonnées (latitude, longitude) de la prise de vue, il faut donc que l'appareil photo intègre un GPS (ce qui est le cas des smartphones), si nous double-cliquons sur cette clé "34853", nous obtenons les informations suivantes :

pixel

Les lignes 1, 2, 3 et 4 vont particulièrement nous intéresser :

  • ligne 1 : précise que nous sommes dans l'hémisphère Nord
  • ligne 2 : nous avons la latitude ((47, 1), (37, 1), (29107360, 1000000)) nous avons ici une latitude en degrés, minute, seconde (ici : 47 degrés 37 minutes et 29,107360 secondes, aussi noté 47°37'29,107360")
  • ligne 3 : précise que nous sommes à l'ouest (W) du méridien de Greenwich
  • ligne 4 : nous avons la longitude ((3, 1), (25, 1), (42976570, 1000000)) ici aussi la longitude est donnée en degrés, minute, seconde (ici : 3°25'42,976570")

Pour convertir des (degrés, minute, seconde aussi noté DMS) en "degrés décimaux" (DD) (unité que nous avons utilisée dans le module "cartographie"), il faut appliquer la formule suivante :

DD = degrés+(minute/60)+(seconde/3600)

/60)+(seconde/3600)

ATTENTION : pour que la conversion soit correcte, il faut ajouter un signe moins devant la longitude au format DD si nous sommes situés à l'ouest du méridien de Greenwich.

À faire vous-même 4

En vous aidant de ce qui a été expliqué ci-dessus et de ce que vous avez vu dans le module "cartographie", écrivez un programme Python permettant de générer une carte Open Street Map avec un marqueur situé à l'endroit où a été prise la photo "photo.jpg"


À faire vous-même 5

Recommencez ce qui a été demandé dans le "À faire vous-même 4" avec, par exemple, une photo prise avec votre smartphone.