Multispektrinen tapahtumakamera

Multispectral Event Camera -moduuli yhdistää GENX320-tapahtumasensorin ja 1 MP:n PAG7936-globaalisuljinvärisensorin yhdelle moduulille — synkronoitu tapahtuma- ja väriputki nopeaan kohteiden seurantaan, LED-seurantaan, nestevirtaukseen ja muihin dynaamisiin kohtauksiin.

Multispektrinen tapahtumakamera

Täydellinen datalehti, kuvat ja tilaustiedot löytyvät Multispectral Event Camera -tuotesivulta.

Muista

Tuettu vain OpenMV N6:lla.

Kohokohdat

  • 320x320 tapahtumasensori, >140 dB dynaaminen alue, 375 Hz+ histogrammit

  • PAG7936-väri: 1280x800 @ 120 FPS, 640x400 @ 240 FPS

  • Synkronoidut tapahtuma-aikaleimat jaetulla valotuslaukaisimella

  • Näkee alle 5 luxissa ilman automaattista valotusta

  • Teho alkaa noin 3 mW:sta tapahtumien suoratoistossa

  • Suunnattu nopeaan seurantaan, LED-seurantaan ja neste-/hiukkasvirtaukseen

Käyttö

Värisensori ja GENX320-tapahtumasensori saavat kumpikin oman csi.CSI-instanssinsa. Ensimmäinen kutsu käyttää oletuksena ensisijaista sensoria (PAG7936); toinen sitoutuu GENX320:een välittämällä cid= csi.GENX320. Nollaa värisensori kovalla nollauksella csi.CSI.reset (hard=True) jännitelinjan käynnistämiseksi, ja määritä GENX320 arvolla hard=False, jotta sen ajuri vain ohjelmoi sirun uudelleen nollausta uudelleen kytkemättä.

GENX320 tuottaa 320x320 histogrammitilassa; PAG7936 tarkkuudella csi.QVGA tuottaa 320x200. Alla oleva peruspäällys leikkaa GENX320-kehyksen alimmat 120 riviä. Käytä homografiamuunnosta (alla) sovitettuun päällykseen tai suurempaan PAG7936-kehyskokoon.

Kaksi työpuskuria pysyy muuttumattomana kehyssilmukan aikana — 256x1 alfapaletti, joka on tallennettu image.Image-objektina niin, että histogrammipikselit keskiharmaalla perustasolla (128) muuttuvat läpinäkyviksi ja sekä ON-tapahtumien korostukset että OFF-tapahtumien varjot muuttuvat läpinäkymättömiksi, sekä GENX320-kehyspuskuri, joka on esivarattu image.Image-objektilla, jotta csi.CSI.snapshot (blocking=False, image=...) voi täyttää sen paikallaan joka iteraatiossa ilman uudelleenvarausta:

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

Jokainen iteraatio ottaa estävän väritilannekuvan ja ei-estävän GENX320-tilannekuvan. Image.draw_image yhdistää sitten nämä kaksi: color_palette= image.PALETTE_EVT_LIGHT (tai image.PALETTE_EVT_DARK tummalle taustalle) kuvaa GENX320:n harmaasävyhistogrammin väriramppiin, alpha_palette= sekoittaa jokaisen pikselin V-muotoisen alfakartan avulla niin, että kohtauksen hiljaiset alueet jäävät värikuvan läpi, ja hint= image.BILINEAR pehmentää skaalausta ylöspäin, kun värisensori toimii suuremmalla resoluutiolla kuin GENX320.

GENX320:n bias-esiasetukset, AFK-suodatin, kuumien pikselien kalibrointi ja STC-suodattimen ioctl:t toimivat kaikki samalla tavalla tässä kaksoiskamerakokoonpanossa — kutsu niitä kohteelle csi1 funktion csi.CSI.reset jälkeen. Katso lisätietoja alla olevista osioista.

GPU-kiihdytetty kohdistus

