Caméra événementielle multispectrale

Le module de caméra événementielle multispectrale associe le capteur événementiel GENX320 à un capteur couleur global-shutter PAG7936 de 1 MP sur un seul module — un pipeline événementiel + couleur synchronisé pour le suivi d’objets à haute vitesse, le suivi de LED, l’écoulement de fluides et d’autres scènes dynamiques.

Caméra événementielle multispectrale

Pour la fiche technique complète, les photos et les informations de commande, consultez la page produit de la caméra événementielle multispectrale.

Note

Pris en charge uniquement sur l’OpenMV N6.

Points forts

  • Capteur événementiel 320x320, plage dynamique >140 dB, histogrammes à 375 Hz et plus

  • Couleur PAG7936 : 1280x800 à 120 FPS, 640x400 à 240 FPS

  • Horodatages d’événements synchronisés avec déclencheur d’exposition partagé

  • Voit en dessous de 5 lux sans exposition automatique

  • La consommation démarre à environ 3 mW pour le streaming d’événements

  • Conçu pour le suivi à haute vitesse, le suivi de LED et l’écoulement de fluides/particules

Utilisation

Le capteur couleur et le capteur événementiel GENX320 disposent chacun de leur propre instance csi.CSI. Le premier appel cible par défaut le capteur principal (le PAG7936) ; le second se lie au GENX320 en passant cid= csi.GENX320. Effectuez une réinitialisation matérielle du capteur couleur avec csi.CSI.reset (hard=True) pour activer son alimentation, et configurez le GENX320 avec hard=False afin que son pilote se contente de reprogrammer la puce sans réactiver le reset.

Le GENX320 produit du 320x320 en mode histogramme ; le PAG7936 en csi.QVGA produit du 320x200. La superposition basique ci-dessous tronque les 120 dernières lignes de la trame GENX320. Utilisez la transformation par homographie (ci-dessous) pour une superposition ajustée ou une taille de trame PAG7936 plus grande.

Deux tampons de travail restent constants tout au long de la boucle de traitement des trames — une palette alpha 256x1 stockée sous forme d”image.Image afin que les pixels d’histogramme à la valeur de référence gris moyen (128) deviennent transparents tandis que les surbrillances des événements ON et les ombres des événements OFF deviennent opaques, et un tampon d’image GENX320 pré-alloué avec image.Image afin que csi.CSI.snapshot (blocking=False, image=...) puisse le remplir sur place à chaque itération sans réallocation:

import time
import csi
import image
import math

# V-shaped alpha: pixels far from the baseline 128 become opaque.
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
    alpha_pal[i] = int(math.pow(abs(i - 128) / 128.0, 2) * 255)

# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True)  # force hardware reset.
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)

csi1 = csi.CSI(cid=csi.GENX320)
csi1.reset(hard=False)  # no hardware reset - just configure GENX320
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize((320, 320))
csi1.brightness(128)  # histogram baseline (default)
csi1.contrast(64)     # per-event step

clock = time.clock()

img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())

while True:
    clock.tick()
    img0 = csi0.snapshot()
    csi1.snapshot(blocking=False, image=img1)
    img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_EVT_LIGHT,
                    alpha_palette=alpha_pal,
                    hint=image.BILINEAR)
    print(clock.fps())

Chaque itération effectue une capture couleur bloquante et une capture GENX320 non bloquante. Image.draw_image compose ensuite les deux : color_palette= image.PALETTE_EVT_LIGHT (ou image.PALETTE_EVT_DARK pour un fond sombre) mappe l’histogramme en niveaux de gris du GENX320 sur une rampe de couleurs, alpha_palette= mélange chaque pixel à l’aide de la carte alpha en forme de V de sorte que les régions calmes de la scène laissent transparaître l’image couleur, et hint= image.BILINEAR lisse l’agrandissement lorsque le capteur couleur fonctionne à une résolution plus élevée que le GENX320.

Les présélections de biais, le filtre AFK, l’étalonnage des pixels chauds et les ioctls du filtre STC du GENX320 fonctionnent tous de la même manière dans cette configuration à deux caméras — appelez-les sur csi1 après csi.CSI.reset. Consultez les sections ci-dessous pour plus de détails.

Alignement accéléré par GPU

