Suivi d'objets automatisé par vision avec Raspberry Pi et OpenCV
Histoire
Introduction
Dans le tutoriel précédent, nous avons appris à contrôler un servo pan/tilt pour positionner une caméra Raspberry Pi. Aujourd'hui, nous étendrons cette configuration pour que la caméra puisse suivre automatiquement un objet coloré.
C'est ma première expérience pratique avec OpenCV, et je suis déjà enchanté par cette bibliothèque open-source de vision par ordinateur.
OpenCV est gratuit pour usage académique et commercial, offre des interfaces C++, C, Python et Java, et fonctionne sur Windows, Linux, macOS, iOS et Android. Dans cette série, nous nous concentrerons sur le Raspberry Pi (Raspbian) et Python, car OpenCV est conçu pour l'efficacité computationnelle et les applications temps réel — exactement ce dont vous avez besoin pour les projets de calcul physique.
Étape 1 : Liste du matériel (BOM)
Pièces principales :
- Raspberry Pi V3 – 32,00 $US
- Module caméra vidéo mini 5 MP 1080p OV5647 – 13,00 $US
- Servo micro TowerPro SG90 9G 180° (×2) – 4,00 $US
- Plateforme pan/tilt anti-vibration mini avec 2 servos (*) – 8,00 $US
- LED rouge
- Résistance 220 Ω
- Résistance 1 kΩ (×2) – Optionnel
- Divers : pièces métalliques, bandes, etc. (si vous construisez votre propre mécanisme pan/tilt)
(*) Vous pouvez acheter une plateforme pan/tilt complète avec servos ou construire la vôtre.
Étape 2 : Installation d'OpenCV 3
Sur un Raspberry Pi V3 sous le dernier Raspbian Stretch, la méthode la plus fiable est de suivre le tutoriel d'Adrian Rosebrock (Raspbian Stretch : Installer OpenCV 3 + Python sur votre Raspberry Pi). Il vous guide dans la compilation d'OpenCV depuis les sources et configure un environnement virtuel Python dédié.
Après avoir complété le tutoriel, activez l'environnement virtuel et confirmez l'installation :
source ~/.profile
workon cv
python
import cv2
print(cv2.__version__)
Vous devriez voir la version 3.3.0 ou plus récente. La sortie confirme qu'OpenCV est prêt à l'emploi dans l'environnement virtuel cv.
Étape 3 : Test de votre caméra
Avec OpenCV installé, vérifiez que le PiCamera diffuse correctement. Exécutez le script suivant (ou téléchargez simpleCamTest.py) :
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, -1) # Retourner verticalement si nécessaire
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Appuyez sur q ou Ctrl+C pour quitter. Une exécution réussie affiche les flux couleur et niveaux de gris.
Étape 4 : Détection de couleur avec OpenCV
OpenCV travaille dans l'espace HSV (Teinte, Saturation, Valeur), qui s'aligne mieux avec la perception des couleurs humaine. Pour détecter une couleur spécifique, déterminez d'abord ses valeurs BGR, convertissez en HSV et établissez des bornes inférieures/supérieures.
Exemple : Suivi d'un objet jaune. En utilisant un sélecteur de couleur (ex: PowerPoint), vous avez trouvé les valeurs BGR (71, 234, 213). Convertissez-les en HSV avec le script ci-dessous (ou téléchargez bgr_hsv_converter.py) :
import sys, numpy as np, cv2
blue, green, red = int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])
color = np.uint8([[[blue, green, red]]])
hsv = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)
hue = hsv[0][0][0]
print('Borne inférieure:', [hue-10, 100, 100])
print('Borne supérieure:', [hue+10, 255, 255])
L'exécution de python bgr_hsv_converter.py 71 234 213 affiche :
Borne inférieure: [24, 100, 100] Borne supérieure: [44, 255, 255]
Utilisez ces bornes pour masquer la couleur dans une image :
import cv2, numpy as np
img = cv2.imread('yellow_object.JPG', 1)
img = cv2.resize(img, (0,0), fx=0.2, fy=0.2)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([24, 100, 100], dtype=np.uint8)
upper = np.array([44, 255, 255], dtype=np.uint8)
mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('mask', mask)
cv2.imshow('image', img)
while True:
k = cv2.waitKey(0)
if k == 27:
break
cv2.destroyAllWindows()
Enregistrez le script sous colorDetection.py et exécutez python colorDetection.py (assurez-vous que l'image est dans le même répertoire).
Étape 5 : Suivi d'objets en temps réel
En s'appuyant sur le masque, nous pouvons suivre le centroïde de l'objet image par image. Le code ci-dessous s'inspire du tutoriel Ball Tracking d'Adrian Rosebrock et incorpore les bornes HSV définies précédemment.
Assurez-vous d'abord que la bibliothèque imutils est installée :
pip install imutils
Puis exécutez ball_tracking.py :
python ball_tracking.py
Le script retourne l'image verticalement (si nécessaire) et applique le masque. Lorsque l'objet est détecté, un cercle et le centroïde sont dessinés.
Étape 6 : Test des GPIOs
Ajoutons maintenant une LED rouge au Pi et confirmons que nous pouvons la contrôler via GPIO.
Câblage : Connectez la cathode de la LED au GPIO 21, l'anode à la masse via une résistance 220 Ω.
Si RPi.GPIO n'est pas encore installé dans l'environnement cv, installez-le :
pip install RPi.GPIO
Script de test (LED_simple_test.py) :
import sys, time, RPi.GPIO as GPIO
led = int(sys.argv[1])
freq = int(sys.argv[2])
GPIO.setmode(GPIO.BCM)
GPIO.setup(led, GPIO.OUT)
GPIO.setwarnings(False)
print(f'Clignotement LED sur GPIO {led} toutes les {freq}s, 5 fois.')
for _ in range(5):
GPIO.output(led, GPIO.LOW)
time.sleep(freq)
GPIO.output(led, GPIO.HIGH)
time.sleep(freq)
GPIO.cleanup()
Exécutez avec python LED_simple_test.py 21 1 pour faire clignoter la LED cinq fois par seconde.
Étape 7 : Reconnaissance de couleur & interaction GPIO
Combinez la logique de suivi avec le contrôle GPIO pour que la LED s'allume chaque fois que la couleur cible est détectée. Les ajouts principaux sont :
import RPi.GPIO as GPIO
led = 21
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led, GPIO.OUT)
GPIO.output(led, GPIO.LOW)
ledOn = False
À l'intérieur de la boucle de détection, après confirmation d'un rayon valide, ajoutez :
if not ledOn:
GPIO.output(led, GPIO.HIGH)
ledOn = True
Script complet : object_detection_LED.py. Exécutez avec python object_detection_LED.py. La LED s'allume uniquement lorsque la couleur de l'objet tombe dans les bornes HSV.
Étape 8 : Le mécanisme Pan/Tilt
Avec OpenCV et GPIO fonctionnels, connectez les servos à une alimentation externe 5 V. Câblez les broches de données comme suit :
- GPIO 17 → Servo Tilt
- GPIO 27 → Servo Pan
Partagez la masse entre le Pi, les servos et l'alimentation. Optionnellement, placez une résistance 1 kΩ en série entre la broche GPIO du Pi et la broche de données du servo pour protéger le Pi des pics de courant.
Testez le contrôle des servos avec angleServoCtrl.py :
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
def setServoAngle(servo, angle):
pwm = GPIO.PWM(servo, 50)
pwm.start(8)
duty = angle / 18. + 3.
pwm.ChangeDutyCycle(duty)
sleep(0.3)
pwm.stop()
if __name__ == '__main__':
import sys
servo = int(sys.argv[1])
GPIO.setup(servo, GPIO.OUT)
setServoAngle(servo, int(sys.argv[2]))
GPIO.cleanup()
Exemple : python angleServoCtrl.py 17 45 bouge le servo tilt à 45°.
Étape 9 : Détermination de la position temps réel de l'objet
Pour centrer la caméra sur la cible, nous avons d'abord besoin des coordonnées du centroïde de l'objet. Modifiez objectDetect_LED.py pour afficher les valeurs x et y :
def mapObjectPosition(x, y):
print(f'[INFO] Centre objet à X={x}, Y={y}')
Les coordonnées varient de 0–500 (gauche à droite) pour x et 0–350 (haut en bas) pour y. Déplacez l'objet et observez la sortie en direct.
Étape 10 : Système de suivi de position d'objet
Définissez une région « centrée » (ex: 220 < x < 280 et 160 < y < 210). Si l'objet en sort, ajustez les servos pan et tilt en conséquence :
def mapServoPosition(x, y):
global panAngle, tiltAngle
if x < 220:
panAngle = min(panAngle + 10, 140)
positionServo(panServo, panAngle)
if x > 280:
panAngle = max(panAngle - 10, 40)
positionServo(panServo, panAngle)
if y < 160:
tiltAngle = min(tiltAngle + 10, 140)
positionServo(tiltServo, tiltAngle)
if y > 210:
tiltAngle = max(tiltAngle - 10, 40)
positionServo(tiltServo, tiltAngle)
La fonction auxiliaire positionServo(servo, angle) appelle simplement angleServoCtrl.py :
import os
def positionServo(servo, angle):
os.system(f'python angleServoCtrl.py {servo} {angle}')
print(f'[INFO] Positionnement servo GPIO {servo} à {angle}°')
Tous les scripts sont dans le même répertoire ; téléchargez l'implémentation complète depuis objectDetectTrack.py.
Étape 11 : Conclusion
Ce projet démontre comment combiner OpenCV, Raspberry Pi GPIO et un support servo pan-tilt pour créer un système de suivi d'objets colorés autonome. N'hésitez pas à expérimenter avec différentes couleurs, formes et vitesses de servo.
Code complet et ressources supplémentaires disponibles sur GitHub et le blog MJRoBot.org.
Merci de votre lecture — à bientôt pour le prochain tutoriel !
Processus de fabrication
- Maîtriser la programmation orientée objet Python : classes, héritage, encapsulation et polymorphisme
- Suivi avancé de balle de ping-pong sur Raspberry Pi avec OpenCV
- Speathe : Communication pilotée par la respiration pour utilisateurs paralysés
- Reconnaissance faciale en temps réel sur Raspberry Pi – Guide complet
- Maîtriser la programmation orientée objet en Python : Guide complet
- Mesure de la précision du suivi d'objets dynamiques dans les systèmes de capture de mouvement
- Nouveau filtre améliore la vision robotique pour estimation de pose 6D précise
- Comprendre les presses automatiques : fonctionnement, avantages et applications
- Comprendre les presses à puissance automatiques : caractéristiques, avantages et applications