Cameră de evenimente multispectrală

Modulul Multispectral Event Camera asociază senzorul de evenimente GENX320 cu un senzor de culoare PAG7936 de 1 MP cu obturator global, pe un singur modul — un flux sincronizat de evenimente + culoare pentru urmărirea obiectelor la viteză mare, urmărirea LED-urilor, curgerea fluidelor și alte scene dinamice.

Cameră de evenimente multispectrală

Pentru fișa tehnică completă, fotografii și comenzi, consultați pagina de produs Multispectral Event Camera.

Notă

Compatibil doar cu OpenMV N6.

Aspecte importante

  • senzor de evenimente 320x320, gamă dinamică >140 dB, histograme la 375 Hz+

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

  • marcaje temporale ale evenimentelor sincronizate cu declanșator de expunere comun

  • vede sub 5 lux fără expunere automată

  • consumul pornește de la ~3 mW pentru fluxul de evenimente

  • destinat urmăririi la viteză mare, urmăririi LED-urilor și curgerii fluidelor/particulelor

Utilizare

Senzorul de culoare și senzorul de evenimente GENX320 primesc fiecare propria instanță csi.CSI. Primul apel are ca implicit senzorul principal (PAG7936); al doilea se leagă la GENX320 prin transmiterea cid= csi.GENX320. Resetați la rece senzorul de culoare cu csi.CSI.reset (hard=True) pentru a porni alimentarea și configurați GENX320 cu hard=False astfel încât driverul său doar să reprogrameze cipul fără a comuta din nou resetarea.

GENX320 produce 320x320 în modul histogramă; PAG7936 la csi.QVGA produce 320x200. Suprapunerea de bază de mai jos decupează cele 120 de rânduri inferioare ale cadrului GENX320. Folosiți transformarea de homografie (mai jos) pentru o suprapunere ajustată sau o dimensiune de cadru PAG7936 mai mare.

Două tampoane temporare rămân constante de-a lungul buclei de cadre — o paletă alfa 256x1 stocată ca image.Image astfel încât pixelii histogramei la baza gri-mediu (128) să devină transparenți, iar atât evidențierile evenimentelor ON, cât și umbrele evenimentelor OFF să devină opace, și un tampon de cadre (frame buffer) GENX320 prealocat cu image.Image astfel încât csi.CSI.snapshot (blocking=False, image=...) să îl poată umple pe loc la fiecare iterație fără realocare:

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

Fiecare iterație preia un instantaneu de culoare blocant și un instantaneu GENX320 neblocant. Image.draw_image compune apoi cele două: color_palette= image.PALETTE_EVT_LIGHT (sau image.PALETTE_EVT_DARK pentru un fundal întunecat) mapează histograma în tonuri de gri a GENX320 într-o rampă de culoare, alpha_palette= îmbină fiecare pixel folosind harta alfa în formă de v astfel încât regiunile liniștite ale scenei să lase să treacă imaginea de culoare, iar hint= image.BILINEAR netezește mărirea atunci când senzorul de culoare rulează la o rezoluție mai mare decât GENX320.

Presetările de polarizare ale GENX320, filtrul AFK, calibrarea pixelilor fierbinți și ioctl-urile filtrului STC funcționează toate în același mod în această configurație cu cameră dublă — apelați-le pe csi1 după csi.CSI.reset. Consultați secțiunile de mai jos pentru detalii.

Aliniere accelerată de GPU

Image.draw_image acceptă un argument transform= — o matrice de homografie 3x3 ca tablou ulab.numpy 2-D. Pe OpenMV N6, GPU-ul rulează proiecția per-pixel în cadrul aceleiași desenări, astfel încât cadrul GENX320 poate fi realiniat la perspectiva camerei de culoare fără o trecere de deformare separată — util când cei doi senzori au optici sau câmpuri vizuale ușor diferite, sau când camera de culoare rulează la o rezoluție mai mare. Calibrați matricea pentru fiecare cameră cu instrumentul GenX320 Overlay Calibration, care afișează o tablă de șah pâlpâitoare astfel încât senzorul de evenimente să producă evenimente de colț fără nicio mișcare fizică:

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

Această variantă rulează camera de culoare la csi.VGA (640x480) și GENX320 la rezoluția sa nativă 320x320 — homografia proiectează cadrul GENX320 mai mic în cadrul de culoare mai mare ca parte a desenării, astfel încât factorul de mărire este integrat în matricea însăși, în loc să fie aplicat separat.

