Dans cette partie du TP, les fonctions OpenCV utilisées/utilisables sont les suivantes :
Un histogramme sera représenté en mémoire avec un tableau nd de numpy de 255 lignes et 1 colonne. Il contiendra des float :
histogramme = np.zeros((256,1),np.float32)
Pour afficher un histogramme, vous utiliserez le module pyplot du package matplotlib
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread('...')
histogramme = np.zeros((256,1),np.float32)
# ...
cv2.imshow('image',image)
plt.figure()
plt.title("Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(histogramme)
plt.xlim([0, 255])
plt.show(block=False)
cv2.waitKey(0)
plt.close('all')
cv2.destroyAllWindows()
En cas de souci avec Matplotlib dans les salles de Tps, voici une fonction permettant de dessiner un histogramme dans une image OpenCV :
import cv2
import numpy as np
def plotHistogramImage(hist, nbins, color, width, height, result = None):
if result is None:
result = np.zeros((height, width, 3))
norm_hist = hist * ((height-10) / np.max(hist))
norm_hist = norm_hist.astype(int)
for i in range(1,nbins):
x1 = int((i-1) * width / nbins)
x2 = int((i) * width / nbins)
cv2.line(result, (x1, height - norm_hist[i-1][0]-5), (x2, height - norm_hist[i][0]-5), color)
return result
image = cv2.imread('...')
histogramme = np.zeros((256,1),np.float32)
cv2.imshow('image',image)
cv2.imshow('histogramme',plotHistogramImage(histogramme,256,(255,0,0),600,300))
cv2.waitKey(0)
Cette fonction renvoie en résultat une image noire avec le dessin de l'histogramme. Elle prend en argument :
Afin de vous familiariser avec les parcours d'images, les fonctions suivantes seront à faire sans utiliser la bibliothèque OpenCV.
Chaque fonction devra être testée en affichant l'image originale et l'histogramme correspondant.
Question 1 : Utiliser la fonction cv2.calcHist pour calculer l'histogramme d'une image en niveaux de gris passée en argument. L'histogramme sera calculé pour l'ensemble des valeurs possibles (de 0 à 255).
Question 2 : Utiliser la fonction cv2.normalize afin appliquer l'algorithme d'étalement d'histogrmme vu en cours.
Question 3 : Afficher les histogramme de l'image avant et après la normalisation.
Question 1 : Ecrire la fonction histogrammeCumule permettant, à partir d'un histogramme passé en argument, de calculer l'histogramme cumulé.
Question 2 : Ecrire la fonction histogrammeNormalise permettant, à partir d'un histogramme (normal ou cumulé) et des dimensions de l'image, de calculer l'histogramme normalisé.
Question 3 : Utiliser la fonction cv2.equalizeHist afin d'appliquer l'algorithme d'égalisation d'histogrmme vu en cours.
Question 4 : Afficher les histogrammes de l'image avant et après l'éqalisation. Obtient-on un histogramme plat ?
Question 5 : Afficher les histogrammes cumulés normalisés de l'image avant et après l'éqalisation. Obtient-on un histogramme linéaire ?
L'objectif de cet exercice est d'appliquer une transformation aux luminances d'une image. Cette transformation est appelée correction gamma et se modélise de la façon suivante :
Icorr = 255 * (Iinit / 255) ^ (1 / gamma)
Question 1 : En utilisant la fonction cv2.equalizeHist, écrire la fonction egalisationLuminance qui, sur l'image couleur passée en argument, va égaliser les luminances de cette image. Le résultat sera donnée dans une nouvelle image.
Question 2 : Ecrire une fonction correctionGamma(image,gamma) réalisant la correction gamma des luminances d'une image couleur passée en argument. Cette fonction devra renvoyer l'image corrigée en résultat.
La mise en oeuvre naïve consiste à faire une double boucle de parcours de l'image pour modifier les luminances. Dans le cas de cet algorithme une valeur de luminance Iinit est toujours remplacée par une même valeur Icorr.
Dans ce cas, il est possible de construire un tableau de correspondance associant Iinit à Icorr. Ce tableau contiendra, dans la case d'incide Iinit la valeur Icorr. Une fois ce tableau construit pour toutes les valeurs possibles de Iinit, il suffit d'utiliser la fonction cv2.LUT qui s'occupera de faire la conversion de toutes les valeurs.
Question 3 : Utiliser la fonction mse (tp intro) pour comparer les deux images obtenues.
Votre programme devra permettre de modifier le coefficient gamma à l'aide d'un slider OpenCV.
Dans cette partie du TP, les fonctions OpenCV utilisées/utilisables sont les suivantes :
Afin de pouvoir tester les fonctions de filtrages, voici quelques fonctions permettant d'ajouter du "bruit" à une image selon différentes méthodes.
def bruitGaussien(image,moyenne,variance):
if len(image.shape)==3:
row,col,ch= image.shape
sigma = variance**0.5
gauss = np.random.normal(moyenne,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy = image + gauss
return noisy.astype(np.uint8)
else:
row,col= image.shape
sigma = variance**0.5
gauss = np.random.normal(moyenne,sigma,(row,col))
print(np.min(gauss),np.max(gauss))
gauss = gauss.reshape(row,col)
noisy = image + gauss
return noisy.astype(np.uint8)
def bruitPoivreEtSel(image,prob):
row= image.shape[0]
col = image.shape[1]
out = image.copy()
if len(image.shape) == 2:
black = 0
white = 255
else:
colorspace = image.shape[2]
if colorspace == 3: # RGB
black = np.array([0, 0, 0], dtype='uint8')
white = np.array([255, 255, 255], dtype='uint8')
else: # RGBA
black = np.array([0, 0, 0, 255], dtype='uint8')
white = np.array([255, 255, 255, 255], dtype='uint8')
probs = np.random.random(out.shape[:2])
# Pepper mode
out[probs < (prob / 2)] = black
# Salt mode
out[probs > 1 - (prob / 2)] = white
return out.astype(np.uint8)
def bruitPoisson(image):
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
noisy = np.random.poisson(image * vals) / float(vals)
return noisy.astype(np.uint8)
def bruitSpeckle(image):
gauss = np.random.normal(0,1,image.size)
if len(image.shape)==3:
row,col,ch = image.shape
gauss = gauss.reshape(row,col,ch).astype(np.uint8)
noisy = image + image * gauss
return noisy.astype(np.uint8)
else:
row,col = image.shape
gauss = gauss.reshape(row,col).astype(np.uint8)
noisy = image + image * gauss
return noisy.astype(np.uint8)
Ecrire un programme permettant de comparer le floutage d'une image en utilisant les 3 méthodes : cv2.blur, cv2.GaussianBlur et cv2.medianBlur.
Vous devrez, dans un premier temps, ajouter du bruit à une image préalablement chargée.
Votre programme devra permettre de modifier la taille du noyau de filtrage grace à un slider (la même taille de noyau sera utilisée pour les 3 filtres).
Pour comparer les résultats, utiliser la fonction mse donnée en fin du tp d'introduction.
Les 3 fonctions utilisées précédemment permettent d'utiliser des filtres usuels de taille carrée (ou rectangulaire).
Il est possible d'appliquer des filtres de taille et de forme non usuelles. Pour cela, on utilise la fonction cv2.getStructuringElement. Cette fonction va renvoyer une matrice 2d dont les éléments inclus dans la forme définie par le paramètre shape sont initialisés à 1 alors que les autres seront à 0.
Le noyau de filtrage ainsi obtenu peut être appliqué à une image en utilisant la fonction cv2.filter2D.
Utiliser ces fonction pour appliquer un filtre moyen en croix de taille 5x5 sur une image. Comparer les résultats avec ceux obtenus par un filtrage moyen de même taille en utilisant la fonction cv2.blur.
Dans cette partie du TP, les fonctions OpenCV utilisées/utilisables sont les suivantes :
Ecrire un programme permettant de binariser une image en niveaux de gris en utilisant la fonction cv2.threshold.
Le seuil de binarisation devra être paramétrable grace à un slider.
Tester les différentes valeurs possibles du paramètre type de cette fonction.
Dans l'exercice précédent, la binarisation de l'image se fait à pratir d'une unique valeur de luminance.
Une autre méthode de binarisation permettant plus facilement de dissocier un objet de son environnement consiste à analyser la répartition des couleurs d'un élément (le fond ou l'objet) et de rechercher dans l'image les zones ayant à peu près la même répartition de couleur. C'est le principe général du ChromaKeying utilisé lors de captations de vidéos sur fond vert comme au cinéma.
Pour cela, il suffit de :