Dans cet article, nous allons découvrir les bases de la vision par ordinateur et réaliser une première détection d’objet en temps réel avec une webcam, Python, OpenCV et YOLO.

Les systèmes de détection d’objet sont utilisés dans de nombreux domaines : robotique, drones, véhicules autonomes, vidéosurveillance intelligente, tri industriel ou encore systèmes embarqués. L’objectif de ce tutoriel est de comprendre les bases avant d’aller plus loin avec des modèles personnalisés.


Démonstration vidéo


Prérequis

  • Une webcam USB ou intégrée à votre ordinateur

  • Python installé sur votre machine

  • Des objets pour tester la reconnaissance

  • Les fichiers suivants :

    • coco.names
    • yolov4-tiny.cfg
    • yolov4-tiny.weights

Comment fonctionne OpenCV ?

OpenCV est une bibliothèque open source dédiée à la vision par ordinateur.

Elle permet notamment de :

  • lire une image ou une vidéo ;
  • utiliser une webcam ;
  • modifier une image ;
  • détecter des formes ;
  • afficher du texte ou des rectangles ;
  • traiter des images en temps réel ;
  • utiliser des modèles d’intelligence artificielle.

Dans ce tutoriel, OpenCV va servir à :

  1. récupérer l’image de la webcam ;
  2. préparer l’image pour YOLO ;
  3. exécuter le modèle de détection ;
  4. afficher les objets détectés avec un rectangle autour d’eux.

Comment fonctionne YOLO ?

YOLO signifie You Only Look Once.

C’est un modèle d’intelligence artificielle basé sur les réseaux de neurones capable de détecter plusieurs objets dans une image en une seule analyse. Contrairement à d’autres méthodes plus anciennes, YOLO regarde l’image complète et prédit directement :

  • la classe de l’objet ;
  • sa position ;
  • son niveau de confiance.

Par exemple, si une personne est devant la caméra, YOLO peut retourner :

person : 86 %

avec les coordonnées du rectangle autour de la personne.

Dans ce projet, nous allons utiliser YOLOv4-tiny. C’est une version allégée de YOLOv4, plus rapide et plus adaptée aux ordinateurs peu puissants.

Schéma deep learning — réseau de neurones convolutif


Installation de l’environnement

Installer Python depuis le site officiel :

https://www.python.org/downloads/

Logo Python

Ensuite, ouvrez un terminal dans le dossier du projet et installez les bibliothèques nécessaires :

python -m pip install --upgrade pip
python -m pip install opencv-python
python -m pip install numpy

Votre dossier de projet doit ressembler à ceci :

Detection-YOLO/
├── main.py
├── coco.names
├── yolov4-tiny.cfg
└── yolov4-tiny.weights

Code Python commenté

# Importe le module time pour calculer le nombre d'images par seconde (FPS)
import time

# Importe OpenCV, la bibliothèque utilisée pour la webcam et le traitement d'image
import cv2

# Importe NumPy, utilisé ici pour trouver la classe ayant le meilleur score
import numpy as np


# Seuil minimum de confiance pour accepter une détection
CONFIDENCE_THRESHOLD = 0.5

# Seuil utilisé pour supprimer les rectangles en double
NMS_THRESHOLD = 0.4


# Chemin vers le fichier de configuration du modèle YOLOv4-tiny
MODEL_CONFIG = "yolov4-tiny.cfg"

# Chemin vers le fichier contenant les poids entraînés du modèle
MODEL_WEIGHTS = "yolov4-tiny.weights"

# Chemin vers le fichier contenant les noms des classes détectables
CLASS_NAMES_FILE = "coco.names"


def load_model():
    with open(CLASS_NAMES_FILE, "r", encoding="utf-8") as file:
        class_names = [line.strip() for line in file if line.strip()]

    network = cv2.dnn.readNetFromDarknet(MODEL_CONFIG, MODEL_WEIGHTS)
    network.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
    network.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
    output_layers = network.getUnconnectedOutLayersNames()

    return network, output_layers, class_names


