Scroll to top

Aujourd’hui je vais vous proposer un nouveau tutoriel pour OpenCV menant directement sur une application pratique: le Face Tracking. Au cours de ce tutoriel, nous allons réaliser un programme le plus simple possible permettant d’effectuer le suivi d’un visage à partir d’un flux vidéo.

La théorie

Et oui je sais que cela ne vous intéresse pas forcément, mais je vous assure que c’est important afin de mieux comprendre le fonctionnement du programme. Pour ce cas de Face Tracking, j’ai choisi d’utiliser une des techniques les plus utilisées: la méthode de Viola et Jones. 

Le but de cette méthode va être de créer un classificateur contenant un ensemble de propriétés d’un objet précis, dans notre cas un visage. Ce classificateur est donc construit en utilisant des caractéristiques pseudo-haar et un apprentissage grâce à un très grand nombre d’images. Viola et Jones choisissent d’utiliser une classification par boosting, le principe de ce boosting est d’utiliser plusieurs classificateurs dits faibles afin d’en créer un fort.

Les classificateurs faibles ne contiennent en général qu’une caractéristique à vérifier et sont donc rapides en terme de calcul. Par la suite on utilise cette série de classificateurs faible en « cascade » afin de vérifier si l’objet est détecté dans l’image. Pour plus d’information sur cette méthode, je vous invite à consulter l’article wikipédia sur le sujet.

La pratique

Pour cette implémentation, nous n’allons pas nous occuper de la construction du classificateur, je vous le fournis ici. Nous allons donc nous concentrer sur l’utilisation de l’algorithme qui est implémenté dans OpenCV.

La base

Pour commencer, nous allons mettre en place les premières briques du programme. On commence par inclure les fichiers nécessaires au programme.

#include <opencv/cv.h> 

#include <opencv/highgui.h>

 #include <stdio.h>

Ensuite on va déclarer deux de manière globale deux variables, le premier est le classificateur et le second une zone mémoire utilisée comme « buffer » pour la détection des visages. Le fait de les déclarer de manière globale n’est pas forcément idéal, mais le but est ici d’avoir le code le plus simple possible. Pour une application plus importante, il est recommandé de déclarer ces deux variables dans la partie nécessitant la détection de visage.

CvHaarClassifierCascade *cascade; 

CvMemStorage *storage;

int key;

On rentre maintenant dans la fonction main, et nous allons déclarer tous les objets nécessaires par la suite. Nous avons besoin de peu d’élément, le premier sera une image (IplImage), le second sera le périphérique d’entrée de la caméra (CvCapture) et le dernier sera un int nous permettant de sortir de la boucle de traitement. Ce qui nous donne:

CvCapture *capture; IplImage *frame; int key;

Il faut ensuite initialiser tout ce beau monde. On commence par ouvrir le fichier du classificateur Haar

cascade = ( CvHaarClassifierCascade* )cvLoad( « haarcascade_frontalface_alt.xml », 0, 0, 0 );

On ouvre le flux caméra avec cvCreateCameraCapture

capture = cvCreateCameraCapture(CV_CAP_ANY)

Enfin on initialise l’espace mémoire

storage = cvCreateMemStorage( 0 );

Afin d’afficher tout cela, nous aurons besoin d’une fenêtre

cvNamedWindow( « Window-FT », 1 );

Nous sommes en C++, il ne faut donc pas oublier de libérer la mémoire avant la fin du programme, on doit alors effacer tous les objets précédemment créé.

cvReleaseCapture( &capture ); 

cvDestroyWindow( « Window-FT » );

 cvReleaseHaarClassifierCascade( &cascade );

cvReleaseMemStorage( &storage );

Nous avons donc ici la base du programme. Si vous compilez vous ne devriez pas avoir grand-chose qui se passe et c’est normal, il manque l’essentiel, la boucle de traitement d’image ainsi que la fonction permettant l’affichage du tracking facial. C’est ce que nous allons voir dès maintenant.

La boucle de traitement

Cette étape est plutôt simple, mais elle est très importante, le principe est d’effectuer, à chaque image envoyée par la caméra au programme, la détection de visage. On en profite pour rajouter une petite commande permettant de quitter la boucle ( et donc le programme) en appuyant sur la touche « q ». Voici la boucle en question

while( key != ‘q’ )

{ 

img= cvQueryFrame( capture ); detectFaces( img ); key = cvWaitKey( 10 ); 

}

Pas grand-chose à expliquer ici, une boucle while classique, on déclare une frame (image) qui correspondra à chaque instant à l’image envoyée par la caméra. La fonction detectFaces est la fonction que nous allons étudier juste après qui permet de faire la dectetion de visage à proprement parler. Si vous voulez tester votre caméra, il vous suffit de remplacer detectFaces(img); par cvShowImage( « Window-FT », img );si vous compilez, vous devriez voir en temps réel ce que votre caméra est en train de filmer.

La fonction detectFaces

Il ne reste plus qu’a créer la fonction detectFaces afin de permettre le face tracking. Voici la fonction

void detectFaces( IplImage *img ) {

int i;

CvSeq *faces = cvHaarDetectObjects(img, cascade, storage, 1.1, 3 , 0,  cvSize( 40, 40 ) );

for( i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ )

{

CvRect *r = ( CvRect* )cvGetSeqElem( faces, i );

cvRectangle( img, cvPoint( r->x, r->y ), cvPoint( r->x + r->width, r->y + r->height ), CV_RGB( 255, 0, 0 ), 1, 8, 0 );

}

cvShowImage( « Window-FT », img );

}

La fonction récupère en paramètre l’image de la caméra récupérer pendant la boucle de traitement. C’est sur cette image que toutes les opérations vont être effectuées par la suite. C’est là où vous allez apprécier OpenCV, car pour la détection de visage, la méthode de Viola et Jones est déjà implémentée et deviens très facile à utilisé. Tout réside dans la fonction cvHaarDetectObjects.

Le résultat de cette fonction est une série d’objets qui ont passé les critères de sélection définis par votre classificateur. On définit donc une CvSeq qui correspond à une séquence d’objet d’un même type, dans notre cas ce sera nos différents visages détectés.

Au niveau des paramètres de cette fonction img représente l’image a traité, cascade est le classificateur choisi pour faire le test, storage est l’espace mémoire nécessaire pour effectuer l’opération, 1.1 représente le « scale factor », 3 représente le nombre de voisins minimum , 0 est un paramètre supplémentaire qui permet de rajouter des filtres particuliers par exemple un filtre de canny avec CV_HAAR_DO_CANNY_PRUNING cvSize( 40, 40 ) représente la taille minimale d’un objet dans la vidéo.

Nous avons maintenant l’ensemble des visages qui ont été détectés dans l’image dans notre CvSeq, et afin d’afficher le résultat à l’écran nous allons simplement dessiner un carré autour du visage détecté. Ensuite on rentre dans une boucle for qui va passer en revue tous les visages détectés, et pour chacun créer un rectangle autour du visage repéré.

Je ne détaille pas le dessin du rectangle, si vous avez des questions n’hésitez pas à les poser en commentaire. Enfin la dernière étape est d’afficher à chaque appel de fonction l’image de la caméra avec les carrés permettant de détecter les visages, grâce à la fonction cvShowImage( « Window-FT », img ); 

Pour cette fonction le « Window-FT » est le nom de la fenêtre que vous avez créée et le img représente l’image à afficher dans la fenêtre. Voilà vous disposer maintenant d’un programme fonctionnel, je vous invite à poster vos questions en commentaires. Vous trouverez le classificateur ici et pour les sources de ce petit programme c’est par ici.

 

Related posts