Image.draw_image hyväksyy transform=-argumentin — 3x3 homografiamatriisin 2-ulotteisena ulab.numpy-taulukkona. OpenMV N6:lla GPU suorittaa pikselikohtaisen projektion saman piirron aikana, joten GENX320-kehys voidaan kohdistaa uudelleen värikameran perspektiiviin ilman erillistä vääntövaihetta — hyödyllistä, kun kahdella sensorilla on hieman erilaiset optiikat tai näkökentät, tai kun värikamera toimii suuremmalla resoluutiolla. Kalibroi matriisi kullekin kameralle GenX320 Overlay Calibration -työkalulla, joka näyttää vilkkuvan ruutukuvion niin, että tapahtumasensori tuottaa kulmatapahtumia ilman mitään fyysistä liikettä:

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

Tämä variantti ajaa värikameraa tarkkuudella csi.VGA (640x480) ja GENX320:tä sen natiivilla 320x320:lla — homografia projisoi pienemmän GENX320-kehyksen suurempaan värikehykseen osana piirtoa, joten skaalauskerroin on leivottu itse matriisiin sen sijaan, että se sovellettaisiin erikseen.

Tapahtumakameran yksityiskohdat

GENX320 on tapahtumapohjainen konenäkösensori — sen sijaan, että se lukisi koko 320x320-taulukon kiinteällä kehyskellolla, jokainen pikseli raportoi asynkronisia ”tapahtumia” sillä hetkellä, kun se havaitsee kirkkauden muutoksen. Jokainen tapahtuma sisältää X/Y-koordinaatin, ON/OFF-polariteetin (kirkkaasta tummaan tai tummasta kirkkaaseen) ja mikrosekunnin aikaleiman. Tästä juontuvat sensorin mikrosekunnin aikatarkkuus, liike-epäterävyyden puute, erittäin korkea dynaaminen alue ja aktiivisuuteen skaalautuva tehonkulutus. Staattiset kohtaukset eivät tuota dataa.

OpenMV-laiteohjelmisto tarjoaa GENX320:n csi.CSI-rajapinnan kautta arvolla cid= csi.GENX320. Käytettävissä on kaksi toimintatilaa:

  • Histogrammitila (oletus) — tapahtumat kerätään sirulla pikselikohtaisiin lokeroihin ja raportoidaan 320x320 harmaasävykehyksenä määriteltävällä nopeudella (~20-350 FPS). Sensori käyttäytyy kuin tavallinen kamera, joten kaikki vakiona olevat kuvankäsittelyrutiinit (Image.find_blobs, paletit jne.) toimivat suoraan.

  • Tapahtumatila — raakatapahtumat suoratoistetaan numpy-objektiin ndarray täysillä mikrosekunnin aikaleimoilla sovelluksia varten, jotka tarvitsevat ajallisen tarkkuuden esikerätyn kehyksen sijaan.

Histogrammitila

Histogrammitilassa GENX320 tuottaa harmaasävykehyksiä, joissa jokainen pikseli koodaa kyseisen sijainnin viimeaikaisen tapahtuma-aktiivisuuden. Kirkkauden perustason yläpuolella olevat pikselit ovat ON-tapahtumia (kirkkaus nousee), alapuolella olevat OFF-tapahtumia (kirkkaus laskee). Oletusperustason kirkkaus on 128 ja tapahtumakohtainen kontrastiaskel on 16 — nosta kontrastia, jotta tapahtumat erottuvat:

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 ja csi.CSI.framerate ovat ne kolme säädintä, jotka muokkaavat histogrammin tulostetta.

Väritetty tuloste

Aseta csi.CSI.color_palette arvoon image.PALETTE_EVT_LIGHT vaaleaa taustaa varten tai image.PALETTE_EVT_DARK tummaa varten — ajuri tuottaa RGB565-kehyksiä käyttäen palettia suoraan:

csi0.color_palette(image.PALETTE_EVT_LIGHT)

Kuumien pikselien kalibrointi

Tapahtumasensoreihin kertyy ”kuumia pikseleitä”, jotka laukeavat virheellisesti. Suorita csi.IOCTL_GENX320_CALIBRATE staattista kohtausta vasten niiden poistamiseksi käytöstä. Ajuri rakentaa 320x320 pikselikohtaisen osumalukumäärän, laskee keskiarvon ja keskihajonnan ja poistaa käytöstä jokaisen pikselin, jonka lukumäärä on yli mean + sigma * stddev — sen jälkeen käytöstä poistetut pikselit lakkaavat tuottamasta tapahtumia sensoritasolla.

