Подійна камера GENX320

Модуль подійної камери GENX320 — це датчик технічного зору на основі подій від компанії Prophesee з роздільною здатністю 320x320 та мікросекундною точністю відліку часу.

GENX320 Event Camera

Повний технічний опис, фотографії та інформацію про замовлення дивіться на сторінці продукту GENX320 Event Camera.

Примітка

Підтримується на платформах OpenMV H7 Plus, RT1062 та N6.

Особливості

  • Датчик технічного зору на основі подій 320x320

  • Динамічний діапазон 140 дБ, відсутність розмиття руху

  • Частота виведення гістограми подій 375 Гц і вище

  • Споживання енергії масштабується з активністю сцени — від ~3 мВт

  • Робота від <5 люкс до яскравого сонячного світла без автовитримки

  • Виведення кадрів у відтінках сірого або потоків необроблених подій

Використання

GENX320 — це датчик технічного зору на основі подій: замість зчитування всього масиву 320x320 з фіксованою тактовою частотою, кожен піксель асинхронно повідомляє «події» в момент виявлення зміни яскравості. Кожна подія містить координати X/Y, полярність ON/OFF (яскравий→темний або темний→яскравий) та мікросекундну позначку часу. Саме звідси походять мікросекундна точність, відсутність розмиття руху, дуже широкий динамічний діапазон та споживання енергії, масштабоване за активністю сцени. Статичні сцени не генерують жодних даних.

Мікропрограма OpenMV надає доступ до GENX320 через csi.CSI з cid= csi.GENX320. Доступні два режими роботи:

  • Режим гістограми (за замовчуванням) — події накопичуються на чипі в комірках для кожного пікселя та виводяться як кадр у відтінках сірого 320x320 з налаштовуваною частотою (~20–350 кадрів/с). Датчик поводиться як звичайна камера, тому всі стандартні процедури обробки зображень (Image.find_blobs, палітри тощо) працюють безпосередньо.

  • Режим подій — необроблені події надходять у ndarray numpy з повними мікросекундними мітками часу для застосунків, яким потрібна тимчасова деталізація, а не попередньо накопичений кадр.

Режим гістограми

У режимі гістограми GENX320 виводить кадри у відтінках сірого, де кожен піксель кодує нещодавню активність подій у цій точці. Пікселі вище базового рівня яскравості — це події ON (зростання яскравості), нижче — події OFF (спадання яскравості). Базова яскравість за замовчуванням дорівнює 128, а крок контрасту на одну подію — 16; збільшіть контраст, щоб події стали помітнішими:

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 та csi.CSI.framerate — три параметри, що формують вивід гістограми.

Розфарбований вивід

Встановіть csi.CSI.color_palette на image.PALETTE_EVT_LIGHT для світлого фону або image.PALETTE_EVT_DARK для темного — драйвер безпосередньо виводить кадри RGB565 з використанням цієї палітри:

csi0.color_palette(image.PALETTE_EVT_LIGHT)

Калібрування гарячих пікселів

Датчики подій накопичують «гарячі пікселі», що спрацьовують хибно. Виконайте csi.IOCTL_GENX320_CALIBRATE на статичній сцені, щоб вимкнути їх. Драйвер формує лічильник попадань 320x320 для кожного пікселя, обчислює середнє значення та стандартне відхилення і вимикає будь-який піксель, кількість попадань якого перевищує mean + sigma * stddev — після чого вимкнені пікселі перестають генерувати події на рівні датчика.

Два параметри керують калібруванням:

  • event_count — кількість подій для підрахунку перед обчисленням статистики. Цикл захоплює кадри, доки загальна кількість подій не перевищить цей ліміт. Більша кількість дає надійнішу оцінку ціною довшого часу калібрування. 10000 — розумна початкова точка.

  • sigma — множник порогу на стандартне відхилення. Менші значення більш агресивні (більше пікселів вимикається); більші — більш консервативні. 0.5 — хороше значення за замовчуванням.

Спочатку направте датчик на статичну сцену, щоб події, спричинені рухом, не зараховувалися проти пікселів, які насправді справні:

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

Антибліковий (AFK) фільтр

