[Plan du site]
Vous êtes ici ---
> Le Site du Zéro
> Les tutoriels
> Non-Officiels
> Programmation
> Général
> Vision par Ordinateur > Notions de base et traitement d'images > Binarisation et images binaires
> Lecture du tutoriel
Binarisation et images binaires
Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
J'espère que vous êtes en forme, parce que nous attaquons une partie copieuse !
Dans ce chapitre et le prochain, nous allons apprendre ce qu'est la binarisation, à quoi ça peut servir, comment on binarise une image avec OpenCV, et les traitements que l'on applique en général sur les images binaires : les opérateurs morphologiques.
Ce n'est pas particulièrement compliqué, car les images binaires sont simples à concevoir, mais la morphologie mathématique est un principe qu'il faut bien comprendre, pour être capable de l'appliquer correctement.
Pour ce qui est de la pratique, nous allons travailler sur le même TP pendant deux chapitres, afin que vous puissiez avoir un aperçu de la binarisation avant de jouer avec les traitements morphologiques.
Définition
Une
image binaire, c'est une image qui n'a que 2 couleurs : le noir et le blanc.
On appelle
binarisation, le fait de transformer une image en image binaire.
Exemple :
Laissez-moi tout d'abord vous présenter ma charmante assistante : la jolie Lena.
Comme je vous l'ai dit dans l'introduction du chapitre 4, il s'agit d'une image communément utilisée pour tester les algorithmes de traitement d'image et de vision.
Bien !
Si je binarise Lena, un résultat possible est celui-ci :
Vous voyez, le principe est on ne peut plus limpide !
Algorithmes de binarisation
Il existe de très nombreux algorithmes de binarisation, qui varient selon la méthode employée, ou le résultat escompté.
Nous allons nous contenter de deux pour le moment, très proches l'un de l'autre : le
seuillage et le
seuillage inverse.
Le principe du seuillage est simplissime :
On choisit un seuil : c'est un niveau de gris qui va nous permettre de prendre une décision.
On parcourt l'image en niveaux de gris.
-> Si le pixel sur lequel on se trouve est plus clair que le seuil, il devient blanc.
-> Sinon, il devient noir.
Pour le seuillage inverse, c'est le contraire : si le pixel est plus clair que le seuil, il devient noir, sinon, il devient blanc.
Intérêts et avantages de la binarisation
Travailler avec des images binaires est plus simple, dans une certaine mesure, qu'avec des images en niveaux de gris, pour les raisons suivantes :
- On peut très facilement identifier des objets à condition qu'ils soient bien séparés (on appelle ça "l'analyse par composantes connexes").
- On a beaucoup moins d'information à traiter, donc les calculs sont globalement plus rapides.
- Si notre image est bien binarisée, les algorithmes sont dans l'ensemble très robustes.
Inconvénients
Evidemment, il y a un certain nombre d'inconvénients à binariser une image (sinon, ceci serait le dernier chapitre du tutoriel !

) :
- Il faut choisir un seuil correct, ce qui n'est pas toujours facile, comme vous allez le constater.
- On passe d'un espace de couleurs de dimension 255 à un nouvel espace de dimension 2 : on perd énormément d'information qui pourrait s'avérer utile !
- La plupart des algorithmes de binarisation sont très sensibles au bruit, on est souvent obligé de lisser l'image en pré-traitement.
Conclusion : binariser ou non, c'est un choix qui dépend beaucoup du type d'images que l'on traite, ainsi que du problème que l'on cherche à résoudre.
Je sais, le seuillage et les trackbars, ça n'a rien à voir

, mais si je les mets ensemble, c'est parce que je regroupe tout ce qui va nous servir pour la première partie du TP.
Seuillage d'une image en niveaux de gris
En anglais, le mot pour "seuil" est
threshold. Ainsi, la fonction de seuillage d'OpenCV est :
void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type );
Détail des paramètres
- src : l'image en niveaux de gris initiale.
- dst : l'image en niveaux de gris dans laquelle on récupère le résultat du seuillage.
- threshold : le seuil de binarisation.
- max_value : la couleur "claire" (le blanc). On mettra 255 pour une "vraie" binarisation.
- threshold_type : l'algorithme de seuillage utilisé. Dans notre cas, ce sera CV_THRESH_BINARY ou bien CV_THRESH_BINARY_INV pour un seuillage inverse
.
Utilisation des trackbars
C'est quoi une trackbar ?
Ah, oui ! C'est vrai...
Avant d'en utiliser, il faudrait peut-être que je vous explique ce que c'est

