Corrigé
informatique
Traitement d’image
1.
Représentation d’une image en Python
Question 1. Pour cette première question, je choisis de créer trois images cides de dimensions identiques à l’image source, puis à recopier dans chacune des trois l’une des trois composantes couleur de l’image. Ceci conduit au script :
img_rouge = np.zeros_like(img) img_vert = np.zeros_like(img) img_bleu = np.zeros_like(img) n, p = img.shape[:2] for i in range(n): for j in range(p): img_rouge[i, j, 0] = img[i, j, 0] img_vert[i, j, 1] = img[i, j, 1] img_bleu[i, j, 2] = img[i, j, 2]
Il reste à les visualiser :
plt.imshow(img_rouge) plt.imshow(img_vert) plt.imshow(img_bleu)
Figure1 – Les trois composantes primaires qui composent l’image test.
Lorsqu’elles sont appliquées à des tableaux de typenumpy.array, les fonctions prédéfinies agissent de manière vectorielle ; ainsi, sit1ett2sont deux tableaux de mêmes dimensions,t1 + t2est le tableau obtenu en additionnant chacune des cases de mêmes indices (l’addition matricielle, donc). Pour visualiser l’image obtenue en ne gardant que deux des trois composantes de couleur, il suffit donc d’additionner deux des trois images obtenues ci-dessus :
plt.imshow(img_vert + img_bleu) plt.imshow(img_bleu + img_rouge) plt.imshow(img_rouge + img_vert)
Comme cela était prévisible, on obtient des images dont les teintes majoritaires sont les couleurs complémentaires en synthèse additive des couleurs primaires : le cyan, le magenta et le jaune.
Enfin, la multiplication d’un tableau par un scalaire est aussi une opération vectorielle en Python, ce qui permet de visualiser simplement une image dans laquelle chaque composante de couleur a été divisée par 2 :
Figure2 – L’addition de deux des trois composantes primaires.
plt.imshow(img // 2)
Figure3 – La diminuation de 50% de chacune des trois composantes.
La luminance de chacune des trois composantes de couleur a été diminuée de 50%, ce qui produit une image moins lumineuse.
Transformations élémentaires
Question 2. Il s’agit ici de remplacer chaque composante de couleur c par sa valeur complémentaire 255 − c. On peut utiliser l’addition vectorielle pour agir sur les trois composantes de chaque pixel en une fois :
def negatif(im): n, p = im.shape[:2] im_neg = np.zeros_like(im) for i in range(n): for j in range(p): im_neg[i, j] = [255, 255, 255] − im[i, j] return im_neg
Remarque. Bien que cela n’ait aucun sens mathématique, Python permet l’addition d’un scalaire et d’une matrice : dans ce cas chacune des composantes de la matrice est additionnée avec ce scalaire. Cela permet d’écrire plus simplement la fonction demandée :
def negatif(im): return 255 − im
Question 3. Si p désigne le nombre de colonnes de la matrice, le point symétrique du point de coordonnées (i, j) est celui de coordonnées (i, p − 1 − j). D’où la fonction :
def symetrie(im): n, p = im.shape[:2] im_sym = np.zeros_like(im) for i in range(n): for j in range(p): im_sym[i, j] = im[i, p−1−j] return im_sym page 2
Question 4. La fonction qui suit tient compte du fait que l’image passée en argument peut ne pas être carrée.
def rotation(im):
n, p, s = im.shape
im_rot = np.zeros((n, p, s), dtype=np.uint8)
for i in range(n):
for j in range(p):
im_rot[p−1−j, i] = im[i, j]
return im_rot
Figure4 – Le résultat des quatre fonctions demandées sur l’image test.
Conversion en niveau de gris
Question 5. Je choisis de définir tout d’abord une fonction qui calcule la luminance d’un pixel.
def luminance(p):
return np.round(0.2126*p[0] + 0.7152*p[1] + 0.0722*p[2])
Il faut ensuite créer une image bi-dimensionnelle (puisqu’il n’y a plus qu’une seule composante de luminance) et la remplir :
def niveaudegris(im):
n, p = im.shape[:2]
im_lum = np.zeros((n, p), dtype=np.uint8)
for i in range(n):
for j in range(p):
im_lum[i, j] = luminance(im[i, j])
return im_lum
On visualise le résultat sur l’image test en choisissant la bonne échelle de couleur :
img_lum = niveaudegris(img) plt.imshow(img_lum, cmap='gray')
2.
Traitement d’image
Question 6. Dans un premier temps, je calcule pour chaque pixel le vecteur s dont les composantes sont les valeurs m∗ij de chacune des trois couches de couleur. Dans un deuxième temps je remplace chaque valeur qui dépasse 255 par 255 et chaque valeur en deçà de 0 par 0. Enfin, cette valeur est stockée dans la matrice M ⊗ C.
def convolution(m, c): n, p, q = m.shape mc = np.zeros_like(m) for i in range(1, n−1): for j in range(1, p−1): s = 0 for u in range(3):
for v in range(3): s += c[u, v] * m[i−1+u, j−1+v] for k in range(q): if s[k] < 0: mc[i, j, k] = 0 elif s[k] > 255: mc[i, j, k] = 255 else: mc[i, j, k] = s[k] return mc Question 7. def lissage(im):
c = 1/9 * np.ones((3, 3), dtype=float)
return convolution(im, c) def contraste(im):
c = np.array([[0, −1, 0], [−1, 5, −1], [0, −1, 0]], dtype=float)
return convolution(im, c) def repoussage(im):
c = np.array([[−2, −1, 0], [−1, 1, 1], [0, 1, 2]], dtype=float)
return convolution(im, c)
Figure5 – Le résultat des trois filtres définis ci-dessus sur l’image test.
3.
Stéganographie d’une image
Les fonctions >>et<<sont des fonctions vectorielles (comme la plupart des fonctions redéfinies parnumpy), ce qui permet de les appliquer à des tableaux de typenumpy.array: dans ce cas, cette même fonction s’applique à chacune des composantes du tableau. Cette fonctionnalité rend très simples les deux fonctions d’encodage et de décodage :
Question 8. def encodage(a, b): return ((a >> 4) << 4) + (b >> 4) Question 9. def decodage(c): return (c << 4) page 4