Détection d'objets avec YOLO
Place à l’apprentissage profond : YOLO (You Only Look Once) localise et classe plusieurs objets en une seule passe. Vous l’utiliserez d’abord pré-entraîné, puis vous l’entraînerez sur vos propres objets grâce à un dataset généré dans la simulation.
Partie A — YOLO pré-entraîné (baseline)
Section intitulée « Partie A — YOLO pré-entraîné (baseline) »0. Installer ultralytics
Section intitulée « 0. Installer ultralytics »pip install ultralytics # tire torch/torchvision automatiquement1. Inférence sur une image
Section intitulée « 1. Inférence sur une image »Un modèle pré-entraîné sur COCO (80 classes courantes : person, bottle, cup…)
se charge en une ligne :
from ultralytics import YOLO
model = YOLO("yolo11n.pt") # téléchargé automatiquement au 1er appelresults = model("capture.png") # inférenceresults[0].show() # affiche l'image annotéeLancez le monde et faites apparaître un objet « réaliste » que COCO connaît
(trash_bottle → classe bottle) :
ros2 launch bootcamp_vision vision_world.launch.pyros2 launch bootcamp_vision spawn_object.launch.py object_type:=yolo2. Lire les résultats
Section intitulée « 2. Lire les résultats »Chaque détection expose sa classe, son score et sa boîte (xyxy) :
for box in results[0].boxes: cls = model.names[int(box.cls)] # ex. "bottle" conf = float(box.conf) # score de confiance x1, y1, x2, y2 = box.xyxy[0].tolist() print(f"{cls} ({conf:.2f}) — bbox=({x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f})")Partie B — Entraîner YOLO sur vos objets
Section intitulée « Partie B — Entraîner YOLO sur vos objets »3. Générer un dataset… dans la simulation
Section intitulée « 3. Générer un dataset… dans la simulation »Entraîner un détecteur demande beaucoup d’images annotées (objet + boîte + classe). Les annoter à la main est fastidieux. L’atout de la simulation : on connaît la position des objets, donc on peut générer ET labelliser automatiquement des milliers d’images en variant la pose, l’éclairage et les distracteurs (domain randomization).
bootcamp_vision fournit un outil qui fait exactement cela :
# Génère un dataset YOLO auto-labellisé pour 5 classes, 300 images chacuneros2 run bootcamp_vision capture_dataset \ --classes coffee_pack_1 coffee_pack_2 coffee_pack_3 trash_bottle trash_can \ --per-class 300 --out ~/yolo_ds --val-split 0.2→ Vous obtenez une arborescence au format ultralytics :
~/yolo_ds/ images/train/ images/val/ # les .png capturés labels/train/ labels/val/ # un .txt YOLO par image (classe + bbox normalisée) data.yaml # noms de classes + chemins4. Lancer l’entraînement
Section intitulée « 4. Lancer l’entraînement »yolo detect train model=yolo11n.pt data=~/yolo_ds/data.yaml epochs=30 imgsz=640YOLO part du modèle pré-entraîné (transfer learning) et l’adapte à vos classes. Les
poids du meilleur modèle sont sauvegardés dans
runs/detect/train/weights/best.pt.
5. Tester votre modèle
Section intitulée « 5. Tester votre modèle »model = YOLO("runs/detect/train/weights/best.pt")results = model("capture.png")results[0].show()Spawnez un coffee_pack_2 et vérifiez que votre modèle le détecte alors que le
modèle COCO en était incapable.
Partie C — Nœud ROS 2 /detections
Section intitulée « Partie C — Nœud ROS 2 /detections »On réutilise le squelette du
socle commun. Le modèle est
chargé une fois dans le constructeur ; à chaque image, on ajoute une Detection par
boîte (make_det y est défini). YOLO fournit directement la classe, le score et la boîte.
from ultralytics import YOLO# ... (imports rclpy / Node / Image / Point / cv_bridge / Detection, DetectionArray)
class YoloDetector(Node): def __init__(self): super().__init__("yolo_detector") self.bridge = CvBridge() self.model = YOLO("best.pt") # votre modèle entraîné (ou "yolo11n.pt") self.pub = self.create_publisher(DetectionArray, "/detections", 10) self.create_subscription(Image, "/camera/image_raw", self.on_image, 10)
def on_image(self, msg): frame = self.bridge.imgmsg_to_cv2(msg, "bgr8") out = DetectionArray() out.header = msg.header for box in self.model(frame, verbose=False)[0].boxes: if float(box.conf) < 0.5: continue x1, y1, x2, y2 = box.xyxy[0].tolist() u, v = (x1 + x2) / 2, (y1 + y2) / 2 # centre de la boîte w, h = x2 - x1, y2 - y1 out.detections.append(self.make_det( self.model.names[int(box.cls)], int(box.cls), float(box.conf), u, v, w, h)) self.pub.publish(out)ros2 run mon_projet_vision yolo_detectorros2 topic echo /detections # class_name = label, pose.position = centre back-projetéPour aller plus loin
Section intitulée « Pour aller plus loin »- Augmentez
--per-classet le nombre d’epochs, comparez la précision obtenue. - Ajoutez des distracteurs lors de la capture et observez l’effet sur la robustesse.
- Envie d’entraîner un réseau de zéro ? Tentez l’atelier Chiffres (CNN). Sans IA : Formes ou ArUco.
Cours conçu et animé par Etienne Schmitz