02 读取事件
任务目标
把"事件流"取到你的程序里。事件来源分两种:实时相机和录像文件。本页给出两种来源的读取方式与字段含义。
涉及类与概念
Shimeta::hv::Camera::GetFrame/SetEventCallback:实时取事件(同步 / 异步)。Shimeta::codec::Evt2Decoder/Evt3Decoder(及 MIPI 的MipiRaw8Decoder):把原始事件字节解码为EventCD。Shimeta::io::EventReader:从 RAW 文件读取并解码。Shimeta::EventCD:单个事件,字段(x, y, t, polarity)——坐标、时间戳(微秒)、极性。
v2.0 的关键变化
v2.0 相机给的是原始事件字节(Frame.evs / EventPacket.data,格式由 DeviceConfig.event_fmt 决定),不直接给解码后的事件。你需要用对应的 codec 把字节解码成 EventCD。这取代了旧版 startEventCapture 直接回调 vector<EventCD> 的用法。
实时相机:取事件 + 解码
同步:GetFrame + 解码 Frame.evs
#include <shimetapi/hv/camera.h>
#include <shimetapi/hv/device_config.h>
#include <shimetapi/codec/evt2_codec.h>
#include <vector>
Shimeta::hv::Camera cam;
Shimeta::hv::DeviceConfig cfg;
cfg.backend = Shimeta::hv::Backend::Usb;
cfg.vendor_id = 0x1d6b;
cfg.product_id = 0x0105;
cfg.event_fmt = Shimeta::hv::EventFormat::Evt2; // 决定 Frame.evs 的格式 → 选哪个 Decoder
cam.Init(cfg);
cam.StartStream();
Shimeta::codec::Evt2Decoder dec; // 有状态:跨包维护时间基准,循环外构造、复用
Shimeta::Frame f;
while (cam.GetFrame(f, 1000)) {
std::vector<Shimeta::EventCD> events;
dec.Decode(f.evs.data, f.evs.size, events); // 原始字节 → EventCD
for (const auto& e : events) {
// e.x, e.y:像素坐标;e.polarity:极性(true 变亮 / false 变暗);e.t:时间戳(us)
}
}
cam.StopStream();
cam.Destroy();event_fmt 与解码器的对应:Evt2 → Evt2Decoder;Evt3 → Evt3Decoder。两者均有状态,多包流复用同一实例,开始新流前调用 Reset()。
异步:SetEventCallback
回调给的是 EventPacket,其 data 是一包原始事件字节,同样用 codec 解码:
Shimeta::codec::Evt2Decoder dec; // 跨回调复用,勿每次构造
cam.SetEventCallback([&dec](const Shimeta::hv::EventPacket& pkt) {
std::vector<Shimeta::EventCD> events;
dec.Decode(pkt.data.data, pkt.data.size, events);
// 处理 events
});回调线程注意事项
回调在派发线程串行触发(采集线程不回调)。不要在回调中做阻塞操作或反向调用相机的同步接口;重计算应转存后在工作线程处理。
MIPI HVS:用 MipiRaw8Decoder
Backend::MipiHvs 的 Frame.evs 不是 EVT2/EVT3 字节流,而是 apx003 RAW8 子帧流 —— 必须用 MipiRaw8Decoder 解码(不能用 Evt2/Evt3Decoder)。它无状态,无需跨包复用、无需 Reset:
#include <shimetapi/codec/mipi_raw8_codec.h>
Shimeta::codec::MipiRaw8Decoder dec;
Shimeta::Frame f;
while (cam.GetFrame(f, 1000)) {
std::vector<Shimeta::EventCD> events;
dec.Decode(f.evs.data, f.evs.size, events); // RAW8 子帧流 → EventCD
}旧版 MIPI 的「录制回调 / 显示回调 / RAW8 回调」三路拆分在 v2.0 统一 API 中已合并:你拿到原始字节后自行解码,显示帧率由应用层控制(如降低取帧频率或只处理部分子帧)。
S100 与 X5 的事件字节布局和解码器相同;差异主要在平台库、传感器索引和 APS 格式。事件读取代码无需分成两套。
录像文件:EventReader
Shimeta::io::EventReader 打开 RAW 文件后,按头部 ev_version 自动选 EVT2/EVT3 解码,readAllEvents 一次返回全部解码事件:
#include <shimetapi/io/event_reader.h>
#include <iostream>
Shimeta::io::EventReader reader;
reader.open("events.raw");
std::vector<Shimeta::EventCD> events;
size_t n = reader.readAllEvents(events); // 内部自动选 EVT2/EVT3 解码
std::cout << "共 " << n << " 个事件" << std::endl;当前限制
v2.0 EventReader 目前只提供 readAllEvents(全量读入内存),暂未提供分批 / 流式读取。超大文件需注意内存占用;如需逐块处理,可自行按字节偏移切块后交给对应 Decoder。
文件格式(EVT2 / RAW8 / CSV)与转换见 数据格式。
EventCD 字段
struct EventCD {
uint16_t x; // 像素 X 坐标
uint16_t y; // 像素 Y 坐标
int64_t t; // 时间戳(微秒)
bool polarity; // true = CD_ON(变亮),false = CD_OFF(变暗)
};字段名与旧版
Metavision::EventCD略有不同:极性字段为polarity(bool),而非旧的p(int)。
进阶
- 完整 API:Toolkit C++ API
- 把读到的事件存下来:指引 03 录制与回放
- 读到的事件先去噪再用:指引 04 事件处理(去噪)