Detalii despre camera de evenimente

GENX320 este un senzor de viziune bazat pe evenimente — în loc să citească întreaga matrice 320x320 la un ceas de cadre fix, fiecare pixel raportează „evenimente” asincrone în momentul în care detectează o schimbare de luminozitate. Fiecare eveniment poartă o coordonată X/Y, o polaritate ON/OFF (luminos→întunecat sau întunecat→luminos) și un marcaj temporal în microsecunde. De aici provin precizia temporală în microsecunde a senzorului, lipsa neclarității de mișcare, gama dinamică foarte ridicată și consumul de putere scalat în funcție de activitate. Scenele statice nu generează date.

Firmware-ul OpenMV expune GENX320 prin csi.CSI cu cid= csi.GENX320. Sunt disponibile două moduri de funcționare:

  • Modul histogramă (implicit) — evenimentele sunt acumulate pe cip în coșuri per-pixel și raportate ca un cadru în tonuri de gri 320x320 la o rată configurabilă (~20-350 FPS). Senzorul se comportă ca o cameră obișnuită, astfel încât toate rutinele standard de procesare a imaginii (Image.find_blobs, palete etc.) funcționează direct.

  • Modul eveniment — evenimentele brute curg într-un ndarray numpy cu marcaje temporale complete în microsecunde, pentru aplicații care au nevoie de detaliul temporal mai degrabă decât de un cadru pre-grupat.

Modul histogramă

În modul histogramă, GENX320 produce cadre în tonuri de gri în care fiecare pixel codifică activitatea recentă a evenimentelor la acea locație. Pixelii peste baza de luminozitate sunt evenimente ON (luminozitate în creștere), cei de sub sunt evenimente OFF (luminozitate în scădere). Luminozitatea de bază implicită este 128, iar pasul de contrast per-eveniment este 16 — măriți contrastul pentru a face evenimentele să iasă în evidență:

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 și csi.CSI.framerate sunt cele trei butoane care modelează ieșirea histogramei.

Ieșire colorată

Setați csi.CSI.color_palette la image.PALETTE_EVT_LIGHT pentru un fundal deschis sau image.PALETTE_EVT_DARK pentru unul întunecat — driverul emite cadre RGB565 folosind direct paleta:

csi0.color_palette(image.PALETTE_EVT_LIGHT)

Calibrarea pixelilor fierbinți

Senzorii de evenimente acumulează „pixeli fierbinți” care se declanșează în mod fals. Rulați csi.IOCTL_GENX320_CALIBRATE pe o scenă statică pentru a-i dezactiva. Driverul construiește un contor de lovituri per-pixel 320x320, calculează media și abaterea standard și dezactivează orice pixel al cărui contor este peste mean + sigma * stddev — apoi pixelii dezactivați încetează să emită evenimente la nivelul senzorului.

Doi parametri controlează calibrarea:

  • event_count — câte evenimente să se numere înainte de a calcula statisticile. Bucla capturează cadre până când totalul curent de evenimente depășește acest buget. Valori mai mari oferă o estimare mai fiabilă cu prețul unui timp de calibrare mai lung. 10000 este un punct de plecare rezonabil.

  • sigma — multiplicatorul de prag pentru abaterea standard. Valorile mai mici sunt mai agresive (mai mulți pixeli dezactivați); valorile mai mari sunt mai conservatoare. 0.5 este o valoare implicită bună.

Îndreptați mai întâi senzorul către o scenă statică, astfel încât eventualele evenimente provocate de mișcare să nu fie numărate împotriva pixelilor care sunt de fapt în regulă:

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

Filtru anti-pâlpâire (AFK)

Sursele de lumină periodice (fluorescente, afișaje conduse de LED-uri) generează volume uriașe de evenimente redundante. Filtrul AFK respinge evenimentele al căror pixel comută la o frecvență dintr-o bandă — activați-l prin csi.IOCTL_GENX320_SET_AFK cu marginile benzii în herți:

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

Presetări de polarizare