Image.draw_image accepte un argument transform= — une matrice d’homographie 3x3 sous forme de tableau ulab.numpy 2-D. Sur l’OpenMV N6, le GPU exécute la projection par pixel pendant le même tracé, de sorte que la trame GENX320 peut être réalignée sur la perspective de la caméra couleur sans passe de déformation séparée — utile lorsque les deux capteurs ont des optiques ou des champs de vision légèrement différents, ou lorsque la caméra couleur fonctionne à une résolution plus élevée. Étalonnez la matrice pour chaque caméra avec l”outil d’étalonnage de superposition GenX320, qui affiche un damier clignotant afin que le capteur événementiel produise des événements de coin sans aucun mouvement physique:

import time
import csi
import image
from ulab import numpy as np
import math

# Calibration matrix from the GenX320 Overlay Calibration tool.
m = np.array([
    [2.000000, 0.000000,   0.000000],
    [0.000000, 2.000000,  80.000000],
    [0.000000, 0.000000,   1.000000],
])

alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
    alpha_pal[i] = int(math.pow(abs(i - 128) / 128.0, 2) * 255)

# Setup the color camera sensor.
csi0 = csi.CSI()
csi0.reset(hard=True)
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)

csi1 = csi.CSI(cid=csi.GENX320)
csi1.reset(hard=False)
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize((320, 320))
csi1.brightness(128)
csi1.contrast(64)

clock = time.clock()

img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())

while True:
    clock.tick()
    img0 = csi0.snapshot()
    csi1.snapshot(blocking=False, image=img1)
    img0.draw_image(img1, 0, 0, color_palette=image.PALETTE_EVT_LIGHT,
                    alpha_palette=alpha_pal,
                    hint=image.BILINEAR,
                    transform=m)
    print(clock.fps())

Cette variante fait fonctionner la caméra couleur en csi.VGA (640x480) et le GENX320 à sa résolution native 320x320 — l’homographie projette la plus petite trame GENX320 dans la plus grande trame couleur dans le cadre du tracé, de sorte que le facteur d’agrandissement est intégré à la matrice elle-même plutôt qu’appliqué séparément.

Détails de la caméra événementielle

Le GENX320 est un capteur de vision événementiel — au lieu de lire l’ensemble du tableau 320x320 selon une horloge de trame fixe, chaque pixel signale des « événements » asynchrones dès qu’il détecte un changement de luminosité. Chaque événement porte une coordonnée X/Y, une polarité ON/OFF (clair→sombre ou sombre→clair) et un horodatage à la microseconde. C’est de là que proviennent la précision temporelle à la microseconde du capteur, l’absence de flou de mouvement, sa très haute plage dynamique et sa consommation proportionnelle à l’activité. Les scènes statiques ne génèrent aucune donnée.

Le micrologiciel OpenMV expose le GENX320 via csi.CSI avec cid= csi.GENX320. Deux modes de fonctionnement sont disponibles :

  • Mode histogramme (par défaut) — les événements sont accumulés sur la puce dans des bacs par pixel et rapportés sous forme de trame 320x320 en niveaux de gris à une cadence configurable (~20-350 FPS). Le capteur se comporte comme une caméra ordinaire, de sorte que toutes les routines standard de traitement d’image (Image.find_blobs, palettes, etc.) fonctionnent directement.

  • Mode événementiel — les événements bruts sont diffusés dans un ndarray numpy avec des horodatages complets à la microseconde, pour les applications qui ont besoin du détail temporel plutôt que d’une trame pré-classée.

Mode histogramme

En mode histogramme, le GENX320 produit des trames en niveaux de gris où chaque pixel encode l’activité événementielle récente à cet emplacement. Les pixels au-dessus de la référence de luminosité sont des événements ON (luminosité en hausse), ceux en dessous sont des événements OFF (luminosité en baisse). La référence de luminosité par défaut est 128 et le pas de contraste par événement est de 16 — augmentez le contraste pour faire ressortir les événements:

import csi
import time

csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize((320, 320))
csi0.brightness(128)  # baseline (default 128)
csi0.contrast(16)     # per-event step
csi0.framerate(50)    # 20-350 FPS

clock = time.clock()
while True:
    clock.tick()
    img = csi0.snapshot()
    print(clock.fps())

csi.CSI.brightness, csi.CSI.contrast et csi.CSI.framerate sont les trois réglages qui façonnent la sortie de l’histogramme.

