Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

abstract post-processing filter factory via context #12425

Merged
merged 2 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ target_sources(${LRS_TARGET}
"${CMAKE_CURRENT_LIST_DIR}/sensor.cpp"
"${CMAKE_CURRENT_LIST_DIR}/hid-sensor.cpp"
"${CMAKE_CURRENT_LIST_DIR}/uvc-sensor.cpp"
"${CMAKE_CURRENT_LIST_DIR}/rscore-pp-block-factory.h"
"${CMAKE_CURRENT_LIST_DIR}/rscore-pp-block-factory.cpp"
"${CMAKE_CURRENT_LIST_DIR}/software-device.cpp"
"${CMAKE_CURRENT_LIST_DIR}/software-device-info.cpp"
"${CMAKE_CURRENT_LIST_DIR}/software-sensor.cpp"
Expand Down
7 changes: 7 additions & 0 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifdef BUILD_WITH_DDS
#include "dds/rsdds-device-factory.h"
#endif
#include "rscore-pp-block-factory.h"

#include <librealsense2/hpp/rs_types.hpp> // rs2_devices_changed_callback
#include <librealsense2/rs.h> // RS2_API_FULL_VERSION_STR
Expand Down Expand Up @@ -177,4 +178,10 @@ namespace librealsense {
}


std::shared_ptr< processing_block_interface > context::create_pp_block( std::string const & name,
nlohmann::json const & settings )
{
return rscore_pp_block_factory().create_pp_block( name, settings );
}

} // namespace librealsense
6 changes: 6 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace librealsense
{
class device_factory;
class device_info;
class processing_block_interface;


class context : public std::enable_shared_from_this<context>
Expand Down Expand Up @@ -58,6 +59,11 @@ namespace librealsense

const nlohmann::json & get_settings() const { return _settings; }

// Create processing blocks given a name and settings.
//
std::shared_ptr< processing_block_interface > create_pp_block( std::string const & name,
nlohmann::json const & settings );

private:
void invoke_devices_changed_callbacks( std::vector< std::shared_ptr< device_info > > const & devices_removed,
std::vector< std::shared_ptr< device_info > > const & devices_added );
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ target_sources(${LRS_TARGET}
"${CMAKE_CURRENT_LIST_DIR}/info.h"
"${CMAKE_CURRENT_LIST_DIR}/extension.h"
"${CMAKE_CURRENT_LIST_DIR}/pose-frame.h"
"${CMAKE_CURRENT_LIST_DIR}/pp-block-factory.h"
"${CMAKE_CURRENT_LIST_DIR}/processing.h"
"${CMAKE_CURRENT_LIST_DIR}/processing-block-interface.h"
"${CMAKE_CURRENT_LIST_DIR}/recommended-processing-blocks-interface.h"
Expand Down
38 changes: 38 additions & 0 deletions src/core/pp-block-factory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2023 Intel Corporation. All Rights Reserved.
#pragma once

#include <nlohmann/json_fwd.hpp>
#include <string>


namespace librealsense {


class processing_block_interface;


// Instantiator of post-processing filters, AKA processing blocks, based on name and settings.
// These are the ones you see in the Viewer, and are also returned by
// sensor_interface::get_recommended_processing_blocks(). Their names are serialized to rosbags when recording and
// reinstantiated on playback.
//
// Do not use directly: the context manages these!
//
class pp_block_factory
{
public:
virtual ~pp_block_factory() = default;

// Creates a post-processing block. If the name is unrecognized, a null pointer is returned. Otherwise, if the
// settings are wrong or some other error condition is encountered, an exception is raised.
//
// The name is case-insensitive.
//
virtual std::shared_ptr< processing_block_interface > create_pp_block( std::string const & name,
nlohmann::json const & settings )
= 0;
};


} // namespace librealsense
46 changes: 14 additions & 32 deletions src/dds/rs-dds-sensor-proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,7 @@
#include <src/core/frame-callback.h>
#include <src/stream.h>

// Processing blocks for DDS SW sensors
#include <proc/decimation-filter.h>
#include <proc/disparity-transform.h>
#include <proc/hdr-merge.h>
#include <proc/hole-filling-filter.h>
#include <proc/sequence-id-filter.h>
#include <proc/spatial-filter.h>
#include <proc/temporal-filter.h>
#include <proc/threshold.h>
#include <proc/color-formats-converter.h>
#include <src/proc/color-formats-converter.h>

#include <rsutils/json.h>

Expand Down Expand Up @@ -563,28 +554,19 @@ void dds_sensor_proxy::add_processing_block( std::string const & filter_name )
if( processing_block_exists( get_recommended_processing_blocks(), filter_name ) )
return; // Already created by another stream of this sensor

if( filter_name.compare( "Decimation Filter" ) == 0 )
// sensor.cpp sets format option based on sensor type, but the filter does not use it and selects the
// appropriate decimation algorithm based on processed frame profile format.
super::add_processing_block( std::make_shared< decimation_filter >() );
else if( filter_name.compare( "HDR Merge" ) == 0 )
super::add_processing_block( std::make_shared< hdr_merge >() );
else if( filter_name.compare( "Filter By Sequence id" ) == 0 )
super::add_processing_block( std::make_shared< sequence_id_filter >() );
else if( filter_name.compare( "Threshold Filter" ) == 0 )
super::add_processing_block( std::make_shared< threshold >() );
else if( filter_name.compare( "Depth to Disparity" ) == 0 )
super::add_processing_block( std::make_shared< disparity_transform >( true ) );
else if( filter_name.compare( "Disparity to Depth" ) == 0 )
super::add_processing_block( std::make_shared< disparity_transform >( false ) );
else if( filter_name.compare( "Spatial Filter" ) == 0 )
super::add_processing_block( std::make_shared< spatial_filter >() );
else if( filter_name.compare( "Temporal Filter" ) == 0 )
super::add_processing_block( std::make_shared< temporal_filter >() );
else if( filter_name.compare( "Hole Filling Filter" ) == 0 )
super::add_processing_block( std::make_shared< hole_filling_filter >() );
else
throw std::runtime_error( "Unsupported processing block '" + filter_name + "' received" );
try
{
auto ppb = get_device().get_context()->create_pp_block( filter_name, {} );
if( ! ppb )
LOG_WARNING( "Unsupported processing block '" + filter_name + "' received" );
else
super::add_processing_block( ppb );
}
catch( std::exception const & e )
{
// Bad settings, error in configuration, etc.
LOG_ERROR( "Failed to create processing block '" << filter_name << "': " << e.what() );
}
}


Expand Down
86 changes: 45 additions & 41 deletions src/media/ros/ros_reader.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2019 Intel Corporation. All Rights Reserved.

#include <cstring>
#include "ros_reader.h"
#include "ds/ds-device-common.h"
#include "ds/d400/d400-private.h"
#include "proc/disparity-transform.h"
#include "proc/decimation-filter.h"
#include "proc/threshold.h"
#include "proc/spatial-filter.h"
#include "proc/temporal-filter.h"
#include "proc/hole-filling-filter.h"
#include "proc/hdr-merge.h"
#include "proc/sequence-id-filter.h"
#include "std_msgs/Float32MultiArray.h"
#include <src/depth-sensor.h>
#include <src/core/pose-frame.h>
#include <src/core/motion-frame.h>
#include <src/core/video-frame.h>
#include <src/color-sensor.h>

#include <rsutils/string/from.h>
#include <cstring>


namespace librealsense
Expand Down Expand Up @@ -885,7 +878,13 @@ namespace librealsense
{
throw invalid_value_exception("Failed to get options interface from sensor snapshots");
}
auto proccesing_blocks = read_proccesing_blocks(file, { get_device_index(), sensor_index }, time, options_api, file_version, pid, sensor_name);
auto proccesing_blocks = read_proccesing_blocks( file,
{ get_device_index(), sensor_index },
time,
options_api,
file_version,
pid,
sensor_name );
sensor_extensions[RS2_EXTENSION_RECOMMENDED_FILTERS] = proccesing_blocks;
}