.
Une trackbar, c'est une barre qui nous permet de choisir la valeur d'un paramètre entier comme ceci :
Il suffit de faire glisser le curseur avec la souris (ou la molette) pour faire varier la valeur du paramètre concerné (ici le "Seuil").
Avec OpenCV, on peut placer des trackbars dans les fenêtres, et on a le choix entre deux méthodes pour les gérer

.
Méthode 1 : on modifie juste la valeur de l'entier
Pour cette méthode, on associe la trackbar à un entier, et par exemple, on place un petit
cvWaitKey(0) pour laisser le temps à l'utilisateur de fixer son paramètre.
Quand il appuiera sur une touche, on pourra continuer nos traitements et la valeur de l'entier sera celle désignée par la trackbar.
Pratique ! Mais il y a mieux

.
Méthode 2 : on déclenche une fonction à chaque modification du curseur
Une telle fonction est appelée "
fonction de callback" dans le jargon de la programmation événementielle.
On peut nommer la fonction comme on veut, mais elle doit impérativement avoir la signature suivante :
void ma_fonction(int valeur);
Cette fonction prend en paramètre une valeur entière, devinez à quoi il sert ?
...
A récupérer la nouvelle position du curseur, exactement !
Créer une trackbar et l'associer à une fenêtre
Attention, vous allez encore constater ici la puissance sidérante de la sous-bibliothèque
highgui.h !
Pour créer une trackbar, et l'associer à une fenêtre, on utilise la fonction :
int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change );
Quoi ? C'est tout ?!
Eh oui

!
Détail des paramètres
- trackbar_name : le nom de la trackbar. Sur l'exemple plus haut, c'est "Seuil".
- window_name : le nom de la fenêtre à laquelle on associe la trackbar.
- value : un pointeur sur le paramètre entier que la trackbar va piloter.
- count : la valeur maximale du paramètre (la valeur minimale étant toujours 0).
- on_change : la fonction de callback (ou NULL si on utilise la méthode 1).
Voilà ! Vous savez tout ce qu'il faut pour réaliser la première partie du TP

.
Dans cette première partie du TP, nous allons réaliser un petit programme qui va nous permettre,
avec deux trackbars, de binariser une image, en laissant à l'utilisateur le choix du seuil (de 0 à 255) et de la méthode (seuillage ou seuillage inversé).
Variables utilisées
Comme nous allons utiliser des fonctions de callback, nos variables seront déclarées comme des variables
globales.
Nous allons avoir besoin de trois images : une pour charger le fichier, une pour contenir l'image en niveaux de gris, et une dernière pour contenir l'image binaire.
On va utiliser deux entiers : un pour le seuil, et un autre (qui sera égal à 0 ou 1) pour décider de l'algorithme de seuillage.
Code : C++1
2
3
4
5
6 | IplImage *img;
IplImage *img_nvg;
IplImage *img_bin;
int seuil;
int inverser;
|
Remarque : Pour
img, il n'est pas nécessaire de la déclarer en variable globale, on peut se contenter de la laisser dans le main. La seule raison pour laquelle je l'ai mise en globale, c'est qu'ainsi, on déclare toutes les variables ensemble

.
La fonction main, premier jet
Pour le début de la fonction
main, c'est un peu comme d'habitude : on charge l'image, on vérifie l'origine, on la convertit en niveaux de gris, et on initialise l'image binaire en faisant une première binarisation d'office.
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | int main(){}
//Initialisations
img=cvLoadImage("/home/arnaud/Images/lena.jpg");
img_nvg=cvCreateImage(cvGetSize(img), img->depth, 1);
img_bin=cvCloneImage(img_nvg);
//Contrôle de l'origine
int flip=0;
if(img->origin!=IPL_ORIGIN_TL){
flip=CV_CVTIMG_FLIP;
}
cvConvertImage(img, img_nvg, flip);
cvNamedWindow("Originale", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Binarisation", CV_WINDOW_AUTOSIZE);
cvShowImage("Originale", img);
//Première binarisation
seuil=127;
inverser=0;
cvThreshold(img_nvg, img_bin, seuil, 255, CV_THRESH_BINARY);
//Affichage du résultat
cvShowImage("Binarisation", img_bin);
cvWaitKey(0);
return 0;
}
|
La fonction de callback
Notre fonction de callback va être appelée chaque fois qu'une trackbar sera modifiée.
Dans cette fonction, on a juste à :
- Déterminer l'algorithme de seuillage à utiliser (en fonction de la valeur de la variable inverser).
- Effectuer le seuillage avec le seuil seuil.
- Raffraîchir l'affichage de l'image binarisée
En gros, ça va nous donner :
Code : C++1
2
3
4
5
6
7
8
9 | void seuillage(int valeur){
int traitement;
if(inverser==0)traitement=CV_THRESH_BINARY;
else traitement=CV_THRESH_BINARY_INV;
cvThreshold(img_nvg, img_bin, seuil, 255, traitement);
cvShowImage("Binarisation", img_bin);
}
|
Vous voyez, c'est pas sorcier

