Multispectrale Event-camera

De Multispectral Event Camera Module combineert de GENX320 event-sensor met een 1 MP PAG7936 global-shutter kleursensor op één module — een gesynchroniseerde event- + kleurpijplijn voor het volgen van snelle objecten, LED-tracking, vloeistofstromen en andere dynamische scènes.

Multispectrale Event-camera

Voor de volledige datasheet, foto’s en bestelinformatie zie de productpagina van de Multispectral Event Camera.

Notitie

Alleen ondersteund op de OpenMV N6.

Hoogtepunten

  • 320x320 event-sensor, >140 dB dynamisch bereik, 375 Hz+ histogrammen

  • PAG7936 kleur: 1280x800 @ 120 FPS, 640x400 @ 240 FPS

  • Gesynchroniseerde event-timestamps met gedeelde belichtingstrigger

  • Ziet onder 5 lux zonder automatische belichting

  • Stroomverbruik begint bij ~3 mW voor event-streaming

  • Gericht op snelle tracking, LED-tracking en vloeistof-/deeltjesstroom

Gebruik

De kleursensor en de GENX320 event-sensor krijgen elk hun eigen csi.CSI-instantie. De eerste aanroep gebruikt standaard de primaire sensor (de PAG7936); de tweede koppelt aan de GENX320 door cid= csi.GENX320 door te geven. Voer een harde reset uit op de kleursensor met csi.CSI.reset (hard=True) om de voedingsrail op te starten, en configureer de GENX320 met hard=False zodat de driver alleen de chip herprogrammeert zonder de reset opnieuw te schakelen.

De GENX320 levert 320x320 in histogrammodus; de PAG7936 op csi.QVGA levert 320x200. De basisoverlay hieronder snijdt de onderste 120 rijen van het GENX320-frame af. Gebruik de homografietransformatie (hieronder) voor een passende overlay of een grotere PAG7936-framegrootte.

Twee scratch-buffers blijven constant gedurende de framelus — een 256x1 alfapalet opgeslagen als een image.Image zodat histogrampixels op de middengrijze basislijn (128) transparant worden en zowel ON-event-highlights als OFF-event-schaduwen ondoorzichtig worden, en een GENX320-framebuffer vooraf gealloceerd met image.Image zodat csi.CSI.snapshot (blocking=False, image=...) deze bij elke iteratie ter plekke kan vullen zonder opnieuw te alloceren:

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())

Elke iteratie maakt een blokkerende kleur-snapshot en een niet-blokkerende GENX320-snapshot. Image.draw_image combineert vervolgens de twee: color_palette= image.PALETTE_EVT_LIGHT (of image.PALETTE_EVT_DARK voor een donkere achtergrond) zet het grijswaarden-histogram van de GENX320 om in een kleurverloop, alpha_palette= mengt elke pixel met behulp van de v-vormige alfakaart zodat rustige delen van de scène doorvallen naar de kleurafbeelding, en hint= image.BILINEAR verzacht de opschaling wanneer de kleursensor op een hogere resolutie draait dan de GENX320.

De bias-presets, AFK-filter, hot-pixelkalibratie en STC-filter-ioctls van de GENX320 werken allemaal op dezelfde manier in deze dual-camera-opstelling — roep ze aan op csi1 na csi.CSI.reset. Zie de onderstaande secties voor details.

GPU-versnelde uitlijning

Image.draw_image accepteert een transform=-argument — een 3x3 homografiematrix als een 2D ulab.numpy-array. Op de OpenMV N6 voert de GPU de per-pixelprojectie uit tijdens dezelfde tekenbewerking, zodat het GENX320-frame opnieuw kan worden uitgelijnd ten opzichte van het perspectief van de kleurcamera zonder een aparte warp-doorgang — handig wanneer de twee sensoren licht verschillende optiek of gezichtsvelden hebben, of wanneer de kleurcamera op een hogere resolutie draait. Kalibreer de matrix per camera met de GenX320 Overlay Calibration tool, die een flikkerend schaakbordpatroon weergeeft zodat de event-sensor hoekevents produceert zonder enige fysieke beweging:

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())

