Events Iterator using Python

In the File Loading Tutorial, we learned how to use metavision_core.event_io.RawReader and metavision_core.event_io.EventDatReader to load RAW and DAT files in a flexible way.

The flexibility of these classes comes with a performance cost: events are copied in a ring buffer before being served to the user.

An alternative and more efficient way to access events is to use metavision_core.event_io.EventsIterator. Iterators are especially convenient for loop processing.

%matplotlib inline
import os
from matplotlib import pyplot as plt
import numpy as np

from metavision_core.event_io import EventsIterator

Reading RAW or DAT Files with EventsIterator

Let’s start by getting a sample file.

raw_path = "spinner.raw"
# if the file doesn't exist, it will be downloaded from Prophesee's public sample server
from metavision_core.utils import get_sample

get_sample(raw_path, folder=".")
# open a file
mv_it = EventsIterator(raw_path, delta_t=10000, max_duration=int(1e6))
print(mv_it)  # show some metadata

print("\nImager size : ", mv_it.get_size())
delta_t 10000 us
starts_ts 0 us end_ts 1000000

Imager size :  (480, 640)

We just created an iterator: to do so, we specified the delta_t which is the duration of the time slice we will receive at each iteration, and an optional max_duration which will define when to stop reading the file.

Have a look at metavision_core.event_io.EventsIterator for more options.

Now we can use a simple for loop over the iterator.

for ev in mv_it:

Using the EventsIterator and numpy, we can write compact and efficient code. For instance, let’s compute the event rate on the previous file for each millisecond (1000us):

def ev_rate_computation_iterator():
    ev_rate_millisecond = np.zeros(int(1e6)//1000)  # we preallocate an array for the result
    for ev in EventsIterator(raw_path, delta_t=10000, max_duration=int(1e6)):
        # np.unique allow to do an histogram quickly
        index, counts = np.unique(ev['t'] // 1000, return_counts=True)
        # for each timestamp (in millisecond) in index, we get the number of events in counts
        ev_rate_millisecond[index.astype(int)] = counts
    return ev_rate_millisecond
ev_rate_millisecond = ev_rate_computation_iterator()
plt.plot(np.arange(int(1e6)//1000)* 1000, ev_rate_millisecond)
plt.title('Number of events by milliseconds as a function of time in us')

Internally, EventsIterator uses a pool of buffers. So if performance and efficiency are a concern, it is a good practice to only keep the event array variable in memory as long as it is needed. The following snippet shows the best way to iterate over events and process them using a user-defined function my_pipeline:

# ev is released at every iteration
for ev in EventsIterator(raw_path, delta_t=10000):
    # your event-based pipeline using a time slice of 10000 us

On the contrary, the following snippet keeps all events in memory, which, while feasible in some cases, is very inefficient in terms of memory use:

all_events = [ev for ev in EventsIterator(raw_path, delta_t=10000)]

Creating a HAL device to initialize an EventsIterator

Alternatively an EventsIterator can be constructed from a HAL device instead of passing a path or a camera serial number string. This allows a user to access or modify any facilities the device might have.

from metavision_core.event_io.raw_reader import initiate_device
device = initiate_device(path="")
# Access any facility on the Device, like trigger_in for example
i_trigger_in = device.get_i_trigger_in()
# Create EventsIterator from the Device
mv_it = EventsIterator.from_device(device=device)
for ev in mv_it:
# Note that it is not recommended to leave a device in the global scope. So either create the HAL device in a
# function or delete it explicitly afterwards. Otherwise, it could result in an undefined behaviour.
del device


This tutorial was created using Jupiter Notebooks

Download the source code.