• 15 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Mis à jour le 01/02/2019

Comprenez comment un ordinateur voit une image

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

L'image vue comme une fonction mathématique

Qu'est-ce qu'une image ?

Cette question simple admet en réalité plusieurs réponses, plus ou moins techniques, selon le domaine étudié. Commençons par donner la réponse qui vient naturellement à la majorité d'entre nous : une image est une représentation visuelle de quelque chose ou de quelqu'un.

Portrait de Lena
Lena, l'exemple canonique du traitement d'images

Le traitement d'images désigne l'ensemble des techniques permettant de modifier une image, souvent dans le but de l'améliorer – par exemple, on peut la rendre plus lumineuse ou plus nette. Cette discipline se situe à la croisée des mathématiques appliquées et de l'informatique, c'est pourquoi nous nous intéresserons désormais à la définition d'une image dans ces deux domaines.

En mathématiques, une image est une fonction. Cette fonction quantifie l'intensité lumineuse de n'importe quel point dans l'image. Dans une image en noir et blanc, l'intensité est le niveau de gris : plus un point est sombre, plus son niveau de gris est faible.

Comme une image est une surface délimitée du plan, on peut se munir d'un repère cartésien et repérer la position de ses points par les coordonnées $\((x,y)\)$, avec $\(x\)$ son abscisse et $\(y\)$ son ordonnée. Plus formellement, l'image comme fonction mathématique s’écrit comme ceci :

$\[\begin{matrix}I\;: & \mathbb{R}^2 & \rightarrow & \mathbb{R} \\ & (x,y) & \mapsto & I(x,y)\end{matrix}\]$

Et si mon image est en couleurs ?

Dans ce cas, l'intensité d'un point désigne sa couleur. Celle-ci peut être perçue comme un mélange des trois couleurs primaires (rouge, vert et bleu). Ainsi, une image ne correspond non plus à une seule fonction, mais à trois : on associe à chaque point son intensité de rouge, de vert et de bleu. Ces trois valeurs sont respectivement notées $\(r(x,y)\)$, $\(g(x,y)\)$ et $\(b(x,y)\)$ et stockées dans un vecteur colonne de taille trois, de sorte que l'image puisse être représentée comme une fonction vectorielle :

$\[\begin{matrix}I\;: & \mathbb{R}^2 & \rightarrow & \mathbb{R}^3\ \\ & (x,y) & \mapsto & \begin{bmatrix} r(x,y) \\ g(x,y) \\ b(x,y) \end{bmatrix} \\ \end{matrix}\]$

Nous avons ainsi introduit une définition rigoureuse de l'image, vue comme une fonction mathématique.

Mais pourquoi se compliquer la vie à rendre aussi abstrait un concept intuitif ? 

En traitement d'images, on ne peut absolument pas se contenter de définir une image comme "quelque chose que l'on voit et qui représente une information". En effet, comme vous le verrez très bientôt, la modification d'une image fait intervenir des opérations mathématiques. Celles-ci sont formulées de manière beaucoup plus intelligible et précise si l'on considère l'objet auquel elles s'appliquent – l'image – comme un objet mathématique.

L'image numérique

Je vous avais dit que le traitement d'images faisait intervenir des outils non seulement issus des mathématiques appliquées, mais aussi de l'informatique. La définition mathématique d'une image ne convient pas à un ordinateur : des restrictions doivent être imposées sur les ensembles de définition et d'arrivée de la fonction.

Dans notre définition mathématique, l'abscisse, l'ordonnée et l'intensité d'un point donné de l'image peuvent prendre n'importe quelle valeur réelle. C'est pourquoi nous parlons de modèle continu, ou d'image analogique.

Nous savons déjà qu'une image est une surface délimitée du plan. Est-ce alors pertinent d'attribuer une intensité lumineuse à tous les points de $\(\mathbb{R}^2\)$ si l'on cherche seulement à en décrire une petite zone ?

Eh bien non ! Affinons donc le domaine de définition, en gardant uniquement la portion utile du plan, c'est-à-dire un rectangle de largeur $\(w\)$ (width) et de hauteur $\(h\)$ (height) contenant l'image. 

Une image en informatique est ainsi une discrétisation – ou numérisation – de notre modèle continu : on l'appelle image numérique. Cette discrétisation se fait à la fois sur l'ensemble de définition de la fonction image (échantillonnage, ou sampling en anglais) et sur son ensemble d'arrivée (quantification).