Kaksi parametria ohjaa kalibrointia:

  • event_count — kuinka monta tapahtumaa lasketaan ennen tilastojen laskemista. Silmukka kaappaa kehyksiä, kunnes käynnissä oleva tapahtumien kokonaismäärä ylittää tämän budjetin. Suuremmat määrät antavat luotettavamman arvion pidemmän kalibrointiajan kustannuksella. 10000 on järkevä lähtökohta.

  • sigma — kynnyskerroin keskihajonnalle. Pienemmät arvot ovat aggressiivisempia (enemmän pikseleitä poistetaan käytöstä); suuremmat arvot ovat varovaisempia. 0.5 on hyvä oletusarvo.

Suuntaa sensori ensin staattiseen kohtaukseen, jotta liikkeen aiheuttamia tapahtumia ei lasketa sellaisia pikseleitä vastaan, jotka itse asiassa ovat kunnossa:

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

Vilkkumisenesto (AFK) -suodatin

Jaksolliset valonlähteet (loisteputket, LED-ohjatut näytöt) tuottavat valtavia määriä tarpeettomia tapahtumia. AFK-suodatin hylkää tapahtumat, joiden pikseli vaihtaa tilaa kaistan sisällä olevalla taajuudella — ota se käyttöön funktiolla csi.IOCTL_GENX320_SET_AFK antamalla kaistan reunat hertseinä:

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

Bias-esiasetukset

Jokainen GenX320:n pikseli ajaa analogista etupäätä useilla määriteltävillä biaseilla. Ne ohjaavat yhdessä herkkyyttä, kohinaa, pikselin kaistanleveyttä ja tapahtumanopeutta — oikea yhdistelmä riippuu kohtauksesta. Yksittäiset biasit ovat:

  • DIFF_ON — positiivisen komparaattorin kontrastikynnysarvo. Pikseli tuottaa ON-tapahtuman, kun sen logaritminen valaistus on noussut tämän verran. Pienempi = herkempi kirkkaille siirtymille.

  • DIFF_OFF — negatiivisen komparaattorin kontrastikynnysarvo (symmetrinen vastine OFF-tapahtumille). Pienempi = herkempi tummille siirtymille.

  • FO — pikselin alipäästön rajataajuus. Korkeampi = leveämpi pikselin kaistanleveys (nopeampi vaste, pienempi viive) mutta enemmän taustakohina-aktiivisuutta.

  • HPF — ylipäästön rajataajuus. Korkeampi = voimakkaampi hitaiden kirkkausmuutosten hylkääminen; vain nopeat siirtymät yltävät komparaattoreihin. Hyödyllinen ympäröivän ajautumisen sivuuttamiseen.

  • REFR — refraktäärinen jakso. Kun pikseli on lauennut, se pysyy nollaustilassa tämän ajan ennen kuin se voi laueta uudelleen. Korkeampi = pidempi kuollut aika, hyödyllinen pikselikohtaisen tapahtumanopeuden rajaamiseen.

Funktion csi.CSI.reset jälkeen ajuri soveltaa esiasetusta csi.GENX320_BIASES_LOW_NOISE, ei csi.GENX320_BIASES_DEFAULT — datalehden oletukset tuottavat paljon korkeamman taustatapahtumanopeuden, joten LOW_NOISE käytetään lähtökohtana virran pitämiseksi hiljaisena. Kutsu csi.IOCTL_GENX320_SET_BIASES eri esiasetuksella, kun sovellus tarvitsee enemmän herkkyyttä tai kaistanleveyttä.