Періодичні джерела світла (люмінесцентні лампи, дисплеї на LED-основі) генерують величезні обсяги зайвих подій. Фільтр AFK відкидає події, у яких перемикання пікселя відбувається з частотою в межах певного діапазону — увімкніть його через csi.IOCTL_GENX320_SET_AFK із граничними значеннями діапазону в герцах:

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

Попередньо встановлені зміщення

Кожен піксель у GenX320 має аналоговий вхідний каскад із декількома налаштовуваними зміщеннями. Вони разом визначають чутливість, шуми, смугу пропускання пікселя та швидкість подій — оптимальна комбінація залежить від сцени. Окремі зміщення:

  • DIFF_ON — поріг контрасту позитивного компаратора. Піксель генерує подію ON, коли його логарифм освітленості зріс на цю величину. Менше = більш чутливий до яскравих переходів.

  • DIFF_OFF — поріг контрасту негативного компаратора (симетричний аналог для подій OFF). Менше = більш чутливий до темних переходів.

  • FO — частота зрізу низькочастотного фільтра пікселя. Вище = ширша смуга пропускання пікселя (швидша реакція, менша затримка), але більша фонова шумова активність.

  • HPF — частота зрізу верхньочастотного фільтра. Вище = краще придушення повільних змін яскравості; до компараторів доходять лише швидкі переходи. Корисно для ігнорування дрейфу фону.

  • REFR — рефрактерний період. Після спрацьовування пікселя він залишається у стані скидання протягом цього часу. Вище = довший мертвий час, корисно для обмеження швидкості подій на піксель.

Після csi.CSI.reset драйвер застосовує csi.GENX320_BIASES_LOW_NOISE, а не csi.GENX320_BIASES_DEFAULT — значення за замовчуванням із технічного опису генерують значно вищу фонову швидкість подій, тому LOW_NOISE використовується як початкова точка для заспокоєння потоку. Викличте csi.IOCTL_GENX320_SET_BIASES з іншим набором налаштувань, якщо застосунку потрібна більша чутливість або смуга пропускання.

csi.IOCTL_GENX320_SET_BIASES застосовує один із п’яти попередньо встановлених наборів:

  • csi.GENX320_BIASES_DEFAULT — значення за замовчуванням з технічного опису GenX320. Збалансована чутливість, шуми та смуга пропускання для загальних сцен.

  • csi.GENX320_BIASES_LOW_LIGHT — обидва пороги контрасту розширені для підвищення чутливості, FO знижено для зменшення шумів, а HPF встановлено в 0, щоб повільні зміни яскравості також реєструвалися — сцена при слабкому освітленні сама по собі генерує мало подій, тому потрібно пропустити якомога більше.

  • csi.GENX320_BIASES_ACTIVE_MARKER — налаштований для відстеження миготливих LED-маркерів із високим контрастом. Пороги контрасту підвищені, щоб спрацьовували лише різкі переходи; FO та HPF максимально підвищені для збільшення смуги пропускання пікселя та придушення повільного фонового дрейфу; REFR опущений до 0, щоб захоплювалися обидва фронти кожного блимання. Результат: потік, що складається майже виключно з фронтів LED, зручний для відстеження.

  • csi.GENX320_BIASES_LOW_NOISE — за замовчуванням драйвера. Обидва пороги контрасту підвищені порівняно з DEFAULT (менш чутливий), а FO знижений (повільніший піксель = тихіший піксель). Найкраще для статичних або повільних сцен, де хибні події в іншому випадку домінували б.

  • csi.GENX320_BIASES_HIGH_SPEED — FO підвищений для прискорення реакції кожного пікселя, HPF підвищений для придушення повільного дрейфу яскравості, а REFR підвищений, щоб одна швидко рухома межа не перевантажила зчитування — довший мертвий час обмежує обсяг подій при інтенсивному русі.

Замініть окремі зміщення за допомогою csi.IOCTL_GENX320_SET_BIAS разом із одним із csi.GENX320_BIAS_DIFF_ON, csi.GENX320_BIAS_DIFF_OFF, csi.GENX320_BIAS_FO, csi.GENX320_BIAS_HPF або csi.GENX320_BIAS_REFR та значенням DAC. Кожне зміщення встановлюється незалежно — виберіть набір налаштувань як початкову точку, а потім підлаштуйте потрібні зміщення під свою сцену:

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

Відстеження

