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())
EventsIterator(spinner.raw)
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:
print(ev.size)
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')
plt.show()

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
my_pipeline(ev)
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()
i_trigger_in.enable(0)
# Create EventsIterator from the Device
mv_it = EventsIterator.from_device(device=device)
for ev in mv_it:
mv_it.reader.device
pass
# 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