Sauter au contenu
Logo image

Algèbre linéaire Intuition et rigueur

Section 7.3 Traitement d’images (EN CONSTRUCTIION)

Aller aux exercices 7.3.4 de la section.
Une image sur un ordinateur est composée de pixels, des petits carrés de couleur. Une image de qualité contient davantage de pixels par pouce (ppi). On dit que l’image a une grande résolution. Une image prise par un apparail photo peut être exportée en format RAW, où tous les pixels tels que captés par l’objectif seront présents, ou dans un format compressé, par exemple JPEG, afin de réduire la taille du fichier. Différents algorithme menant à l’image compressée existent. Certains sont basés sur l’observation que, dans le voisinage d’un pixel quelconque, il est peu probable qu’il y ait de grands changements de couleur. On peut alors prendre la couleur moyenne d’un groupe de pixels et fusionner ces pixels en un unique représentant. Cela réduit alors le nombres de pixels par pouces, produisant une image de taille inférieure.
Si l’on prend comme hypothèse que l’image est uniquement en noir et blanc, chaque pixel peut être représenté par un nombre, typiquement entre \(0\) (noir) et \(255\) (blanc). Les entrées d’une matrice du format de l’image correspondent alors à la « couleur» de chaque pixel, en ton de gris. Pour les images en couleur, on doit ajouter une dimension afin de représenter les couleurs selon la quantité de rouge, vert et bleu. En voyant ces images comme des matrices, il est possible de faire des opérations sur ces images et d’obtenir des résultats intéressants. Parfois, ces matrices sont composées uniquement de valeurs entre \(0\) et \(1\text{.}\) Les entrées représentent alors le pourcentage de blanc ou de couleur.

Sous-section 7.3.1 Premiers pas

Sage est en mesure de produire une image en ton de gris à partir d’une matrice. La commande matrix_plot(A,cmap="gray") lui permet de prendre la matrice \(A\) et de donner sa représentation graphique. L’argument cmap="gray" s’assure de convertir les entrées de la matrice en tons de gris si les nombres ne sont pas dans le format \(0\)-\(255\text{.}\)
On peut également créer une image aléatoire.
Pour un effet plus intéressant, on peut bien sûr partir d’une véritable image. Il suffit de la charger dans Sage et de la convertir en format noir et blanc. Par exemple, voici une version déjà compressée de la couverture du manuel.

Sous-section 7.3.2 Algoritmes de floutage

L’un des premiers effet que l’on considère est celui du floutage d’une image. L’idée est de remplacer chacune des entrées de la matrice par une moyenne de la valeur et de ses voisins. Le résultat varie selon le type de moyenne utilisé. Le cas le plus simple est celui d’une moyenne régulière.

Définition 7.3.1. Noyau de floutage simple.

Une matrice \(N\in\mathcal{M}_{(2n+1)\times (2n+1)}\) où chaque entrée vaut \(\frac{1}{(2n+1)^2}\) est appelé un noyau de floutage simple dans le contexte du traitement d’image. Par exemple, les matrices
\begin{align*} N_3&=\begin{pmatrix} \frac{1}{9}&\frac{1}{9}&\frac{1}{9}\\ \frac{1}{9}&\frac{1}{9}&\frac{1}{9}\\ \frac{1}{9}&\frac{1}{9}&\frac{1}{9}\\ \end{pmatrix}\\ N_5&=\begin{pmatrix} \frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}\\ \frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}\\ \frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}\\ \frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}\\ \frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}&\frac{1}{25}\\ \end{pmatrix} \end{align*}
sont deux noyaux de floutage, respectivement d’ordre \(3\) et \(5\text{.}\)
Pour déterminer la nouvelle image, on effectue un passage du noyau sur la matrice. L’entrée au centre est remplacée par la moyenne des neufs entrées couvertes par le noyau. La figure 7.3.2 illustre ce concept.
Une grille de taille huit par huit est composée d’entiers sur laquelle on peut voir une autre grille de taille trois par trois qui est centrée sur l’élément en position cinq, quatre. La petite grille est bleu et représente le noyeau de floutage. À sa droite, on retrouve une grille presque entièrement vide, avec l’élément central du noyeau remplacé par la moyenne des neufs valeurs à la position correspondante.
Figure 7.3.2. Le floutage d’une entrée par un noyau d’ordre $3$
Pour les entrées sur le bord de la grille, il n’y a pas nécessairement neuf voisins. Dans ces cas, on prend remplace la valeur des voisins absents par \(0\text{.}\) L’animation suivante montre le processus complet de l’application du noyau sur la grille de l’image précédente.
Une grille de taille huit par huit est composée d’entiers sur laquelle on peut voir une autre grille de taille trois par trois qui se déplace le long de la grande grillee. La petite grille est bleu et représente le noyeau de floutage. À sa droite, on retrouve la même grille, qui se remplit graduellement avec la moyenne des valeurs dans la noyau de floutage.
Figure 7.3.3. Application d’un noyau de floutage sur une matrice
On regarde un exemple de floutage à l’aide de ce noyau.

