Note
This C++ sample has a corresponding Python sample.
Synced Camera Streams Slicer using C++
The Synced Camera Streams Slicer sample demonstrates how to utilize the SyncedCameraStreamsSlicer
class from the Metavision SDK to divide and process event streams generated by a master and slave Camera
instances. This can be done based on either a fixed number of events or a specified time duration.
Expected Output
How to start
You can directly execute pre-compiled binary installed with Metavision SDK or compile the source code as described in this tutorial.
To start the sample based on recorded data, provide the full path to synchronized RAW files (here, we use files from our Sample Recordings):
Linux
./metavision_synced_camera_streams_slicer -i courtyard_walk_stereo.master.hdf5 courtyard_walk_stereo.slave.hdf5
Windows
metavision_synced_camera_streams_slicer.exe -i courtyard_walk_stereo.master.hdf5 courtyard_walk_stereo.slave.hdf5
This sample cannot be run with the first available cameras as it needs to know which camera is the master and which are the slaves. To start the sample based on the live stream from your cameras, run:
Linux
./metavision_synced_camera_streams_slicer -s SN_MASTER SN_SLAVE_1 ... SN_SLAVE_N
Windows
metavision_synced_camera_streams_slicer.exe -s SN_MASTER SN_SLAVE_1 ... SN_SLAVE_N
To check for additional options:
Linux
./metavision_synced_camera_streams_slicer -h
Windows
metavision_synced_camera_streams_slicer.exe -h
Code Overview
First we start by building the camera system meaning the master and slaves cameras. To do so, we rely on the
SyncedCameraSystemBuilder
helper class. We pass all the provided
command line arguments to it and then call the build() method to create the camera system. Internally, the builder
will determine if a live or offline camera system should be created based on the provided arguments and build and
configure all the camera instances accordingly:
Metavision::SyncedCameraSystemBuilder builder;
const auto get_settings_file_path = [&config](const std::string &serial) -> std::optional<std::filesystem::path> {
namespace fs = std::filesystem;
const auto settings_file_path = fs::path(config.settings_dir) / (serial + ".json");
if (!fs::exists(settings_file_path)) {
return std::nullopt;
}
return settings_file_path;
};
for (const auto &serial_number : config.serial_numbers) {
builder.add_live_camera_parameters({serial_number, {}, get_settings_file_path(serial_number)});
}
builder.set_record(config.record);
builder.set_record_dir(config.record_dir);
for (const auto &path : config.record_paths) {
builder.add_record_path(path);
}
builder.set_file_config_hints(Metavision::FileConfigHints{}.real_time_playback(config.real_time_playback));
auto &&[master, slaves] = builder.build();
Next, we create a SyncedCameraStreamsSlicer
instance by
transferring the ownership of the camera system to it and setting the desired slicing mode:
Metavision::SyncedCameraStreamsSlicer slicer(std::move(master), std::move(slaves), config.slicing_condition);
Finally, we start slicing the synchronized event streams by iterating over the slicer. The information about the slices is printed to the console and the slice of each camera is displayed in a separate window:
for (const auto &slice : slicer) {
for (auto &frame : slice_frames) {
frame.setTo(0);
}
MV_LOG_INFO() << "MASTER ts: " << slice.t << " " << slice.n_events << " [" << slice.master_events->front().t
<< ", " << slice.master_events->back().t << "]";
Metavision::BaseFrameGenerationAlgorithm::generate_frame_from_events(
slice.master_events->cbegin(), slice.master_events->cend(), slice_frames[0]);
cv::imshow("Master slice", slice_frames[0]);
for (size_t i = 0; i < slice.slave_events.size(); ++i) {
const auto &slave_slice = slice.slave_events[i];
MV_LOG_INFO() << "SLAVE " << i + 1 << " ts: " << slice.t << " " << slave_slice->size() << " ["
<< slave_slice->front().t << ", " << slave_slice->back().t << "]";
Metavision::BaseFrameGenerationAlgorithm::generate_frame_from_events(
slave_slice->cbegin(), slave_slice->cend(), slice_frames[i + 1]);
cv::imshow("Slave slice " + std::to_string(i + 1), slice_frames[i + 1]);
}
const auto key = cv::waitKey(1);
if (key == 'q')
break;
}