Niveau
Débutant
Env.
Local (Windows), Local (Linux)
Code
Python
Libs
Cv2, matplotlib
Sources

Détection faciale avec OpenCV

OpenCV ?

La reconnaissance de visage est aujourd’hui un domaine mature qui fait d’ailleurs l’objet de plusieurs librairies, framework mais aussi et surtout de services cognitifs (Microsoft, Google, etc.). Je vous propose aujourd’hui de découvrir comment utiliser la librairie OpenCV (Open Source bien sûr) pour effectuer ce genre d’opération.

Pour information :

OpenCV (pour Open Computer Vision) est une bibliothèque graphique libre, initialement développée par Intel, spécialisée dans le traitement d’images en temps réel. La société de robotique Willow Garage et la société ItSeez se sont succédé au support de cette bibliothèque. Depuis 2016 et le rachat de ItSeez par Intel, le support est de nouveau assuré par Intel. Cette bibliothèque est distribuée sous licence BSD.

Wikipédia

Nous reviendrons régulièrement sur cette librairie car au delà de la détection faciale que nous allons aborder dans cet article elle permet aussi de retravailler les images et les vidéos, elle propose des fonctions de calcul matriciels très utiles quand on traite des données multimédia et bien sur embarque des algorithmes d’apprentissages. Bref, c’est une petite pépite pour ceux qui veulent traiter des données multimédia !

Pour cet article, j’utiliserai Python 3.7, il faudra juste veiller à installer la librairie OpenCV 4.2.0 bien sur. Pour cela le site d’OpenCV vous guide de manière assez bien détaillée.

Si vous êtes comme moi sur linux tapez simplement en ligne de commande :

pip install opencv-python

Premier test

Pour ce premier test nous allons utiliser une photo :

Avant toute chose il faut récupérer les modèles pré-configurés sur le site Github. Pour cela allez sur https://github.com/opencv/opencv/tree/3.4/data/haarcascades et copiez localement le contenu du répertoire ./opencv/

Vous trouverez plus d’informations sur ces modèles ici : https://docs.opencv.org/3.4/db/d28/tutorial_cascade_classifier.html

Nous allons dans un premier temps utiliser le modèle pré-configuré haarcascade_frontalface_default.xml.

import cv2
import sys
from matplotlib import pyplot as plt

imagePath = r'image0.jpg'
dirCascadeFiles = r'../opencv/haarcascades_cuda/'
cascadefile = dirCascadeFiles + "haarcascade_frontalface_default.xml"
classCascade = cv2.CascadeClassifier(cascadefile)
image = cv2.imread(imagePath)
plt.imshow(image)

Ces lignes de commandes initialisent OpenCV (enfin surtout le classifier avec le modèle préconfiguré) et affichent l’image précédente.

Maintenant nous devons convertir l’image en niveau de gris afin de pouvoir utiliser la fonction de détection faciale. La conversion en niveau de gris est une transformations dans l’espace RVB (Rouge/Vert/Bleu) comme l’ajout / la suppression du canal alpha, l’inversion de l’ordre des canaux, la conversion vers / depuis la couleur RVB 16 bits (R5: G6: B5 ou R5: G5: B5), ainsi que la conversion vers / depuis l’échelle de gris.

Une ligne en Python suffit pour cela :

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
plt.imshow(gray)

Voilà le résultat de la transformation opéré par OpenCV :

Maintenant nous pouvons lancer l’opération de détection de visage :

faces = classCascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30),
    flags = cv2.CASCADE_SCALE_IMAGE
)
print("Il y a {0} visage(s).".format(len(faces)))

Bizarrement, vous devriez obtenir ce résultat :

Il y a 3 visage(s).

Plutôt étonnant n’est-ce pas ? y-aurait-il 2 autres personnes cachées dans cette photo ? regardons de plus près en demandant à OpenCV de marquer via des cadres de couleurs les visages détectés. Opération plutôt simple puisque la fonction de détection de visage renvoit aussi les coordonnées des rectangles contenant ces derniers (ici via l’objet faces) :