Calcul 7.3.4. Floutage par noyau simple.

On propose de flouter la couverture du manuel à l’aide d’un noyau simple d’ordre 3. Dans un premier temps, on doit charger l’image. La cellule suivante est identique à celle se trouvant dans le texte ci-haut.
Pour le moment, \(G\) est une matrice de taille \(200\times 155\text{.}\) Afin de pouvoir appliquer le floutage sur l’ensemble de ces valeurs, il est utile d’ajouter un contour de zéros à cette matrice afin de pouvoir appliquer le noyau sans se soucier des bords. On appelle ce procédé le bourrage. Pour cela, la commande block_diagonal_matrix peut être utile. Celle-ci permet de créer une matrice en définissant les blocs se retrouvant le long de la diagonale principale. Sage complètera la matrice afin qu’elle soit de la bonne taille en ajoutant des zéros. En anglais, cet ajout de zéros se nomme “padding”. Voici un exemple simple avant de l’appliquer sur la matrice \(G\text{.}\)
Dans le cas de la couverture du manuel, on veut simplement encadrer la matrice \(G\) de zéros. On peut procéder comme suit.
Pour appliquer le floutage, on doit calculer la moyenne de chaque pixel de la matrice \(G\) et de ses voisins immédiats. Dans la cellule précédente, on voit le coin supérieur gauche de la matrice modifiée. Dans ce cas, la moyenne du premier pixel et de ses vosins est de \(103.55556\text{.}\) On doit convertir les entrées de la matrices en liste afin de calculer la moyenne.
On crée une fonction qui prend comme argument une paire de nombres \(i,j\) et une matrice Gpad et retourne la moyenne de l’entrée en position \(i,j\) et de ses voisins immédiats dans la matrice . On s’assure également que l’argument ne peut pas être au bord de la matrice.
Enfin, on crée la nouvelle matrice formée de ces moyennes. À noter le décalage nécessaire puisque le pixel correspondant dans la matrice Gpad se trouve une ligne et une colonne plus loin.
On peut assez bien distinguer l’image originale de celle qui a subi le floutage, bien que l’effet soit subtil. Pour obtenir un meilleur effet, on pourrait appliquer à nouveau le floutage. L’exercice [provisional cross-reference: exo-fctplusieurspassage] permet d’explorer cette possibilité.
Une autre option consiste à augmenter la taille du noyau de floutage. Il faut également penser à augmenter la taille du bourrage effectué. On commence par créer une fonction qui prend une matrice et un entier \(n\) comme arguments et effectue un bourrage d’ordre \(n\text{.}\) On rappelle que selon la définition 7.3.1, \(n\) doit être un nombre impair. Si \(n=2k+1\text{,}\) alors il faut ajouter à la matrice \(k\) lignes et colonnes de chaque côté.
La prochaine étape consiste à modifier la fonction noyausimple afin qu’elle soit modulable selon la valeur \(n\) du noyau. La nouvelle version prend comme arguments la matrice de l’image originale \(G\) ainsi que l’ordre du noyau \(n\text{.}\)
Finalement, on crée la fonction qui permet de flouter une image \(G\) selon un noyau d’ordre \(n\) impair.
La cellule ci-dessous permet de comparer l’effet de l’ordre de floutage sur l’image originale de manière interactive.
Lorsque la taille du noyau augmente, il est légitime de se demander si le fait d’attribuer autant de poids aux pixels éloignés du centre est la chose à faire. Dans une image haute résolution, plus on s’éloigne d’un pixel, plus les chances sont que les couleurs (ou dans ce cas-ci, les tons de gris) soit différentes augmentent. On peut alors utiliser un noyeau pondéré.

Définition 7.3.5. Noyeau de floutage pondéré.

Une matrice \(N\in\mathcal{M}_{(2n+1)\times (2n+1)}\) dont la somme de éléments vaut 1 et pour laquelle les valeurs au centre sont plus grandes que les valeurs éloignées est appelé un noyau de floutage pondéré.

Exemple 7.3.6. Des noyaux de floutage pondéré.