csi.IOCTL_GENX320_SET_BIASES soveltaa yhtä viidestä esiasetuksesta:

  • csi.GENX320_BIASES_DEFAULT — GenX320-datalehden oletukset. Tasapainotettu herkkyys, kohina ja kaistanleveys yleisiä kohtauksia varten.

  • csi.GENX320_BIASES_LOW_LIGHT — molempia kontrastikynnysarvoja löysennetty suuremman herkkyyden saavuttamiseksi, FO laskettu kohinan pitämiseksi alhaalla, ja HPF asetettu arvoon 0, jotta hitaat kirkkausmuutokset edelleen rekisteröityvät — hämärä kohtaus tuottaa itsestään vähän tapahtumia, joten haluamme mahdollisimman monen läpi.

  • csi.GENX320_BIASES_ACTIVE_MARKER — viritetty korkeakontrastisten vilkkuvien LEDien seurantaan. Kontrastikynnysarvot nostettu niin, että vain terävät siirtymät laukaisevat; FO ja HPF nostettu korkealle pikselin kaistanleveyden maksimoimiseksi ja minkä tahansa hitaan ympäröivän ajautumisen hylkäämiseksi; REFR vedetty arvoon 0, jotta jokainen vilkkureuna tallennetaan peräkkäin. Tulos: virta, joka on lähes pelkkiä LED-reunoja, helppo seurata.

  • csi.GENX320_BIASES_LOW_NOISE — ajurin oletus. Molempia kontrastikynnysarvoja nostettu verrattuna arvoon DEFAULT (vähemmän herkkä) ja FO laskettu (hitaampi pikseli = hiljaisempi pikseli). Paras staattisille tai hitaille kohtauksille, joissa virheelliset tapahtumat muuten dominoisivat.

  • csi.GENX320_BIASES_HIGH_SPEED — FO nostettu, jotta jokainen pikseli voi vastata nopeammin, HPF nostettu hitaan kirkkausajautumisen hylkäämiseksi, ja REFR nostettu, jotta yksittäinen nopeasti liikkuva reuna ei tulvi luenta — pidempi kuollut aika pitää tapahtumamäärän rajoitettuna voimakkaassa liikkeessä.

Ohita yksittäiset biasit funktiolla csi.IOCTL_GENX320_SET_BIAS sekä yhdellä konstanteista csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF tai csi.GENX320_BIAS_REFR ja DAC-arvolla. Jokainen bias asetetaan itsenäisesti — valitse esiasetus lähtökohdaksi ja säädä sitten niitä biaseja, joita kohtauksesi tarvitsee:

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

Seuranta

Koska histogrammitilan tuloste on vain harmaasävykuva, tavallinen blob-seuranta toimii suoraan. Seurataksesi aktiivisen merkin LEDiä lataa aktiivisen merkin bias-esiasetus ja etsi blobeja histogrammin kirkkaasta päästä:

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

Tapahtumatila

Tapahtumatila ohittaa sirulla olevan histogrammin ja suoratoistaa raakatapahtumat numpy-objektiin ndarray. Jokainen tapahtuma on rivi, jossa on kuusi uint16-saraketta:

  • [0] tapahtuman tyyppi — katso alla

  • [1] sekuntien aikaleima

  • [2] millisekuntien aikaleima

  • [3] mikrosekuntien aikaleima

  • [4] X-koordinaatti, 0-319

  • [5] Y-koordinaatti, 0-319

Ajuri tuottaa kuusi tapahtumatyyppiä sarakkeessa [0]:

  • csi.PIX_OFF_EVENT — pikseli havaitsi kirkkauden vähenemisen (DIFF_OFF-komparaattorin kynnysarvo ylitettiin). X/Y osoittavat lauenneeseen pikseliin.

  • csi.PIX_ON_EVENT — pikseli havaitsi kirkkauden lisääntymisen (DIFF_ON-kynnysarvo ylitettiin). X/Y osoittavat pikseliin.

  • csi.EXT_TRIGGER_FALLING — sensorin ulkoinen laukaisinnasta näki laskevan reunan. X/Y ovat käyttämättömiä.

  • csi.EXT_TRIGGER_RISING — sensorin ulkoinen laukaisinnasta näki nousevan reunan. X/Y ovat käyttämättömiä.

  • csi.RST_TRIGGER_FALLING — pikselin nollauslaukaisin, laskeva reuna. X/Y ovat käyttämättömiä. Laiteohjelmisto ei tuota tätä tällä hetkellä.

  • csi.RST_TRIGGER_RISING — pikselin nollauslaukaisin, nouseva reuna. X/Y ovat käyttämättömiä. Laiteohjelmisto ei tuota tätä tällä hetkellä.