Deze variant draait de kleurcamera op csi.VGA (640x480) en de GENX320 op zijn eigen native 320x320 — de homografie projecteert het kleinere GENX320-frame in het grotere kleurframe als onderdeel van de tekenbewerking, zodat de opschaalfactor in de matrix zelf is verwerkt in plaats van afzonderlijk te worden toegepast.

Details van de event-camera

De GENX320 is een event-gebaseerde vision-sensor — 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 microseconde-timestamp. Daar komen de microseconde-temporele precisie, het ontbreken van bewegingsonscherpte, het zeer hoge dynamische bereik en het activiteitsgeschaalde stroomverbruik van de sensor vandaan. Statische scènes 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 on-chip geaccumuleerd in per-pixelbakken en gerapporteerd als een 320x320 grijswaarden-frame met een instelbare snelheid (~20-350 FPS). De sensor gedraagt zich als een gewone camera, dus alle standaard beeldverwerkingsroutines (Image.find_blobs, paletten, enz.) werken direct.

  • Event-modus — ruwe events stromen in een numpy ndarray met volledige microseconde-timestamps, voor toepassingen die de temporele details nodig hebben in plaats van een voorgebinned frame.

Histogrammodus

In histogrammodus levert de GENX320 grijswaarden-frames 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 basislijnhelderheid 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 levert RGB565-frames met het palet rechtstreeks:

csi0.color_palette(image.PALETTE_EVT_LIGHT)

Hot-pixelkalibratie

Event-sensoren verzamelen “hot pixels” die spontaan vuren. Voer csi.IOCTL_GENX320_CALIBRATE uit tegen een statische scène om ze uit te schakelen. De driver bouwt een 320x320 per-pixel-hittelling op, berekent het gemiddelde en de standaarddeviatie, en schakelt elke pixel uit waarvan de telling boven mean + sigma * stddev ligt — daarna stoppen de uitgeschakelde pixels met het uitzenden van events op sensorniveau.

Twee parameters bepalen de kalibratie:

  • event_count — hoeveel events geteld worden voordat de statistieken worden berekend. De lus legt frames vast totdat het lopende event-totaal dit budget overschrijdt. Hogere tellingen geven een betrouwbaardere schatting ten koste van een langere kalibratietijd. 10000 is een redelijk startpunt.

  • sigma — drempelvermenigvuldiger op de standaarddeviatie. Lagere waarden zijn agressiever (meer pixels uitgeschakeld); hogere waarden zijn voorzichtiger. 0.5 is een goede standaardwaarde.

Richt de sensor eerst op een statische scène zodat eventuele door beweging veroorzaakte events niet worden aangerekend aan 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-licht, LED-aangedreven displays) genereren enorme hoeveelheden redundante 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-presets

