Pour implémenter une détection robuste de couleurs sur des microcontrôleurs embarqués, le framework MaixPy — basé sur MicroPython et conçu pour les puces Kendryte K210 — offre des primitives optimisées via la bibliothèque image. Contrairement aux approches classiques utilisant OpenCV sur PC, MaixPy opère directement dans l’espace LAB, mieux adapté à la vision embarquée sous contraintes de ressources.
Espace colorimétrique LAB : pourquoi privilégier LAB plutôt que HSV ou RGB ?
L’espace LAB (CIELAB) est perceptuellement uniforme : des écarts égaux entre valeurs L*, a* et b* correspondent approximativement à des différences visuelles similaires pour l’œil humain. Il est aussi indépendant du dispositif — ce qui garantit une cohérence de détection quel que soit l’éclairage ou le capteur utilisé — et ne dépend ni de la luminosité ambiante ni des caractéristiques spectrales de l’affichage.
- L* : canal de luminance, de 0 (noir) à 100 (blanc)
- a* : axe vert-rouge, typiquement borné entre −128 et +127
- b* : axe bleu-jaune, également borné entre −128 et +127
Principe de détection par seuillage chromatique
La méthode repose sur la fonciton find_blobs(), qui extrait des régions connexes homogènes selon un seuil défini sur les trois canaux LAB. Chaque seuil est spécifié sous forme d’un tuple à six éléments : (L_min, L_max, a_min, a_max, b_min, b_max). Le système applique alors un masque binaire où seuls les pixels respectant simultanément les trois plages sont conservés.
Calibration interactive des seuils
Avant toute implémentation, il est essentiel de calibrer les seuils dans des conditions réelles (éclairage, distance, angle). L’IDE MaixPy fournit un outil intégré « Thrsehold Editor » permettant d’ajuster dynamiquement les six curseurs tout en visualisant l’image binaire résultante. Cette étape est critique : une marge trop large introduit du bruit ; trop étroite rend la détection instable face aux variations lumineuses.
Exemples pratiques avec code réécrit
Les exemples suivants ont été entièrement refactorisés : noms de variables cohérents, gestion robuste des blobs absents, initialisation explicite des paramètres de capteur, et suppression des appels redondants.
Détection d’un objet rouge
import sensor, image, lcd, time
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
# Seuil LAB calibré pour le rouge (lumière naturelle diffusée)
RED_REGION = (48, 72, 36, 68, 45, 12)
while True:
frame = sensor.snapshot()
targets = frame.find_blobs([RED_REGION], pixels_threshold=20, area_threshold=20)
for obj in targets:
frame.draw_rectangle(obj.rect(), color=(255, 0, 0), thickness=2)
frame.draw_cross(obj.cx(), obj.cy(), color=(255, 0, 0), size=10)
lcd.display(frame)
Détection d’un objet vert
import sensor, image, lcd, time
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
# Seuil LAB calibré pour le vert (fond neutre, lumière indirecte)
GREEN_REGION = (-12, 85, -52, -2, -20, 15)
while True:
frame = sensor.snapshot()
candidates = frame.find_blobs([GREEN_REGION], pixels_threshold=25, area_threshold=25)
for region in candidates:
x, y, w, h = region.rect()
frame.draw_rectangle(x, y, w, h, color=(0, 255, 0), thickness=2)
frame.draw_cross(region.cx(), region.cy(), color=(0, 255, 0), size=8)
lcd.display(frame)
Détection multi-couleur (rouge + vert + bleu)
import sensor, image, lcd, time
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
# Trois seuils distincts pour trois couleurs
COLOR_RANGES = [
(48, 72, 36, 68, 45, 12), # Rouge
(-12, 85, -52, -2, -20, 15), # Vert
(-128, 30, -128, -20, -128, -40) # Bleu
]
while True:
img = sensor.snapshot()
all_blobs = img.find_blobs(COLOR_RANGES, pixels_threshold=15, area_threshold=15)
for blob in all_blobs:
# Couleur du cadre selon la classe détectée (approximation heuristique)
if blob.code() == 1:
color = (255, 0, 0) # Rouge
elif blob.code() == 2:
color = (0, 255, 0) # Vert
else:
color = (0, 120, 255) # Bleu
img.draw_rectangle(blob.rect(), color=color, thickness=2)
img.draw_cross(blob.cx(), blob.cy(), color=color, size=6)
lcd.display(img)
Optimisations recommandées
- Utiliser
pixels_thresholdetarea_thresholdpour filtrer les petits artefacts - Appeler
sensor.skip_frames()après la configuration pour stabiliser l’exposition - Éviter les appels répétés à
img.get_pixel()dans la boucle principale — privilégier les propriétés natives commeblob.cx(),blob.cy(),blob.pixels() - Préférer
blob.code()plutôt qu’une comparaison manuelle des seuils pour identifier la couleur dans les cas multi-région
Limitations et bonnes pratiques
La détection LAB est sensible aux ombres portées et aux reflets directs. Pour des applications industrielles, on recommande :
- L’éclairage contrôlé (LEDs monochromes ou diffuseurs)
- La normalisation de luminance via
img.lens_corr()ou prétraitement adaptatif - Le filtrage temporel (moyenne glissante sur les coordonnées des blobs sur plusieurs trames)
- L’intégration d’un modèle de suivi (ex. : algorithme de Kalman simplifié) pour lisser les trajectoires