GENX320:n ulkoinen laukaisintulo on kytketty kameran kehyssynkronointilinjaan, joka on myös reititetty nastaan P10 sekä prosessorissa että nastaliittimessä — ohjaa P10:tä syöttääksesi synkronointireunoja tapahtumavirtaan ja poimi ne EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING -tapahtumina pikselidatan ohella.

Useimmat sovellukset välittävät vain tyypeistä PIX_OFF_EVENT ja PIX_ON_EVENT; laukaisintyyppien avulla voit korreloida tapahtumat ulkoisten ajoitussignaalien kanssa.

Varaa tapahtumapuskuri muodolla (EVT_res, 6), jossa EVT_res on kahden potenssi väliltä 1024 ja 65536, ja siirry sitten tapahtumatilaan funktiolla csi.IOCTL_GENX320_SET_MODE arvolla csi.GENX320_MODE_EVENT ja puskurin koolla. Lue tapahtumat funktiolla csi.IOCTL_GENX320_READ_EVENTS, joka täyttää puskurin sen kapasiteettiin asti ja palauttaa kelvollisten rivien lukumäärän.

Image.draw_event_histogram rasteroi tapahtumat harmaasävykuvaksi — jokaista ON-tapahtumaa kohti se lisää contrast lokeroon; jokaista OFF-tapahtumaa kohti se vähentää. clear=True nollaa kuvan arvoon brightness ensin; clear=False kerää monen kutsun yli:

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

Histogrammitilan bias-esiasetukset, AFK-suodatin ja kuumien pikselien kalibroinnin ioctl:t toimivat kaikki samalla tavalla tapahtumatilassa — kutsu niitä funktion csi.IOCTL_GENX320_SET_MODE jälkeen.

Suodatus polariteetin mukaan

Leikkaa tapahtumataulukko ulabilla pitääksesi vain ON-tapahtumat (liike kirkkaampaan tilaan) tai vain OFF-tapahtumat:

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)

Pitkän valotuksen kerääminen

Aseta clear=False jatkaaksesi tapahtumien pinoamista samaan kuvaan monen kehyksen ajan — tulos on liikejäljen visualisointi. Nollaa ajoittain aloittaaksesi uuden valotuksen:

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

Suurnopeuskäsittely

Pudota visualisointi vapauttaaksesi suoritintehoa tapahtumien käsittelyyn. Tulosta tilastot vain joka N:nnellä iteraatiolla — tulostusrivin työntäminen joka iteraatiossa muodostuu pullonkaulaksi korkeilla tapahtumanopeuksilla:

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

Spatiotemporaalinen kontrasti (STC) -suodatin

Todellinen liikkuva kontrastireuna laukaisee yleensä kohinaisen purskeen tapahtumia samalla pikselillä lyhyen aikaikkunan sisällä — pikselien epäsovitus ja analoginen kohina tuottavat ylimääräisiä tapahtumia aidon siirtymän ympärille, jotka eivät ole hyödyllisiä sovellukselle. STC-suodatin on sirulla oleva jälkikäsittely, joka pitää vain yhden (tai muutaman) tapahtuman purskeesta ja pudottaa loput.

Se toteuttaa kolme strategiaa, jotka valitaan funktiolla csi.IOCTL_GENX320_SET_STC ja GENX320_STC_*-konstantilla. Jokainen tila määritellään sen mukaan, mitkä tapahtumat se välittää purskeesta:

Tila

Pitää

Pudottaa

csi.GENX320_STC_DISABLE

jokainen tapahtuma

ei mitään

csi.GENX320_STC_ONLY

purskeen toinen tapahtuma

ensimmäinen + myöhemmät tapahtumat

csi.GENX320_STC_TRAIL_ONLY

purskeen ensimmäinen tapahtuma

myöhemmät tapahtumat

csi.GENX320_STC_TRAIL

ensimmäinen + myöhemmät reunat

vain tarpeeton kohina

