Event store

The dv-processing library provides an easy to use and an efficient data structure to store and manage incoming event data from the camera - the dv::EventStore class. It is implemented as a shallow, shared ownership data structure which only holds pointers to actual memory locations containing event data. Similarly to how OpenCV handles image data, the dv::EventStore does not copy the data, instead it only holds pointers to received packets of events and uses metadata of these packets to efficiently slice the data given time-intervals.

Create and store events

The following sample code shows how to create an empty event store and fill it with software generated events:

 1#include <dv-processing/core/core.hpp>
 2#include <dv-processing/core/utils.hpp>
 3
 4int main() {
 5    // Initialize an empty store
 6    dv::EventStore store;
 7
 8    // Get the current timestamp
 9    const int64_t timestamp = dv::now();
10
11    // Add some events into the event store
12    // This allocates and inserts events at the back, the function arguments are:
13    // timestamp, x, y, polarity
14    store.emplace_back(timestamp, 0, 0, true);
15    store.emplace_back(timestamp + 1000, 1, 1, false);
16    store.emplace_back(timestamp + 2000, 2, 2, false);
17    store.emplace_back(timestamp + 3000, 3, 3, true);
18
19    // Perform time-based slicing of event store, the output event store "sliced" will contain
20    // the second and third events from above. The end timestamp (second argument) is 2001, since start
21    // timestamp (first argument) is inclusive and timestamp is exclusive, so 1 is added.
22    const dv::EventStore sliced = store.sliceTime(timestamp + 1000, timestamp + 2001);
23
24    // This should print two events
25    for (const dv::Event &ev : sliced) {
26        std::cout << fmt::format("Sliced event [{}, {}, {}, {}]", ev.timestamp(), ev.x(), ev.y(), ev.polarity())
27                  << std::endl;
28    }
29
30    return 0;
31}

Slicing Event Stores

dv::EventStore can be sliced by time or by the number of events. Slicing is a shallow operation, it does not copy any data. Slicing returns a new dv::EventStore that only references the data requested. The original store is unaffected.

Slicing by time

dv::EventStore implements event data slicing by time in an efficient way. By reusing the underlying packet structure, the slicing is performed with O(log n) time complexity. The following sample shows the usage of time based slicing functions:

 1#include <dv-processing/core/core.hpp>
 2#include <dv-processing/data/generate.hpp>
 3
 4int main() {
 5    using namespace std::chrono_literals;
 6
 7    // Generate 10 events with time range [10000; 20000]
 8    const auto store = dv::data::generate::uniformEventsWithinTimeRange(10000, 10ms, cv::Size(100, 100), 10);
 9
10    // Get all events with timestamp above 12500, it will be 13000 and up
11    dv::EventStore eventsAfterTimestamp = store.sliceTime(12'500);
12
13    // Print the timestamp ranges
14    std::cout << "1. " << eventsAfterTimestamp << std::endl;
15
16    // Slice event within time range [12000; 16000); the end time is exclusive
17    const dv::EventStore eventsInRange = store.sliceTime(12'000, 16'000);
18
19    // Print the timestamp ranges; It will print that range is [12000; 15000] since end time is exclusive and
20    // event at timestamp 16000 is not going to be included.
21    std::cout << "2. " << eventsInRange << std::endl;
22
23    return 0;
24}

Slicing by number of events

dv::EventStore provides slicing capabilities by an index and number of events. The first argument to the dv::EventStore::slice() method is a starting index from which the output slice starts, the second optional argument is the number of events to be sliced. If the number argument is not provided, the slice will contain all events from given index.

Following sample shows how to slice an event store within given indices of the underlying events:

 1#include <dv-processing/core/core.hpp>
 2#include <dv-processing/data/generate.hpp>
 3
 4int main() {
 5    using namespace std::chrono_literals;
 6
 7    // Add 10 event with timestamps in range [10000; 20000]
 8    const auto store = dv::data::generate::uniformEventsWithinTimeRange(10000, 10ms, cv::Size(100, 100), 10);
 9
10    // Get all events beyond and including index 5
11    dv::EventStore eventsAfterIndex = store.slice(5);
12    std::cout << "1. " << eventsAfterIndex << std::endl;
13
14    // Get 3 events starting with index 2
15    dv::EventStore eventsInRange = store.slice(2, 3);
16    std::cout << "2. " << eventsInRange << std::endl;
17
18    // Use sliceBack to retrieve event from the end; this call will retrieve last 3 events
19    dv::EventStore lastEvents = store.sliceBack(3);
20    std::cout << "3. " << lastEvents << std::endl;
21
22    return 0;
23}

Combining multiple EventStores

Multiple instances of dv::EventStore can be added together to have a single object to access and manage it. Since dv::EventStore uses pointers to underlying event packet data, combining does not involve any deep data copies, the implementation takes over shared memory ownership instead. Following sample show how to efficiently combine multiple event stores into one:

 1#include <dv-processing/core/core.hpp>
 2#include <dv-processing/data/generate.hpp>
 3
 4int main() {
 5    using namespace std::chrono_literals;
 6
 7    // Generate 10 events with timestamps in range [10000; 20000]
 8    const auto store1 = dv::data::generate::uniformEventsWithinTimeRange(10000, 10ms, cv::Size(100, 100), 10);
 9
10    // Generate second event store with 10 events with timestamps in range [20000; 29000] to the second store
11    const auto store2 = dv::data::generate::uniformEventsWithinTimeRange(20000, 10ms, cv::Size(100, 100), 10);
12
13    // Final event store which will contain all events
14    dv::EventStore finalStore;
15
16    // Add the events into the final store; this operation is shallow, so no data copies
17    // are performed, but the underlying data has shared ownership between all stores
18    finalStore.add(store1);
19    finalStore.add(store2);
20
21    // Print specific information on what we contain in the event store
22    std::cout << finalStore << std::endl;
23
24    return 0;
25}