Câmara de Eventos Multispectral¶
O Módulo de Câmara de Eventos Multispectral combina o sensor de eventos GENX320 com um sensor de cor PAG7936 de obturador global de 1 MP num único módulo — um pipeline sincronizado de eventos + cor para rastreamento de objetos a alta velocidade, rastreamento de LEDs, fluxo de fluidos e outras cenas dinâmicas.
Para ficha técnica completa, fotografias e encomenda, consulte a página do produto Câmara de Eventos Multispectral.
Nota
Suportado apenas na OpenMV N6.
Destaques¶
Sensor de eventos 320x320, >140 dB de gama dinâmica, histogramas a 375 Hz+
Cor PAG7936: 1280x800 @ 120 FPS, 640x400 @ 240 FPS
Marcas temporais de eventos sincronizadas com gatilho de exposição partilhado
Visão abaixo de 5 lux sem exposição automática
Consumo a partir de ~3 mW em modo de streaming de eventos
Orientado para rastreamento a alta velocidade, rastreamento de LEDs e fluxo de fluidos/partículas
Utilização¶
O sensor de cor e o sensor de eventos GENX320 recebem cada um a sua própria instância de csi.CSI. A primeira chamada utiliza por defeito o sensor principal (o PAG7936); a segunda associa-se ao GENX320 passando cid= csi.GENX320. Reinicialize o sensor de cor com csi.CSI.reset (hard=True) para ativar o barramento, e configure o GENX320 com hard=False para que o seu controlador apenas reprograme o chip sem voltar a acionar o reset.
O GENX320 emite 320x320 em modo histograma; o PAG7936 em csi.QVGA emite 320x200. A sobreposição básica abaixo recorta as 120 linhas inferiores do fotograma do GENX320. Utilize a transformação por homografia (abaixo) para uma sobreposição ajustada ou um tamanho de fotograma maior para o PAG7936.
Dois buffers de trabalho mantêm-se constantes ao longo do ciclo de fotogramas — uma paleta alfa de 256x1 armazenada como image.Image para que os pixels do histograma no nível base de cinzento médio (128) se tornem transparentes e tanto os realces de eventos ON como as sombras de eventos OFF se tornem opacos, e um buffer de fotograma do GENX320 pré-alocado com image.Image para que csi.CSI.snapshot (blocking=False, image=...) o possa preencher no lugar em cada iteração sem realocar:
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())
Cada iteração obtém uma captura de imagem de cor bloqueante e uma captura de imagem do GENX320 não bloqueante. Image.draw_image compõe depois as duas: color_palette= image.PALETTE_EVT_LIGHT (ou image.PALETTE_EVT_DARK para fundo escuro) mapeia o histograma em escala de cinzentos do GENX320 numa rampa de cor, alpha_palette= mistura cada pixel usando o mapa alfa em forma de V para que as regiões silenciosas da cena sejam substituídas pela imagem de cor, e hint= image.BILINEAR suaviza o aumento de escala quando o sensor de cor funciona a uma resolução superior à do GENX320.
Os ioctls de predefinições de bias, filtro AFK, calibração de pixels quentes e filtro STC do GENX320 funcionam da mesma forma nesta configuração de câmara dupla — invoque-os em csi1 após csi.CSI.reset. Consulte as secções abaixo para mais detalhes.
Alinhamento acelerado por GPU¶
Image.draw_image aceita um argumento transform= — uma matriz de homografia 3x3 como array 2D ulab.numpy. Na OpenMV N6, a GPU executa a projeção por pixel durante o mesmo desenho, pelo que o fotograma do GENX320 pode ser realinhado em relação à perspetiva da câmara de cor sem uma passagem de distorção separada — útil quando os dois sensores têm óticas ou campos de visão ligeiramente diferentes, ou quando a câmara de cor funciona a uma resolução superior. Calibre a matriz por câmara com a ferramenta de Calibração de Sobreposição GenX320, que apresenta um tabuleiro de xadrez intermitente para que o sensor de eventos produza eventos de canto sem qualquer movimento físico:
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())
Esta variante executa a câmara de cor em csi.VGA (640x480) e o GENX320 na sua resolução nativa 320x320 — a homografia projeta o fotograma menor do GENX320 no fotograma maior de cor como parte do desenho, pelo que o fator de aumento de escala está incorporado na própria matriz em vez de ser aplicado separadamente.
Detalhes da câmara de eventos¶
O GENX320 é um sensor de visão baseado em eventos — em vez de ler toda a matriz 320x320 num relógio de fotogramas fixo, cada pixel comunica «eventos» assíncronos no instante em que deteta uma mudança de brilho. Cada evento transporta uma coordenada X/Y, uma polaridade ON/OFF (claro→escuro ou escuro→claro) e uma marca temporal em microssegundos. É daí que vêm a precisão temporal em microssegundos do sensor, a ausência de desfocagem por movimento, a gama dinâmica muito elevada e o consumo de energia proporcional à atividade. Cenas estáticas não geram dados.
O firmware OpenMV expõe o GENX320 através de csi.CSI com cid= csi.GENX320. Estão disponíveis dois modos de funcionamento:
Modo histograma (predefinição) — os eventos são acumulados no chip em contadores por pixel e reportados como um fotograma em escala de cinzentos 320x320 a uma taxa configurável (~20-350 FPS). O sensor comporta-se como uma câmara normal, pelo que todas as rotinas padrão de processamento de imagem (
Image.find_blobs, paletas, etc.) funcionam diretamente.Modo evento — os eventos brutos são transmitidos para um
ndarraynumpy com marcas temporais completas em microssegundos, para aplicações que necessitam do detalhe temporal em vez de um fotograma pré-agregado.
Modo histograma¶
Em modo histograma, o GENX320 emite fotogramas em escala de cinzentos onde cada pixel codifica a atividade de eventos recente nessa localização. Os pixels acima do nível base de brilho são eventos ON (brilho a aumentar), abaixo são eventos OFF (brilho a diminuir). O nível base de brilho predefinido é 128 e o passo de contraste por evento é 16 — aumente o contraste para realçar os eventos:
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 e csi.CSI.framerate são os três parâmetros que moldam a saída do histograma.
Saída colorizada¶
Defina csi.CSI.color_palette para image.PALETTE_EVT_LIGHT com fundo claro ou image.PALETTE_EVT_DARK com fundo escuro — o controlador emite fotogramas RGB565 usando a paleta diretamente:
csi0.color_palette(image.PALETTE_EVT_LIGHT)
Calibração de pixels quentes¶
Os sensores de eventos acumulam «pixels quentes» que disparam de forma espúria. Execute csi.IOCTL_GENX320_CALIBRATE contra uma cena estática para os desativar. O controlador constrói uma contagem de ocorrências por pixel 320x320, calcula a média e o desvio padrão, e desativa qualquer pixel cuja contagem esteja acima de mean + sigma * stddev — os pixels desativados deixam então de emitir eventos ao nível do sensor.
Dois parâmetros controlam a calibração:
event_count— quantos eventos contabilizar antes de calcular as estatísticas. O ciclo captura fotogramas até que o total acumulado de eventos ultrapasse este orçamento. Contagens mais elevadas fornecem uma estimativa mais fiável ao custo de maior tempo de calibração.10000é um bom ponto de partida.sigma— multiplicador de limiar sobre o desvio padrão. Valores mais baixos são mais agressivos (mais pixels desativados); valores mais altos são mais conservadores.0.5é um bom valor predefinido.
Aponte o sensor para uma cena estática primeiro, para que os eventos provocados por movimento não sejam contabilizados em pixels que estão, na verdade, a funcionar bem:
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")
Filtro anti-cintilação (AFK)¶
Fontes de luz periódicas (fluorescentes, ecrãs controlados por LED) geram enormes volumes de eventos redundantes. O filtro AFK rejeita eventos cujo pixel alterna a uma frequência dentro de uma banda — ative-o via csi.IOCTL_GENX320_SET_AFK com os limites da banda em hertz:
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 1, 130, 160) # 130-160 Hz
csi0.ioctl(csi.IOCTL_GENX320_SET_AFK, 0) # disable
Predefinições de bias¶
Cada pixel do GenX320 executa um front-end analógico com vários biases configuráveis. Em conjunto governam a sensibilidade, o ruído, a largura de banda do pixel e a taxa de eventos — a combinação certa depende da cena. Os biases individuais são:
DIFF_ON — limiar de contraste do comparador positivo. Um pixel emite um evento ON quando a sua log-iluminação tiver aumentado este tanto. Menor = mais sensível a transições claras.
DIFF_OFF — limiar de contraste do comparador negativo (o equivalente simétrico para eventos OFF). Menor = mais sensível a transições escuras.
FO — frequência de corte passa-baixo do pixel. Maior = maior largura de banda do pixel (resposta mais rápida, menor latência) mas mais atividade de ruído de fundo.
HPF — frequência de corte passa-alto. Maior = maior rejeição de variações lentas de brilho; apenas as transições rápidas chegam aos comparadores. Útil para ignorar deriva ambiental.
REFR — período refratário. Após um pixel disparar, permanece em reset durante este tempo antes de poder disparar novamente. Maior = maior tempo morto, útil para limitar a taxa de eventos por pixel.
Após csi.CSI.reset, o controlador aplica csi.GENX320_BIASES_LOW_NOISE, não csi.GENX320_BIASES_DEFAULT — as predefinições da ficha técnica emitem uma taxa de eventos de fundo muito mais elevada, pelo que LOW_NOISE é usado como ponto de partida para manter o fluxo silencioso. Invoque csi.IOCTL_GENX320_SET_BIASES com uma predefinição diferente quando a aplicação necessitar de mais sensibilidade ou largura de banda.
csi.IOCTL_GENX320_SET_BIASES aplica uma de cinco predefinições:
csi.GENX320_BIASES_DEFAULT— predefinições da ficha técnica do GenX320. Sensibilidade, ruído e largura de banda equilibrados para cenas gerais.csi.GENX320_BIASES_LOW_LIGHT— ambos os limiares de contraste alargados para maior sensibilidade, FO reduzido para manter o ruído baixo, e HPF definido para 0 para que variações lentas de brilho ainda sejam registadas — uma cena com pouca luz gera poucos eventos por si só, por isso queremos que o maior número possível passe.csi.GENX320_BIASES_ACTIVE_MARKER— ajustado para rastreamento de LEDs intermitentes de alto contraste. Limiares de contraste aumentados para que apenas transições abruptas disparem; FO e HPF maximizados para maximizar a largura de banda do pixel e rejeitar qualquer deriva ambiental lenta; REFR a 0 para que cada aresta do intermitente seja capturada consecutivamente. O resultado: um fluxo quase exclusivamente composto por arestas de LED, fácil de rastrear.csi.GENX320_BIASES_LOW_NOISE— predefinição do controlador. Ambos os limiares de contraste aumentados face aDEFAULT(menos sensível) e FO reduzido (pixel mais lento = pixel mais silencioso). Melhor para cenas estáticas ou lentas onde eventos falsos dominariam de outra forma.csi.GENX320_BIASES_HIGH_SPEED— FO aumentado para que cada pixel possa responder mais rapidamente, HPF elevado para rejeitar deriva lenta de brilho, e REFR aumentado para que uma única aresta de movimento rápido não inunde a leitura — o maior tempo morto mantém o volume de eventos limitado sob movimento intenso.
Substitua biases individuais com csi.IOCTL_GENX320_SET_BIAS mais um de csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF ou csi.GENX320_BIAS_REFR e um valor DAC. Cada bias é definido de forma independente — escolha uma predefinição como ponto de partida e depois ajuste os biases que a sua cena necessita:
csi0.ioctl(csi.IOCTL_GENX320_SET_BIASES, csi.GENX320_BIASES_LOW_LIGHT)
csi0.ioctl(csi.IOCTL_GENX320_SET_BIAS, csi.GENX320_BIAS_HPF, 20)
Rastreamento¶
Como a saída em modo histograma é apenas uma imagem em escala de cinzentos, o rastreamento de manchas normal funciona diretamente. Para rastrear um LED marcador ativo, carregue a predefinição de bias de marcador ativo e encontre manchas na extremidade clara do histograma:
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())
Modo evento¶
O modo evento contorna o histograma no chip e transmite eventos brutos para um ndarray numpy. Cada evento é uma linha de seis colunas uint16:
[0]tipo de evento — ver abaixo[1]marca temporal em segundos[2]marca temporal em milissegundos[3]marca temporal em microssegundos[4]coordenada X, 0-319[5]coordenada Y, 0-319
O controlador emite seis tipos de eventos na coluna [0]:
csi.PIX_OFF_EVENT— um pixel detetou uma diminuição de brilho (o limiar do comparadorDIFF_OFFfoi cruzado). X/Y apontam para o pixel que disparou.csi.PIX_ON_EVENT— um pixel detetou um aumento de brilho (o limiarDIFF_ONfoi cruzado). X/Y apontam para o pixel.csi.EXT_TRIGGER_FALLING— o pino de gatilho externo do sensor detetou uma aresta descendente. X/Y não são usados.csi.EXT_TRIGGER_RISING— o pino de gatilho externo do sensor detetou uma aresta ascendente. X/Y não são usados.csi.RST_TRIGGER_FALLING— gatilho de reset de pixel, aresta descendente. X/Y não são usados. Não gerado pelo firmware de momento.csi.RST_TRIGGER_RISING— gatilho de reset de pixel, aresta ascendente. X/Y não são usados. Não gerado pelo firmware de momento.
A entrada de gatilho externo do GENX320 está ligada à linha de sincronização de fotogramas da câmara, que também está encaminhada para P10 tanto no processador como no cabeçalho de pinos — acione P10 para injetar arestas de sincronização no fluxo de eventos e leia-as como eventos EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING juntamente com os dados de pixel.
A maioria das aplicações apenas precisa de PIX_OFF_EVENT e PIX_ON_EVENT; os tipos de gatilho permitem correlacionar eventos com sinais de temporização externos.
Aloque o buffer de eventos com a forma (EVT_res, 6) onde EVT_res é uma potência de dois entre 1024 e 65536, depois entre no modo evento através de csi.IOCTL_GENX320_SET_MODE com csi.GENX320_MODE_EVENT e o tamanho do buffer. Leia os eventos com csi.IOCTL_GENX320_READ_EVENTS, que preenche o buffer até à sua capacidade e devolve o número de linhas válidas.
Image.draw_event_histogram rasteriza eventos numa imagem em escala de cinzentos — para cada evento ON adiciona contrast ao contentor; para cada evento OFF subtrai. clear=True repõe a imagem para brightness primeiro; clear=False acumula ao longo de várias chamadas:
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())
As predefinições de bias do modo histograma, o filtro AFK e os ioctls de calibração de pixels quentes funcionam da mesma forma em modo evento — invoque-os após csi.IOCTL_GENX320_SET_MODE.
Filtragem por polaridade¶
Fatie o array de eventos com ulab para manter apenas eventos ON (movimento para um estado mais claro) ou apenas eventos 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)
Acumulação de longa exposição¶
Defina clear=False para continuar a empilhar eventos na mesma imagem ao longo de muitos fotogramas — o resultado é uma visualização de rastro de movimento. Reinicie periodicamente para iniciar uma nova exposição:
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
Processamento de alta velocidade¶
Remova a visualização para libertar CPU para processamento de eventos. Imprima estatísticas apenas a cada N-ésima iteração — enviar uma linha de impressão em cada iteração torna-se o gargalo a taxas de eventos elevadas:
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")
Filtro de contraste espácio-temporal (STC)¶
Uma aresta de contraste real em movimento tende a desencadear uma rajada ruidosa de eventos no mesmo pixel dentro de uma janela de tempo curta — o desfasamento dos pixels e o ruído analógico produzem eventos extra em torno da transição genuína que não são úteis para a aplicação. O filtro STC é um pós-processamento no chip que mantém apenas um (ou alguns) eventos por rajada e descarta os restantes.
Implementa três estratégias, selecionadas via csi.IOCTL_GENX320_SET_STC e uma constante GENX320_STC_*. Cada modo é definido pelos eventos que reencaminha de uma rajada:
Modo |
Mantém |
Descarta |
|---|---|---|
todos os eventos |
nada |
|
segundo evento de uma rajada |
primeiro + eventos posteriores |
|
primeiro evento de uma rajada |
eventos subsequentes |
|
primeiro + arestas subsequentes |
apenas ruído redundante |
Em detalhe:
csi.GENX320_STC_DISABLE— filtro desativado, todos os eventos passam (predefinição).csi.GENX320_STC_ONLY— mantém o segundo evento de uma rajada. Parâmetro:stc_threshold(ms). Se um novo evento num pixel chegar dentro destc_thresholdde um evento anterior, é considerado o «segundo» da rajada e é reencaminhado — o primeiro evento e quaisquer eventos subsequentes na mesma rajada são filtrados. Melhor quando se pretende uma transição confirmada por ruído em vez da primeira ocorrência.csi.GENX320_STC_TRAIL_ONLY— mantém o primeiro evento de uma rajada. Parâmetro:trail_threshold(ms). Após um pixel disparar, os eventos subsequentes no mesmo pixel são descartados atétrail_thresholdter decorrido. Preserva a temporização precisa da aresta inicial — útil quando o momento da mudança de polaridade importa mais do que a confirmação por rajada.csi.GENX320_STC_TRAIL— combina ambos. Parâmetros:stc_thresholdetrail_threshold(ambos em ms). Mantém a aresta inicial segundo o modo Trail mais arestas subsequentes segundo o modo STC, pelo que vários eventos de uma rajada ainda passam — maior débito de eventos do que os filtros de modo único mas sinal mais rico.
Os dois limiares devem manter-se numa proporção de aproximadamente 13:1 — o sensor rejeita configurações em que um é mais de ~13x o outro:
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_TRAIL, 1, 2)
csi0.ioctl(csi.IOCTL_GENX320_SET_STC, csi.GENX320_STC_DISABLE)
Profundidade do buffer¶
Quando as taxas de eventos disparam, o pipeline de triplo buffer predefinido favorece o fotograma mais recente e descarta os antigos. Aumente a profundidade da FIFO via csi.CSI.framebuffers para colocar eventos em fila — ao custo de processar dados ligeiramente mais antigos quando o anfitrião fica para trás:
csi0.framebuffers(10) # FIFO depth, > 3 enables queueing
Streaming e visualização no ambiente de trabalho¶
Para visualização GUI em tempo real num PC anfitrião, a ferramenta de Streaming de Eventos GenX320 no repositório openmv-projects combina a câmara com um front-end DearPyGui. A GUI do PC executa duas visualizações lado a lado: uma tela de acumulação de eventos (mesma ideia que Image.draw_event_histogram mas com paletas selecionáveis e modos de janela deslizante vs. auto-limpar) e um mapa de frequência por pixel conduzido por um filtro passa-banda IIR — útil para detetar sinais periódicos (ventoinhas em rotação, LEDs intermitentes, etc.) diretamente no fluxo de eventos.
Inclui dois scripts de streaming na câmara:
Modo processado (
genx320_event_mode_streaming_on_cam.py) — a câmara descodifica os eventos comcsi.IOCTL_GENX320_READ_EVENTSe transmite cada linha como 12 bytes via USB ([0]tipo,[1]seg,[2]ms,[3]us,[4]x,[5]y). Fácil de consumir no PC porque o formato do fio corresponde ao formato ndarray na câmara.Modo bruto (
genx320_raw_event_mode_streaming_on_cam.py) — a câmara transmite as palavras de eventos de 32 bits empacotadas nativas do chip através decsi.IOCTL_GENX320_READ_EVENTS_RAW. São 4 bytes por evento versus 12 no modo processado (cerca de 3x menos dados via USB), portanto ~3x maior taxa de eventos alcançável quando a ligação é o gargalo. O PC descodifica as palavras empacotadas de volta para o mesmo layout de eventos de 6 colunas usando numpy vetorizado, pelo que o código do visualizador a jusante é idêntico.
O modo bruto é o predefinido na GUI porque o débito USB é a restrição determinante às taxas que o GenX320 pode produzir; mude para o modo processado se precisar de incorporar lógica de processamento no script na câmara.