Dans le domaine de la vision par ordinateur, OpenCV (Open Computer Vision) se positionne aujourd’hui comme l’outil standard pour le traitement d’images, l’analyse vidéo et l’apprentissage automatique (Machine Learning). Accessible aux développeurs grâce à sa bibliothèque, OpenCV permet de détecter des objets sur des images avec seulement quelques lignes de code. Ce domaine a connu une popularité croissante ces dernières années, avec de nombreuses entreprises et startups technologiques exploitant désormais cet outil de manière intensive.
L’histoire d’OpenCV
OpenCV est un projet né en 1999 chez Intel mobilisant ses nombreux experts, notamment de sa filière Russe, afin de promouvoir et d’améliorer le monde des applications nécessitant une puissance CPU importante. De là, la bibliothèque, gérée et enrichie par différents acteurs, est passée par des versions bêtas avant de voir une version 1.0 sortir en 2006. S’en est suivi une version 2.0 sortie 2009 appelée “OpenCV2″, laissant place aujourd’hui à une bibliothèque open-source de vision par ordinateur bénéficiant d’une vaste communauté, d’un support actif et d’une compatibilité multiplateforme.
OpenCV, techniquement, qu’est-ce que c’est ?
D’un point de vue technique, il s’agit d’une bibliothèque open source écrite principalement en C++ (disponible ici : https://github.com/opencv/opencv). Elle propose des interfaces pour les langages C++, Python, Java et Matlab, facilitant ainsi l’accès aux développeurs sur différentes plateformes. De plus, des interfaces pour Javascript et PHP sont également disponibles, ce qui en fait une option attrayante pour le développement d’applications Web. OpenCV offre des SDK pour diverses plateformes telles que Windows, Linux, Android et iOS, ce qui contribue largement à sa popularité. La bibliothèque se distingue par son efficacité dans le traitement de tâches complexes de vision par ordinateur, ce qui la rend utilisable sur un large éventail de plateformes matérielles, allant des microcontrôleurs aux supercalculateurs.
Les applicatifs d’OpenCV dans l’industrie technologique
Dotée de 2500 algorithmes optimisés, comprenant un ensemble complet d’algorithmes de vision par ordinateur et d’apprentissage automatique classique et de pointe, la librairie peut être utilisée pour détecter des visages, des objets fixes ou en mouvement, des paysages, et bien plus encore. Comptant une communauté active, la bibliothèque est largement adoptée par des entreprises, chercheurs, organismes et développeurs indépendants. Des géants de l’industrie tels que Google, Microsoft, Intel, IBM, Sony, Honda, Toyota, ainsi que de nombreuses start-ups tirent pleinement parti d’OpenCV. Que ce soit pour l’assemblage d’images pour StreetView, la détection d’intrusions dans des zones sensibles, la reconnaissance d’accidents de noyade dans les piscines en Europe, l’inspection des pistes d’aéroport en Turquie, ou l’identification rapide des visages au Japon, OpenCV s’impose comme une bibliothèque puissante et polyvalente, expliquant ainsi sa popularité mondiale.
Installer OpenCV sous Python
Dans le présent article, nous privilégions le choix du langage Python pour la facilité d’installation d’OpenCV. De plus, ce langage est très populaire dans le domaine de l’Intelligence Artificielle dû à ses nombreuses ressources et sa facilité d’intégration.
Voici les prérequis pour installer OpenCV sous Python :
● Des connaissances de base en Python sont préférables pour la bonne compréhension du code.
● Sur Windows et MacOS :
– Installez Python 3.x (3.4+) ou 2.7.x depuis le site officiel Python (https://www.python.org/downloads/)
– Ouvrez un terminal et vérifiez la bonne installation de Python avec “python –version”.
– Puis “pip –version” afin de vérifier l’installation du package manager PIP.
– Enfin, installer OpenCV avec la commande suivante : “pip install opencv-python”.
● Sur Linux :
– L’installation est légèrement différente. Nous vous invitons à regarder, en fonction de votre distribution, les nombreux tutoriels disponibles sur internet.
● Utilisez un éditeur de code pouvant exécuter des scripts Python.
Créez un fichier python, puis vérifiez la bonne installation d’OpenCV. (Figure 1)
1 2 |
import cv2 print(cv2.__version__) |
Figure 1 : afficher la version d’OpenCV
Une fois ces étapes effectuées, vous pouvez exécuter le script. Si la version d’OpenCV s’affiche dans le terminal, vous êtes prêts à utiliser la librairie.
Détecter des chats sur une image avec OpenCV
Examinons une application simple de la librairie en utilisant Python. Nous nous basons ici sur un des modèles pré-entraînés, accessible dans la librairie, qui a été généré en amont à partir d’un ensemble volumineux de données afin de résoudre un problème spécifique. Pour notre besoin, nous utilisons celui conçu pour relever des visages de chats.
Pour aller plus loin, ces modèles sont fondés sur la méthode de détection d’objets en cascade basée sur les fonctionnalités Haar. C’est une approche de reconnaissance d’objets particulièrement efficace proposée par Paul Viola et Michael Jones dans leur article « Rapid Object Detection using a Boosted Cascade of Simple Features » publié en 2001. En effet, elle repose sur l’apprentissage automatique à partir d’un ensemble d’images positives (contenant des visages de chats dans notre exemple) et négatives (ne contenant pas de visages de chats).
Voyons comment mettre en œuvre ce modèle pré-entraîné sur un script Python.
L’import de la bibliothèque se réalise simplement avec la commande “import”. (Figure 2)
1 |
import cv2 |
Figure 2 : import de la bibliothèque OpenCV
Une fois cette étape franchie, nous pouvons exploiter les différentes fonctionnalités d’OpenCV qui nous permettent de :
● Charger l’image.
● Charger le modèle de données pré-entraîné pour identifier des visages de chats.
● Lancer la détection.
● Dessiner des rectangles sur les têtes de chats dévoilés par l’algorithme et les compter.
● Enfin, afficher le résultat.
Commençons avec le chargement de l’image depuis un fichier qui se fait de façon très simple grâce à la fonction “cv2.imread()”. Cette méthode transforme notre image en une matrice (type Mat), élément mathématique clef d’OpenCV. C’est sous cette forme que peuvent être appliqués les différents traitements. (Figure 3)
1 2 |
# Charger l'image à partir du chemin spécifié image = cv2.imread(image_path) |
Figure 3 : implémentation de la méthode “imread()”
Puis, convertissons l’image en noir et blanc (niveaux de gris) pour améliorer l’efficacité du traitement. (Figure 4)
1 2 |
# Convertir l'image en niveaux de gris (pour améliorer la détection des visages) grey_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
Figure 4 : conversion en niveau de gris
Le chargement du modèle de données se fait par l’appel de la classe “CascadeClassifier” qui porte différents algorithmes de détection. On utilise son constructeur qui prend en paramètre le chemin du fichier du modèle à charger. (Figure 5)
1 2 |
# Charger le classificateur de visages de chats pré-entraîné cat_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalcatface_extended.xml') |
Figure 5 : chargement du modèle
Ici, nous prenons donc le modèle entraîné à relever les visages de chats.
Ensuite, la traitement s’opère avec l’appel de la méthode “CascadeClassifier::detectMultiScale” qui génère une liste de rectangles correspondant aux objets débusqués à partir du modèle. (Figure 6)
Cette méthode prend en paramètre la matrice à traiter, ainsi que deux autres paramètres influant sur la qualité de la reconnaissance. Le premier permet de jouer sur la capacité de l’algorithme à repérer différentes tailles de l’objet à identifier. Diminuer sa valeur augmente directement la sensibilité de la reconnaissance, notamment aux petits objets, ainsi que son temps de traitement, au risque de voir augmenter le nombre de faux positifs. Des valeurs typiques pour ce paramètre sont comprises entre 1.01 et 1.3, à voir selon le besoin. Le second paramètre spécifie le nombre minimum de voisins requis pour qu’une région candidate soit considérée comme un résultat positif. Augmenter sa valeur réduit ainsi le nombre de détections pour éliminer les faux positifs, mais risque d’entraîner la perte de véritable positif. Des valeurs typiques sont comprises entre 3 et 6 selon le besoin. En ajustant ces paramètres, nous pouvons influencer la sensibilité et la spécificité du repérage.
1 2 |
# Détecter les visages de chats dans l'image cat_faces = cat_cascade.detectMultiScale(grey_image, scaleFactor=1.1, minNeighbors=2) |
Figure 6 : exécution de la méthode d’identification des visages de chats.
La valeur de retour de cette méthode est une liste de rectangles (“cat_faces” dans la Figure 6). Calculer sa longueur permet de déterminer le nombre de visages décelés. Une simple fonction traçant ces rectangles sur l’image met en lumière le résultat que l’on affiche ensuite avec “imshow” (Figures 7, 8 et 9).
1 2 3 4 5 6 |
# Tracer les rectangles sur les visages détectés for (x, y, w, h) in cat_faces: cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2) # Afficher l'image avec les rectangles autour des têtes de chats détectées cv2.imshow('Image avec têtes de chats détectées', image) cv2.waitKey(0) |
Figure 7 : affichage du résultat
Il ne faut pas hésiter à jouer avec les paramètres de “detectMultiScale” pour affiner le résultat et améliorer les performances d’identification.
Figure 8 : distinction entre les visages de chats et ceux des autres espèces
Figure 9 : détection de plusieurs visages de chats
Avec seulement quelques lignes de code (Figure 10), on obtient ainsi une application de reconnaissance de visages de chats, introduction idéale pour une prise en main facilitée de la librairie OpenCV via utilisation d’un de ses modèles pré-entrainés.
Figure 10 : script final du premier exemple
Pour aller plus loin : détecter des visages sur le flux vidéo d’une webcam
Nous avons vu dans la partie précédente que la librairie OpenCV pouvait traiter une image. Cependant, il est possible d’aller encore plus loin en traitant des vidéos. Le principe est sensiblement le même car une vidéo n’est rien d’autre qu’une succession d’images. Ainsi, les fonctions testées dans le premier exemple peuvent aussi être appliquées pour chacune d’entre elles.
Pour illustrer ce propos, nous allons utiliser la webcam de l’ordinateur afin de détecter, cette fois-ci, des visages humains grâce à un modèle pré-entraîné disponible dans la librairie.
Pour commencer, nous allons afficher la webcam dans une fenêtre. La fonction “cv2.VideoCapture()” permet de capturer une vidéo à partir d’une caméra ou d’un fichier vidéo de l’ordinateur. (Figure 11)
import cv2
1 2 3 |
# Capture d'une vidéo à partir d'une caméra # 0 étant l'identifiant de la caméra principale cap = cv2.VideoCapture(0) |
Figure 11 : capture d’une séquence d’images à partir de la webcam de l’ordinateur
L’identifiant 0 est généralement celui de la webcam de votre ordinateur. De son côté, la classe “VideoCapture” possède plusieurs fonctions pour manipuler le format vidéo.
Ensuite, nous voulons lire chaque capture de la vidéo puis afficher ces dernières dans une fenêtre.
Pour ce faire, nous utilisons la fonction “read()” de la classe “VideoCapture” afin de récupérer deux arguments :
● Un boolean qui nous indique si la capture a été réalisée avec succès.
● L’image en elle-même, de type Mat.
Puis, nous pouvons utiliser la fonction “imshow()” de la librairie pour afficher le résultat. (Figure 12)
1 2 |
success, frame = cap.read() cv2.imshow("video", frame) |
Figure 12 : affichage d’une image de la vidéo
Cependant, ce code n’affiche que la première image de la vidéo car la fonction “read()” n’en récupère qu’une seule à la fois. Nous devons donc itérer sur ce bloc d’instructions afin de récupérer chacune des images capturées. Pour cela, nous ajoutons une boucle “while” avec pour condition la fonction “isOpened()”, de la classe “VideoCapture”. Cette dernière retourne un boolean qui permet de vérifier si la tentative d’ouverture d’une caméra ou d’un fichier vidéo a réussi.
Nous ajoutons à cela une condition “if” dans la boucle pour l’interrompre si nous appuyons sur la touche “échap”. (Figure 13)
1 2 3 4 5 6 7 8 9 |
while cap.isOpened(): success, frame = cap.read() cv2.imshow("video", frame) # Interruption de la boucle en appuyant sur la touche "échap" if cv2.waitKey(1) & 0xFF == 27: break # Libération des ressources permettant la capture de la vidéo cap.release() cv2.destroyAllWindows() |
Figure 13 : boucle while sur la webcam
Puis, la fonction “release()” permet de libérer les ressources allouées à la capture de la vidéo avant la fermeture de notre fenêtre.
Une fois ceci effectué, votre code doit ressembler à la figure 14.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import cv2 # Capture d'une vidéo à partire d'une caméra # 0 étant l'identifiant de la caméra principale cap = cv2.VideoCapture(0) while cap.isOpened(): success, frame = cap.read() cv2.imshow("video", frame) # Interruption de la boucle en appuyant sur la touche "échap" if cv2.waitKey(1) & 0xFF == 27: break # Libération des ressources permettant la capture de la vidéo cap.release() cv2.destroyAllWindows() |
Figure 14 : exemple pour afficher les images d’une caméra.
Maintenant, nous pouvons comme dans l’exemple précédent, détecter des visages sur chacune des images que nous récupérons.
Pour ce faire, nous allons charger le modèle pré-entraîné concernant les visages humains. (Figure 15)
Attention, ce modèle que nous retenons ne reconnaît que les visages de face et non de profil, même s’il existe d’autres modèles dans la librairie pouvant réaliser cette tâche.
1 2 3 4 |
cap = cv2.VideoCapture(0) face_classifier = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) |
Figure 15 : chargement du modèle pré-entraîné
Par la suite, nous créons une fonction “displayFaces()” pour permettre de traiter chaque image de la vidéo avec le modèle pré-entraîné. (Figure 16)
1 2 3 4 5 6 7 8 9 10 11 12 |
import cv2 def displayFaces(frame, face_classifier): gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_classifier.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(80,80)) countOfFaces = len(faces) if countOfFaces != 0: for (x,y,w,h) in faces: cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 0), 2) cv2.imshow("video", frame) # Capture d'une vidéo à partire d'une caméra # 0 étant l'identifiant de la caméra principale cap = cv2.VideoCapture(0) |
Figure 16 : exemple de fonction repérant des visages humains
Comme dans l’exemple précédent, nous passons l’image en gris pour une meilleure efficacité de traitement avec la fonction “cvtColor()”. Puis, nous utilisons “detectMultiScale()” afin de détecter tous les visages. Ici, on ajoute une entrée en plus dans la fonction, par rapport à l’exemple précédent, qui est le “minSize”. Cet argument nous donne la possibilité de déterminer la taille minimum en nombre de pixels que doivent avoir les objets à repérer (width, height).
Ensuite, nous récupérons le nombre de visages dans notre liste “faces”, nous permettant ainsi de boucler sur celle-ci, s’il y a bien sûr au moins un visage capturé (figure 16). Pour chaque visage, nous créons, dans l’image de base “frame”, un rectangle à la position et aux dimensions de ce dernier, comme cela a été fait dans la démonstration précédente.
Puis, nous affichons le résultat avec “imshow()”.
Pour finir, on injecte notre fonction “displayFaces()” dans notre boucle en vérifiant avant si l’image a été lue avec succès, grâce à la variable “success” récupérée depuis la fonction “read()”. (Figure 17)
1 2 3 4 5 6 7 |
while cap.isOpened(): success, frame = cap.read() if success: displayFaces(frame, face_classifier) # Interruption de la boucle en appuyant sur la touche "échap" if cv2.waitKey(1) & 0xFF == 27: break |
Figure 17 : ajout de la fonction avec la condition de succès
Ainsi, votre code complet doit ressembler à la figure 18.
Figure 18 : code final du deuxième exemple
La logique est quasiment la même que dans l’exemple précédent, avec l’ajout d’une boucle “while” pour récupérer chaque image.
De plus, nous pouvons encore voir ici l’avantage qu’offre la librairie OpenCV où nous avons facilement construit un programme fonctionnel permettant de traiter une vidéo.
Conclusion
OpenCV est une bibliothèque facile à prendre en main dans le domaine de la vision par ordinateur. Grâce à ses très nombreux modèles pré-entraînés, il vous est possible avec seulement quelques lignes de codes de vous lancer dans la détection de visages humains, de sourires, de corps ou encore de plaques d’immatriculation. A ce sujet, la documentation d’OpenCV représente un bon point de départ : https://docs.opencv.org/4.9.0/.
De plus, la bibliothèque vous permet d’aller encore plus loin en explorant les possibilités de Machine Learning, pour créer et entraîner vos propres modèles. Cependant, elle possède certaines limites dans ce domaine si vos besoins deviennent plus complexes. Afin d’y pallier, il est alors possible d’associer OpenCV à d’autres librairies spécialisées, comme TensorFlow ou PyTorch.
Concernant les performances logicielles, OpenCV fournit quelques astuces d’optimisation notamment liées à Python. Nous n’avons pas réalisé de comparatif avec d’autres langages (potentiellement plus rapides), Python se révélant suffisamment performant sur un ordinateur adapté.
Une piste d’optimisation à explorer serait d’exploiter son propre GPU (à l’aide de librairies adéquates) ou ceux proposés par un service cloud afin de miser sur des performances hardware en vue d’accélérer les processus d’apprentissage notamment pour les gros projets de développement d’IA.
Toutefois, la question des performances persiste pour les utilisateurs de la librairie sur des systèmes embarqués comme un Rasperry où les contraintes techniques sont plus strictes et les performances hardware restreintes. De manière générale, si vous voulez faire de l’apprentissage, il vaut mieux entraîner un modèle sur un ordinateur (ou service cloud) puis le déployer sur vos appareils portables dans un second temps.
Pour terminer, nous vous invitons comme nous à suivre attentivement les développements futurs de la communauté, convaincus que de nouvelles avancées prometteuses nous attendent.
———————
Sources :
https://en.wikipedia.org/wiki/OpenCV
https://opencv.org/about/
https://github.com/opencv/opencv
https://docs.opencv.org/4.9.0/db/d28/tutorial_cascade_classifier.html
Il est possible de retrouver l’intégralité de cet article dans le hors-série #14 spécial « IA » de printemps 2024 du magazine « Programmez ».