Expand Down Expand Up @@ -1002,8 +1001,14 @@ namespace librealsense
return std::make_shared<recommended_proccesing_blocks_snapshot>(processing_blocks{});
}

std::shared_ptr<recommended_proccesing_blocks_snapshot> ros_reader::read_proccesing_blocks(const rosbag::Bag& file, device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp,
std::shared_ptr<options_interface> options, uint32_t file_version, std::string pid, std::string sensor_name)
std::shared_ptr< recommended_proccesing_blocks_snapshot >
ros_reader::read_proccesing_blocks( const rosbag::Bag & file,
device_serializer::sensor_identifier sensor_id,
const nanoseconds & timestamp,
std::shared_ptr< options_interface > options,
uint32_t file_version,
std::string pid,
std::string sensor_name )
{
processing_blocks blocks;
std::shared_ptr<recommended_proccesing_blocks_snapshot> res;
Expand All @@ -1027,8 +1032,8 @@ namespace librealsense
last_item = it++;

auto block = create_processing_block(*last_item, depth_to_disparity, options);
assert(block);
blocks.push_back(block);
if( block )
blocks.push_back(block);
}

res = std::make_shared<recommended_proccesing_blocks_snapshot>(blocks);
Expand Down Expand Up @@ -1434,35 +1439,34 @@ namespace librealsense
return std::make_pair(id, std::make_shared<const_value_option>(description, value));
}