.
La fonction main, les trackbars
Il nous suffit maintenant de créer les deux trackbars, les inclure dans une fenêtre, et leur associer notre fonction callback, et le tour est joué

.
Voici la fonction
main finale :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | int main()
{
//Initialisations
img=cvLoadImage("/home/arnaud/Images/lena.jpg");
img_nvg=cvCreateImage(cvGetSize(img), img->depth, 1);
img_bin=cvCloneImage(img_nvg);
//Contrôle de l'origine
inverser=0;
int flip=0;
if(img->origin!=IPL_ORIGIN_TL){
flip=CV_CVTIMG_FLIP;
}
cvConvertImage(img, img_nvg, flip);
cvNamedWindow("Originale", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Binarisation", CV_WINDOW_AUTOSIZE);
cvShowImage("Originale", img);
//Première binarisation
seuil=127;
cvThreshold(img_nvg, img_bin, seuil, 255, CV_THRESH_BINARY);
//Affichage du résultat
cvShowImage("Binarisation", img_bin);
//Création des trackbars
cvCreateTrackbar( "Seuil de binarisation ", "Binarisation", &seuil , 255 , seuillage );
cvCreateTrackbar( "Inverser (0 = non, 1 = oui)", "Binarisation", &inverser, 1, seuillage );
cvWaitKey(0);
return 0;
}
|
Fichier final
Au final, cela va nous donner le fichier suivant :
Secret (cliquez pour afficher)Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 | #include <opencv/cv.h>
#include <opencv/highgui.h>
IplImage *img;
IplImage *img_nvg;
IplImage *img_bin;
int seuil;
int inverser;
void seuillage(int valeur){
int traitement;
if(inverser==0)traitement=CV_THRESH_BINARY;
else traitement=CV_THRESH_BINARY_INV;
cvThreshold(img_nvg, img_bin, seuil, 255, traitement);
cvShowImage("Binarisation", img_bin);
}
int main()
{
//Initialisations
img=cvLoadImage("/home/arnaud/Images/lena.jpg");
img_nvg=cvCreateImage(cvGetSize(img), img->depth, 1);
img_bin=cvCloneImage(img_nvg);
//Contrôle de l'origine
inverser=0;
int flip=0;
if(img->origin!=IPL_ORIGIN_TL){
flip=CV_CVTIMG_FLIP;
}
cvConvertImage(img, img_nvg, flip);
cvNamedWindow("Originale", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Binarisation", CV_WINDOW_AUTOSIZE);
cvShowImage("Originale", img);
//Première binarisation
seuil=127;
cvThreshold(img_nvg, img_bin, seuil, 255, CV_THRESH_BINARY);
//Affichage du résultat
cvShowImage("Binarisation", img_bin);
//Création des trackbars
cvCreateTrackbar( "Seuil de binarisation ", "Binarisation", &seuil , 255 , seuillage );
cvCreateTrackbar( "Inverser (0 = non, 1 = oui)", "Binarisation", &inverser, 1, seuillage );
cvWaitKey(0);
return 0;
}
|
Vous devriez obtenir un résultat qui ressemble à ceci :
Pas mal hein ?
Bon, jusqu'ici, tout va bien, on a binarisé Lena, et vous avez appris à vous servir de trackbars.
Nous allons enchaîner sur les traitements mathématiques que l'on applique aux images binaires : la
morphologie.
Vous allez voir quelques opérateurs "petits mais costauds", avec lesquels on peut obtenir des résultats très intéressants

.
En plus, "morphologie", c'est un joli mot non ?
Rassurez-vous, c'est plus facile à faire qu'à prononcer

.