Fiecare pixel din GenX320 rulează un front-end analogic cu mai multe polarizări configurabile. Acestea guvernează împreună sensibilitatea, zgomotul, lățimea de bandă a pixelului și rata de evenimente — combinația potrivită depinde de scenă. Polarizările individuale sunt:

  • DIFF_ON — pragul de contrast al comparatorului pozitiv. Un pixel emite un eveniment ON când log-iluminarea sa a crescut cu această valoare. Mai mic = mai sensibil la tranziții luminoase.

  • DIFF_OFF — pragul de contrast al comparatorului negativ (omologul simetric pentru evenimentele OFF). Mai mic = mai sensibil la tranziții întunecate.

  • FO — frecvența de tăiere trece-jos a pixelului. Mai mare = lățime de bandă a pixelului mai mare (răspuns mai rapid, latență mai mică), dar mai multă activitate de zgomot de fundal.

  • HPF — frecvența de tăiere trece-sus. Mai mare = respingere mai puternică a schimbărilor lente de luminozitate; doar tranzițiile rapide ajung la comparatoare. Util pentru ignorarea derivei ambientale.

  • REFR — perioada refractară. După ce un pixel se declanșează, rămâne în resetare pentru acest interval înainte de a se putea declanșa din nou. Mai mare = timp mort mai lung, util pentru limitarea ratei de evenimente per-pixel.

După csi.CSI.reset, driverul aplică csi.GENX320_BIASES_LOW_NOISE, nu csi.GENX320_BIASES_DEFAULT — valorile implicite din fișa tehnică emit o rată de evenimente de fundal mult mai mare, așa că LOW_NOISE este folosit ca punct de plecare pentru a menține fluxul liniștit. Apelați csi.IOCTL_GENX320_SET_BIASES cu o presetare diferită atunci când aplicația are nevoie de mai multă sensibilitate sau lățime de bandă.

csi.IOCTL_GENX320_SET_BIASES aplică una dintre cele cinci presetări:

  • csi.GENX320_BIASES_DEFAULT — valorile implicite din fișa tehnică GenX320. Sensibilitate, zgomot și lățime de bandă echilibrate pentru scene generale.

  • csi.GENX320_BIASES_LOW_LIGHT — ambele praguri de contrast relaxate pentru o sensibilitate mai mare, FO coborât pentru a menține zgomotul scăzut și HPF setat la 0 astfel încât schimbările lente de luminozitate să fie totuși înregistrate — o scenă cu lumină slabă generează puține evenimente de la sine, așa că vrem să treacă cât mai multe posibil.

  • csi.GENX320_BIASES_ACTIVE_MARKER — reglat pentru urmărirea LED-urilor intermitente cu contrast ridicat. Praguri de contrast ridicate astfel încât doar tranzițiile clare să se declanșeze; FO și HPF setate la valori mari pentru a maximiza lățimea de bandă a pixelului și a respinge orice derivă ambientală lentă; REFR adus la 0 astfel încât fiecare margine de clipire să fie capturată una după alta. Rezultatul: un flux care este aproape în întregime margini de LED, ușor de urmărit.

  • csi.GENX320_BIASES_LOW_NOISE — valoarea implicită a driverului. Ambele praguri de contrast ridicate față de DEFAULT (mai puțin sensibil) și FO coborât (pixel mai lent = pixel mai liniștit). Cel mai bun pentru scene statice sau lente unde evenimentele false ar domina altfel.

  • csi.GENX320_BIASES_HIGH_SPEED — FO mărit astfel încât fiecare pixel să poată răspunde mai repede, HPF ridicat pentru a respinge deriva lentă de luminozitate, și REFR ridicat astfel încât o singură margine în mișcare rapidă să nu inunde citirea — timpul mort mai lung menține volumul de evenimente limitat sub mișcare intensă.

Suprascrieți polarizările individuale cu csi.IOCTL_GENX320_SET_BIAS plus una dintre csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF sau csi.GENX320_BIAS_REFR și o valoare DAC. Fiecare polarizare este setată independent — alegeți o presetare ca punct de plecare, apoi ajustați polarizările de care are nevoie scena dvs.:

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

Urmărire

Deoarece ieșirea în modul histogramă este doar o imagine în tonuri de gri, urmărirea obișnuită a blob-urilor funcționează direct. Pentru a urmări un LED active-marker, încărcați presetarea de polarizare active-marker și găsiți blob-uri la capătul luminos al histogramei:

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

Modul eveniment