Sortie colorisée

Réglez csi.CSI.color_palette sur image.PALETTE_EVT_LIGHT pour un fond clair ou image.PALETTE_EVT_DARK pour un fond sombre — le pilote émet des trames RGB565 en utilisant directement la palette:

csi0.color_palette(image.PALETTE_EVT_LIGHT)

Étalonnage des pixels chauds

Les capteurs événementiels accumulent des « pixels chauds » qui se déclenchent de façon parasite. Exécutez csi.IOCTL_GENX320_CALIBRATE sur une scène statique pour les désactiver. Le pilote construit un comptage de déclenchements par pixel en 320x320, calcule la moyenne et l’écart-type, et désactive tout pixel dont le comptage est supérieur à mean + sigma * stddev — les pixels désactivés cessent alors d’émettre des événements au niveau du capteur.

Deux paramètres contrôlent l’étalonnage :

  • event_count — combien d’événements comptabiliser avant de calculer les statistiques. La boucle capture des trames jusqu’à ce que le total cumulé d’événements dépasse ce budget. Des comptages plus élevés donnent une estimation plus fiable au prix d’un temps d’étalonnage plus long. 10000 est un bon point de départ.

  • sigma — multiplicateur de seuil sur l’écart-type. Des valeurs plus faibles sont plus agressives (plus de pixels désactivés) ; des valeurs plus élevées sont plus conservatrices. 0.5 est une bonne valeur par défaut.

Pointez d’abord le capteur vers une scène statique afin que les événements dus à un mouvement ne soient pas comptés à l’encontre de pixels qui sont en réalité corrects:

csi0.snapshot(time=5000)  # let the user steady the camera
disabled = csi0.ioctl(csi.IOCTL_GENX320_CALIBRATE, 10000, 0.5)
print(f"disabled {disabled} hot pixels")

Filtre anti-scintillement (AFK)

Les sources lumineuses périodiques (tubes fluorescents, écrans à LED) génèrent d’énormes volumes d’événements redondants. Le filtre AFK rejette les événements dont le pixel bascule à une fréquence située dans une bande — activez-le via csi.IOCTL_GENX320_SET_AFK avec les bornes de bande en hertz:

csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 1, 130, 160)  # 130-160 Hz
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 0)            # disable

Présélections de biais

Chaque pixel du GenX320 dispose d’un étage analogique d’entrée comportant plusieurs biais configurables. Ils régissent conjointement la sensibilité, le bruit, la bande passante du pixel et le taux d’événements — la bonne combinaison dépend de la scène. Les biais individuels sont :

  • DIFF_ON — le seuil de contraste du comparateur positif. Un pixel émet un événement ON lorsque son log-éclairement a augmenté de cette valeur. Plus bas = plus sensible aux transitions vers le clair.

  • DIFF_OFF — le seuil de contraste du comparateur négatif (l’équivalent symétrique pour les événements OFF). Plus bas = plus sensible aux transitions vers le sombre.

  • FO — la fréquence de coupure passe-bas du pixel. Plus haute = bande passante du pixel plus large (réponse plus rapide, latence plus faible) mais plus d’activité due au bruit de fond.

  • HPF — la fréquence de coupure passe-haut. Plus haute = rejet plus marqué des changements lents de luminosité ; seules les transitions rapides atteignent les comparateurs. Utile pour ignorer la dérive ambiante.

  • REFR — la période réfractaire. Après qu’un pixel s’est déclenché, il reste en reset pendant cette durée avant de pouvoir se déclencher à nouveau. Plus haute = temps mort plus long, utile pour plafonner le taux d’événements par pixel.

Après csi.CSI.reset, le pilote applique csi.GENX320_BIASES_LOW_NOISE, et non csi.GENX320_BIASES_DEFAULT — les valeurs par défaut de la fiche technique émettent un taux d’événements de fond bien plus élevé, c’est pourquoi LOW_NOISE est utilisé comme point de départ pour garder le flux silencieux. Appelez csi.IOCTL_GENX320_SET_BIASES avec une présélection différente lorsque l’application a besoin de plus de sensibilité ou de bande passante.

