10- Matrices de pixels et images
Une image numérique est un tableau de pixels (picture elements). C'est un bon support pour manipuler des tableaux à deux dimensions, c'est-à-dire des listes de listes.
I. Représentation d'une image
a) Images en niveaux de gris
Dans une image en niveaux de gris, chaque pixel est un entier entre 0 (noir) et 255 (blanc). Une image de hauteur
Loading editor...
# une petite image de 4 lignes et 5 colonnes : un carré blanc sur fond noir
petite = [[0, 0, 0, 0, 0],
[0, 255, 255, 255, 0],
[0, 255, 255, 255, 0],
[0, 0, 0, 0, 0]]
print("hauteur :", len(petite))
print("largeur :", len(petite[0]))
print("pixel ligne 1, colonne 2 :", petite[1][2])On accède à un pixel par image[y][x] : d'abord la ligne (l'ordonnée
b) Afficher une image
On utilise les bibliothèques PIL (pour lire le fichier) et matplotlib (pour afficher l'image) :
c) Créer et parcourir une image
On crée une image vide (noire) de taille
Loading editor...
def image_noire(h, w):
return [[0 for x in range(w)] for y in range(h)]
degrade = image_noire(100, 256)
for y in range(100):
for x in range(256):
degrade[y][x] = x
imshow(degrade)Ne pas écrire [[0] * w] * h : on obtiendrait
On ne modifie en général pas l'image de départ : on en construit une nouvelle. Pour copier une image :
Loading editor...
def copie(image):
return [[pixel for pixel in ligne] for ligne in image]II. Transformations géométriques
a) Symétrie et rotation
Pour une symétrie gauche-droite, le pixel en colonne
Loading editor...
def symetrie(image):
h, w = len(image), len(image[0])
return [[image[y][w - 1 - x] for x in range(w)] for y in range(h)]
imshow(symetrie(guepiers))Pour une rotation d'un quart de tour dans le sens horaire, l'image obtenue a pour hauteur la largeur de l'image de départ (et inversement). La ligne
Loading editor...
def rotation(image):
h, w = len(image), len(image[0])
return [[image[h - 1 - x][y] for x in range(h)] for y in range(w)]
imshow(rotation(guepiers))Vérifiez la formule de rotation sur la petite image de 2 lignes et 3 colonnes [[1, 2, 3], [4, 5, 6]].
Loading editor...
rotation([[1, 2, 3], [4, 5, 6]])
b) Réduction et agrandissement
Pour réduire une image d'un facteur 2, on peut garder un pixel sur deux dans chaque direction, ou (mieux) remplacer chaque carré de
Loading editor...
def reduction(image):
h, w = len(image), len(image[0])
return [[(image[2*y][2*x] + image[2*y][2*x+1] + image[2*y+1][2*x] + image[2*y+1][2*x+1]) // 4
for x in range(w // 2)] for y in range(h // 2)]
petite_image = reduction(reduction(reduction(guepiers)))
print(len(petite_image), "x", len(petite_image[0]))
imshow(petite_image)Pour agrandir une image d'un facteur 2, le plus simple est de dupliquer chaque pixel en un carré de
Loading editor...
def agrandissement(image):
h, w = len(image), len(image[0])
return [[image[y // 2][x // 2] for x in range(2 * w)] for y in range(2 * h)]
imshow(agrandissement(petite_image))L'image agrandie est "pixelisée" : on ne peut pas retrouver l'information perdue lors de la réduction.
III. Convolution
Beaucoup de traitements d'images (flou, détection de contours, netteté...) sont des convolutions : chaque pixel de l'image obtenue est une combinaison des pixels voisins dans l'image de départ.
Définition : convolution par un filtre
Voici le calcul, pixel par pixel, sur une petite image (choisissez le filtre) :
Chaque pixel de sortie est la somme des 9 pixels autour, multipliés par les coefficients du filtre.
Loading editor...
def convolution(image, filtre):
h, w = len(image), len(image[0])
resultat = image_noire(h, w)
for y in range(1, h - 1):
for x in range(1, w - 1):
s = 0
for i in range(3):
for j in range(3):
s += image[y - 1 + i][x - 1 + j] * filtre[i][j]
# on ramène la valeur entre 0 et 255
resultat[y][x] = min(255, max(0, int(s)))
return resultat
flou = [[1/9, 1/9, 1/9], [1/9, 1/9, 1/9], [1/9, 1/9, 1/9]]
contours = [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]
imshow(convolution(petite_image, contours))- Le filtre flou remplace chaque pixel par la moyenne de ses voisins : les détails s'estompent.
- Le filtre contours donne 0 dans les zones uniformes (la somme de ses coefficients est nulle), et une grande valeur là où l'intensité change brusquement.
La complexité d'une convolution est en
Exercices
Exercice 1
Écrire une fonction negatif(image) qui renvoie le négatif de l'image : chaque pixel
Loading editor...
def negatif(image):
return [[255 - p for p in ligne] for ligne in image]Exercice 2
Écrire une fonction symetrie_verticale(image) qui renvoie l'image retournée "la tête en bas" (symétrie par rapport à l'axe horizontal).
Loading editor...
def symetrie_verticale(image):
h = len(image)
return [image[h - 1 - y][:] for y in range(h)]Exercice 3
Écrire une fonction seuillage(image, s) qui renvoie une image en noir et blanc : les pixels de valeur au moins s deviennent blancs (255), les autres noirs (0).
Loading editor...
def seuillage(image, s):
return [[255 if p >= s else 0 for p in ligne] for ligne in image]