Reconnaissance faciale TP2 : Détection faciale avec cascade de Haar

Le code python

Notre classe de détection avec cascade de Haar

Allez hop ! On crée un nouveau fichier qui va s’appeler haarDetection.py dans le répertoire outils.

On importe cv2, logique

import cv2

Ensuite, on déclare notre classe DetectVisageAvecHaar.

class DetectVisageAvecHaar:

On crée notre attribut qui va contenir notre classifieur. Comme tu pourras le constater, il s’agit d’un fichier XML qui est dans le répertoire d’opencv. Moi, anaconda est installé dans D:\anaconda3 car je préfère éviter les espaces. A toi de mettre à jour ce chemin dans ton script.

    def __init__(self):
        self.__faceCascade = cv2.CascadeClassifier('D:\Anaconda3\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml')

Ensuite on va créer notre méthode detectVisage. En argument, elle recevra l’image dans laquelle elle doit détecter un visage.

    def detectVisage(self,image):

On passe l’image en niveau de gris car c’est comme ça que notre cascade de classifieurs a été entrainée.

        ## On passe en niveau de gris (nécessaire pour haar)
        imageEnGris = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

Une fois détecté, le ou les visages sont renvoyés sous forme de coordonnées. Plus précisément, la coordonnée horizontale du point en haut à gauche qu’on appellera désormais x1. La coordonnée verticale du point en haut à gauche qu’on appellera désormais y1 ainsi que la largeur et la hauteur du cadre dans lequel est le visage. Ça nous donne une liste du type x1, y1, largeur, hauteur.

Si il y a plusieurs visages, alors on aura une liste de coordonnées de visages.

Ensuite, tout se passe en une seule ligne ! Tout. Y a pas plus simple

        ## Detection des visages
        coordVisages = self.__faceCascade.detectMultiScale(imageEnGris, 1.1, 4)

Notre classifieur a une méthode qui s’appelle detectMultiscale. Elle prend en argument notre image évidemment, mais on va lui en ajouter 2 autres.

Le premier, 1.1 c’est le scaleFactor. Sans rentrer dans les détails, c’est un paramètre qui est utilisé pour créer une pyramide d’image (de plus en plus petite). L’entrainement d’un visage a été fait avec une taille fixe. Du coup, si on réduit l’image, un visage qui n’était pas détectable car pas à la bonne taille peut devenir détectable.

Le second argument qu’on va donner à manger à notre méthode, c’est minNeighbors . Disons qu’en gros, c’est à partir de combien de rectangle proche détecté qu’on décide de garder la détection. Plus ce chiffre est grand et moins il y aura de faux positifs; mais du coup plus de risque pour un faux négatif.

N’hésite pas à jouer avec ces paramètres pour regarder le comportement résultant.

Et voilà ! Notre classe de détection avec cascade de Haar est terminée 🙂

Script principal

Bon, il va falloir intégrer tout ça dans notre script principal.

Première chose évidemment, on va ajouter aux imports notre nouvelle classe.

import cv2
import outils.perfImage as perfImage
from outils.webcamThreadParallele import FluxVideoParallele
from outils.haarDetection import DetectVisageAvecHaar
import time

On crée donc notre nouvel objet de détection de visage qu’on va appeler haar. Et comme pour le TP précédent, on crée l’objet videoWebcam et l’objet monPerfImage.

## On crée notre objet depuis la classe 
haar = DetectVisageAvecHaar()

## On initialise le flux de capture vidéo
## depuis la webcam ou caméra de surveillance
## videoWebcam = cv2.VideoCapture(0)
videoWebcam = FluxVideoParallele(0,100).demarrer()

## On instancie notre objet depuis la classe PerfImage
monPerfImage = perfImage.PerfImage(1)

On attaque notre boucle infinie et on récupère l’image depuis la webcam

## Top départ de notre boucle inifinie
## Tant que Vrai est toujours vrai :)
while True:
    ##on récupère la dernière image de la vidéo 
    valeurRetour, imageWebcam = videoWebcam.image()

    ## on s'assure qu'aucune erreur n'a été rencontrée
    if valeurRetour:

