Détection de couleurs en temps réel avec MaixPy sur cartes K210

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_threshold et area_threshold pour 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 comme blob.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

Étiquettes: maixpy k210 lab-color-space micro-python Computer-Vision

Publié le 25 septembre à 21h26