GENX320 Event Camera¶
De GENX320 Event Camera-module is een op gebeurtenissen gebaseerde visiesensor van Prophesee met een resolutie van 320x320 en temporele precisie op microsecondeniveau.
Voor de volledige datasheet, foto’s en bestelinformatie, zie de GENX320 Event Camera productpagina.
Notitie
Ondersteund op de OpenMV H7 Plus, RT1062 en N6.
Hoogtepunten¶
320x320 op gebeurtenissen gebaseerde visiesensor
140 dB dynamisch bereik, geen bewegingsonscherpte
375 Hz+ uitvoersnelheid voor event-histogrammen
Stroomverbruik schaalt mee met scene-activiteit — begint bij ~3 mW
Werkt van <5 lux tot fel zonlicht zonder automatische belichting
Levert grijswaardenframes of ruwe event-streams
Gebruik¶
De GENX320 is een op gebeurtenissen gebaseerde visiesensor — in plaats van de volledige 320x320 array op een vaste frameklok uit te lezen, rapporteert elke pixel asynchrone “events” op het moment dat hij een helderheidsverandering detecteert. Elk event bevat een X/Y-coördinaat, een ON/OFF-polariteit (licht→donker of donker→licht) en een tijdstempel in microseconden. Daar komen de temporele precisie op microsecondeniveau, het ontbreken van bewegingsonscherpte, het zeer hoge dynamische bereik en het activiteitsgeschaalde stroomverbruik van de sensor vandaan. Statische scenes genereren geen data.
De OpenMV-firmware stelt de GENX320 beschikbaar via csi.CSI met cid= csi.GENX320. Er zijn twee bedrijfsmodi beschikbaar:
Histogrammodus (standaard) — events worden op de chip geaccumuleerd in bins per pixel en gerapporteerd als een 320x320 grijswaardenframe met een instelbare snelheid (~20-350 FPS). De sensor gedraagt zich als een gewone camera, dus alle standaard afbeeldingsverwerkingsroutines (
Image.find_blobs, paletten, enz.) werken direct.Eventmodus — ruwe events stromen in een numpy
ndarraymet volledige tijdstempels in microseconden, voor toepassingen die het temporele detail nodig hebben in plaats van een vooraf gebinde frame.
Histogrammodus¶
In de histogrammodus levert de GENX320 grijswaardenframes waarbij elke pixel de recente event-activiteit op die locatie codeert. Pixels boven de helderheidsbasislijn zijn ON-events (helderheid stijgt), eronder zijn OFF-events (helderheid daalt). De standaard basishelderheid is 128 en de contraststap per event is 16 — verhoog het contrast om events te laten opvallen:
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 en csi.CSI.framerate zijn de drie knoppen die de histogramuitvoer vormgeven.
Gekleurde uitvoer¶
Stel csi.CSI.color_palette in op image.PALETTE_EVT_LIGHT voor een lichte achtergrond of image.PALETTE_EVT_DARK voor een donkere — de driver geeft RGB565-frames uit waarbij het palet direct wordt gebruikt:
csi0.color_palette(image.PALETTE_EVT_LIGHT)
Hot-pixelkalibratie¶
Eventsensoren verzamelen “hot pixels” die spontaan afgaan. Voer csi.IOCTL_GENX320_CALIBRATE uit op een statische scene om ze uit te schakelen. De driver bouwt een 320x320 hit-telling per pixel op, berekent het gemiddelde en de standaardafwijking en schakelt elke pixel uit waarvan de telling boven mean + sigma * stddev ligt — daarna stoppen de uitgeschakelde pixels met het uitsturen van events op sensorniveau.
Twee parameters bepalen de kalibratie:
event_count— hoeveel events er geteld moeten worden voordat de statistieken worden berekend. De lus legt frames vast totdat het lopende eventtotaal dit budget overschrijdt. Hogere aantallen geven een betrouwbaardere schatting ten koste van een langere kalibratietijd.10000is een redelijk startpunt.sigma— drempelvermenigvuldiger op de standaardafwijking. Lagere waarden zijn agressiever (meer pixels uitgeschakeld); hogere waarden zijn conservatiever.0.5is een goede standaardwaarde.
Richt de sensor eerst op een statische scene zodat door beweging veroorzaakte events niet worden meegeteld voor pixels die eigenlijk prima zijn:
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")
Anti-flikker (AFK) filter¶
Periodieke lichtbronnen (TL-verlichting, LED-aangestuurde displays) genereren enorme hoeveelheden overbodige events. Het AFK-filter verwerpt events waarvan de pixel schakelt op een frequentie binnen een band — schakel het in via csi.IOCTL_GENX320_SET_AFK met de bandranden in hertz:
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 1, 130, 160) # 130-160 Hz
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 0) # disable
Bias-voorinstellingen¶
Elke pixel in de GenX320 draait een analoge front-end met verschillende instelbare biassen. Samen bepalen ze gevoeligheid, ruis, pixelbandbreedte en eventsnelheid — de juiste combinatie hangt af van de scene. De individuele biassen zijn:
DIFF_ON — de positieve contrastdrempel van de comparator. Een pixel geeft een ON-event uit wanneer zijn log-belichting met dit bedrag is gestegen. Lager = gevoeliger voor heldere overgangen.
DIFF_OFF — de negatieve contrastdrempel van de comparator (de symmetrische tegenhanger voor OFF-events). Lager = gevoeliger voor donkere overgangen.
FO — de laagdoorlaat-afsnijfrequentie van de pixel. Hoger = bredere pixelbandbreedte (snellere respons, lagere latentie) maar meer achtergrondruisactiviteit.
HPF — de hoogdoorlaat-afsnijfrequentie. Hoger = sterkere verwerping van langzame helderheidsveranderingen; alleen snelle overgangen bereiken de comparatoren. Nuttig om omgevingsdrift te negeren.
REFR — de refractaire periode. Nadat een pixel is afgegaan, blijft hij zo lang in reset voordat hij opnieuw kan afgaan. Hoger = langere dode tijd, nuttig om de eventsnelheid per pixel af te toppen.
Na csi.CSI.reset past de driver csi.GENX320_BIASES_LOW_NOISE toe, niet csi.GENX320_BIASES_DEFAULT — de datasheet-standaardwaarden geven een veel hogere achtergrond-eventsnelheid, dus LOW_NOISE wordt gebruikt als startpunt om de stream rustig te houden. Roep csi.IOCTL_GENX320_SET_BIASES aan met een andere voorinstelling wanneer de toepassing meer gevoeligheid of bandbreedte nodig heeft.
csi.IOCTL_GENX320_SET_BIASES past een van de vijf voorinstellingen toe:
csi.GENX320_BIASES_DEFAULT— GenX320 datasheet-standaardwaarden. Gebalanceerde gevoeligheid, ruis en bandbreedte voor algemene scenes.csi.GENX320_BIASES_LOW_LIGHT— beide contrastdrempels versoepeld voor hogere gevoeligheid, FO verlaagd om ruis te beperken, en HPF ingesteld op 0 zodat langzame helderheidsveranderingen toch geregistreerd worden — een scene met weinig licht genereert vanzelf weinig events, dus we willen er zoveel mogelijk doorlaten.csi.GENX320_BIASES_ACTIVE_MARKER— afgestemd op het volgen van knipperende LED’s met hoog contrast. Contrastdrempels verhoogd zodat alleen scherpe overgangen triggeren; FO en HPF hoog opgevoerd om de pixelbandbreedte te maximaliseren en langzame omgevingsdrift te verwerpen; REFR teruggebracht naar 0 zodat elke knipperflank achter elkaar wordt vastgelegd. Het resultaat: een stream die bijna geheel uit LED-flanken bestaat en gemakkelijk te volgen is.csi.GENX320_BIASES_LOW_NOISE— driverstandaard. Beide contrastdrempels verhoogd t.o.v.DEFAULT(minder gevoelig) en FO verlaagd (langzamere pixel = rustigere pixel). Het best voor statische of langzame scenes waar valse events anders zouden domineren.csi.GENX320_BIASES_HIGH_SPEED— FO opgevoerd zodat elke pixel sneller kan reageren, HPF verhoogd om langzame helderheidsdrift te verwerpen, en REFR verhoogd zodat een enkele snelbewegende flank de uitlezing niet overspoelt — de langere dode tijd houdt het eventvolume begrensd onder zware beweging.
Overschrijf individuele biassen met csi.IOCTL_GENX320_SET_BIAS plus een van csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF of csi.GENX320_BIAS_REFR en een DAC-waarde. Elke bias wordt onafhankelijk ingesteld — kies een voorinstelling als startpunt en stel vervolgens de biassen bij die jouw scene nodig heeft:
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_LOW_LIGHT)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIAS, csi.GENX320_BIAS_HPF, 20)
Volgen¶
Omdat de uitvoer in de histogrammodus gewoon een grijswaardenafbeelding is, werkt het reguliere blob-volgen direct. Om een active-marker-LED te volgen, laad je de active-marker bias-voorinstelling en zoek je blobs aan het heldere uiteinde van het histogram:
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())
Eventmodus¶
De eventmodus omzeilt het on-chip-histogram en streamt ruwe events in een numpy ndarray. Elk event is een rij van zes uint16-kolommen:
[0]eventtype — zie hieronder[1]tijdstempel in seconden[2]tijdstempel in milliseconden[3]tijdstempel in microseconden[4]X-coördinaat, 0-319[5]Y-coördinaat, 0-319
De driver geeft zes eventtypes uit in kolom [0]:
csi.PIX_OFF_EVENT— een pixel detecteerde een helderheidsafname (deDIFF_OFF-comparatordrempel werd overschreden). X/Y wijzen naar de pixel die afging.csi.PIX_ON_EVENT— een pixel detecteerde een helderheidstoename (deDIFF_ON-drempel werd overschreden). X/Y wijzen naar de pixel.csi.EXT_TRIGGER_FALLING— de externe triggerpin van de sensor zag een dalende flank. X/Y worden niet gebruikt.csi.EXT_TRIGGER_RISING— de externe triggerpin van de sensor zag een stijgende flank. X/Y worden niet gebruikt.csi.RST_TRIGGER_FALLING— pixel-reset-trigger, dalende flank. X/Y worden niet gebruikt. Wordt op dit moment niet door de firmware gegenereerd.csi.RST_TRIGGER_RISING— pixel-reset-trigger, stijgende flank. X/Y worden niet gebruikt. Wordt op dit moment niet door de firmware gegenereerd.
De externe triggeringang van de GENX320 is bedraad naar de frame-sync-lijn van de camera, die ook is doorgeleid naar P10 op zowel de processor als de pinheader — stuur P10 aan om sync-flanken in de event-stream te injecteren en pik ze op als EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING events naast de pixeldata.
De meeste toepassingen geven alleen om PIX_OFF_EVENT en PIX_ON_EVENT; met de triggertypes kun je events correleren met externe timingsignalen.
Reserveer de eventbuffer met vorm (EVT_res, 6) waarbij EVT_res een macht van twee is tussen 1024 en 65536, en ga vervolgens naar de eventmodus via csi.IOCTL_GENX320_SET_MODE met csi.GENX320_MODE_EVENT en de buffergrootte. Lees events met csi.IOCTL_GENX320_READ_EVENTS, wat de buffer tot zijn capaciteit vult en het aantal geldige rijen retourneert.
Image.draw_event_histogram rastert events in een grijswaardenafbeelding — voor elk ON-event voegt het contrast toe aan de bin; voor elk OFF-event trekt het af. clear=True zet de afbeelding eerst terug op brightness; clear=False accumuleert over meerdere aanroepen:
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())
De bias-voorinstellingen, het AFK-filter en de hot-pixelkalibratie-ioctls uit de histogrammodus werken allemaal op dezelfde manier in de eventmodus — roep ze aan na csi.IOCTL_GENX320_SET_MODE.
Filteren op polariteit¶
Snijd de events-array met ulab om alleen ON-events (beweging naar een helderdere toestand) of alleen OFF-events te behouden:
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)
Accumulatie met lange belichting¶
Stel clear=False in om events over meerdere frames in dezelfde afbeelding te blijven stapelen — het resultaat is een visualisatie van bewegingssporen. Reset periodiek om een nieuwe belichting te starten:
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
Hogesnelheidsverwerking¶
Laat de visualisatie weg om CPU vrij te maken voor eventverwerking. Print alleen statistieken bij elke Nde iteratie — een printregel bij elke iteratie wordt de bottleneck bij hoge eventsnelheden:
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")
Spatio-temporeel contrast (STC) filter¶
Een echte bewegende contrastrand neigt ertoe een ruizige burst van events op dezelfde pixel binnen een kort tijdsvenster te triggeren — pixelmismatch en analoge ruis produceren extra events rond de echte overgang die voor de toepassing niet nuttig zijn. Het STC-filter is een on-chip nabewerking die slechts één (of een paar) events per burst behoudt en de rest verwijdert.
Het implementeert drie strategieën, geselecteerd via csi.IOCTL_GENX320_SET_STC en een GENX320_STC_*-constante. Elke modus wordt gedefinieerd door welke events hij uit een burst doorstuurt:
Modus |
Behoudt |
Verwijdert |
|---|---|---|
elk event |
niets |
|
tweede event van een burst |
eerste + latere events |
|
eerste event van een burst |
volgende events |
|
eerste + volgende flanken |
alleen overbodige ruis |
In detail:
csi.GENX320_STC_DISABLE— filter uit, elk event komt erdoor (standaard).csi.GENX320_STC_ONLY— behoudt het tweede event van een burst. Parameter:stc_threshold(ms). Als een nieuw event op een pixel binnenstc_thresholdvan een eerder event aankomt, wordt het beschouwd als het “tweede” van een burst en doorgestuurd — het eerste event en alle volgende events in dezelfde burst worden weggefilterd. Het best wanneer je een ruisbevestigde overgang wilt in plaats van de allereerste hit.csi.GENX320_STC_TRAIL_ONLY— behoudt het eerste event van een burst. Parameter:trail_threshold(ms). Nadat een pixel is afgegaan, worden volgende events op dezelfde pixel verwijderd totdattrail_thresholdis verstreken. Behoudt de precieze timing van de voorste flank — nuttig wanneer het moment van polariteitswissel belangrijker is dan burstbevestiging.csi.GENX320_STC_TRAIL— combineert beide. Parameters:stc_thresholdentrail_threshold(beide ms). Behoudt de voorste flank zoals in de Trail-modus plus volgende flanken zoals in de STC-modus, zodat meerdere events uit een burst er toch doorkomen — hogere event-doorvoer dan de enkelvoudige filters, maar het rijkste signaal.
De twee drempels moeten binnen ongeveer een 13:1-verhouding blijven — de sensor verwerpt configuraties waarbij de ene meer dan ~13x de andere is:
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_TRAIL, 1, 2)
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_DISABLE)
Bufferdiepte¶
Wanneer eventsnelheden pieken, geeft de standaard triple-bufferpipeline voorrang aan het nieuwste frame en verwerpt het de oude. Verhoog de FIFO-diepte via csi.CSI.framebuffers om events in plaats daarvan in de wachtrij te zetten — ten koste van het verwerken van iets oudere data wanneer de host achterop raakt:
csi0.framebuffers(10) # FIFO depth, > 3 enables queueing
Desktop-streaming en visualisatie¶
Voor realtime GUI-visualisatie op een host-pc combineert de GenX320 Event Streaming tool in de openmv-projects-repo de cam met een DearPyGui-frontend. De pc-GUI draait twee visualisaties naast elkaar: een event-accumulatiecanvas (hetzelfde idee als Image.draw_event_histogram maar met selecteerbare paletten en schuifvenster- vs. auto-clearmodi) en een frequentiekaart per pixel aangedreven door een IIR-banddoorlaatfilter — nuttig om periodieke signalen (draaiende ventilatoren, knipperende LED’s, enz.) rechtstreeks in de event-stream op te sporen.
Het levert twee on-cam streamingscripts:
Verwerkte modus (
genx320_event_mode_streaming_on_cam.py) — de cam decodeert events metcsi.IOCTL_GENX320_READ_EVENTSen streamt elke rij als 12 bytes over USB ([0]type,[1]sec,[2]ms,[3]us,[4]x,[5]y). Eenvoudig te verwerken op de pc omdat het wire-formaat overeenkomt met het on-cam ndarray-formaat.Ruwe modus (
genx320_raw_event_mode_streaming_on_cam.py) — de cam streamt de native 32-bits gepakte eventwoorden van de chip viacsi.IOCTL_GENX320_READ_EVENTS_RAW. Dat is 4 bytes per event versus 12 in de verwerkte modus (ongeveer 3x minder data over USB), dus een ~3x hogere haalbare eventsnelheid wanneer de verbinding de bottleneck is. De pc decodeert de gepakte woorden terug naar dezelfde 6-koloms eventindeling met vectorized numpy, zodat de downstream-visualisatiecode identiek is.
Ruwe modus is de standaard in de GUI omdat de USB-doorvoer de bindende beperking is bij de snelheden die de GenX320 kan produceren; schakel over naar verwerkte modus als je verwerkingslogica in het on-cam script wilt inpluggen.