csi.IOCTL_GENX320_SET_BIASES applique l’une des cinq présélections :

  • csi.GENX320_BIASES_DEFAULT — valeurs par défaut de la fiche technique du GenX320. Sensibilité, bruit et bande passante équilibrés pour les scènes générales.

  • csi.GENX320_BIASES_LOW_LIGHT — les deux seuils de contraste sont assouplis pour une plus grande sensibilité, FO est abaissé pour limiter le bruit, et HPF est réglé sur 0 afin que les changements lents de luminosité soient quand même enregistrés — une scène en faible luminosité génère peu d’événements par elle-même, donc on veut en faire passer le plus possible.

  • csi.GENX320_BIASES_ACTIVE_MARKER — réglé pour le suivi de LED clignotantes à fort contraste. Seuils de contraste relevés afin que seules les transitions nettes déclenchent ; FO et HPF poussés au maximum pour maximiser la bande passante du pixel et rejeter toute dérive ambiante lente ; REFR ramené à 0 afin que chaque front de clignotement soit capturé sans interruption. Résultat : un flux constitué presque uniquement de fronts de LED, facile à suivre.

  • csi.GENX320_BIASES_LOW_NOISE — valeur par défaut du pilote. Les deux seuils de contraste sont relevés par rapport à DEFAULT (moins sensible) et FO est abaissé (pixel plus lent = pixel plus silencieux). Idéal pour les scènes statiques ou lentes où les faux événements domineraient autrement.

  • csi.GENX320_BIASES_HIGH_SPEED — FO augmenté afin que chaque pixel puisse répondre plus rapidement, HPF relevé pour rejeter la dérive lente de luminosité, et REFR relevé afin qu’un seul front en déplacement rapide n’inonde pas la lecture — le temps mort plus long maintient le volume d’événements borné en cas de mouvement intense.

Remplacez des biais individuels avec csi.IOCTL_GENX320_SET_BIAS accompagné de l’un de csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF ou csi.GENX320_BIAS_REFR et d’une valeur DAC. Chaque biais est réglé indépendamment — choisissez une présélection comme point de départ, puis ajustez les biais dont votre scène a besoin:

csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_LOW_LIGHT)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIAS, csi.GENX320_BIAS_HPF, 20)

Suivi

Comme la sortie en mode histogramme est simplement une image en niveaux de gris, le suivi de blobs classique fonctionne directement. Pour suivre une LED en mode marqueur actif, chargez la présélection de biais marqueur actif et recherchez des blobs à l’extrémité claire de l’histogramme:

import csi
import time

csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize((320, 320))
csi0.brightness(128)
csi0.contrast(16)
csi0.framerate(200)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_ACTIVE_MARKER)

clock = time.clock()
while True:
    clock.tick()
    img = csi0.snapshot()
    for blob in img.find_blobs([(120, 140)], invert=True,
                               pixels_threshold=2, area_threshold=4,
                               merge=True):
        img.draw_detection(blob)
    print(clock.fps())

Mode événementiel

Le mode événementiel contourne l’histogramme sur puce et diffuse les événements bruts dans un ndarray numpy. Chaque événement est une ligne de six colonnes uint16 :

  • [0] type d’événement — voir ci-dessous

  • [1] horodatage en secondes

  • [2] horodatage en millisecondes

  • [3] horodatage en microsecondes

  • [4] coordonnée X, 0-319

  • [5] coordonnée Y, 0-319

Le pilote émet six types d’événements dans la colonne [0] :

  • csi.PIX_OFF_EVENT — un pixel a détecté une baisse de luminosité (le seuil du comparateur DIFF_OFF a été franchi). X/Y pointent vers le pixel qui s’est déclenché.

  • csi.PIX_ON_EVENT — un pixel a détecté une hausse de luminosité (le seuil DIFF_ON a été franchi). X/Y pointent vers le pixel.

  • csi.EXT_TRIGGER_FALLING — la broche de déclenchement externe du capteur a vu un front descendant. X/Y sont inutilisés.

  • csi.EXT_TRIGGER_RISING — la broche de déclenchement externe du capteur a vu un front montant. X/Y sont inutilisés.

  • csi.RST_TRIGGER_FALLING — déclencheur de reset de pixel, front descendant. X/Y sont inutilisés. Non généré par le micrologiciel pour l’instant.

  • csi.RST_TRIGGER_RISING — déclencheur de reset de pixel, front montant. X/Y sont inutilisés. Non généré par le micrologiciel pour l’instant.