Yksityiskohtaisesti:

  • csi.GENX320_STC_DISABLE — suodatin pois päältä, jokainen tapahtuma menee läpi (oletus).

  • csi.GENX320_STC_ONLY — pitää purskeen toisen tapahtuman. Parametri: stc_threshold (ms). Jos uusi tapahtuma pikselillä saapuu ajan stc_threshold sisällä edellisestä tapahtumasta, sitä pidetään purskeen ”toisena” ja se välitetään — ensimmäinen tapahtuma ja kaikki saman purskeen myöhemmät tapahtumat suodatetaan pois. Paras, kun haluat kohinalla vahvistetun siirtymän aivan ensimmäisen osuman sijaan.

  • csi.GENX320_STC_TRAIL_ONLY — pitää purskeen ensimmäisen tapahtuman. Parametri: trail_threshold (ms). Kun pikseli on lauennut, saman pikselin myöhemmät tapahtumat pudotetaan, kunnes trail_threshold on kulunut. Säilyttää johtavan reunan tarkan ajoituksen — hyödyllinen, kun polariteetin vaihtohetki on tärkeämpi kuin purskeen vahvistus.

  • csi.GENX320_STC_TRAIL — yhdistää molemmat. Parametrit: stc_threshold ja trail_threshold (molemmat ms). Pitää johtavan reunan Trail-tilan mukaan sekä myöhemmät reunat STC-tilan mukaan, joten useita tapahtumia purskeesta pääsee silti läpi — korkeampi tapahtumien läpäisykyky kuin yksitilaisilla suodattimilla mutta rikkain signaali.

Kahden kynnysarvon on pysyttävä suunnilleen 13:1-suhteen sisällä — sensori hylkää konfiguraatiot, joissa toinen on yli ~13x toista:

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

Puskurin syvyys

Kun tapahtumanopeudet piikittävät, oletuksena oleva kolmoispuskuriputki suosii uusinta kehystä ja hylkää vanhat. Nosta FIFO-syvyyttä funktiolla csi.CSI.framebuffers jonottaaksesi tapahtumia sen sijaan — sillä kustannuksella, että käsitellään hieman vanhempaa dataa, kun isäntä jää jälkeen:

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

Työpöytäsuoratoisto ja visualisointi

Reaaliaikaista GUI-visualisointia varten isäntä-PC:llä GenX320 Event Streaming -työkalu openmv-projects-repositoriossa yhdistää kameran DearPyGui-käyttöliittymään. PC:n GUI ajaa kahta visualisointia vierekkäin: tapahtumien kerääntymiskankaan (sama idea kuin Image.draw_event_histogram, mutta valittavilla paleteilla sekä liukuvan ikkunan ja automaattisen tyhjennyksen tiloilla) ja pikselikohtaisen taajuuskartan, jota ohjaa IIR-kaistanpäästösuodatin — hyödyllinen jaksollisten signaalien (pyörivät tuulettimet, vilkkuvat LEDit jne.) havaitsemiseen suoraan tapahtumavirrasta.

Se sisältää kaksi kamerassa ajettavaa suoratoistoskriptiä:

  • Käsitelty tila (genx320_event_mode_streaming_on_cam.py) — kamera dekoodaa tapahtumat funktiolla csi.IOCTL_GENX320_READ_EVENTS ja suoratoistaa jokaisen rivin 12 tavuna USB:n yli ([0] tyyppi, [1] s, [2] ms, [3] us, [4] x, [5] y). Helppo käsitellä PC:llä, koska siirtomuoto vastaa kameran ndarray-muotoa.

  • Raakatila (genx320_raw_event_mode_streaming_on_cam.py) — kamera suoratoistaa sirun natiivit 32-bittiset pakatut tapahtumasanat funktiolla csi.IOCTL_GENX320_READ_EVENTS_RAW. Se on 4 tavua tapahtumaa kohti verrattuna 12:een käsitellyssä tilassa (noin 3x vähemmän dataa USB:n yli), joten ~3x korkeampi saavutettavissa oleva tapahtumanopeus, kun yhteys on pullonkaula. PC dekoodaa pakatut sanat takaisin samaan 6-sarakkeiseen tapahtumamuotoon vektoroidulla numpyllä, joten alavirran visualisoijan koodi on identtinen.

Raakatila on oletus GUI:ssa, koska USB-läpäisykyky on sitova rajoite niillä nopeuksilla, joita GenX320 voi tuottaa; vaihda käsiteltyyn tilaan, jos sinun täytyy liittää käsittelylogiikkaa kamerassa ajettavaan skriptiin.