GENX320 händelsekamera

GENX320 händelsekameramodulen är en händelsebaserad bildsensor från Prophesee med 320x320 upplösning och temporal precision på mikrosekundnivå.

GENX320 händelsekamera

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 ndarray med 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 med DEFAULT (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ärdet DIFF_OFF korsades). X/Y pekar på pixeln som avfyrades.

  • csi.PIX_ON_EVENT — en pixel upptäckte en ökning av ljusstyrkan (tröskelvärdet DIFF_ON korsades). 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

csi.GENX320_STC_DISABLE

varje händelse

ingenting

csi.GENX320_STC_ONLY

andra händelsen i en skur

första + senare händelser

csi.GENX320_STC_TRAIL_ONLY

första händelsen i en skur

efterföljande händelser

csi.GENX320_STC_TRAIL

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 inom stc_threshold frå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 tills trail_threshold har 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_threshold och trail_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 med csi.IOCTL_GENX320_READ_EVENTS och 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 genom csi.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.