On charge la photo Plage.png
sous forme de matrice (variable appelée Photo
) puis on l’affiche à l’aide
de Python.
# Cellule à exécuter :
# Import des modules :
from matplotlib.pyplot import *
import matplotlib.image as mpimg
import numpy as np
# Import de l'image :
Photo = mpimg.imread('Plage.png')
# Affichage :
imshow(Photo)
show()
Une image est codée par une matrice à trois dimensions : le nombre de lignes, de colonnes, et la profondeur, de longueur 3.
La profondeur de chaque case contient trois réels codant une couleur sous le format RGB (rouge, vert, bleu).
Le
poids pour chaque couleur est compris entre 0 et 1 ((0,0,0) pour le noir jusqu'à (1,1,1) pour le
blanc poiur le format .png
) ou c’est un entier entre 0 et 255 (formats .bmp
et .jpg
).
La matrice est un tableau numpy
donc on accède à l’élément d’indices i
, j
et k
avec la syntaxe Photo[i,j,k]
(pour rappel avec des listes de listes la syntaxe serait Photo[i][j][k]
). On pourra
utiliser la technique du slicing vue dans les précédents TPs.
On récupère la taille de cette matrice avec la méthode shape
du module numpy
. On notera m
et n
le nombre de lignes
et de colonnes :
# Cellule à exécuter :
m, n = Photo.shape[:2]
print(m, n)
Q1. Tester et comprendre l’instruction suivante :
# Cellule à exécuter
imshow(Photo[600:,:1000,:])
# Cellule pour répondre :
Q2. Tester et comprendre les instructions suivantes :
# Cellule à exécuter
# liste de listes définie par compréhension qu'on transforme en tableau numpy avec np.array
Photo2 = np.array([ [ [ 0. for k in range(3)] for j in range(n) ] for i in range(m) ])
# ou Photo2 = zeros([m, n, 3]) avec le module numpy (hors-programme en PC)
for k in range(3) :
Photo2[:, :, k] = ( Photo[:, :, 0] + Photo[:, :, 1] + Photo[:, :, 2] ) / 3
imshow(Photo2)
# Cellule pour répondre
Q3. Tester et comprendre les instructions suivantes :
# Cellule à exécuter :
for i in range(m) :
for j in range(n) :
Photo[i,j,1]=0
Photo[i,j,2]=0
imshow(Photo)
# Cellule pour répondre :
Nous allons chercher à obtenir un effet miroir, une rotation et la détection des contours
de la photo Plage.png
.
Q4. Proposer un algorithme permettant de réaliser un effet miroir et le tester. On pourra compléter l’algorithme suivant :
# Cellule à compléter
def symetrie(matB):
nb_lig, nb_col, nb_coul = matB.shape # nb_coul=3
# nouvelle image
matC = np.array([ [ [ 0. for k in range(nb_coul)] for j in range(nb_col) ] for i in range(nb_lig) ])
for i in range(nb_lig) :
for j in range(nb_col) :
for k in range(nb_coul):
??????????????
return matC
# Cellule pour tester
Photo = mpimg.imread('Plage.png')
Photo_miroir = symetrie(Photo)
imshow(Photo_miroir)
Q5. Sur le même modèle, proposer un algorithme permettant d’effectuer une rotation de $\pi/2$
de la photo Plage.png
.
# Cellule à compléter
def rotation(matB) :
# Cellule pour tester
Photo_rotation = rotation(Photo)
imshow(Photo_rotation)
La reconnaissance de formes dans une image est une composante importante de l’analyse d’images. Elle se décompose en plusieurs étapes qui consistent à extraire les contours des objets dans l’image afin de les reconnaitre ou d’en détecter le mouvement. La première de ces étapes est la mise en évidence des contours des objets dans l’image. C’est cette étape que nous allons aborder très succinctement.
Un contour définit la limite d’un objet dans une image. Cette limite est caractérisée par un changement dans l’image : un changement de couleur ou de contraste. Ce changement se traduit dans la valeur des pixels qui sont localisés de part et d’autre de la limite. Nous sommes donc à la recherche d’un moyen de détecter et de localiser un changement.
Considérons un pixel p(i,j)
dans une image couleur (type list
ou type array
avec les 3 valeurs
R, G, B). Il s’agit ensuite de mesurer la différence, une distance, entre notre pixel
de référence et ses voisins en utilisant une fonction de norme standard. On se propose d’utiliser
la fonction suivante :
norme = ( distance(p1, p3) )**2 + ( distance(p2, p4) )**2
où on a posé p1 = p(i − 2, j)
, p2 = p(i, j − 2)
, p3 = p(i + 2, j)
et p4 = p(i, j + 2)
(ce sont des "voisins" de p(i,j)
).
On donne la
fonction distance
:
# Cellule à exécuter :
def distance(L1, L2) :
d = 0
for i in range( len(L1) ) :
d = d + ( L1[i] - L2[i] )**2
return np.sqrt(d)
Si cette norme est "grande", c’est-à-dire au-delà d’un certain seuil (que l’on fixera à 1
pour commencer),
cela signifie que le pixel est sur un contour, on l’affiche en noir.
Si cette norme est "petite", c’est-à-dire en deça du seuil, cela signifie qu’il n’y a pas de rupture de couleur. Le pixel n’est donc pas sur un contour, on l’affiche en blanc.
Q6. Créer une fonction DetectionContour
qui prend en argument la photo dont on souhaite
délimiter le contour et un seuil, et qui renvoie une photo faisant apparaître seulement les contours.
# Cellule à compléter :
def DetectionContour(matB, seuil) :
Q7. Tester sur l’image Plage.png
. Faire varier la valeur de seuil et observer les différences.
# Cellule pour tester :
Photo = mpimg.imread('Plage.png')
Photo_contour = DetectionContour(Photo, 1)
imshow(Photo_contour)
Dans cette partie, nous nous intéressons à la mise en place d’un floutage d’une image.
Pour réaliser un floutage par moyenne simple sur la matrice de pixels, il faut lui appliquer un filtre, que l’on appelle également un masque. Afin de bien comprendre ce principe, nous proposons d’étudier un exemple de filtrage.
On considère les matrices :
$$A=\left(\begin{array}{ccc}1/9&1/9&1/9\\ 1/9&1/9&1/9\\ 1/9&1/9&1/9\end{array}\right)$$
et:
$$B=\left(\begin{array}{cccccc}5&6&7&8&9&10\\ -5&-6&-7&-8&-9&-10\\ 1&1&1&1&1&1\\ 2&2&3&3&4&4\\ 0&0&1&3&3&3\end{array}\right)$$
Pour chaque élément $b_{i,j}$ de $B$ qui n'est pas en bordure, on considère la matrice $3\times 3$ $B_{i,j}$ qui l’entoure, on calcule
le produit de convolution de $A$ par $B_{i,j}$ (multiplication coefficient par coefficient $\neq$ produit matriciel) et
on note $c_{i,j}$ la somme des coefficients de la matrice produit obtenue (on pourra utiliser la
fonction np.sum
du module numpy
sur une liste).
Si $b_{i,j}$ est un élément en bordure de $B$, on posera $c_{i,j} = b_{i,j}$.
On forme ainsi une nouvelle matrice $C$ de même taille que $B$ dont les éléments intérieurs sont les $c_{i,j}$ et les éléments au bord sont les $b_{i,j}$.
On dit qu’on a filtré la matrice $B$ par la matrice $A$, ou qu’on a appliqué le masque (filtre) $A$ sur l’image $B$.
Q8. Créer la fonction filtrer1(filtreA, matB)
qui prend en argument une matrice carrée
filtreA
de dimension taille*taille
(taille
est un entier impair = 3) et une matrice quelconque matB
de dimensions supérieures, et qui renvoie la matrice C
. On remarquera que
si taille > 3
, la bordure devra être plus épaisse.
Le produit de convolution ( = coefficient par coefficient ) de deux matrices numpy
M
et N
est obtenu avec M*N
.
# Cellule à compléter :
def filtrer1(filtreA, matB) :
# Cellule pour tester :
A = np.array( [ [1./9., 1./9., 1./9.], [1./9., 1./9., 1./9.], [1./9., 1./9., 1./9.] ] )
B = np.array( [ [5., 6., 7., 8., 9., 10.],\
[-5., -6., -7., -8., -9., -10.],\
[1., 1., 1., 1., 1., 1.],\
[2., 2., 3., 3., 4., 4.],\
[0., 0., 1., 3., 3., 3.] ] )
C = filtrer1(A, B)
D = np.array( [[ 5., 6., 7., 8., 9., 10. ], [ -5., 1/3, 0.33333333, 0.33333333, 0.33333333, -10. ], \
[ 1., -0.88888889, -1.11111111, -1.22222222, -1.44444444, 1. ], \
[ 2., 1.22222222, 1.66666667, 2.22222222, 2.55555556, 4. ], \
[ 0., 0., 1., 3., 3., 3. ]] )
print(np.abs(C - D) <= 10**(-8) ) # on peut pas tester l'égalité entre 2 flottants
On souhaite maintenant appliquer le filtre A
à une matrice de pixels B
, c’est à dire aux
3 tableaux B[:, :, 0]
, B[:, :, 1]
, B[:, :, 2]
et enregistrer le résultat dans une matrice C
de
même format que B
.
Q9. Créer une fonction filtrer(filtreA, matB)
qui prend en argument une matrice carrée
filtreA
de dimension taille*taille
et un tableau numpy
matB
de dimensions n × p × 3
, et
qui renvoie le tableau C
de dimensions identiques.
Vous pourrez calculer successivement C[:, :, 0]
, C[:, :, 1]
, C[ :, :, 2]
à l’aide d’une boucle.
Tester sur l’image Plage.png
.
# Cellule à compléter
def filtrer(filtreA, matB) :
# Cellule pour tester
Photo = mpimg.imread('Plage.png')
imshow(Photo)
# Cellule pour tester :
A = (1/(11.**2))*np.array([[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.],\
[1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.]])
C = filtrer(A, Photo)
imshow(C)
Le but de cet exercice est d’incorporer votre portrait à l’image Plage.png
.
Vous devez donc vous prendre en photo devant le tableau vert de votre salle de cours. Il s'agit ensuite de supprimer le décor, c’est-à-dire le tableau de la classe.
Q10. Récupérer votre photo au format .png
sous Python, l’afficher, stocker sa taille (m2 , n2)
.
Q11. Créer une fonction tableau
qui reçoit un triplet de flottants (r, g, b)
et décide (en renvoyant True
ou False
) si ce triplet désigne la couleur du tableau. On admet, bien que ce
soit perfectible, que le triplet (r, g, b)
doit être supprimé si les conditions suivantes sont
vérifiées :
$$\begin{array}{ccc}0.11\leq r \leq0.80&0.20\leq g\leq0.85&0.13\leq r\leq 0.80\\
-0.03\leq g-b \leq0.14&-0.09\leq b-r\leq0.10&-0.17\leq r-g\leq 0.01\end{array}$$
On pourra tester cette fonction en remplaçant les pixels représentant le tableau sur le
portrait par des pixels noirs.
En jouant sur les conditions on peut améliorer le résultat.
Q12. Remplacer les pixels de la matrice Photo
de la plage par les pixels de votre portrait, à
l’endroit de votre choix, en omettant ceux qui représentent le tableau.
Afficher le résultat.