GENX320 händelsekamera¶
GENX320 händelsekameramodulen är en händelsebaserad bildsensor från Prophesee med 320x320 upplösning och temporal precision på mikrosekundnivå.
För fullständigt datablad, foton och beställning, se produktsidan för GENX320 händelsekamera.
Anteckning
Stöds på OpenMV H7 Plus, RT1062 och N6.
Höjdpunkter¶
320x320 händelsebaserad bildsensor
140 dB dynamiskt omfång, ingen rörelseoskärpa
375 Hz+ utmatningshastighet för händelsehistogram
Strömförbrukningen skalar med scenaktiviteten — börjar vid ~3 mW
Fungerar från <5 lux till starkt solljus utan automatisk exponering
Matar ut gråskalebildrutor eller råa händelseströmmar
Användning¶
GENX320 är en händelsebaserad bildsensor — i stället för att läsa ut hela 320x320-matrisen på en fast bildrutsklocka rapporterar varje pixel asynkrona ”händelser” i samma ögonblick som den upptäcker en ljusstyrkeförändring. Varje händelse bär med sig en X/Y-koordinat, en ON/OFF-polaritet (ljus→mörk eller mörk→ljus) och en tidsstämpel på mikrosekundnivå. Det är därifrån sensorns temporala precision på mikrosekundnivå, frånvaro av rörelseoskärpa, mycket höga dynamiska omfång och aktivitetsskalade strömförbrukning kommer. Statiska scener genererar ingen data.
OpenMV-firmware exponerar GENX320 genom csi.CSI med cid= csi.GENX320. Två driftlägen finns tillgängliga:
Histogramläge (standard) — händelser ackumuleras på chippet i pixelvisa fack och rapporteras som en 320x320 gråskalebildruta med en konfigurerbar hastighet (~20-350 FPS). Sensorn beter sig som en vanlig kamera, så alla standardrutiner för bildbehandling (
Image.find_blobs, paletter osv.) fungerar direkt.Händelseläge — råa händelser strömmar in i en numpy
ndarraymed fullständiga tidsstämplar på mikrosekundnivå, för tillämpningar som behöver den temporala detaljrikedomen i stället för en förbinnad bildruta.
Histogramläge¶
I histogramläge matar GENX320 ut gråskalebildrutor där varje pixel kodar den senaste händelseaktiviteten på den platsen. Pixlar över ljusstyrkebaslinjen är ON-händelser (stigande ljusstyrka), under är OFF-händelser (fallande ljusstyrka). Standardbaslinjens ljusstyrka är 128 och kontraststeget per händelse är 16 — höj kontrasten för att få händelserna att framträda tydligare:
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 och csi.CSI.framerate är de tre rattar som formar histogramutmatningen.
Färgad utmatning¶
Sätt csi.CSI.color_palette till image.PALETTE_EVT_LIGHT för en ljus bakgrund eller image.PALETTE_EVT_DARK för en mörk — drivrutinen matar ut RGB565-bildrutor med paletten direkt:
csi0.color_palette(image.PALETTE_EVT_LIGHT)
Kalibrering av varma pixlar¶
Händelsesensorer samlar på sig ”varma pixlar” som avfyras felaktigt. Kör csi.IOCTL_GENX320_CALIBRATE mot en statisk scen för att inaktivera dem. Drivrutinen bygger en pixelvis träffräkning på 320x320, beräknar medelvärdet och standardavvikelsen och inaktiverar varje pixel vars räkning ligger över mean + sigma * stddev — sedan slutar de inaktiverade pixlarna att avge händelser på sensornivå.
Två parametrar styr kalibreringen:
event_count— hur många händelser som ska räknas innan statistiken beräknas. Slingan fångar bildrutor tills det löpande händelsetotalen passerar denna budget. Högre räkningar ger en mer tillförlitlig uppskattning på bekostnad av längre kalibreringstid.10000är en rimlig utgångspunkt.sigma— tröskelvärdesmultiplikator på standardavvikelsen. Lägre värden är mer aggressiva (fler pixlar inaktiveras); högre värden är mer konservativa.0.5är ett bra standardvärde.
Rikta sensorn mot en statisk scen först så att inga rörelsedrivna händelser räknas mot pixlar som faktiskt är felfria:
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")
Antiflimmerfilter (AFK)¶
Periodiska ljuskällor (lysrör, LED-drivna skärmar) genererar enorma mängder redundanta händelser. AFK-filtret avvisar händelser vars pixel växlar med en frekvens inom ett band — aktivera det via csi.IOCTL_GENX320_SET_AFK med bandgränserna i hertz:
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 1, 130, 160) # 130-160 Hz
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 0) # disable
Förinställda biasvärden¶
Varje pixel i GenX320 kör en analog framände med flera konfigurerbara biasvärden. De styr gemensamt känslighet, brus, pixelbandbredd och händelsehastighet — den rätta kombinationen beror på scenen. De enskilda biasvärdena är:
DIFF_ON — det positiva komparatorkontrasttröskelvärdet. En pixel avger en ON-händelse när dess log-belysning har stigit med så mycket. Lägre = känsligare för ljusa övergångar.
DIFF_OFF — det negativa komparatorkontrasttröskelvärdet (den symmetriska motsvarigheten för OFF-händelser). Lägre = känsligare för mörka övergångar.
FO — pixelns lågpassgränsfrekvens. Högre = bredare pixelbandbredd (snabbare respons, lägre latens) men mer bakgrundsbrusaktivitet.
HPF — högpassgränsfrekvensen. Högre = starkare avvisning av långsamma ljusstyrkeförändringar; endast snabba övergångar når komparatorerna. Användbart för att ignorera omgivande drift.
REFR — refraktärperioden. Efter att en pixel avfyrats förblir den återställd så här länge innan den kan avfyras igen. Högre = längre död tid, användbart för att begränsa den pixelvisa händelsehastigheten.
Efter csi.CSI.reset tillämpar drivrutinen csi.GENX320_BIASES_LOW_NOISE, inte csi.GENX320_BIASES_DEFAULT — databladets standardvärden avger en mycket högre bakgrundshändelsehastighet, så LOW_NOISE används som utgångspunkt för att hålla strömmen tyst. Anropa csi.IOCTL_GENX320_SET_BIASES med en annan förinställning när tillämpningen behöver mer känslighet eller bandbredd.
csi.IOCTL_GENX320_SET_BIASES tillämpar en av fem förinställningar:
csi.GENX320_BIASES_DEFAULT— GenX320 databladets standardvärden. Balanserad känslighet, brus och bandbredd för allmänna scener.csi.GENX320_BIASES_LOW_LIGHT— båda kontrasttröskelvärdena uppluckrade för högre känslighet, FO sänkt för att hålla nere bruset, och HPF satt till 0 så att långsamma ljusstyrkeförändringar fortfarande registreras — en svagt belyst scen genererar få händelser på egen hand, så vi vill att så många som möjligt ska komma igenom.csi.GENX320_BIASES_ACTIVE_MARKER— avstämd för att spåra blinkande LED-lampor med hög kontrast. Kontrasttröskelvärdena höjda så att endast skarpa övergångar utlöser; FO och HPF vridna högt för att maximera pixelbandbredden och avvisa all långsam omgivande drift; REFR dragen till 0 så att varje blinkkant fångas i tät följd. Resultatet: en ström som nästan helt består av LED-kanter, lätt att spåra.csi.GENX320_BIASES_LOW_NOISE— drivrutinens standard. Båda kontrasttröskelvärdena höjda jämfört medDEFAULT(mindre känslig) och FO sänkt (långsammare pixel = tystare pixel). Bäst för statiska eller långsamma scener där falska händelser annars skulle dominera.csi.GENX320_BIASES_HIGH_SPEED— FO höjd så att varje pixel kan svara snabbare, HPF höjd för att avvisa långsam ljusstyrkedrift, och REFR höjd så att en enda snabbrörlig kant inte översvämmar utläsningen — den längre döda tiden håller händelsevolymen begränsad under kraftig rörelse.
Åsidosätt enskilda biasvärden med csi.IOCTL_GENX320_SET_BIAS plus ett av csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF eller csi.GENX320_BIAS_REFR och ett DAC-värde. Varje biasvärde sätts oberoende — välj en förinställning som utgångspunkt och justera sedan de biasvärden som din scen behöver:
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_LOW_LIGHT)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIAS, csi.GENX320_BIAS_HPF, 20)
Spårning¶
Eftersom histogramlägets utmatning bara är en gråskalebild fungerar vanlig blobspårning direkt. För att spåra en aktiv markörs-LED, ladda biasförinställningen för aktiv markör och hitta blobbar i histogrammets ljusa ände:
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())
Händelseläge¶
Händelseläge kringgår histogrammet på chippet och strömmar råa händelser in i en numpy ndarray. Varje händelse är en rad med sex uint16-kolumner:
[0]händelsetyp — se nedan[1]tidsstämpel i sekunder[2]tidsstämpel i millisekunder[3]tidsstämpel i mikrosekunder[4]X-koordinat, 0-319[5]Y-koordinat, 0-319
Drivrutinen avger sex händelsetyper i kolumn [0]:
csi.PIX_OFF_EVENT— en pixel upptäckte en minskning av ljusstyrkan (komparatortröskelvärdetDIFF_OFFkorsades). X/Y pekar på pixeln som avfyrades.csi.PIX_ON_EVENT— en pixel upptäckte en ökning av ljusstyrkan (tröskelvärdetDIFF_ONkorsades). X/Y pekar på pixeln.csi.EXT_TRIGGER_FALLING— sensorns externa utlösarstift såg en fallande kant. X/Y används inte.csi.EXT_TRIGGER_RISING— sensorns externa utlösarstift såg en stigande kant. X/Y används inte.csi.RST_TRIGGER_FALLING— pixelåterställningsutlösare, fallande kant. X/Y används inte. Genereras inte av firmware för närvarande.csi.RST_TRIGGER_RISING— pixelåterställningsutlösare, stigande kant. X/Y används inte. Genereras inte av firmware för närvarande.
GENX320:s externa utlösaringång är kopplad till kamerans bildrutssynkroniseringslinje, som också är dragen till P10 på både processorn och stiftraden — driv P10 för att injicera synkroniseringskanter i händelseströmmen och fånga upp dem som EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING-händelser tillsammans med pixeldatan.
De flesta tillämpningar bryr sig bara om PIX_OFF_EVENT och PIX_ON_EVENT; utlösartyperna låter dig korrelera händelser med externa tidssignaler.
Allokera händelsebufferten med formen (EVT_res, 6) där EVT_res är en tvåpotens mellan 1024 och 65536, gå sedan in i händelseläge genom csi.IOCTL_GENX320_SET_MODE med csi.GENX320_MODE_EVENT och buffertstorleken. Läs händelser med csi.IOCTL_GENX320_READ_EVENTS, som fyller bufferten upp till dess kapacitet och returnerar antalet giltiga rader.
Image.draw_event_histogram rastrerar händelser till en gråskalebild — för varje ON-händelse lägger den till contrast till facket; för varje OFF-händelse subtraherar den. clear=True återställer först bilden till brightness; clear=False ackumulerar över många anrop:
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())
Histogramlägets biasförinställningar, AFK-filtret och ioctl:erna för kalibrering av varma pixlar fungerar alla på samma sätt i händelseläge — anropa dem efter csi.IOCTL_GENX320_SET_MODE.
Filtrering efter polaritet¶
Skiva händelsematrisen med ulab för att behålla endast ON-händelser (rörelse till ett ljusare tillstånd) eller endast OFF-händelser:
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)
Långexponeringsackumulering¶
Sätt clear=False för att fortsätta stapla händelser i samma bild över många bildrutor — resultatet är en visualisering av rörelsespår. Återställ regelbundet för att starta en ny exponering:
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
Höghastighetsbehandling¶
Släpp visualiseringen för att frigöra CPU till händelsebehandling. Skriv ut statistik endast vid var N:te iteration — att skicka en utskriftsrad vid varje iteration blir flaskhalsen vid höga händelsehastigheter:
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")
Spatiotemporalt kontrastfilter (STC)¶
En verklig rörlig kontrastkant tenderar att utlösa en brusig skur av händelser på samma pixel inom ett kort tidsfönster — pixelmissanpassning och analogt brus producerar extra händelser kring den genuina övergången som inte är användbara för tillämpningen. STC-filtret är en efterbehandling på chippet som behåller endast en (eller några få) händelser per skur och kastar resten.
Det implementerar tre strategier, valda via csi.IOCTL_GENX320_SET_STC och en GENX320_STC_*-konstant. Varje läge definieras av vilka händelser det vidarebefordrar från en skur:
Läge |
Behåller |
Kastar |
|---|---|---|
varje händelse |
ingenting |
|
andra händelsen i en skur |
första + senare händelser |
|
första händelsen i en skur |
efterföljande händelser |
|
första + efterföljande kanter |
endast redundant brus |
I detalj:
csi.GENX320_STC_DISABLE— filter av, varje händelse passerar igenom (standard).csi.GENX320_STC_ONLY— behåller den andra händelsen i en skur. Parameter:stc_threshold(ms). Om en ny händelse på en pixel anländer inomstc_thresholdfrån en tidigare händelse betraktas den som den ”andra” i en skur och vidarebefordras — den första händelsen och eventuella efterföljande händelser i samma skur filtreras bort. Bäst när du vill ha en brusbekräftad övergång snarare än den allra första träffen.csi.GENX320_STC_TRAIL_ONLY— behåller den första händelsen i en skur. Parameter:trail_threshold(ms). Efter att en pixel avfyrats kastas efterföljande händelser på samma pixel tillstrail_thresholdhar förflutit. Bevarar den exakta tidpunkten för den ledande kanten — användbart när polaritetsväxlingsögonblicket är viktigare än skurbekräftelse.csi.GENX320_STC_TRAIL— kombinerar båda. Parametrar:stc_thresholdochtrail_threshold(båda ms). Behåller den ledande kanten enligt Trail-läget plus efterföljande kanter enligt STC-läget, så att flera händelser från en skur ändå kommer igenom — högre händelsegenomströmning än enkellägesfiltren men den rikaste signalen.
De två tröskelvärdena måste hålla sig inom ungefär ett 13:1-förhållande — sensorn avvisar konfigurationer där det ena är mer än ~13x det andra:
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_TRAIL, 1, 2)
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_DISABLE)
Buffertdjup¶
När händelsehastigheterna toppar gynnar standardpipelinen med trippelbuffert den senaste bildrutan och kastar de gamla. Höj FIFO-djupet via csi.CSI.framebuffers för att i stället köa händelser — till priset av att behandla något äldre data när värden hamnar på efterkälken:
csi0.framebuffers(10) # FIFO depth, > 3 enables queueing
Strömning och visualisering på skrivbordet¶
För realtidsvisualisering med grafiskt gränssnitt på en värd-PC parar GenX320 Event Streaming-verktyget i openmv-projects-arkivet ihop kameran med en DearPyGui-framände. PC-gränssnittet kör två visualiseringar sida vid sida: en duk för händelseackumulering (samma idé som Image.draw_event_histogram men med valbara paletter och lägen för glidande fönster respektive automatisk rensning) och en pixelvis frekvenskarta driven av ett IIR-bandpassfilter — användbart för att upptäcka periodiska signaler (roterande fläktar, blinkande LED-lampor osv.) direkt i händelseströmmen.
Det levereras med två strömningsskript på kameran:
Bearbetat läge (
genx320_event_mode_streaming_on_cam.py) — kameran avkodar händelser medcsi.IOCTL_GENX320_READ_EVENTSoch strömmar varje rad som 12 byte över USB ([0]typ,[1]sek,[2]ms,[3]us,[4]x,[5]y). Lätt att konsumera på PC eftersom trådformatet matchar ndarray-formatet på kameran.Råläge (
genx320_raw_event_mode_streaming_on_cam.py) — kameran strömmar chippets inbyggda 32-bitars packade händelseord genomcsi.IOCTL_GENX320_READ_EVENTS_RAW. Det är 4 byte per händelse jämfört med 12 i bearbetat läge (ungefär 3x mindre data över USB), alltså ~3x högre uppnåelig händelsehastighet när länken är flaskhalsen. PC:n avkodar de packade orden tillbaka till samma 6-kolumns händelselayout med vektoriserad numpy, så koden i den nedströms liggande visualiseraren är identisk.
Råläge är standard i gränssnittet eftersom USB-genomströmningen är den bindande begränsningen vid de hastigheter som GenX320 kan producera; byt till bearbetat läge om du behöver koppla in behandlingslogik i kameraskriptet.