Elke pixel in de GenX320 heeft een analoge front-end met verschillende configureerbare biases. Samen bepalen ze gevoeligheid, ruis, pixelbandbreedte en event-snelheid — de juiste combinatie hangt af van de scène. De individuele biases zijn:

  • DIFF_ON — de positieve comparator-contrastdrempelwaarde. Een pixel zendt een ON-event uit wanneer zijn log-illuminatie met dit bedrag is gestegen. Lager = gevoeliger voor heldere overgangen.

  • DIFF_OFF — de negatieve comparator-contrastdrempelwaarde (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 achtergrondruis-activiteit.

  • HPF — de hoogdoorlaat-afsnijfrequentie. Hoger = sterkere onderdrukking van trage helderheidsveranderingen; alleen snelle overgangen bereiken de comparators. Handig om omgevingsdrift te negeren.

  • REFR — de refractaire periode. Nadat een pixel heeft gevuurd, blijft hij zo lang in reset voordat hij opnieuw kan vuren. Hoger = langere dode tijd, handig om de event-snelheid per pixel te begrenzen.

Na csi.CSI.reset past de driver csi.GENX320_BIASES_LOW_NOISE toe, niet csi.GENX320_BIASES_DEFAULT — de datasheet-standaardwaarden zenden een veel hogere achtergrond-event-snelheid uit, dus LOW_NOISE wordt gebruikt als startpunt om de stream rustig te houden. Roep csi.IOCTL_GENX320_SET_BIASES aan met een andere preset wanneer de toepassing meer gevoeligheid of bandbreedte nodig heeft.

csi.IOCTL_GENX320_SET_BIASES past een van vijf presets toe:

  • csi.GENX320_BIASES_DEFAULT — GenX320 datasheet-standaardwaarden. Gebalanceerde gevoeligheid, ruis en bandbreedte voor algemene scènes.

  • csi.GENX320_BIASES_LOW_LIGHT — beide contrastdrempelwaarden versoepeld voor hogere gevoeligheid, FO verlaagd om de ruis laag te houden, en HPF op 0 gezet zodat trage helderheidsveranderingen nog steeds registreren — een scène met weinig licht genereert op zichzelf 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. Contrastdrempelwaarden verhoogd zodat alleen scherpe overgangen triggeren; FO en HPF hoog opgevoerd om de pixelbandbreedte te maximaliseren en eventuele trage omgevingsdrift te verwerpen; REFR teruggebracht naar 0 zodat elke knipperflank achter elkaar wordt vastgelegd. Het resultaat: een stream die vrijwel uitsluitend uit LED-flanken bestaat, eenvoudig te volgen.

  • csi.GENX320_BIASES_LOW_NOISE — driver-standaard. Beide contrastdrempelwaarden verhoogd t.o.v. DEFAULT (minder gevoelig) en FO verlaagd (tragere pixel = rustigere pixel). Het beste voor statische of trage scènes waar valse events anders zouden domineren.

  • csi.GENX320_BIASES_HIGH_SPEED — FO verhoogd zodat elke pixel sneller kan reageren, HPF verhoogd om trage helderheidsdrift te verwerpen, en REFR verhoogd zodat een enkele snelbewegende flank de uitlezing niet overspoelt — de langere dode tijd houdt het event-volume begrensd bij hevige beweging.

Overschrijf individuele biases 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 preset als startpunt en stel vervolgens de biases bij die uw scène 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)

Tracking

Omdat de histogrammodus-uitvoer slechts een grijswaardenafbeelding is, werkt reguliere blob-tracking direct. Om een active-marker-LED te volgen, laadt u de active-marker-bias-preset en zoekt u 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())

Event-modus

De event-modus omzeilt het on-chip histogram en streamt ruwe events in een numpy ndarray. Elk event is een rij van zes uint16-kolommen:

  • [0] event-type — zie hieronder

  • [1] seconden-timestamp

  • [2] milliseconden-timestamp

  • [3] microseconden-timestamp

  • [4] X-coördinaat, 0-319

  • [5] Y-coördinaat, 0-319

De driver zendt zes event-types uit in kolom [0]:

  • csi.PIX_OFF_EVENT — een pixel detecteerde een helderheidsafname (de DIFF_OFF comparator-drempelwaarde werd overschreden). X/Y wijzen naar de pixel die vuurde.

  • csi.PIX_ON_EVENT — een pixel detecteerde een helderheidstoename (de DIFF_ON drempelwaarde 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 verbonden met de frame-sync-lijn van de camera, die ook is doorgevoerd naar P10 op zowel de processor als de pin-header — 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 trigger-types kunt u events correleren met externe timingsignalen.

Alloceer de event-buffer met vorm (EVT_res, 6) waarbij EVT_res een macht van twee tussen 1024 en 65536 is, en ga vervolgens naar de event-modus via csi.IOCTL_GENX320_SET_MODE met csi.GENX320_MODE_EVENT en de buffergrootte. Lees events met csi.IOCTL_GENX320_READ_EVENTS, die de buffer tot zijn capaciteit vult en het aantal geldige rijen retourneert.

Image.draw_event_histogram rastert events naar een grijswaardenafbeelding — voor elk ON-event voegt het contrast toe aan de bak; voor elk OFF-event trekt het af. clear=True reset de afbeelding eerst naar brightness; clear=False accumuleert over vele 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-presets, het AFK-filter en de hot-pixelkalibratie-ioctls van de histogrammodus werken allemaal op dezelfde manier in de event-modus — 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)

Langdurige belichtingsaccumulatie

