Example of Building a Simple Pipeline¶
The code sample in <install-prefix>/share/metavision/sdk/core/samples/metavision_filtering
will be used here
to show how to build a simple pipeline with linear connections. We don’t implement any custom stage in this sample:
this example includes only stages that already exist in Metavision SDK.
The sample is aimed at acquiring events data (from a live camera or a RAW file), applying filters on them (ROI and polarity filters), generating a frame out of filtered data and displaying this frame.
The pipeline can be represented by this graph:

The sample includes only the main function that creates the pipeline and connects the stages:
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | int main(int argc, char *argv[]) {
std::string in_raw_file_path;
const std::string short_program_desc("Code sample showing how the pipeline framework can be used to "
"create a simple application to filter and display events.\n");
const std::string long_program_desc(short_program_desc + "Available keyboard options:\n"
" - r - toggle the ROI filter algorithm\n"
" - p - show only events of positive polarity\n"
" - n - show only events of negative polarity\n"
" - a - show all events\n"
" - q - quit the application\n");
po::options_description options_desc("Options");
// clang-format off
options_desc.add_options()
("help,h", "Produce help message.")
("input-raw-file,i", po::value<std::string>(&in_raw_file_path), "Path to input RAW file. If not specified, the camera live stream is used.")
;
// clang-format on
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(options_desc).run(), vm);
po::notify(vm);
} catch (po::error &e) {
MV_LOG_ERROR() << short_program_desc;
MV_LOG_ERROR() << options_desc;
MV_LOG_ERROR() << "Parsing error:" << e.what();
return 1;
}
if (vm.count("help")) {
MV_LOG_INFO() << short_program_desc;
MV_LOG_INFO() << options_desc;
return 0;
}
MV_LOG_INFO() << long_program_desc;
// A pipeline for which all added stages will automatically be run in their own processing threads (if applicable)
Metavision::Pipeline p(true);
// Construct a camera from a recording or a live stream
Metavision::Camera cam;
if (!in_raw_file_path.empty()) {
cam = Metavision::Camera::from_file(in_raw_file_path);
} else {
cam = Metavision::Camera::from_first_available();
}
const unsigned short width = cam.geometry().width();
const unsigned short height = cam.geometry().height();
/// Pipeline
//
// 0 (Camera) -->-- 1 (ROI) -->-- 2 (Polarity) -->-- 3 (Frame Generation) -->-- 4 (Display)
//
// 0) Stage producing events from a camera
auto &cam_stage = p.add_stage(std::make_unique<Metavision::CameraStage>(std::move(cam)));
// 1) Stage wrapping an ROI filter algorithm
auto &roi_stage = p.add_algorithm_stage(
std::make_unique<Metavision::RoiFilterAlgorithm>(80, 80, width - 80, height - 80, false), cam_stage, false);
// 2) Stage wrapping a polarity filter algorithm
auto &pol_stage = p.add_algorithm_stage(std::make_unique<Metavision::PolarityFilterAlgorithm>(0), roi_stage, false);
// 3) Stage generating a frame from filtered events
auto &frame_stage = p.add_stage(std::make_unique<Metavision::FrameGenerationStage>(width, height, 30), pol_stage);
// 4) Stage displaying the frame
auto &disp_stage = p.add_stage(std::make_unique<Metavision::FrameDisplayStage>("CD events"), frame_stage);
// Run the pipeline step by step to allow user interaction based on key pressed
while (p.step()) {
char last_key = disp_stage.get_last_key();
switch (last_key) {
case 'a':
// show all events
pol_stage.set_enabled(false);
break;
case 'n':
// show only negative events
pol_stage.set_enabled(true);
pol_stage.algo().set_polarity(0);
break;
case 'p':
// show only positive events
pol_stage.set_enabled(true);
pol_stage.algo().set_polarity(1);
break;
case 'r':
// toggle ROI filter
roi_stage.set_enabled(!roi_stage.is_enabled());
break;
}
}
return 0;
}
|
Instantiating a Pipeline¶
First, we instantiate the Pipeline
using Pipeline::Pipeline(bool auto_detach)
constructor:
67 | Metavision::Pipeline p(true);
|
We pass auto_detach argument as true to make the pipeline run all stages in their own processing threads.
Adding Stages to the Pipeline¶
Once the pipeline is instantiated, we add stages to it.
The first stage is a CameraStage
, which is used to produce CD events from a camera or a RAW file.
This stage is added to the pipeline by calling
Pipeline::add_stage(std::unique_ptr<Stage> &&stage)
function. Also, we pass the Camera
instance (that is already instantiated in this
example) using std::move(cam) to transfer the ownership of the camera smart pointer:
84 85 | // 0) Stage producing events from a camera
auto &cam_stage = p.add_stage(std::make_unique<Metavision::CameraStage>(std::move(cam)));
|
Next, we add the RoiFilterAlgorithm
to apply ROI-filtering and acquire
only events in the given Region Of Interest:
87 88 89 | // 1) Stage wrapping an ROI filter algorithm
auto &roi_stage = p.add_algorithm_stage(
std::make_unique<Metavision::RoiFilterAlgorithm>(80, 80, width - 80, height - 80, false), cam_stage, false);
|
Here, we use
Pipeline::add_algorithm_stage(std::unique_ptr<Algorithm> &&algo, BaseStage &prev_stage, bool enabled = true)
function to add the stage, as we are adding a synchronous algorithm to the pipeline.
This stage is deliberately disabled here by setting enabled argument to false.
In the main loop, you can see how it can be dynamically activated, by pressing “r” key on keyboard when the sample is
running.
Then, we add PolarityFilterAlgorithm
to filter events and keep only
events of the given polarity. Also this stage is deliberately disabled here by setting enabled argument to false
and can be activated dynamically by pressing the “n” or “p” keys on the keyboard (“p” key will keep only
events with positive polarity and remove other events, and “n” key will keep only events with negative polarity).
91 92 | // 2) Stage wrapping a polarity filter algorithm
auto &pol_stage = p.add_algorithm_stage(std::make_unique<Metavision::PolarityFilterAlgorithm>(0), roi_stage, false);
|
Then, we add FrameGenerationStage
to generate a frame from events.
94 95 | // 3) Stage generating a frame from filtered events
auto &frame_stage = p.add_stage(std::make_unique<Metavision::FrameGenerationStage>(width, height, 30), pol_stage);
|
Finally, as the last stage, we add FrameDisplayStage
to display the frame
on the screen.
97 98 | // 4) Stage displaying the frame
auto &disp_stage = p.add_stage(std::make_unique<Metavision::FrameDisplayStage>("CD events"), frame_stage);
|
Running the Pipeline¶
Now, with the set up pipeline, we run the pipeline by calling
Pipeline::step()
function in a loop:
while (p.step()) { // Do any required periodic processing, for example to manage user inputs (e.g. via pressed keyboard keys) }
In this case, each call of Pipeline::step()
function executes a step of the
pipeline. Between two calls of Pipeline::step()
,
the threads for each stage will keep running.