# Dessine des rectangles autour des visages trouvés
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
plt.imshow(image)

Nous avons bien un soucis, apparemment la détection de forme via le modèle de classification choisi n’est pas assez précise ! Nous avons détecté 2 visages en trop …

Changeons de modèle prédéfini

C’est en fait une opération plutôt simple car il suffit de changer de fichier xml (Cf. les fichiers que vous avez télécharger au préalable). Utilisons à la place du précédent le fichier haarcascade_frontalface_alt.xml

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cascadefile = dirCascadeFiles + "haarcascade_frontalface_alt.xml"
classCascade = cv2.CascadeClassifier(cascadefile)
faces = classCascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30),
    flags = cv2.CASCADE_SCALE_IMAGE
)
print("Il y a {0} visage(s).".format(len(faces)))
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

plt.imshow(image)

Le résultat semble bien meilleur cette fois-ci :

Et si nous voulions découper notre visage pour enlever les contours inutiles ? rien de plus simple … n’oublions pas qu’une image n’est rien d’autre qu’une matrice :

for (x, y, w, h) in faces:
    crop_img = image[y:y+h, x:x+w]
    plt.imshow(crop_img)

… et sauvegardons cette image découpée dans un fichier grâce toujours à OpenCV :

i=0
for (x, y, w, h) in faces:
    cv2.imwrite('fichier_resultat_' + str(i) + '.jpg', image[y:y+h, x:x+w]) 
    i = i+1

Essayons avec une photo qui a plusieurs visages

Reprenons notre code mais avec une photo qui comporte – vraiment cette fois-ci – plusieurs visages :

imagePath = r'image3.jpg'
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cascadefile = dirCascadeFiles + "haarcascade_frontalface_default.xml"
classCascade = cv2.CascadeClassifier(cascadefile)
faces = classCascade.detectMultiScale(
    gray,
    scaleFactor=1.1,
    minNeighbors=5,
    minSize=(30, 30),
    flags = cv2.CASCADE_SCALE_IMAGE
)
print("Il y a {0} visage(s).".format(len(faces)))
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

plt.imshow(image)

récupérons les coordonnées des cadres de ces deux visages :

for i in range(len(faces)):
    print("Cadre du visage N°{0} --> {1}".format(i, faces[i]))
Cadre du visage N°0 --> [396 101 124 124]
Cadre du visage N°1 --> [101  88 154 154]

Affichons le résultat:

for i in range(len(faces)):
    plt.subplot(1, 2, i+1)
    plt.imshow(image[faces[i][1]:faces[i][1]+faces[i][3], faces[i][0]:faces[i][0]+faces[i][2]])

Conclusion

Nous avons survolé dans cet article comment utiliser les modèles pré-embarqués ainsi que quelques fonctions de retouches d’image fournies en standard par OpenCV. Même si ces fonctions sont très performantes (et vraiment très utiles) on se rend vite compte qu’il faut choisir intelligemment les bons modèles ainsi que les bons paramètres si l’on veut une détection faciale de qualité. La bonne nouvelle c’est que cette librairie regorge d’exemples et de tutoriels qu’il ne faut pas hésiter à parcourir … bien sur nous y reviendrons dans de futurs articles.

Comme d’habitude vous trouverez les codes sources de ce tuto sur GitHub.

Partager cet article

5 Replies to “Détection faciale avec OpenCV”

    1. Bonjour,
      Vous avez raison, soyons puriste: il s’agit bien de détection faciale dans la mesure où l’on n’est pas capable dans cet exemple de différencier deux personnes différentes.
      Je vais changer le titre, merci de votre retour.
      Bien à vous.

  1. Bonjour coach,
    J’ai fait une application de reconnaissance faciale (python, opencv, dlib, face_recognition), qui fait la présence. Mais l’application confond certains visages, mais du moins à 99%. Et si une personne se présente avec une photo. L’application marquera sa présence. Comment puis-je contourner cela? en détectant si c’est une personne physique qui est devant la caméra. Ou, c’est une photo.

    Votre réponse, pourra m’aider à enrichir mon application.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

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