Event Output
This sample shows how to export event-list output from DELTA raw data. It uses a
two-phase workflow: first save live sensor data as a .dvs file, then reopen the
saved file with playback and convert the event output to CSV.
Back to Code Samples.
Example Overview
| Step | SDK API | Purpose |
|---|---|---|
| 1 | scanDevices() / openDevice() |
Find and open a connected DELTA Series camera. |
| 2 | applySensorSetting() |
Apply the recommended sensor setting file. |
| 3 | startStream() |
Start live USB streaming. |
| 4 | startRawSaving() / saveRawBy*() |
Save raw sensor data as a .dvs file. |
| 5 | openFile() / startPlayback() |
Reopen the saved .dvs file for offline conversion. |
| 6 | setFrameGeneration() |
Choose how events are grouped into generated frames. |
| 7 | setOutputType() |
Select ClassicEvents or CompactEvents. |
| 8 | getClassicEvents() / getCompactEvents() |
Read event-list output into caller-owned buffers. |
| 9 | setReadOverCallback() |
Detect when playback reaches the end of the file. |
Expected Result
When the sample runs successfully, an event_output folder is created under
the save directory. The folder contains the raw data captured during Phase 1
and the CSV file generated during Phase 2.
event_output/
├─ raw_data/
│ └─ year-month-day-hour-minute-second-DELTA.dvs
└─ Classic.csv or Compact.csv
The raw_data folder stores the .dvs raw data file recorded from the camera.
The CSV file stores only the positions where events occurred.
If Classic is selected, the output file is Classic.csv.
timestamp_us,x,y,polarity
Each row contains one event with its timestamp, x position, y position, and polarity.
If Compact is selected, the output file is Compact.csv.
frame_timestamp_us,x,y,polarity
Each row contains one event with the timestamp of the generated frame, x position, y position, and polarity.
Note
Classic and Compact may look similar in CSV form, but the timestamp
meaning is different. Classic stores a timestamp for each event, while
Compact uses one frame timestamp generated from the sensor frame-end
packet. Because DELTA sensors do not generate an independent timestamp for
every event, Compact is usually the more efficient format for saving and
transferring event data.
Code Walkthrough
Edit the User Control Panel
The USER CONTROL PANEL section is the only part you normally need to edit.
Each option group has one active line and one or more commented alternatives.
To use a different mode, comment out the current active line and uncomment the
mode you want to use.
Select a Camera
const std::int32_t selectDeviceIndex = 0;
selectDeviceIndex = 0 selects the first detected camera.
Select an Event Format
Only one selected_eventformat line should be active at a time.
(a) Classic
const std::string selected_eventformat = "Classic";
Classic exports one timestamp per event. The CSV header is:
timestamp_us,x,y,polarity
(b) Compact
// const std::string selected_eventformat = "Compact";
Compact exports x, y, and polarity per event, with one frame timestamp shared
by all events in the generated frame. The CSV header is:
frame_timestamp_us,x,y,polarity
Note
ClassicEvent contains x, y, polarity, and per-event timestamp.
CompactEvent contains only x, y, and polarity; the timestamp is
stored once in CompactEventList::frameTimestamp.
Select a Frame Generation Mode
Frame generation controls how raw event data is grouped before event lists are
read during conversion. Only one selected_framemode line should be active.
const std::string selected_framemode = "FrameEndBased";
const std::int32_t frameEndCount = 1;
// const std::string selected_framemode = "TimeBased";
const std::int32_t framePeriodMs = 16;
// const std::string selected_framemode = "EventCountBased";
const std::int32_t eventsPerFrame = 50000;
FrameEndBased follows the recorded frame-end markers. TimeBased groups
events by fixed time intervals, and EventCountBased groups events by event
count.
Select a Raw Saving Mode
The raw saving mode controls how much live data is recorded in Phase 1.
const std::string selected_savemode = "Continuous";
// const std::string selected_savemode = "Time";
const std::int32_t durationMs = 2000;
// const std::string selected_savemode = "FrameCount";
const std::uint64_t targetFrames = 100;
// const std::string selected_savemode = "EventCount";
const std::uint64_t targetEvents = 1000000;
Continuous starts saving when you press s and stops when you press q.
Other modes call saveRawByTime(), saveRawByFrameCount(), or
saveRawByEventCount().
Select Output Directories
const std::filesystem::path rawSaveDirectory =
std::filesystem::path(DELTA_SAMPLE_ROOT) / "saved_data" / "event_output" / "raw_data";
const std::filesystem::path csvSaveDirectory =
std::filesystem::path(DELTA_SAMPLE_ROOT) / "saved_data" / "event_output";
Raw .dvs files are written to rawSaveDirectory. CSV files are written to
csvSaveDirectory.
Phase 1: Capture Raw Data
The example starts live streaming and saves raw data according to the selected save mode.
status = delta::startStream(cameraHandle);
if (selected_savemode == "Continuous") {
status = delta::startRawSaving(cameraHandle, rawSaveDirectoryString.c_str());
if (status == delta::Status::Success) {
// Wait for the user to press 'q'.
status = delta::stopRawSaving(cameraHandle);
}
}
else if (selected_savemode == "Time") {
status = delta::saveRawByTime(cameraHandle, rawSaveDirectoryString.c_str(), durationMs);
}
After saving completes, the example locates the newly created .dvs file and
uses it as the input for Phase 2.
Phase 2: Select Event Output
The saved raw file is reopened through the playback API. The selected frame generation setting is applied before reading events.
status = delta::openFile(rawFileString.c_str(), &fileHandle);
status = delta::setPlaybackMode(fileHandle, delta::PlaybackMode::Once);
status = delta::setFrameGeneration(fileHandle, frameGeneration);
The selected event format controls the processing output type.
if (selected_eventformat == "Classic") {
status = delta::setOutputType(fileHandle, delta::OutputType::ClassicEvents);
}
else if (selected_eventformat == "Compact") {
status = delta::setOutputType(fileHandle, delta::OutputType::CompactEvents);
}
Prepare Event Buffers
Event outputs use caller-owned buffers. Allocate the event array and attach it to the corresponding output structure before polling.
std::vector<delta::ClassicEvent> classicEventBuffer(DELTA_DEFAULT_EVENT_CAPACITY);
delta::ClassicEventList classicEventList{};
classicEventList.events = classicEventBuffer.data();
classicEventList.eventCapacity = DELTA_DEFAULT_EVENT_CAPACITY;
std::vector<delta::CompactEvent> compactEventBuffer(DELTA_DEFAULT_EVENT_CAPACITY);
delta::CompactEventList compactEventList{};
compactEventList.events = compactEventBuffer.data();
compactEventList.eventCapacity = DELTA_DEFAULT_EVENT_CAPACITY;
Detect End of Playback
PlaybackMode::Once fires this callback once the file has been fully read. A
few more frames can still be in flight in the processing pipeline at that
point, so the sample keeps polling for a short grace period afterward instead
of stopping immediately.
std::atomic<bool> playbackDone{false};
status = delta::setReadOverCallback(
fileHandle,
[](void* userData) { static_cast<std::atomic<bool>*>(userData)->store(true); },
&playbackDone
);
Once playbackDone is set, the polling loop allows up to 100 consecutive
empty polls to drain any remaining frames before it stops.
constexpr int kDrainRetriesAfterEnd = 100;
int drainRetries = 0;
while (true) {
const auto result = pollAndWrite(fileHandle, csvFile);
if (result.frameReady) {
drainRetries = 0;
}
else if (playbackDone.load()) {
if (++drainRetries >= kDrainRetriesAfterEnd) { break; }
}
}
Poll Events and Write CSV
For Classic output, each event row contains per-event timestamp, x, y, and polarity.
delta::getClassicEvents(handle, &classicEventList, 0);
for (std::int32_t i = 0; i < classicEventList.eventCount; ++i) {
const auto& e = classicEventList.events[i];
csvFile << e.timestamp << ',' << e.x << ',' << e.y << ','
<< static_cast<int>(e.polarity) << '\n';
}
For Compact output, each event row uses the frame timestamp from
CompactEventList.
delta::getCompactEvents(handle, &compactEventList, 0);
for (std::int32_t i = 0; i < compactEventList.eventCount; ++i) {
const auto& e = compactEventList.events[i];
csvFile << compactEventList.frameTimestamp << ',' << e.x << ',' << e.y << ','
<< static_cast<int>(e.polarity) << '\n';
}
polarity uses the sensor convention:
| Value | Meaning |
|---|---|
0 |
ON event |
1 |
OFF event |
Stop Playback
delta::stopPlayback(fileHandle);
delta::closeFile(fileHandle);