Modul eveniment ocolește histograma de pe cip și transmite evenimente brute într-un ndarray numpy. Fiecare eveniment este un rând de șase coloane uint16:

  • [0] tip de eveniment — vezi mai jos

  • [1] marcaj temporal în secunde

  • [2] marcaj temporal în milisecunde

  • [3] marcaj temporal în microsecunde

  • [4] coordonata X, 0-319

  • [5] coordonata Y, 0-319

Driverul emite șase tipuri de evenimente în coloana [0]:

  • csi.PIX_OFF_EVENT — un pixel a detectat o scădere de luminozitate (pragul comparatorului DIFF_OFF a fost depășit). X/Y indică pixelul care s-a declanșat.

  • csi.PIX_ON_EVENT — un pixel a detectat o creștere de luminozitate (pragul DIFF_ON a fost depășit). X/Y indică pixelul.

  • csi.EXT_TRIGGER_FALLING — pinul de declanșare externă al senzorului a văzut o margine descendentă. X/Y nu sunt utilizate.

  • csi.EXT_TRIGGER_RISING — pinul de declanșare externă al senzorului a văzut o margine ascendentă. X/Y nu sunt utilizate.

  • csi.RST_TRIGGER_FALLING — declanșator de resetare a pixelului, margine descendentă. X/Y nu sunt utilizate. Nu este generat de firmware în acest moment.

  • csi.RST_TRIGGER_RISING — declanșator de resetare a pixelului, margine ascendentă. X/Y nu sunt utilizate. Nu este generat de firmware în acest moment.

Intrarea de declanșare externă a GENX320 este conectată la linia de sincronizare a cadrelor camerei, care este de asemenea direcționată către P10 atât pe procesor, cât și pe conectorul de pini — comandați P10 pentru a injecta margini de sincronizare în fluxul de evenimente și pentru a le prelua ca evenimente EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING alături de datele pixelilor.

Majoritatea aplicațiilor se preocupă doar de PIX_OFF_EVENT și PIX_ON_EVENT; tipurile de declanșare vă permit să corelați evenimentele cu semnale de sincronizare externe.

Alocați tamponul de evenimente cu forma (EVT_res, 6) unde EVT_res este o putere a lui doi între 1024 și 65536, apoi intrați în modul eveniment prin csi.IOCTL_GENX320_SET_MODE cu csi.GENX320_MODE_EVENT și dimensiunea tamponului. Citiți evenimentele cu csi.IOCTL_GENX320_READ_EVENTS, care umple tamponul până la capacitatea sa și returnează numărul de rânduri valide.

Image.draw_event_histogram rasterizează evenimentele într-o imagine în tonuri de gri — pentru fiecare eveniment ON adaugă contrast la coș; pentru fiecare eveniment OFF scade. clear=True resetează mai întâi imaginea la brightness; clear=False acumulează de-a lungul mai multor apeluri:

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

Presetările de polarizare din modul histogramă, filtrul AFK și ioctl-urile de calibrare a pixelilor fierbinți funcționează toate în același mod în modul eveniment — apelați-le după csi.IOCTL_GENX320_SET_MODE.

Filtrare după polaritate

Tăiați tabloul de evenimente cu ulab pentru a păstra doar evenimentele ON (mișcare către o stare mai luminoasă) sau doar evenimentele 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)

Acumulare cu expunere lungă

Setați clear=False pentru a continua să stivuiți evenimente în aceeași imagine de-a lungul mai multor cadre — rezultatul este o vizualizare a urmei de mișcare. Resetați periodic pentru a începe o nouă expunere:

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

Procesare la viteză mare

Renunțați la vizualizare pentru a elibera CPU-ul pentru procesarea evenimentelor. Afișați statisticile doar la fiecare a N-a iterație — emiterea unei linii de afișare la fiecare iterație devine blocajul la rate mari de evenimente:

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

Filtru de contrast spațio-temporal (STC)

O margine de contrast reală în mișcare tinde să declanșeze o rafală zgomotoasă de evenimente pe același pixel într-o fereastră de timp scurtă — neconcordanța pixelilor și zgomotul analogic produc evenimente suplimentare în jurul tranziției autentice, care nu sunt utile pentru aplicație. Filtrul STC este o post-procesare pe cip care păstrează doar un eveniment (sau câteva) per rafală și le elimină pe celelalte.

Implementează trei strategii, selectate prin csi.IOCTL_GENX320_SET_STC și o constantă GENX320_STC_*. Fiecare mod este definit de evenimentele pe care le transmite dintr-o rafală:

Mod

Păstrează

Elimină