Оскільки вивід у режимі гістограми є звичайним зображенням у відтінках сірого, стандартне відстеження плям працює безпосередньо. Для відстеження LED-маркера з активним маркером завантажте відповідний набір зміщень і знайдіть плями у яскравій частині гістограми:

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

Режим подій

Режим подій обходить гістограму на чипі та передає необроблені події у ndarray numpy. Кожна подія — це рядок із шести стовпців uint16:

  • [0] тип події — дивіться нижче

  • [1] позначка часу в секундах

  • [2] позначка часу в мілісекундах

  • [3] позначка часу в мікросекундах

  • [4] координата X, 0–319

  • [5] координата Y, 0–319

Драйвер генерує шість типів подій у стовпці [0]:

  • csi.PIX_OFF_EVENT — піксель виявив зменшення яскравості (перетнуто поріг компаратора DIFF_OFF). X/Y вказують на піксель, що спрацював.

  • csi.PIX_ON_EVENT — піксель виявив збільшення яскравості (перетнуто поріг DIFF_ON). X/Y вказують на піксель.

  • csi.EXT_TRIGGER_FALLING — зовнішній тригерний вивід датчика зафіксував спадаючий фронт. X/Y не використовуються.

  • csi.EXT_TRIGGER_RISING — зовнішній тригерний вивід датчика зафіксував наростаючий фронт. X/Y не використовуються.

  • csi.RST_TRIGGER_FALLING — тригер скидання пікселя, спадаючий фронт. X/Y не використовуються. Наразі мікропрограма не генерує цей тип.

  • csi.RST_TRIGGER_RISING — тригер скидання пікселя, наростаючий фронт. X/Y не використовуються. Наразі мікропрограма не генерує цей тип.

Зовнішній тригерний вхід GENX320 підключений до лінії синхронізації кадрів камери, яка також виведена на P10 як на процесорі, так і на гребінці виводів — подайте сигнал на P10, щоб вставити синхроімпульси в потік подій і отримати їх як події EXT_TRIGGER_RISING / EXT_TRIGGER_FALLING разом із даними пікселів.

Більшість застосунків використовують лише PIX_OFF_EVENT та PIX_ON_EVENT; типи тригерів дозволяють корелювати події із зовнішніми сигналами синхронізації.

Виділіть буфер подій із формою (EVT_res, 6), де EVT_res — ступінь двійки від 1024 до 65536, потім увійдіть у режим подій через csi.IOCTL_GENX320_SET_MODE з csi.GENX320_MODE_EVENT і розміром буфера. Зчитуйте події за допомогою csi.IOCTL_GENX320_READ_EVENTS, яка заповнює буфер до його ємності та повертає кількість дійсних рядків.

Image.draw_event_histogram растеризує події в зображення у відтінках сірого — для кожної події ON вона додає contrast до комірки; для кожної події OFF — віднімає. clear=True скидає зображення до значення brightness перед цим; clear=False накопичує протягом багатьох викликів:

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

Попередньо встановлені зміщення у режимі гістограми, фільтр AFK та ioctls калібрування гарячих пікселів однаково працюють у режимі подій — викликайте їх після csi.IOCTL_GENX320_SET_MODE.

Фільтрування за полярністю

Зріжте масив подій за допомогою ulab, щоб залишити лише події ON (рух у бік більш яскравого стану) або лише події 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)

Накопичення з довгою витримкою

Встановіть clear=False, щоб продовжувати нашаровувати події в одне зображення протягом багатьох кадрів — результат являє собою візуалізацію слідів руху. Регулярно скидайте для початку нової витримки:

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

Високошвидкісна обробка

Вимкніть візуалізацію, щоб звільнити процесор для обробки подій. Виводьте статистику лише кожну N-ну ітерацію — виведення рядка на кожній ітерації стає вузьким місцем при високих швидкостях подій:

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

Просторово-часовий контрастний (STC) фільтр

Реальна рухома контрастна межа, як правило, викликає галасливий сплеск подій на одному пікселі протягом короткого часового вікна — невідповідність пікселів і аналоговий шум генерують зайві події навколо справжнього переходу, які не є корисними для застосунку. Фільтр STC — це внутрічіповий постобробний процес, який зберігає лише одну (або кілька) подій із сплеску, відкидаючи решту.

