Skip to content

Commit

Permalink
add pp-block-factory
Browse files Browse the repository at this point in the history
  • Loading branch information
maloel committed Nov 18, 2023
1 parent efacd6e commit 071ee58
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 96 deletions.
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
8 changes: 8 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 @@ -141,4 +142,11 @@ 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 );
}

}
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:
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" )
{
// 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.
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

0 comments on commit 071ee58

Please sign in to comment.