csi.GENX320_STC_DISABLE

fiecare eveniment

nimic

csi.GENX320_STC_ONLY

al doilea eveniment al unei rafale

primul + evenimentele ulterioare

csi.GENX320_STC_TRAIL_ONLY

primul eveniment al unei rafale

evenimentele ulterioare

csi.GENX320_STC_TRAIL

primele + marginile ulterioare

doar zgomotul redundant

În detaliu:

  • csi.GENX320_STC_DISABLE — filtru dezactivat, fiecare eveniment trece (implicit).

  • csi.GENX320_STC_ONLY — păstrează al doilea eveniment al unei rafale. Parametru: stc_threshold (ms). Dacă un nou eveniment pe un pixel sosește în intervalul stc_threshold de la un eveniment anterior, este considerat „al doilea” al unei rafale și este transmis — primul eveniment și orice evenimente ulterioare din aceeași rafală sunt filtrate. Cel mai bun când doriți o tranziție confirmată prin zgomot mai degrabă decât prima lovitură.

  • csi.GENX320_STC_TRAIL_ONLY — păstrează primul eveniment al unei rafale. Parametru: trail_threshold (ms). După ce un pixel se declanșează, evenimentele ulterioare pe același pixel sunt eliminate până când a trecut trail_threshold. Păstrează sincronizarea precisă a marginii principale — util când momentul comutării polarității contează mai mult decât confirmarea rafalei.

  • csi.GENX320_STC_TRAIL — le combină pe ambele. Parametri: stc_threshold și trail_threshold (ambele ms). Păstrează marginea principală conform modului Trail plus marginile ulterioare conform modului STC, astfel încât mai multe evenimente dintr-o rafală tot trec — debit de evenimente mai mare decât filtrele cu un singur mod, dar cu semnalul cel mai bogat.

Cele două praguri trebuie să rămână într-un raport de aproximativ 13:1 — senzorul respinge configurațiile în care unul este mai mare de ~13x decât celălalt:

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

Adâncimea tamponului

Când ratele de evenimente cresc brusc, pipeline-ul implicit cu triplu tampon favorizează cel mai recent cadru și le elimină pe cele vechi. Măriți adâncimea FIFO prin csi.CSI.framebuffers pentru a pune evenimentele în coadă în schimb — cu prețul procesării datelor ușor mai vechi când gazda rămâne în urmă:

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

Streaming și vizualizare pe desktop

Pentru vizualizarea GUI în timp real pe un PC gazdă, instrumentul GenX320 Event Streaming din depozitul openmv-projects asociază camera cu un front-end DearPyGui. GUI-ul de PC rulează două vizualizări una lângă alta: o pânză de acumulare a evenimentelor (aceeași idee ca Image.draw_event_histogram dar cu palete selectabile și moduri fereastră glisantă vs. auto-ștergere) și o hartă de frecvență per-pixel condusă de un filtru trece-bandă IIR — utilă pentru identificarea semnalelor periodice (ventilatoare rotative, LED-uri intermitente etc.) direct în fluxul de evenimente.

Livrează două scripturi de streaming pe cameră:

  • Modul procesat (genx320_event_mode_streaming_on_cam.py) — camera decodează evenimentele cu csi.IOCTL_GENX320_READ_EVENTS și transmite fiecare rând ca 12 octeți prin USB ([0] tip, [1] sec, [2] ms, [3] us, [4] x, [5] y). Ușor de consumat pe PC deoarece formatul de transmisie se potrivește cu formatul ndarray de pe cameră.

  • Modul brut (genx320_raw_event_mode_streaming_on_cam.py) — camera transmite cuvintele de eveniment native împachetate pe 32 de biți ale cipului prin csi.IOCTL_GENX320_READ_EVENTS_RAW. Acestea sunt 4 octeți per eveniment față de 12 în modul procesat (de aproximativ 3x mai puține date prin USB), deci o rată de evenimente realizabilă de ~3x mai mare când legătura este blocajul. PC-ul decodează cuvintele împachetate înapoi în aceeași dispunere de eveniment cu 6 coloane folosind numpy vectorizat, astfel încât codul vizualizatorului din aval este identic.

Modul brut este implicit în GUI deoarece debitul USB este constrângerea limitativă la ratele pe care le poate produce GenX320; comutați la modul procesat dacă aveți nevoie să integrați logica de procesare în scriptul de pe cameră.