L’entrée de déclenchement externe du GENX320 est câblée à la ligne de synchronisation de trame de la caméra, qui est également routée vers P10 à la fois sur le processeur et sur le connecteur de broches — pilotez P10 pour injecter des fronts de synchronisation dans le flux d’événements et les récupérer en tant qu’événements EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING aux côtés des données de pixels.

La plupart des applications ne s’intéressent qu’à PIX_OFF_EVENT et PIX_ON_EVENT ; les types de déclenchement vous permettent de corréler les événements avec des signaux de synchronisation externes.

Allouez le tampon d’événements avec la forme (EVT_res, 6)EVT_res est une puissance de deux comprise entre 1024 et 65536, puis entrez en mode événementiel via csi.IOCTL_GENX320_SET_MODE avec csi.GENX320_MODE_EVENT et la taille du tampon. Lisez les événements avec csi.IOCTL_GENX320_READ_EVENTS, qui remplit le tampon jusqu’à sa capacité et renvoie le nombre de lignes valides.

Image.draw_event_histogram matricialise les événements en une image en niveaux de gris — pour chaque événement ON, il ajoute contrast au bac ; pour chaque événement OFF, il le soustrait. clear=True réinitialise d’abord l’image à brightness ; clear=False accumule sur de nombreux appels:

import csi
import image
import time
from ulab import numpy as np

img = image.Image(320, 320, image.GRAYSCALE)
events = np.zeros((2048, 6), dtype=np.uint16)

csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT, events.shape[0])

clock = time.clock()
while True:
    clock.tick()
    n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
    img.draw_event_histogram(events[:n], clear=True, brightness=128, contrast=64)
    img.flush()
    print(n, clock.fps())

Les présélections de biais du mode histogramme, le filtre AFK et les ioctls d’étalonnage des pixels chauds fonctionnent tous de la même manière en mode événementiel — appelez-les après csi.IOCTL_GENX320_SET_MODE.

Filtrage par polarité

Découpez le tableau des événements avec ulab pour ne conserver que les événements ON (mouvement vers un état plus clair) ou seulement les événements OFF:

TARGET = csi.PIX_ON_EVENT  # or csi.PIX_OFF_EVENT

events_slice = events[:n]
indices = np.nonzero(events_slice[:, 0] == TARGET)[0]
if len(indices):
    target_events = np.take(events_slice, indices, axis=0)
    img.draw_event_histogram(target_events, clear=True,
                             brightness=128, contrast=64)

Accumulation en longue exposition

Réglez clear=False pour continuer à empiler les événements dans la même image sur de nombreuses trames — le résultat est une visualisation des traînées de mouvement. Réinitialisez périodiquement pour commencer une nouvelle exposition:

EXPOSURE_FRAMES = 30
i = 0
while True:
    n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
    clear = (i % EXPOSURE_FRAMES) == 0
    img.draw_event_histogram(events[:n], clear=clear, brightness=128, contrast=64)
    img.flush()
    i += 1

Traitement à haute vitesse

Supprimez la visualisation pour libérer du CPU pour le traitement des événements. N’affichez les statistiques qu’à chaque Nième itération — afficher une ligne à chaque itération devient le goulot d’étranglement aux taux d’événements élevés:

csi0 = csi.CSI(cid=csi.GENX320)
csi0.reset()
csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT, events.shape[0])

clock = time.clock()
i = 0
while True:
    clock.tick()
    n = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events)
    i += 1
    if not i % 10:
        print(f"{n} events  {clock.fps()} fps")

Filtre de contraste spatio-temporel (STC)

Un véritable front de contraste en mouvement a tendance à déclencher une rafale bruyante d’événements sur le même pixel dans une courte fenêtre temporelle — la disparité entre pixels et le bruit analogique produisent des événements supplémentaires autour de la transition réelle, inutiles à l’application. Le filtre STC est un post-traitement sur puce qui ne conserve qu’un (ou quelques) événement(s) par rafale et écarte le reste.

Il met en œuvre trois stratégies, sélectionnées via csi.IOCTL_GENX320_SET_STC et une constante GENX320_STC_*. Chaque mode est défini par les événements qu’il transmet à partir d’une rafale :

Mode

Conserve

Écarte

csi.GENX320_STC_DISABLE