Він реалізує три стратегії, які вибираються через csi.IOCTL_GENX320_SET_STC та константу GENX320_STC_*. Кожен режим визначається тим, які події він пропускає зі сплеску:

Режим

Зберігає

Відкидає

csi.GENX320_STC_DISABLE

кожну подію

нічого

csi.GENX320_STC_ONLY

другу подію сплеску

першу + наступні події

csi.GENX320_STC_TRAIL_ONLY

першу подію сплеску

наступні події

csi.GENX320_STC_TRAIL

першу + наступні фронти

лише зайвий шум

Детально:

  • csi.GENX320_STC_DISABLE — фільтр вимкнено, кожна подія проходить (за замовчуванням).

  • csi.GENX320_STC_ONLY — зберігає другу подію сплеску. Параметр: stc_threshold (мс). Якщо нова подія на пікселі надходить протягом stc_threshold після попередньої події, вона вважається «другою» у сплеску та пропускається — перша подія та будь-які наступні події в тому самому сплеску відфільтровуються. Найкраще, коли потрібен підтверджений шумом перехід, а не самий перший удар.

  • csi.GENX320_STC_TRAIL_ONLY — зберігає першу подію сплеску. Параметр: trail_threshold (мс). Після спрацьовування пікселя наступні події на тому самому пікселі відкидаються, доки не мине trail_threshold. Зберігає точний момент часу провідного фронту — корисно, коли момент зміни полярності важливіший за підтвердження сплеску.

  • csi.GENX320_STC_TRAIL — поєднує обидва. Параметри: stc_threshold та trail_threshold (обидва в мс). Зберігає провідний фронт відповідно до режиму Trail плюс наступні фронти відповідно до режиму STC, тому через сплеск проходить кілька подій — більша пропускна здатність подій, ніж у одномодальних фільтрів, але найбагатший сигнал.

Два пороги повинні залишатися приблизно в співвідношенні 13:1 — датчик відхиляє конфігурації, де один більш ніж приблизно в 13 разів перевищує інший:

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

Глибина буфера

Коли швидкість подій різко зростає, конвеєр потрійного буфера за замовчуванням надає перевагу останньому кадру та відкидає старі. Збільшіть глибину FIFO через csi.CSI.framebuffers, щоб ставити події в чергу — ціною обробки дещо застарілих даних, коли хост відстає:

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

Потокова передача на робочий стіл і візуалізація

Для візуалізації GUI у реальному часі на ПК-хості інструмент GenX320 Event Streaming tool у репозиторії openmv-projects поєднує камеру з інтерфейсом DearPyGui. GUI на ПК відображає два вікна візуалізації поряд: полотно накопичення подій (та сама ідея, що й Image.draw_event_histogram, але з вибором палітр і режимами ковзного вікна або автоочищення) та карту частот для кожного пікселя, керовану IIR-смуговим фільтром — корисно для виявлення періодичних сигналів (обертових вентиляторів, миготливих LED тощо) безпосередньо в потоці подій.

До нього входять два скрипти потокової передачі на камері:

  • Режим обробки (genx320_event_mode_streaming_on_cam.py) — камера декодує події за допомогою csi.IOCTL_GENX320_READ_EVENTS та передає кожен рядок як 12 байтів через USB ([0] тип, [1] сек, [2] мс, [3] мкс, [4] x, [5] y). Простий для споживання на ПК, оскільки формат проводу відповідає формату ndarray на камері.

  • Сирий режим (genx320_raw_event_mode_streaming_on_cam.py) — камера передає нативні 32-бітні упаковані слова подій чипа через csi.IOCTL_GENX320_READ_EVENTS_RAW. Це 4 байти на подію проти 12 у режимі обробки (приблизно в 3 рази менше даних через USB), тому досяжна швидкість подій приблизно в 3 рази вища, коли лінія є вузьким місцем. ПК декодує упаковані слова назад у той самий 6-стовпчастий формат подій за допомогою векторизованого numpy, тому код подальшого візуалізатора однаковий.

Сирий режим є типовим у GUI, оскільки пропускна здатність USB є обмежуючим фактором при швидкостях, які може забезпечити GenX320; перемкніться на режим обробки, якщо потрібно вбудувати логіку обробки в скрипт на камері.