( Python )
Répondez aux questions et envoyez à votre classe room le fichier
ayant comme nom le format suivant
- TDP_07_Python_NOM_PRENOM.ipynb
</ul>
Nom Prénom :
CHOUBIK Houssam
Détection d’anomalies visuelles dans des captures d’écran. Avant d’appliquer un modèle, vous devez normaliser, éclaircir, et transformer les matrices d’images à l’aide du broadcasting NumPy.
- Données simulées
Voici un exemple de simulation d'une image en niveaux de gris (valeurs de 0 à 255).
Chaque cellule représente un pixel.
import numpy as np
# Image 4x4 simulée (niveau de gris)
image = np.array([
[ 50, 80, 120, 200],
[ 30, 60, 110, 180],
[ 20, 40, 100, 160],
[ 10, 30, 90, 150]
], dtype=np.uint8)
print("Image originale :\n", image)
Image originale : [[ 50 80 120 200] [ 30 60 110 180] [ 20 40 100 160] [ 10 30 90 150]]
Question 1 : Normalisation des intensité
L’objectif est de ramener les valeurs entre 0 et 1.
- Générer aléatoirement une matrice de taille (1_050 , 1_000) à valeur entre 0 et 255.
import numpy as np
img=np.random.randint(0,256,(1_050,1_000),dtype=np.uint8)
print(img)
[[150 26 102 ... 95 94 17] [ 58 81 37 ... 139 132 91] [171 235 80 ... 51 208 8] ... [152 209 94 ... 124 62 246] [ 37 242 9 ... 47 149 210] [227 210 200 ... 76 23 158]]
- Récupérer les valeurs min et max de toute la matrice image.
min_img = np.min(img)
max_img = np.max(img)
print("Le min : ", min_img)
print("Le max : ", max_img)
Le min : 0 Le max : 255
-
Faire un parcours via les boucles for pour réaliser la formule suivante à chaque pixel:
ValPix =( ValPix - minImg )/( maxImg - minImg) -
Calculer le temps écoulé
import time as t
img_normalise = np.zeros_like(img, dtype=float)
debut=t.time()
for i in range(img.shape[0]):
for j in range(img.shape[1]):
valPix=img[i,j]
img_normalise[i,j]=(valPix - min_img) / (max_img - min_img)
fin=t.time()
temps=fin-debut
print(img_normalise.min(), img_normalise.max())
print(img_normalise)
print(f"Temps : {temps:.4f} secondes")
0.0 1.0 [[0.58823529 0.10196078 0.4 ... 0.37254902 0.36862745 0.06666667] [0.22745098 0.31764706 0.14509804 ... 0.54509804 0.51764706 0.35686275] [0.67058824 0.92156863 0.31372549 ... 0.2 0.81568627 0.03137255] ... [0.59607843 0.81960784 0.36862745 ... 0.48627451 0.24313725 0.96470588] [0.14509804 0.94901961 0.03529412 ... 0.18431373 0.58431373 0.82352941] [0.89019608 0.82352941 0.78431373 ... 0.29803922 0.09019608 0.61960784]] Temps : 1.2478 secondes
- Refaire la meme tache en utilisant le Broadcasting : Ici, le broadcasting agit entre la matrice image et des scalaires (min, max).
- comparer les temps d'execution tout en vérifiant l'égalité des résultats obtenus
debut=t.time()
img_broadcasting=(img - min_img) / (max_img - min_img)
fin=t.time()
temps_boradcasting=fin-debut
print(img_broadcasting)
print(f"Temps : {temps_boradcasting:.4f} secondes")
[[0.58823529 0.10196078 0.4 ... 0.37254902 0.36862745 0.06666667] [0.22745098 0.31764706 0.14509804 ... 0.54509804 0.51764706 0.35686275] [0.67058824 0.92156863 0.31372549 ... 0.2 0.81568627 0.03137255] ... [0.59607843 0.81960784 0.36862745 ... 0.48627451 0.24313725 0.96470588] [0.14509804 0.94901961 0.03529412 ... 0.18431373 0.58431373 0.82352941] [0.89019608 0.82352941 0.78431373 ... 0.29803922 0.09019608 0.61960784]] Temps : 0.0040 secondes
if(np.array_equal(img_normalise,img_broadcasting)):
print("egale")
else :
print("non egale")
if(temps<temps_boradcasting):
print("La première méthode en utilisant les boucles est optimale")
else:
print("La deuxième méthode en utilisant le broadcasting est optimale")
egale La deuxième méthode en utilisant le broadcasting est optimale
Question 2 : Correction d’éclairage (broadcasting par ligne)
Supposons que chaque ligne de l’image ait une lumière différente.
Vous devez compenser cela en ajoutant un facteur de luminosité à chaque ligne.
- Générer un vecteur aléatoire qui fait le rôle du vecteur de correction
- les valeurs de ce vecteur sont entre -25 et 25
- N.B : Ce vecteur doit être appliqué à la matrice initiale
import numpy as np
import time
hauteur = 1000
largeur = 1000
image = np.random.randint(0, 256, (hauteur, largeur), dtype=np.uint8)
correction = np.random.randint(-25, 26, hauteur, dtype=np.int16)
- Faire la correction en ajoutant la valeur du vecteur de correction à chaque pixel des lignes de l'image:
- En utilisant un parcours par pixel
- En utilsant un parcours ligne / ligne
- En utisant le broadcasting sur toute la matrice
- Comparer les résultats et les temps d'executions
image_corr_pixel = image.copy().astype(np.int16)
start = time.time()
for i in range(hauteur):
for j in range(largeur):
image_corr_pixel[i, j] += correction[i]
end = time.time()
temps_pixel = end - start
print(f"Temps parcours pixel par pixel : {temps_pixel:.4f} secondes")
Temps parcours pixel par pixel : 1.1625 secondes
image_corr_ligne = image.copy().astype(np.int16)
start = time.time()
for i in range(hauteur):
image_corr_ligne[i, :] += correction[i]
end = time.time()
temps_ligne = end - start
print(f"Temps parcours ligne par ligne : {temps_ligne:.4f} secondes")
Temps parcours ligne par ligne : 0.0054 secondes
image_corr_broadcast = image.copy().astype(np.int16)
start = time.time()
image_corr_broadcast += correction[:, np.newaxis]
end = time.time()
temps_broadcast = end - start
print(f"Temps broadcasting : {temps_broadcast:.4f} secondes")
Temps broadcasting : 0.0022 secondes
print("Pixel == Ligne :", np.array_equal(image_corr_pixel, image_corr_ligne))
print("Pixel == Broadcast :", np.array_equal(image_corr_pixel, image_corr_broadcast))
Pixel == Ligne : True Pixel == Broadcast : True
Vérification du débordement :
- Vérifier qu'il n'y a pas débordement dans les valeurs de l'images 0 ≤ ValPix ≤ 255 , dans le cas contraire (débordement) remettre les valeurs négatives à 0 et les valeurs supérieures à 255 à la valeur maximale 255:
- En utilisant un parcours pixel / pixel
- En utilsant le filtrage booléen
- Vérifier l'égalité des résultats
image_pixel = image_corr_broadcast.copy()
hauteur, largeur = image_pixel.shape
for i in range(hauteur):
for j in range(largeur):
if image_pixel[i, j] < 0:
image_pixel[i, j] = 0
elif image_pixel[i, j] > 255:
image_pixel[i, j] = 255
image_bool = image_corr_broadcast.copy()
image_bool[image_bool < 0] = 0
image_bool[image_bool > 255] = 255
egal = np.array_equal(image_pixel, image_bool)
print("Les deux méthodes donnent le même résultat :", egal)
Les deux méthodes donnent le même résultat : True
Question 3 : Broadcasting pour correction couleur (application à 3 canaux RGB)
Vous allez manipuler une imagette couleur 3D simulée (imgRGB).
- Générer aléatoirment la variable imgRGB contenant 3 matrices d'images, chaune de dimension (7,7), la première représente la composante R (canal Rouge), la deuxieme G (canal Vert) et la troisième B (canal Bleu).
# print(imgRGB.shape) doit afficher : (7, 7, 3)
import numpy as np
hauteur = 7
largeur = 7
canaux = 3
imgRGB = np.random.randint(0, 256, (hauteur, largeur, canaux), dtype=np.uint8)
print("Shape de l'image RGB :", imgRGB.shape)
Shape de l'image RGB : (7, 7, 3)
- l'objectif est de réduire l’intensité du canal rouge et renforcer le bleu, en multipliant les valeurs des matrices-canaux R,G,B par le facteur de correction :
- Facteur de correction pour canal R : 0.8
- Facteur de correction pour canal B : 1.1
- N.B :
- Il faut que les valeurs des matrices images restent entières
- Vérifier et corriger un éventuel débordement pour le canal B
img_corr = imgRGB.astype(np.int16)
facteur_R = 0.8
facteur_B = 1.1
img_corr[:, :, 0] = (img_corr[:, :, 0] * facteur_R).astype(int)
img_corr[:, :, 2] = (img_corr[:, :, 2] * facteur_B).astype(int)
img_corr[:, :, 2][img_corr[:, :, 2] > 255] = 255
img_corr[:, :, 2][img_corr[:, :, 2] < 0] = 0
img_corr = img_corr.astype(np.uint8)
print("Canal R avant / après :", imgRGB[0, :4, 0], img_corr[0, :4, 0])
print("Canal B avant / après :", imgRGB[0, :4, 2], img_corr[0, :4, 2])
Canal R avant / après : [ 60 111 3 19] [48 88 2 15] Canal B avant / après : [ 74 18 182 208] [ 81 19 200 228]
Question 4: Format du broadcasting
Vous travaillez sur un système IoT qui collecte des mesures de température depuis plusieurs capteurs installés dans différentes zones d’un bâtiment.
Chaque ligne de votre matrice représente une zone, et chaque colonne un capteur.
import numpy as np
# Températures (en °C)
# Lignes = zones ; colonnes = capteurs
T = np.array([
[20.5, 21.0, 20.8],
[19.5, 19.8, 20.1],
[22.0, 22.5, 22.1],
])
print("Matrice T :\n", T)
print("Shape :", T.shape)
Matrice T : [[20.5 21. 20.8] [19.5 19.8 20.1] [22. 22.5 22.1]] Shape : (3, 3)
- Pour corriger les mesures, vous devez soustraire un biais de calibration propre à chaque capteur.
# Biais par capteur (colonne)
biais = np.array([+0.5, -0.2, +0.1]) # (3,)
print(biais.shape)
(3,)
- Corriger correctement les valeurs mesurées à l’aide du broadcasting, puis afficher les nouvelles mesures
# Correction par broadcasting
T_corrigee = T - biais
print("Matrice corrigée :\n", T_corrigee)
# Matrice corrigée :
# [[20. 21.2 20.7]
# [19. 20. 20. ]
# [21.5 22.7 22. ]]
Matrice corrigée : [[20. 21.2 20.7] [19. 20. 20. ] [21.5 22.7 22. ]]
- En supposant que vous avez reçu le vecteur AutreBiais au lieu du vecteur biais:
- Corriger les valeurs mesurées à l’aide du broadcasting via AutreBiais, puis afficher les nouvelles mesures
AutreBiais = biais.reshape(3,1)
print("Shape de AutreBiais :", AutreBiais.shape)
Shape de AutreBiais : (3, 1)
# AutreBiais a la forme (3, 1) : T - AutreBiais retirerait le biais par ligne (zone) et non par capteur.
# Il faut le remettre en (1, 3) pour qu'il s'applique sur les colonnes.
T_corrigee2 = T - AutreBiais.reshape(1, 3)
print(T_corrigee2)
print("Même résultat :", np.array_equal(T_corrigee, T_corrigee2))
[[20. 21.2 20.7] [19. 20. 20. ] [21.5 22.7 22. ]] Même résultat : True
- Remarques et conclusions
- Le broadcasting donne le même résultat que les boucles, en étant des centaines de fois plus rapide.
- Il faut faire attention à la forme : un vecteur
(3,)ou(1, 3)s'applique sur les colonnes, un vecteur(3, 1)s'applique sur les lignes.