chaque événement

rien

csi.GENX320_STC_ONLY

le deuxième événement d’une rafale

le premier + les événements ultérieurs

csi.GENX320_STC_TRAIL_ONLY

le premier événement d’une rafale

les événements suivants

csi.GENX320_STC_TRAIL

le premier + les fronts suivants

uniquement le bruit redondant

En détail :

  • csi.GENX320_STC_DISABLE — filtre désactivé, chaque événement passe (par défaut).

  • csi.GENX320_STC_ONLY — conserve le deuxième événement d’une rafale. Paramètre : stc_threshold (ms). Si un nouvel événement sur un pixel arrive dans les stc_threshold suivant un événement précédent, il est considéré comme le « deuxième » d’une rafale et est transmis — le premier événement et tous les événements ultérieurs de la même rafale sont filtrés. Idéal lorsque vous voulez une transition confirmée par le bruit plutôt que le tout premier déclenchement.

  • csi.GENX320_STC_TRAIL_ONLY — conserve le premier événement d’une rafale. Paramètre : trail_threshold (ms). Après qu’un pixel s’est déclenché, les événements suivants sur le même pixel sont écartés jusqu’à ce que trail_threshold se soit écoulé. Préserve la temporisation précise du front d’attaque — utile lorsque le moment du changement de polarité importe plus que la confirmation de rafale.

  • csi.GENX320_STC_TRAIL — combine les deux. Paramètres : stc_threshold et trail_threshold (les deux en ms). Conserve le front d’attaque selon le mode Trail plus les fronts suivants selon le mode STC, de sorte que plusieurs événements d’une rafale passent quand même — débit d’événements plus élevé que les filtres à mode unique mais le signal le plus riche.

Les deux seuils doivent rester dans un rapport d’environ 13:1 — le capteur rejette les configurations où l’un est plus de ~13x l’autre:

csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_TRAIL, 1, 2)
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_DISABLE)

Profondeur de tampon

Lorsque les taux d’événements grimpent en flèche, le pipeline triple-tampon par défaut privilégie la dernière trame et écarte les anciennes. Augmentez la profondeur du FIFO via csi.CSI.framebuffers pour mettre les événements en file d’attente — au prix du traitement de données légèrement plus anciennes lorsque l’hôte prend du retard:

csi0.framebuffers(10)  # FIFO depth, > 3 enables queueing

Streaming et visualisation sur ordinateur

Pour une visualisation graphique en temps réel sur un PC hôte, l”outil de streaming d’événements GenX320 du dépôt openmv-projects associe la caméra à une interface DearPyGui. L’interface graphique du PC exécute deux visualisations côte à côte : un canevas d’accumulation d’événements (même principe que Image.draw_event_histogram mais avec des palettes sélectionnables et des modes fenêtre glissante ou effacement automatique) et une carte de fréquence par pixel pilotée par un filtre passe-bande IIR — utile pour repérer des signaux périodiques (ventilateurs en rotation, LED clignotantes, etc.) directement dans le flux d’événements.

Il est livré avec deux scripts de streaming embarqués sur la caméra :

  • Mode traité (genx320_event_mode_streaming_on_cam.py) — la caméra décode les événements avec csi.IOCTL_GENX320_READ_EVENTS et diffuse chaque ligne sous forme de 12 octets via USB ([0] type, [1] s, [2] ms, [3] us, [4] x, [5] y). Facile à consommer sur le PC car le format de transmission correspond au format ndarray embarqué.

  • Mode brut (genx320_raw_event_mode_streaming_on_cam.py) — la caméra diffuse les mots d’événement natifs de la puce, empaquetés sur 32 bits, via csi.IOCTL_GENX320_READ_EVENTS_RAW. Cela représente 4 octets par événement contre 12 en mode traité (environ 3x moins de données via USB), soit un taux d’événements atteignable ~3x plus élevé lorsque le lien est le goulot d’étranglement. Le PC décode les mots empaquetés vers la même disposition d’événements à 6 colonnes en utilisant du numpy vectorisé, de sorte que le code du visualiseur en aval est identique.

Le mode brut est le mode par défaut dans l’interface graphique car le débit USB est la contrainte limitante aux taux que le GenX320 peut produire ; passez en mode traité si vous devez intégrer une logique de traitement dans le script embarqué.