def main():
    network, output_layers, class_names = load_model()

    camera = cv2.VideoCapture(0)
    camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    camera.set(cv2.CAP_PROP_BUFFERSIZE, 1)

    if not camera.isOpened():
        raise RuntimeError("Impossible d'ouvrir la caméra.")

    previous_time = time.time()

    while True:
        success, frame = camera.read()
        if not success:
            print("Impossible de lire une image.")
            break

        height, width = frame.shape[:2]

        blob = cv2.dnn.blobFromImage(
            frame,
            scalefactor=1 / 255.0,
            size=(416, 416),
            swapRB=True,
            crop=False,
        )

        network.setInput(blob)
        predictions = network.forward(output_layers)

        boxes = []
        confidences = []
        class_ids = []

        for output in predictions:
            for detection in output:
                scores = detection[5:]
                class_id = int(np.argmax(scores))
                confidence = float(scores[class_id])

                if confidence < CONFIDENCE_THRESHOLD:
                    continue

                center_x = int(detection[0] * width)
                center_y = int(detection[1] * height)
                box_width = int(detection[2] * width)
                box_height = int(detection[3] * height)
                x = center_x - box_width // 2
                y = center_y - box_height // 2

                boxes.append([x, y, box_width, box_height])
                confidences.append(confidence)
                class_ids.append(class_id)

        selected_indices = cv2.dnn.NMSBoxes(
            boxes, confidences, CONFIDENCE_THRESHOLD, NMS_THRESHOLD,
        )

        for index in selected_indices:
            index = int(index)
            x, y, box_width, box_height = boxes[index]
            confidence = confidences[index]
            class_id = class_ids[index]

            x = max(0, x)
            y = max(0, y)

            label = class_names[class_id]
            text = f"{label} : {confidence * 100:.1f}%"

            cv2.rectangle(
                frame,
                (x, y),
                (x + box_width, y + box_height),
                (0, 255, 0),
                2,
            )

            cv2.putText(
                frame, text, (x, max(25, y - 10)),
                cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2,
            )

        current_time = time.time()
        fps = 1 / max(current_time - previous_time, 0.001)
        previous_time = current_time

        cv2.putText(
            frame, f"FPS : {fps:.1f}", (10, 30),
            cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2,
        )

        cv2.imshow("Détection d'objets", frame)

        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

    camera.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

Test

Une fois le programme lancé, une fenêtre s’ouvre avec le retour vidéo de la webcam.

Placez différents objets devant la caméra :

  • une personne ;
  • une bouteille ;
  • une tasse ;
  • un téléphone ;
  • une chaise ;
  • un livre ;
  • un ballon.

Si l’objet fait partie des classes connues du dataset COCO, YOLO affichera un rectangle autour de lui avec son nom et un pourcentage de confiance.


Problèmes fréquents

La webcam ne s’ouvre pas

Essayez de remplacer :

camera = cv2.VideoCapture(0)

par :

camera = cv2.VideoCapture(1)

Sous Windows, vous pouvez aussi essayer :

camera = cv2.VideoCapture(0, cv2.CAP_DSHOW)

Le programme est lent

YOLOv4-tiny est plus léger que YOLOv4, mais la détection peut rester lente sur certains ordinateurs.

Vous pouvez améliorer les performances en :

  • réduisant la résolution de la webcam ;
  • fermant les autres applications ;
  • utilisant un modèle plus léger ;
  • utilisant une carte graphique compatible si votre installation le permet.

L’objet n’est pas détecté

Le modèle utilisé ici est entraîné sur le dataset COCO. Il ne peut reconnaître que les classes présentes dans ce dataset.

Par exemple, il peut détecter :

  • person, car, dog, cat, bottle, chair, laptop, cell phone…

Il ne pourra pas reconnaître un objet personnalisé sans entraînement dédié.


Conclusion

Dans ce tutoriel, nous avons vu comment utiliser OpenCV et YOLOv4-tiny pour détecter des objets en temps réel avec une webcam.

Ce projet est une excellente introduction à la vision par ordinateur. Il permet de comprendre les bases nécessaires avant de passer à des projets plus avancés comme :

  • la détection d’objets personnalisés ;
  • la reconnaissance d’animaux ;
  • la détection embarquée sur Raspberry Pi ;
  • la vision par drone ;
  • la détection de requins pour le projet Shark Sentinel.

Dans un prochain article, nous irons plus loin en entraînant notre propre modèle YOLO pour détecter des objets personnalisés en temps réel.


Fichiers à télécharger


Références