std::shared_ptr<librealsense::processing_block_interface> ros_reader::create_processing_block(const rosbag::MessageInstance& value_message_instance, bool& depth_to_disparity, std::shared_ptr<options_interface> options)
std::shared_ptr< librealsense::processing_block_interface >
ros_reader::create_processing_block( const rosbag::MessageInstance & value_message_instance,
bool & depth_to_disparity,
std::shared_ptr< options_interface > sensor_options )
{
auto processing_block_msg = instantiate_msg<std_msgs::String>(value_message_instance);
rs2_extension id;
convert(processing_block_msg->data, id);
std::shared_ptr<librealsense::processing_block_interface> disparity;

switch (id)
{
case RS2_EXTENSION_DECIMATION_FILTER:
return std::make_shared<ExtensionToType<RS2_EXTENSION_DECIMATION_FILTER>::type>();
case RS2_EXTENSION_THRESHOLD_FILTER:
return std::make_shared<ExtensionToType<RS2_EXTENSION_THRESHOLD_FILTER>::type>();
case RS2_EXTENSION_DISPARITY_FILTER:
disparity = std::make_shared<ExtensionToType<RS2_EXTENSION_DISPARITY_FILTER>::type>(depth_to_disparity);
depth_to_disparity = false;
return disparity;
case RS2_EXTENSION_SPATIAL_FILTER:
return std::make_shared<ExtensionToType<RS2_EXTENSION_SPATIAL_FILTER>::type>();
case RS2_EXTENSION_TEMPORAL_FILTER:
return std::make_shared<ExtensionToType<RS2_EXTENSION_TEMPORAL_FILTER>::type>();
case RS2_EXTENSION_HOLE_FILLING_FILTER:
return std::make_shared<ExtensionToType<RS2_EXTENSION_HOLE_FILLING_FILTER>::type>();
case RS2_EXTENSION_HDR_MERGE:
return std::make_shared<ExtensionToType<RS2_EXTENSION_HDR_MERGE>::type>();
case RS2_EXTENSION_SEQUENCE_ID_FILTER:
Nir-Az marked this conversation as resolved.
Show resolved Hide resolved
return std::make_shared<ExtensionToType<RS2_EXTENSION_SEQUENCE_ID_FILTER>::type>();
default:
return nullptr;
std::string name = processing_block_msg->data;
if( name == "Disparity Filter" )
Nir-Az marked this conversation as resolved.
Show resolved Hide resolved
{
// What was recorded was the extension type (without its settings!), but we need to create different
// variants. "Disparity Filter" gets recorded twice! This workaround ensures it's instantiated in its
// non-default flavor the second time:
if( depth_to_disparity )
depth_to_disparity = false;
else
name = "Disparity to Depth";
}
try
{
auto block = m_context->create_pp_block( name, {} );
if( ! block )
LOG_DEBUG( "unknown processing block '" << name << "'; ignored" );
return block;
}
catch( std::exception const & e )
{
LOG_DEBUG( "failed to create processing block '" << name << "': " << e.what() );
return {};
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/media/ros/ros_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ namespace librealsense
static std::pair<rs2_option, std::shared_ptr<librealsense::option>> create_property(const rosbag::MessageInstance& property_message_instance);
/*Starting version 3*/
static std::pair<rs2_option, std::shared_ptr<librealsense::option>> create_option(const rosbag::Bag& file, const rosbag::MessageInstance& value_message_instance);
static std::shared_ptr<processing_block_interface> create_processing_block(const rosbag::MessageInstance& value_message_instance, bool& depth_to_disparity, std::shared_ptr<options_interface> options);

std::shared_ptr< processing_block_interface >
create_processing_block( const rosbag::MessageInstance & value_message_instance,
bool & depth_to_disparity,
std::shared_ptr< options_interface > options );

static notification create_notification(const rosbag::Bag& file, const rosbag::MessageInstance& message_instance);
static std::shared_ptr<options_container> read_sensor_options(const rosbag::Bag& file, device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp, uint32_t file_version);
Expand Down
42 changes: 22 additions & 20 deletions src/media/ros/ros_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,11 +492,17 @@ namespace librealsense
}
}

rs2_extension ros_writer::get_processing_block_extension(const std::shared_ptr<processing_block_interface> block)
static std::string get_processing_block_extension_name( const std::shared_ptr< processing_block_interface > block )
{
#define RETURN_IF_EXTENSION(E, T)\
if (Is<ExtensionToType<T>::type>(E))\
return T;\
// We want to write the block name (as opposed to the extension name):
// The block can behave differently and have a different name based on how it was created (e.g., the disparity
// filter). This makes new rosbag files incompatible with older librealsense versions.
Nir-Az marked this conversation as resolved.
Show resolved Hide resolved
if( block->supports_info( RS2_CAMERA_INFO_NAME ) )
return block->get_info( RS2_CAMERA_INFO_NAME );

#define RETURN_IF_EXTENSION( B, E ) \
if( Is< ExtensionToType< E >::type >( B ) ) \
return rs2_extension_type_to_string( E )

RETURN_IF_EXTENSION(block, RS2_EXTENSION_DECIMATION_FILTER);
RETURN_IF_EXTENSION(block, RS2_EXTENSION_THRESHOLD_FILTER);
Expand All @@ -509,33 +515,29 @@ namespace librealsense

#undef RETURN_IF_EXTENSION

throw invalid_value_exception( rsutils::string::from()
<< "processing block " << block->get_info( RS2_CAMERA_INFO_NAME )
<< "has no map to extension" );
return {};
}

void ros_writer::write_sensor_processing_blocks(device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp, std::shared_ptr<recommended_proccesing_blocks_interface> proccesing_blocks)
{
rs2_extension ext = RS2_EXTENSION_UNKNOWN;
for (auto block : proccesing_blocks->get_recommended_processing_blocks())
{
std::string name = get_processing_block_extension_name( block );
if( name.empty() )
{
LOG_WARNING( "Failed to get recommended processing block name for sensor " << sensor_id.sensor_index );
continue;
}
try
{
try
{
ext = get_processing_block_extension(block);
}
catch (std::exception& e)
{
LOG_WARNING("Failed to write proccesing block " << " for sensor " << sensor_id.sensor_index << ". Exception: " << e.what());
}
std_msgs::String processing_block_msg;
processing_block_msg.data = rs2_extension_type_to_string(ext);
write_message(ros_topic::post_processing_blocks_topic(sensor_id), timestamp, processing_block_msg);
processing_block_msg.data = name;
write_message( ros_topic::post_processing_blocks_topic( sensor_id ), timestamp, processing_block_msg );
}
catch (std::exception& e)
catch( std::exception & e )
{
LOG_WARNING("Failed to get or write recommended proccesing blocks " << " for sensor " << sensor_id.sensor_index << ". Exception: " << e.what());
LOG_WARNING( "Failed to write processing block '" << name << "' for sensor " << sensor_id.sensor_index
<< ": " << e.what() );
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/media/ros/ros_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ namespace librealsense
void write_vendor_info(const std::string& topic, nanoseconds timestamp, std::shared_ptr<info_interface> info_snapshot);
void write_sensor_option(device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp, rs2_option type, const librealsense::option& option);
void write_sensor_options(device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp, std::shared_ptr<options_interface> options);

rs2_extension get_processing_block_extension(const std::shared_ptr<processing_block_interface> block);
void write_sensor_processing_blocks(device_serializer::sensor_identifier sensor_id, const nanoseconds& timestamp, std::shared_ptr<recommended_proccesing_blocks_interface> proccesing_blocks);

template <typename T>
Expand Down
Loading
Loading