Une image numérique est une image échantillonnée et quantifiée. La définition formelle d'une image numérique en noir et blanc est donc la suivante :

$\[\begin{matrix}I\;: & \{0,1,...,w-1\} \times \{0,1,...,h-1\} & \rightarrow & \{0,1,...,255\} \\ & (x,y) & \mapsto & I(x,y)\end{matrix}\]$

L'ordinateur traite une image comme une matrice d'entiers de taille $\(h \times w\)$, contenant les niveaux de gris de ses pixels. 

Notons que si cette représentation est la plus courante pour afficher une image, la lire ou l'écrire dans un fichier, nous travaillerons généralement sur des images sans quantification (l'intensité est un nombre réel, ou plutôt son équivalent pour l'ordinateur, un nombre à virgule flottante) et nous n'appliquerons la quantification qu'à la fin.

Premières manipulations d'images en Python

Passons à la pratique ! L'objectif est d'apprendre à effectuer des manipulations d'images très basiques en Python et de mieux comprendre la notion d'image numérique avec un exemple concret.

Avant de commencer à coder, il faut choisir une image de test en noir et blanc. J'ai personnellement décidé de travailler avec la photo ci-dessous, enregistrée dans le fichier simba.png  :

Légende
Ok, c'est pas vraiment Simba

C'est bon, vous avez trouvé votre image de test ? Alors, c'est parti !

Tout d'abord, nous devons importer le module Image de la bibliothèque Pillow. L'étape préalable indispensable à tout traitement est le chargement de l'image : cela se fait facilement avec la fonction Image.open . Nous pouvons ensuite afficher le résultat renvoyé par cette fonction afin de vérifier que l'image a bien été chargée :

from PIL import Image

# Charger l'image
img = Image.open("simba.png") 

# Afficher l'image chargée
img.show()

A l’exécution de ce script, une petite fenêtre doit apparaître et afficher l'image du fichier simba.png. La variable img contient l'image numérique que notre ordinateur est en mesure de comprendre et traiter.

Nous pouvons obtenir la taille de notre image, donnée en nombre de pixels :

# Récupérer et afficher la taille de l'image (en pixels)
w, h = img.size
print("Largeur : {} px, hauteur : {} px".format(w, h))
Largeur : 250 px, hauteur : 263 px

Ce résultat signifie que l'image analogique a été découpée en 250 pixels sur la largeur et 263 pixels sur la hauteur pendant l'échantillonnage.

Maintenant, inspectons les valeurs de pixels. L'attribut  Image.mode  nous informe sur le format de pixel utilisé, autrement dit sur la façon dont la quantification a été faite. De plus, la méthode Image.getpixel permet de récupérer l'intensité associée au pixel à une position donnée.

# Afficher son mode de quantification
print("Format des pixels : {}".format(img.mode))

# Récupérer et afficher la valeur du pixel à une position précise
px_value = img.getpixel((20,100))
print("Valeur du pixel situé en (20,100) : {}".format(px_value))
Format des pixels : L
Valeur du pixel situé en (20,100) : 196

Nous pouvons également récupérer d'un seul coup les valeurs de tous les pixels de l'image à l'aide de la bibliothèque numpy :

import numpy as np

# Récupérer les valeurs de tous les pixels sous forme d'une matrice
mat = np.array(img)
mat

# Afficher la taille de la matrice de pixels
print("Taille de la matrice de pixels : {}".format(mat.shape))
array([[247, 245, 245, ..., 224, 228, 228],
      [246, 244, 243, ..., 228, 230, 230],
      [244, 242, 240, ..., 230, 231, 231],
      ..., 
      [183, 169, 169, ..., 108, 95, 102],
      [170, 160, 171, ..., 81, 95, 99],
      [150, 155, 174, ..., 133, 115, 111]], dtype=uint8)

Taille de la matrice de pixels : (263, 250)

On retrouve bien la représentation introduite dans la section précédente pour une image numérique en noir et blanc : nous avons une matrice de taille hauteur $\(\times\)$ largeur où chaque élément contient un entier compris entre 0 et 255 afin d'indiquer le niveau de gris du pixel associé. 

Exemple de certificat de réussite
Exemple de certificat de réussite