Si on a bien une image, on lance la détection depuis la cascade de Haar

        #Detection avec haar
        coordVisages = haar.detectVisage(imageWebcam)

Si notre détecteur à trouver des images, alors, il nous renvoie un tableau de coordonnées d’images. On va donc traiter ça

        ## Est ce qu'il y'a des visages ?
        if len(coordVisages) > 0:     

Alors, on traite, on traite… euh… on traite surtout si il a détecté quelque chose ! Donc si le tableau de coordonnées est vide, hé bien on ne fait rien. Par contre, si il contient quelque chose, là, on va pouvoir passer à la suite

            for coordUnVisage in coordVisages:
                x1 = coordUnVisage[0]
                y1 = coordUnVisage[1]
                largeur = coordUnVisage[2]
                hauteur = coordUnVisage[3]
        
                cv2.rectangle(imageWebcam, (x1, y1), (x1+largeur, y1+hauteur), (255, 0, 0), 2)

On commence par faire une boucle pour récupérer chaque tableau coordonnées de visage. Et chacune de ces coordonnées sera mises tour à tour dans la variable coordUnVisage, qui est un petit raccourci pour “coordonnée d’un visage”.

Donc je récupère le point en haut à gauche avec x1,y1 ainsi que la largeur et la hauteur, et avec tout ça je dessine un joli rectangle bleu.

Pour le reste, rien à changer par rapport au TP précédent, mais comme je suis quelqu’un de généreux, je te recolle le code

        ## On récupère notre texte avec les performances
        textePerf = monPerfImage.textePerf()
        
        ## On ajoute notre ligne à l'image
        cv2.putText(imageWebcam, textePerf, (10, 15),
                cv2.FONT_HERSHEY_SIMPLEX , 0.5, (0, 0, 0), thickness=2, lineType=1)    
        
        ## On affiche l'image 
        cv2.imshow('Image de la webcam', imageWebcam)        
    
    ## Comme c'est une boucle infinie, il faut bien se prévoir une sortie
    ## Dans notre cas, ce sera l'appui sur la touche Q
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

## Si on arrive jusque là, c'est qu'on est sortie de notre boucle
# Donc, on libère le flux de la webcam et on détruit la fenêtre d'affichage
videoWebcam.arreter()
cv2.destroyAllWindows() 

Tu n’as plus qu’à faire F5, corriger tes fautes de syntaxe/copier-coller et autres 😀 et observer le résultat !

Pour ce qui est des perfs, c’est assez impressionnant quand même. Dans la console j’ai ça :

Temps écoulé : 1.00 - FPS : 36
Temps écoulé : 1.02 - FPS : 35
Temps écoulé : 1.01 - FPS : 37
Temps écoulé : 1.00 - FPS : 37
Temps écoulé : 1.02 - FPS : 37

et voici mes perfs

Pourquoi ?

Tiens, un petit jeu. Approche-toi très près de l’objectif de la caméra et observe les performances en FPS. Puis recule à 1m50 environ et observe de nouveau les performances. Pourquoi ce comportement d’après toi ? Tout est écrit dans cet article, je te laisse avec ta curiosité !

Les défauts de cette méthode de détection faciale

Le premier défaut, que tu auras trouvé tout seul en jouant devant ta webcam, c’est que cette méthode ne détecte que les visages qui sont relativement de face. Dès que tu tournes une chouille la tête, il n’y a plus de détection. Si tu la penches, même combat.

Le second défaut, mais qui ne nous concerne pas, c’est son temps d’apprentissage. Il faut plusieurs jours voir plusieurs semaines. Autant te dire que tu as intérêt à avoir bien préparé ton entrainement parce que si au bout de 3 semaines d’entrainement, avec tout ce que tu as consommé en électricité, le temps d’attente etc., tu as des perfs pourries… Comment te dire… Va y avoir de quoi se la prendre et se la mordre !!! Surtout qu’il n’y a pas de méthode magique pour présélectionner le nombre d’étage, l’ordre ou les paramètres pour chaque étage. En gros, faut essayer, attendre et aller au résultat…

Soyez le premier à commenter

Poster un Commentaire

Votre adresse de messagerie ne sera pas publiée.


*


Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.