Un histogramme … pourquoi ?
Dans l’article précédent nous avons vu comment étaient composées nos images numériques. Ceci nous amène naturellement à aborder les histogrammes d’images. Bien sur on ne travaille pas une image comme on travaille du texte. Les images étant donc des matrices (comme des cartes de pixels finalement) nous allons les manipuler de manière ensembliste. Le premier axe de travail (et donc de retouche) est la colorimétrie.
Nous allons donc voir dans cet article comment analyser ces composantes de couleurs à travers d’histogrammes.
Chaque pixel étant donc un tuple ou plutôt une superposition de canaux de couleurs (Rouge, Vert et Bleu, soit [R, G, B]), nous allons devoir analyser cette répartition des trois couleurs primaires dans notre image.
Note : Nous allons rester sur des images codées en 24 bits (soit 2 puissance 8 = 256 valeurs possibles par canal).
Un histogramme d’image n’est ni plus ni moins qu’un graphique qui affiche :
- En abscisse (Val. dans le graphe ci-dessous) les différentes valeurs de canaux/pixel
- En ordonnée (Nb Pixel) le nombre de canaux/pixel qui possèdent cette valeur
Dans le graphe exemple ci-dessus, on a 2000 fois un pixel de valeur 100.
Vous remarquerez que je n’ai mis qu’une seule courbe. Cela signifie tout simplement que nous sommes en train de visualiser une image en niveau de gris, mais nous allons voir celà dans le paragraphe suivant.
Couleurs, Niveau de gris et Noir & Blanc
Comment distinguer alors une image en couleur d’une image en niveau de gris d’une image en noir et blanc sans regarder l’image ? Et bien c’est très simple avec les histogrammes d’images:
Une image en noir et Blanc a un histogramme très basique (binaire) qui ne comporte que des valeurs O ou 1 (pas de nuances sur 24 bits par exemple) :
Dans ce graphe (oubliez la droite svp 😉 ), on n’a de valeurs que pour 0 et 1.
Une image en niveau de gris ne possède qu’une seule courbe (celle des nuances de gris):
Si on a une image en couleur il nous faut maintenant avoir les nuances sur les trois canaux (Rouge, Vert et Bleu). On a donc 3 courbes :
Comment créer ces histogrammes avec Python ?
Avec Python il existe au moins 3 façons de créer des histogrammes d’images :
- Directement en utilisant la librairie Numpy et matplotlib (et oui n’oubliez pas que nos images ne sont que des matrices)
- Avec Scikit-Image
- En utilisant OpenCV (Recommandé car beaucoup plus rapide)
Avant de commencer il faut ouvrir (voire convertir nos images) :
Ouverture des images
Importez tout d’abord les librairies Python, comme suit :
import matplotlib.pyplot as plt from skimage.io import imread, imshow from skimage import exposure import matplotlib.pyplot as plt from skimage.color import rgb2gray import numpy as np
Ensuite il suffit de lire l’image avec la fonction imread() de skimage :
image1 = imread('railway.jpg') #, as_gray=True)
Pour lire l’image directement en niveau de gris (avec la conversion couleur -> niveau de gris) soit vous utilisez l’option as_gray=True comme suit :
image1_Gray = imread('railway.jpg', as_gray=True)
Soit vous utiliser la fonction rgb2gray() après avoir lu l’image en couleur :
image1_Gray = rgb2gray(image1)
Vous pouvez afficher l’image tout simplement avec la fonction imshow() :
imshow(image1)
Si vous voulez convertir l’image en noir et blanc, rien de plus simple. Utilisez la méthode de Numpy where qui permet de remplacer les éléments d’une matrice sous une condition. Dans l’exemple ci-dessous je remplace en 0 tous les éléments inférieurs à 128 et 1 tous les autres :
im = np.where(image1_Gray>128/256, 0, 1) imshow(im, cmap=plt.get_cmap('gray'))
Histogrammes avec scikit-image
Avec scikit-image nous utiliserons simplement la fonction histogram pour tracer ces graphes :
def imageHist(image): _, axis = plt.subplots(ncols=2, figsize=(12, 3)) if (image.ndim == 2): # Grascale Image axis[0].imshow(image, cmap=plt.get_cmap('gray')) axis[1].set_title('Histogram') axis[0].set_title('Grayscale Image') hist = exposure.histogram(image) axis[1].plot(hist[0]) else: # Color image axis[0].imshow(image, cmap='gray') axis[1].set_title('Histogram') axis[0].set_title('Colored Image') rgbcolors = ['red', 'green', 'blue'] for i, mycolor in enumerate(rgbcolors): axis[1].plot(exposure.histogram(image[...,i])[0], color=mycolor)
Dans le code ci-dessus vous remarquerez que je regarde en premier lieu le nombre de dimensions de la matrice image. Si on a 3 dimensions c’est que l’on a une image avec couleur sinon on est en niveau de gris. Dans le cas où l’on a une image avec couleur on doit empiler les canaux et donc nous aurons 3 courbes comme suit :
Histogrammes avec OpenCV
Avec OpenCV c’est tout aussi simple et c’est en plus beaucoup plus rapide en temps de traitement. Voici comment visualiser l’histogramme d’une image couleur :
def histogramOpenCV(_img): _, axis = plt.subplots(ncols=2, figsize=(12, 3)) axis[0].imshow(_img) axis[1].set_title('Histogram') axis[0].set_title('Image') rgbcolors = ['red', 'green', 'blue'] for i,col in enumerate(color): histr = cv.calcHist([_img],[i],None,[256],[0,256]) axis[1].plot(histr,color = col)
Voila nous avons vu comment analyser une image avec des histogrammes. Nous verrons dans le prochain article de la série ‘Traitement d’images » à quoi servent ces histogrammes et nous les utiliserons pour effectuer quelques techniques de base de retouche d’image.
Pingback: Traitement d'images (partie 1: L'image numérique) - datacorner par Benoit Cayla
Pingback: Traitement d'images (partie 3: Seuillage d'image) - datacorner par Benoit Cayla
Pingback: Traitement d’images (partie 4: Transformations) - datacorner par Benoit Cayla
Pingback: Traitement d’images (partie 5: Transformations morphologiques) - datacorner par Benoit Cayla
Pingback: Traitement d’images (partie 6: Filtres & Convolution) - datacorner par Benoit Cayla
Pingback: Traitement d’images (partie 7: Les Réseaux de neurones à convolution - CNN) - datacorner par Benoit Cayla
Bonjour,
Merci pour ce tuto très détaillé et complet.
Je l’ai essayé mais l’affichage de l’image (après imshow) ne se produisait pas.
Il semblerait qu’il manque l’instruction plt.show() à la fin.
Merci encore
Je viens de tester ce code:
import matplotlib.pyplot as plt
from skimage.io import imread, imshow
from skimage import exposure
import matplotlib.pyplot as plt
from skimage.color import rgb2gray
import numpy as np
image1 = imread(‘railway.jpg’) #, as_gray=True)
image1_Gray = imread(‘railway.jpg’, as_gray=True)
imshow(image1)
plt.show()
Il manque effectivement plt.show() sinon rien ne s’affiche
bonjour je suis mohamed,
j’aime la page j’aimerai recevoir les contenue actauliser.
merci.
Bonjour Mohamed, il suffit de cliquer sur le lien GitHub en haut pour accéder au notebook.