Stel clear=False in om events over vele frames in dezelfde afbeelding te blijven stapelen — het resultaat is een visualisatie van een bewegingsspoor. 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

Snelle verwerking

Laat de visualisatie weg om CPU vrij te maken voor event-verwerking. Print statistieken slechts elke N-de iteratie — een print-regel bij elke iteratie wordt het knelpunt bij hoge event-snelheden:

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 ruisende burst van events op dezelfde pixel binnen een kort tijdvenster te triggeren — pixelmismatch en analoge ruis produceren extra events rond de echte overgang die niet nuttig zijn voor de toepassing. Het STC-filter is een on-chip nabewerking die slechts één (of enkele) 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 doorstuurt vanuit een burst:

Modus

Behoudt

Verwijdert

csi.GENX320_STC_DISABLE

elk event

niets

csi.GENX320_STC_ONLY

tweede event van een burst

eerste + latere events

csi.GENX320_STC_TRAIL_ONLY

eerste event van een burst

volgende events

csi.GENX320_STC_TRAIL

eerste + volgende flanken

alleen redundante ruis

In detail:

  • csi.GENX320_STC_DISABLE — filter uit, elk event gaat erdoorheen (standaard).

  • csi.GENX320_STC_ONLY — behoudt het tweede event van een burst. Parameter: stc_threshold (ms). Als een nieuw event op een pixel binnen stc_threshold van een voorgaand event arriveert, wordt het beschouwd als het “tweede” van een burst en doorgestuurd — het eerste event en eventuele volgende events in dezelfde burst worden eruit gefilterd. Het beste wanneer u een ruisbevestigde overgang wilt in plaats van de allereerste treffer.

  • csi.GENX320_STC_TRAIL_ONLY — behoudt het eerste event van een burst. Parameter: trail_threshold (ms). Nadat een pixel heeft gevuurd, worden volgende events op dezelfde pixel verwijderd totdat trail_threshold is verstreken. Behoudt de precieze timing van de voorste flank — handig wanneer het moment van polariteitsverschuiving belangrijker is dan burstbevestiging.

  • csi.GENX320_STC_TRAIL — combineert beide. Parameters: stc_threshold en trail_threshold (beide ms). Behoudt de voorste flank zoals in de Trail-modus plus de volgende flanken zoals in de STC-modus, zodat meerdere events uit een burst nog steeds doorkomen — hogere event-doorvoer dan de single-mode-filters maar het rijkste signaal.

De twee drempelwaarden 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 event-snelheden pieken, geeft de standaard triple-buffer-pijplijn voorrang aan het nieuwste frame en verwijdert de oude. Verhoog de FIFO-diepte via csi.CSI.framebuffers om events in de wachtrij te plaatsen — ten koste van het verwerken van iets oudere data wanneer de host achterloopt:

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 camera met een DearPyGui-frontend. De pc-GUI toont twee visualisaties naast elkaar: een event-accumulatiecanvas (hetzelfde idee als Image.draw_event_histogram maar met selecteerbare paletten en schuivend-venster- versus auto-clear-modi) en een per-pixel-frequentiekaart aangedreven door een IIR-banddoorlaatfilter — handig om periodieke signalen (draaiende ventilatoren, knipperende LED’s, enz.) direct in de event-stream op te sporen.

Het wordt geleverd met twee on-cam streaming-scripts:

  • Verwerkte modus (genx320_event_mode_streaming_on_cam.py) — de camera decodeert events met csi.IOCTL_GENX320_READ_EVENTS en 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 camera streamt de native 32-bits gepakte event-woorden van de chip via csi.IOCTL_GENX320_READ_EVENTS_RAW. Dat is 4 bytes per event tegenover 12 in de verwerkte modus (ongeveer 3x minder data over USB), dus een ~3x hogere haalbare event-snelheid wanneer de verbinding het knelpunt is. De pc decodeert de gepakte woorden terug naar dezelfde 6-kolommen-event-lay-out met behulp van gevectoriseerd numpy, zodat de downstream-visualisatiecode identiek is.

De 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 de verwerkte modus als u verwerkingslogica in het on-cam-script moet inpluggen.