Les matrices suivantes sont des noyaux de floutage pondéré:
\begin{align*} A&=\frac{1}{10}\begin{pmatrix} 1&1&1\\ 1&2&1\\ 1&1&1\\ \end{pmatrix}\\ B&=\frac{1}{80}\begin{pmatrix} 5&10&5\\ 10&20&10\\ 5&10&5\\ \end{pmatrix}\\ C&=\frac{1}{48}\begin{pmatrix} 0&1&2&1&0\\ 1&2&4&2&1\\ 2&4&8&4&2\\ 1&2&4&2&1\\ 0&1&2&1&0\\ \end{pmatrix} \end{align*}
Il est commun d’avoir un étalement symétrique des poids alloués aux pixels, comme dans les noyaux de l’exemple 7.3.6, mais ce n’est pas strictement nécessaire. L’effet pourrait toutefois être disproportionné.
Un noyau de floutage pondéré particulièrement utile est le noyeau Gaussien. Les valeurs du noyau sont déterminées selon la distribution de la loi normale, aussi appelée distribution gaussienne. Cette distribution statistique donne un poids plus grand au centre et attribue un poids proportionnellement plus petits aux valeurs éloignées. La loi normale dépend de deux paramètres, la moyenne \(\mu\) et l’écart type \(\sigma\text{,}\) mais pour le noyau de floutage, seul l’écart type est nécessaire. Celui-ci va définir l’intensité du floutage. Voici la représentation de quelques courbes de la loi normale ainsi que leur valeur pour \(\sigma\text{.}\)
Trois courbe de la loi normale pour sigma égale à un, trois et cinq.
Trois courbe de la loi normale sont illustrées. La première, de couleur bleue, est identifiée comme sigma égal à trois et est la plus étroite des trois courbes. La deuxième, identifiée sigma égal à trois est de couleur rouge et est plus aplatie que la première. La dernière, de couleur noire, est identifiée sigma égal à cinq et est encore plus aplatie.
Figure 7.3.7. Quelques courbes de loi normale
Comme on travaille en deux dimensions, il faut considérer l’équation de la loi normale pour deux variables. Celle-ci, pour une moyenne égale à zéro, est donnée par l’équation
\begin{equation} \frac{1}{\sqrt{2\pi \sigma}}e^{-\frac{(x^2+y^2)}{2\sigma^2}}\text{.}\tag{7.3.1} \end{equation}
Pour construire le noyau gaussien, il est pratique de créer une fonction intermédiaire de déphasage permettant à l’entrée au centre d’une matrice d’être considéré comme le point \((0,0)\text{.}\) Les coordonnées des autres entrées de la matrice sont données en relation de leur distance horizontale et verticale avec le centre. Le code suivant donne la fonction de déphasage à utiliser ainsi que son effet sur les entrées d’une matrice \(n\times n\text{.}\)
En théorie, tous les points contribuent à la moyenne d’un noyau gaussien, même ceux très éloignés. En pratique, il n’y a que les points situés à une distance de plus ou moins six sigmas qui auront une contribution significative. Deux choix sont possibles pour la suite. On peut fixer la taille du noyau et renormaliser en divisant par la somme des données. On peut également déterminer la taille du noyau à utiliser en fonction de l’écart type. On prendra l’entier impair plus grand que \(6\sigma+1\text{,}\) afin qu’il y ait \(6\) écarts types de part et d’autre de l’entrée au centre. Pour alléger les calculs, il est parfois possible de réduire ce facteur \(6\text{,}\) en gardant au minimum \(3\text{.}\) Dans ce qui suit, on opte pour l’option de déterminer la taille selon l’écart type. La cellule ci-dessous crée une fonction qui retourne le noyeau gaussien d’écart type sigma de dimension correspondant à plus ou moins nbr écarts types.
Maintenant qu’on a le noyau, il faut l’appliquer à la matrice image. Pour un noyau simple, il suffisait de faire la somme des entrées autour du centre et diviser par le carré de la dimension du noyau. Avec un noyau pondéré, il faut passer par l’étape intermédiaire où l’on multiplie chaque entrée autour du centre dans la matrice image par son poids relatif dans le noyau. Ce n’est pas aussi simple que de passer par la multiplication matricielle, puisqu’au final on veut obtenir une seule valeur pour chaque centre de l’image. La fonction suivante modifie la fonction de floutage simple pour tenir en compte de ce calcul. Attention, un écart type trop grand fera en sorte que les fonctions ci-dessous ne seront pas en mesure de s’exécuter dans un temps appréciable.
Finalement, on combine le tout dans une seule fonction qui transforme l’image initiale à l’aide du noyau pondéré.

Sous-section 7.3.3 Détection de contours

Exercices 7.3.4 Exercices