feat: add enhanced depth filter support with configuration options

This commit is contained in:
ob-yalian
2026-06-30 14:17:58 +08:00
parent ad23464af7
commit 9e901979df
4 changed files with 503 additions and 3 deletions
@@ -40,6 +40,7 @@
#include <sensor_msgs/msg/camera_info.hpp> #include <sensor_msgs/msg/camera_info.hpp>
#include <sensor_msgs/msg/compressed_image.hpp> #include <sensor_msgs/msg/compressed_image.hpp>
#include <sensor_msgs/msg/image.hpp>
#include <camera_info_manager/camera_info_manager.hpp> #include <camera_info_manager/camera_info_manager.hpp>
#include <image_publisher/image_publisher.hpp> #include <image_publisher/image_publisher.hpp>
@@ -297,6 +298,7 @@ class OBCameraNode {
DepthFilterState buildDepthFilterState(const std::string& filter_name, bool enabled, DepthFilterState buildDepthFilterState(const std::string& filter_name, bool enabled,
const std::shared_ptr<ob::Filter>& filter) const; const std::shared_ptr<ob::Filter>& filter) const;
DepthFilterState buildEnhancedDepthFilterState() const;
static std::string normalizeDepthFilterName(const std::string& filter_name); static std::string normalizeDepthFilterName(const std::string& filter_name);
@@ -308,6 +310,18 @@ class OBCameraNode {
bool applyNamedDepthFilterConfig( bool applyNamedDepthFilterConfig(
const std::string& filter_name, bool enabled, const std::string& filter_name, bool enabled,
const std::vector<orbbec_camera_msgs::msg::DepthFilterParam>& params, std::string& message); const std::vector<orbbec_camera_msgs::msg::DepthFilterParam>& params, std::string& message);
bool applyEnhancedDepthFilterConfig(
bool enabled, const std::vector<float>& positional_params,
const std::vector<orbbec_camera_msgs::msg::DepthFilterParam>& named_params,
std::string& message);
bool validateEnhancedDepthFilterConfig(std::string& message) const;
bool ensureEnhancedDepthFilter(std::string& message);
void applyEnhancedDepthConfidenceThreshold();
std::shared_ptr<ob::FrameSet> processEnhancedDepthFilter(
const std::shared_ptr<ob::FrameSet>& frame_set);
bool convertEnhancedDepthColorFrame(const std::shared_ptr<ob::FrameSet>& frame_set);
void setupConfidencePublishers();
void publishConfidenceFrame(const std::shared_ptr<ob::Frame>& confidence_frame);
void setupCameraInfo(); void setupCameraInfo();
@@ -913,6 +927,15 @@ class OBCameraNode {
double diagnostic_period_ = 1.0; double diagnostic_period_ = 1.0;
bool enable_laser_ = false; bool enable_laser_ = false;
std::unique_ptr<ob::Align> align_filter_ = nullptr; std::unique_ptr<ob::Align> align_filter_ = nullptr;
std::shared_ptr<ob::EnhancedDepthFilter> enhanced_depth_filter_ = nullptr;
ob::FormatConvertFilter enhanced_depth_format_convert_filter_;
std::mutex enhanced_depth_filter_mutex_;
std::atomic_bool enable_enhanced_depth_{false};
std::string enhanced_depth_model_path_;
float enhanced_depth_confidence_threshold_ = -1.0f;
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr confidence_image_publisher_;
rclcpp::Publisher<sensor_msgs::msg::CameraInfo>::SharedPtr confidence_camera_info_publisher_;
cv::Mat confidence_image_;
OBStreamType align_target_stream_ = OB_STREAM_COLOR; OBStreamType align_target_stream_ = OB_STREAM_COLOR;
bool retry_on_usb3_detection_failure_ = false; bool retry_on_usb3_detection_failure_ = false;
bool config_json_loaded_ = false; bool config_json_loaded_ = false;
@@ -42,7 +42,8 @@ def load_parameters(context, args):
if config_file_path: if config_file_path:
yaml_params = load_yaml(config_file_path) yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params) default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename'} skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename',
'enhanced_depth_model_path'}
result = {} result = {}
for key, value in default_params.items(): for key, value in default_params.items():
@@ -230,6 +231,9 @@ def generate_launch_description():
DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'), DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'), DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'),
DeclareLaunchArgument('enable_false_positive_filter', default_value='false'), DeclareLaunchArgument('enable_false_positive_filter', default_value='false'),
DeclareLaunchArgument('enable_enhanced_depth', default_value='false'),
DeclareLaunchArgument('enhanced_depth_model_path', default_value=''),
DeclareLaunchArgument('enhanced_depth_confidence_threshold', default_value='0.20'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'), DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'), DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'), DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
@@ -42,7 +42,8 @@ def load_parameters(context, args):
if config_file_path: if config_file_path:
yaml_params = load_yaml(config_file_path) yaml_params = load_yaml(config_file_path)
default_params = merge_params(default_params, yaml_params) default_params = merge_params(default_params, yaml_params)
skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename'} skip_convert = {'config_file_path', 'usb_port', 'serial_number', 'bag_record_filename', 'bag_filename',
'enhanced_depth_model_path'}
result = {} result = {}
for key, value in default_params.items(): for key, value in default_params.items():
@@ -227,6 +228,9 @@ def generate_launch_description():
DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'), DeclareLaunchArgument('enable_spatial_fast_filter', default_value='false'),
DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'), DeclareLaunchArgument('enable_spatial_moderate_filter', default_value='false'),
DeclareLaunchArgument('enable_false_positive_filter', default_value='false'), DeclareLaunchArgument('enable_false_positive_filter', default_value='false'),
DeclareLaunchArgument('enable_enhanced_depth', default_value='false'),
DeclareLaunchArgument('enhanced_depth_model_path', default_value=''),
DeclareLaunchArgument('enhanced_depth_confidence_threshold', default_value='0.20'),
DeclareLaunchArgument('decimation_filter_scale', default_value='-1'), DeclareLaunchArgument('decimation_filter_scale', default_value='-1'),
DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'), DeclareLaunchArgument('sequence_id_filter_id', default_value='-1'),
DeclareLaunchArgument('threshold_filter_max', default_value='-1'), DeclareLaunchArgument('threshold_filter_max', default_value='-1'),
+470 -1
View File
@@ -54,6 +54,9 @@ std::string OBCameraNode::normalizeDepthFilterName(const std::string &filter_nam
if (filter_name == "DispOutliers" || filter_name == "DepthOutliersFilter") { if (filter_name == "DispOutliers" || filter_name == "DepthOutliersFilter") {
return "DispOutliersFilter"; return "DispOutliersFilter";
} }
if (filter_name == "EnhancedDepth" || filter_name == "EnhancedDepthFilter") {
return "EnhancedDepthFilter";
}
return filter_name; return filter_name;
} }
@@ -69,6 +72,20 @@ std::string getDepthFilterStatusName(const std::string &filter_name) {
return filter_name; return filter_name;
} }
const std::unordered_map<OBFormat, OBConvertFormat> &enhancedDepthColorFormatMap() {
static const std::unordered_map<OBFormat, OBConvertFormat> kFormatMap = {
{OB_FORMAT_YUYV, FORMAT_YUYV_TO_RGB}, {OB_FORMAT_UYVY, FORMAT_UYVY_TO_RGB},
{OB_FORMAT_MJPG, FORMAT_MJPG_TO_RGB}, {OB_FORMAT_BGR, FORMAT_BGR_TO_RGB},
{OB_FORMAT_RGBA, FORMAT_RGBA_TO_RGB}, {OB_FORMAT_Y16, FORMAT_Y16_TO_RGB},
{OB_FORMAT_Y8, FORMAT_Y8_TO_RGB},
};
return kFormatMap;
}
bool isEnhancedDepthColorFormatSupported(OBFormat format) {
return format == OB_FORMAT_RGB || enhancedDepthColorFormatMap().count(format) > 0;
}
std::filesystem::path resolveConfigJsonFilePath(const std::string &file_path) { std::filesystem::path resolveConfigJsonFilePath(const std::string &file_path) {
std::filesystem::path path(file_path); std::filesystem::path path(file_path);
if ((file_path == "~" || file_path.rfind("~/", 0) == 0) && std::getenv("HOME") != nullptr) { if ((file_path == "~" || file_path.rfind("~/", 0) == 0) && std::getenv("HOME") != nullptr) {
@@ -410,6 +427,15 @@ DepthFilterState OBCameraNode::buildDepthFilterState(
return filter_state; return filter_state;
} }
DepthFilterState OBCameraNode::buildEnhancedDepthFilterState() const {
DepthFilterState filter_state;
filter_state.filter_name = "EnhancedDepthFilter";
filter_state.enabled = enable_enhanced_depth_.load();
appendDepthFilterParam(filter_state, "confidence_threshold",
std::to_string(enhanced_depth_confidence_threshold_));
return filter_state;
}
void OBCameraNode::publishDepthFiltersStatus() { void OBCameraNode::publishDepthFiltersStatus() {
if (!depth_filters_status_pub_) { if (!depth_filters_status_pub_) {
return; return;
@@ -621,9 +647,14 @@ void OBCameraNode::publishDepthFiltersStatus() {
if (disp_outliers_filter_supported) { if (disp_outliers_filter_supported) {
append_unique_filter_name("DispOutliersFilter"); append_unique_filter_name("DispOutliersFilter");
} }
append_unique_filter_name("EnhancedDepthFilter");
msg.filters.reserve(ordered_filter_names.size()); msg.filters.reserve(ordered_filter_names.size());
for (const auto &filter_name : ordered_filter_names) { for (const auto &filter_name : ordered_filter_names) {
if (filter_name == "EnhancedDepthFilter") {
msg.filters.push_back(buildEnhancedDepthFilterState());
continue;
}
bool enabled = false; bool enabled = false;
auto filter = find_depth_filter(filter_name); auto filter = find_depth_filter(filter_name);
if (filter_name == "NoiseRemovalFilter") { if (filter_name == "NoiseRemovalFilter") {
@@ -4036,6 +4067,14 @@ void OBCameraNode::getParameters() {
setAndGetNodeParameter<bool>(publish_tf_, "publish_tf", true); setAndGetNodeParameter<bool>(publish_tf_, "publish_tf", true);
setAndGetNodeParameter<double>(tf_publish_rate_, "tf_publish_rate", 0.0); setAndGetNodeParameter<double>(tf_publish_rate_, "tf_publish_rate", 0.0);
setAndGetNodeParameter<bool>(depth_registration_, "depth_registration", false); setAndGetNodeParameter<bool>(depth_registration_, "depth_registration", false);
bool enable_enhanced_depth = false;
setAndGetNodeParameter<bool>(enable_enhanced_depth, "enable_enhanced_depth", false);
enable_enhanced_depth_.store(enable_enhanced_depth);
setAndGetNodeParameter<std::string>(enhanced_depth_model_path_, "enhanced_depth_model_path", "");
double enhanced_depth_confidence_threshold = 0.20;
setAndGetNodeParameter<double>(enhanced_depth_confidence_threshold,
"enhanced_depth_confidence_threshold", 0.20);
enhanced_depth_confidence_threshold_ = static_cast<float>(enhanced_depth_confidence_threshold);
setAndGetNodeParameter<bool>(enable_point_cloud_, "enable_point_cloud", false); setAndGetNodeParameter<bool>(enable_point_cloud_, "enable_point_cloud", false);
setAndGetNodeParameter<std::string>(ir_info_url_, "ir_info_url", ""); setAndGetNodeParameter<std::string>(ir_info_url_, "ir_info_url", "");
setAndGetNodeParameter<std::string>(color_info_url_, "color_info_url", ""); setAndGetNodeParameter<std::string>(color_info_url_, "color_info_url", "");
@@ -4376,6 +4415,12 @@ void OBCameraNode::setupTopics() {
syncConfigJsonFilterSettings(left_ir_filter_list_, "left_ir"); syncConfigJsonFilterSettings(left_ir_filter_list_, "left_ir");
syncConfigJsonFilterSettings(right_ir_filter_list_, "right_ir"); syncConfigJsonFilterSettings(right_ir_filter_list_, "right_ir");
setupProfiles(); setupProfiles();
if (enable_enhanced_depth_.load()) {
std::string message;
if (!ensureEnhancedDepthFilter(message)) {
throw std::runtime_error(message);
}
}
setupCameraInfo(); setupCameraInfo();
selectBaseStream(); selectBaseStream();
setupCameraCtrlServices(); setupCameraCtrlServices();
@@ -4576,6 +4621,341 @@ void OBCameraNode::setupPipelineConfig() {
} }
} }
bool OBCameraNode::validateEnhancedDepthFilterConfig(std::string &message) const {
if (!enable_stream_.count(COLOR) || !enable_stream_.at(COLOR) || !enable_stream_.count(DEPTH) ||
!enable_stream_.at(DEPTH)) {
message = "Enhanced depth filter requires color and depth streams";
return false;
}
if (!depth_registration_) {
message = "Enhanced depth filter requires D2C/C2D align mode";
return false;
}
if (align_mode_ != "HW" && align_mode_ != "SW") {
message = "Enhanced depth filter requires D2C/C2D align mode";
return false;
}
if (align_mode_ == "HW" && align_target_stream_ != OB_STREAM_COLOR) {
message = "Enhanced depth filter requires HW D2C align target COLOR";
return false;
}
if (align_mode_ == "SW" && align_target_stream_ != OB_STREAM_COLOR &&
align_target_stream_ != OB_STREAM_DEPTH) {
message = "Enhanced depth filter requires D2C/C2D align mode";
return false;
}
auto color_it = stream_profile_.find(COLOR);
auto depth_it = stream_profile_.find(DEPTH);
if (color_it == stream_profile_.end() || !color_it->second || depth_it == stream_profile_.end() ||
!depth_it->second) {
message = "Enhanced depth filter requires color and depth stream profiles";
return false;
}
auto color_profile = color_it->second->as<ob::VideoStreamProfile>();
auto depth_profile = depth_it->second->as<ob::VideoStreamProfile>();
if (!color_profile || !depth_profile) {
message = "Enhanced depth filter requires video stream profiles";
return false;
}
const bool d2c = align_mode_ == "HW" || align_target_stream_ == OB_STREAM_COLOR;
const OBStreamType align_to_stream = d2c ? OB_STREAM_COLOR : OB_STREAM_DEPTH;
if (!ob::EnhancedDepthFilter::isSupportedResolution(color_profile->getType(), align_to_stream,
color_profile->getWidth(),
color_profile->getHeight())) {
message = d2c ? "Enhanced depth filter requires color frame is: 640 * 480 RGB"
: "Enhanced depth filter requires color frame is: RGB";
return false;
}
if (!ob::EnhancedDepthFilter::isSupportedResolution(depth_profile->getType(), align_to_stream,
depth_profile->getWidth(),
depth_profile->getHeight()) ||
!ob::EnhancedDepthFilter::isSupportedFormat(OB_STREAM_DEPTH, depth_profile->getFormat())) {
message = d2c ? "Enhanced depth filter requires depth frame is: Y16"
: "Enhanced depth filter requires depth frame is: 640 * 480 Y16";
return false;
}
if (!isEnhancedDepthColorFormatSupported(color_profile->getFormat())) {
message =
"Unsupported color stream format for enhanced depth filter. Supported formats are: YUYV "
"UYVY MJPG BGR RGBA Y16 Y8 RGB";
return false;
}
return true;
}
void OBCameraNode::applyEnhancedDepthConfidenceThreshold() {
if (!enhanced_depth_filter_ || enhanced_depth_confidence_threshold_ < 0.0f) {
return;
}
auto range = enhanced_depth_filter_->getConfidenceThresholdRange();
if (enhanced_depth_confidence_threshold_ < range.min ||
enhanced_depth_confidence_threshold_ > range.max) {
std::ostringstream ss;
ss << "Enhanced depth confidence threshold is out of range " << range.min << " - " << range.max;
throw std::runtime_error(ss.str());
}
enhanced_depth_filter_->setConfidenceThreshold(enhanced_depth_confidence_threshold_);
}
bool OBCameraNode::ensureEnhancedDepthFilter(std::string &message) {
if (!validateEnhancedDepthFilterConfig(message)) {
return false;
}
std::lock_guard<std::mutex> lock(enhanced_depth_filter_mutex_);
try {
if (!enhanced_depth_filter_) {
if (enhanced_depth_model_path_.empty()) {
message = "Enhanced depth filter requires enhanced_depth_model_path";
return false;
}
std::ifstream model_file(enhanced_depth_model_path_);
if (!model_file.good()) {
message = "Enhanced depth model file not found: " + enhanced_depth_model_path_;
return false;
}
if (!device_->isLicenseAuthorizationSupported()) {
message = "Enhanced depth filter requires device license authorization support";
return false;
}
auto license_info = device_->readLicenseInfo();
RCLCPP_INFO_STREAM(logger_, "Enhanced depth license info: " << license_info);
if (license_info.empty()) {
message = "Enhanced depth filter requires device license info";
return false;
}
RCLCPP_INFO_STREAM(logger_, "Creating enhanced depth filter with model path: "
<< enhanced_depth_model_path_);
enhanced_depth_filter_ =
std::make_shared<ob::EnhancedDepthFilter>(device_, enhanced_depth_model_path_);
}
const bool d2c = align_mode_ == "HW" || align_target_stream_ == OB_STREAM_COLOR;
auto target_profile = d2c ? stream_profile_.at(COLOR)->as<ob::VideoStreamProfile>()
: stream_profile_.at(DEPTH)->as<ob::VideoStreamProfile>();
enhanced_depth_filter_->setResolution(target_profile->getWidth(), target_profile->getHeight());
applyEnhancedDepthConfidenceThreshold();
setupConfidencePublishers();
} catch (const ob::Error &e) {
message =
"Failed to create enhanced depth filter: " + orbbec_camera::formatObErrorWithStatus(e);
return false;
} catch (const std::exception &e) {
message = "Failed to create enhanced depth filter: " + std::string(e.what());
return false;
}
return true;
}
bool OBCameraNode::convertEnhancedDepthColorFrame(const std::shared_ptr<ob::FrameSet> &frame_set) {
auto color_frame = frame_set ? frame_set->getFrame(OB_FRAME_COLOR) : nullptr;
if (!color_frame) {
return false;
}
const auto color_format = color_frame->getFormat();
if (color_format == OB_FORMAT_RGB) {
return true;
}
const auto &format_map = enhancedDepthColorFormatMap();
auto it = format_map.find(color_format);
if (it == format_map.end()) {
RCLCPP_ERROR_STREAM_THROTTLE(
logger_, *node_->get_clock(), 1000,
"Unsupported color stream format for enhanced depth filter: " << color_format);
return false;
}
try {
enhanced_depth_format_convert_filter_.setFormatConvertType(it->second);
auto converted = enhanced_depth_format_convert_filter_.process(color_frame);
if (!converted) {
RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth color format conversion failed");
return false;
}
frame_set->pushFrame(converted);
} catch (const ob::Error &e) {
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth color format conversion failed: "
<< orbbec_camera::formatObErrorWithStatus(e));
return false;
} catch (const std::exception &e) {
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth color format conversion failed: " << e.what());
return false;
}
return true;
}
std::shared_ptr<ob::FrameSet> OBCameraNode::processEnhancedDepthFilter(
const std::shared_ptr<ob::FrameSet> &frame_set) {
if (!frame_set) {
return frame_set;
}
{
std::lock_guard<std::mutex> lock(enhanced_depth_filter_mutex_);
if (!enable_enhanced_depth_.load()) {
return frame_set;
}
}
std::string message;
if (!ensureEnhancedDepthFilter(message)) {
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *node_->get_clock(), 1000, message);
return frame_set;
}
if (!frame_set->getFrame(OB_FRAME_COLOR) || !frame_set->getFrame(OB_FRAME_DEPTH)) {
RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth filter requires color and depth frames");
return frame_set;
}
if (!convertEnhancedDepthColorFrame(frame_set)) {
return frame_set;
}
std::shared_ptr<ob::EnhancedDepthFilter> filter;
{
std::lock_guard<std::mutex> lock(enhanced_depth_filter_mutex_);
if (!enable_enhanced_depth_.load()) {
return frame_set;
}
filter = enhanced_depth_filter_;
}
try {
auto processed = filter->process(frame_set);
if (!processed || !processed->is<ob::FrameSet>()) {
RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth filter returned invalid frameset");
return frame_set;
}
auto processed_frame_set = processed->as<ob::FrameSet>();
publishConfidenceFrame(processed_frame_set->getFrame(OB_FRAME_CONFIDENCE));
return processed_frame_set;
} catch (const ob::Error &e) {
RCLCPP_ERROR_STREAM_THROTTLE(
logger_, *node_->get_clock(), 1000,
"Enhanced depth filter failed: " << orbbec_camera::formatObErrorWithStatus(e));
} catch (const std::exception &e) {
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *node_->get_clock(), 1000,
"Enhanced depth filter failed: " << e.what());
}
return frame_set;
}
void OBCameraNode::setupConfidencePublishers() {
if (confidence_image_publisher_ && confidence_camera_info_publisher_) {
return;
}
auto image_qos_profile = getRMWQosProfileFromString(image_qos_[DEPTH]);
auto camera_info_qos_profile = getRMWQosProfileFromString(camera_info_qos_[DEPTH]);
if (use_intra_process_) {
image_qos_profile = rmw_qos_profile_default;
camera_info_qos_profile = rmw_qos_profile_default;
}
if (!confidence_image_publisher_) {
confidence_image_publisher_ = node_->create_publisher<sensor_msgs::msg::Image>(
"confidence/image_raw",
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(image_qos_profile), image_qos_profile));
}
if (!confidence_camera_info_publisher_) {
confidence_camera_info_publisher_ = node_->create_publisher<sensor_msgs::msg::CameraInfo>(
"confidence/camera_info",
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(camera_info_qos_profile),
camera_info_qos_profile));
}
}
void OBCameraNode::publishConfidenceFrame(const std::shared_ptr<ob::Frame> &confidence_frame) {
if (!confidence_frame || !confidence_frame->is<ob::VideoFrame>()) {
return;
}
setupConfidencePublishers();
if ((!confidence_image_publisher_ ||
confidence_image_publisher_->get_subscription_count() == 0) &&
(!confidence_camera_info_publisher_ ||
confidence_camera_info_publisher_->get_subscription_count() == 0)) {
return;
}
auto video_frame = confidence_frame->as<ob::VideoFrame>();
const int width = static_cast<int>(video_frame->getWidth());
const int height = static_cast<int>(video_frame->getHeight());
int image_type = CV_8UC1;
std::string encoding = sensor_msgs::image_encodings::MONO8;
int unit_step_size = sizeof(uint8_t);
if (confidence_frame->getFormat() == OB_FORMAT_Y16) {
image_type = CV_16UC1;
encoding = sensor_msgs::image_encodings::MONO16;
unit_step_size = sizeof(uint16_t);
} else if (confidence_frame->getFormat() != OB_FORMAT_Y8) {
RCLCPP_ERROR_STREAM_THROTTLE(
logger_, *node_->get_clock(), 1000,
"Unsupported confidence frame format: " << confidence_frame->getFormat());
return;
}
if (confidence_image_.empty() || confidence_image_.cols != width ||
confidence_image_.rows != height || confidence_image_.type() != image_type) {
confidence_image_.create(height, width, image_type);
}
memcpy(confidence_image_.data, video_frame->getData(), video_frame->getDataSize());
auto timestamp = fromUsToROSTime(getFrameTimestampUs(confidence_frame));
std::string frame_id =
depth_registration_ ? depth_aligned_frame_id_[DEPTH] : optical_frame_id_[DEPTH];
OBCameraIntrinsic intrinsic{};
OBCameraDistortion distortion{};
bool has_camera_params = false;
try {
auto stream_profile = confidence_frame->getStreamProfile();
if (stream_profile) {
auto video_stream_profile = stream_profile->as<ob::VideoStreamProfile>();
if (video_stream_profile) {
intrinsic = video_stream_profile->getIntrinsic();
distortion = video_stream_profile->getDistortion();
has_camera_params = true;
}
}
} catch (const std::exception &) {
has_camera_params = false;
}
if (!has_camera_params && stream_profile_.count(DEPTH) && stream_profile_[DEPTH]) {
auto depth_profile = stream_profile_[DEPTH]->as<ob::VideoStreamProfile>();
if (depth_profile) {
intrinsic = depth_profile->getIntrinsic();
distortion = depth_profile->getDistortion();
has_camera_params = true;
}
}
if (!has_camera_params) {
RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000,
"Failed to get confidence camera info");
return;
}
auto camera_info = convertToCameraInfo(intrinsic, distortion, width);
camera_info.header.stamp = timestamp;
camera_info.header.frame_id = frame_id;
camera_info.width = width;
camera_info.height = height;
if (confidence_camera_info_publisher_) {
confidence_camera_info_publisher_->publish(camera_info);
}
if (!confidence_image_publisher_ || confidence_image_publisher_->get_subscription_count() == 0) {
return;
}
sensor_msgs::msg::Image::UniquePtr image_msg(new sensor_msgs::msg::Image());
cv_bridge::CvImage(std_msgs::msg::Header(), encoding, confidence_image_).toImageMsg(*image_msg);
image_msg->header.stamp = timestamp;
image_msg->header.frame_id = frame_id;
image_msg->is_bigendian = false;
image_msg->step = width * unit_step_size;
confidence_image_publisher_->publish(std::move(image_msg));
}
void OBCameraNode::setupCameraInfo() { void OBCameraNode::setupCameraInfo() {
std::string color_camera_name = camera_name_ + "_color"; std::string color_camera_name = camera_name_ + "_color";
if (!color_info_url_.empty()) { if (!color_info_url_.empty()) {
@@ -4669,6 +5049,9 @@ void OBCameraNode::setupPublishers() {
*node_, "depth/image_unaligned", depth_image_qos_profile); *node_, "depth/image_unaligned", depth_image_qos_profile);
} }
} }
if (enable_enhanced_depth_.load()) {
setupConfidencePublishers();
}
if (enable_sync_output_accel_gyro_) { if (enable_sync_output_accel_gyro_) {
std::string topic_name = stream_name_[GYRO] + "_" + stream_name_[ACCEL] + "/sample"; std::string topic_name = stream_name_[GYRO] + "_" + stream_name_[ACCEL] + "/sample";
@@ -5397,6 +5780,12 @@ void OBCameraNode::onNewFrameSetCallback(std::shared_ptr<ob::FrameSet> frame_set
"null or color frame is null"); "null or color frame is null");
} }
if (enable_enhanced_depth_.load()) {
frame_set = processEnhancedDepthFilter(frame_set);
depth_frame = frame_set->getFrame(OB_FRAME_DEPTH);
color_frame = frame_set->getFrame(OB_FRAME_COLOR);
}
// Refresh frame from current frameset before logging to reflect post-filter/alignment output. // Refresh frame from current frameset before logging to reflect post-filter/alignment output.
for (const auto &stream_index : IMAGE_STREAMS) { for (const auto &stream_index : IMAGE_STREAMS) {
if (!enable_stream_[stream_index]) { if (!enable_stream_[stream_index]) {
@@ -6884,6 +7273,73 @@ bool OBCameraNode::applyNamedDepthFilterConfig(
return true; return true;
} }
bool OBCameraNode::applyEnhancedDepthFilterConfig(
bool enabled, const std::vector<float> &positional_params,
const std::vector<orbbec_camera_msgs::msg::DepthFilterParam> &named_params,
std::string &message) {
if (positional_params.size() > 1) {
message = "EnhancedDepthFilter only supports one positional parameter";
return false;
}
if (!positional_params.empty() && !named_params.empty()) {
message = "filter_param and filter_config cannot be used at the same time";
return false;
}
bool has_confidence_threshold = false;
float confidence_threshold = enhanced_depth_confidence_threshold_;
if (!positional_params.empty()) {
has_confidence_threshold = true;
confidence_threshold = positional_params[0];
}
for (const auto &param : named_params) {
if (param.name != "confidence_threshold") {
message = "Unknown filter config '" + param.name + "' for EnhancedDepthFilter";
return false;
}
double parsed_value = 0.0;
if (!parseFilterConfigDouble(param.value, parsed_value, message)) {
return false;
}
has_confidence_threshold = true;
confidence_threshold = static_cast<float>(parsed_value);
}
std::string validate_message;
if (enabled && !validateEnhancedDepthFilterConfig(validate_message)) {
message = validate_message;
return false;
}
const float previous_threshold = enhanced_depth_confidence_threshold_;
if (has_confidence_threshold) {
enhanced_depth_confidence_threshold_ = confidence_threshold;
}
if (enabled) {
if (!ensureEnhancedDepthFilter(message)) {
enhanced_depth_confidence_threshold_ = previous_threshold;
return false;
}
} else if (has_confidence_threshold && enhanced_depth_filter_) {
try {
applyEnhancedDepthConfidenceThreshold();
} catch (const std::exception &e) {
enhanced_depth_confidence_threshold_ = previous_threshold;
message = e.what();
return false;
}
}
{
std::lock_guard<std::mutex> lock(enhanced_depth_filter_mutex_);
enable_enhanced_depth_.store(enabled);
}
filter_status_["EnhancedDepthFilter"] = enabled;
publishDepthFiltersStatus();
return true;
}
void OBCameraNode::setFilterCallback(const std::shared_ptr<SetFilter ::Request> &request, void OBCameraNode::setFilterCallback(const std::shared_ptr<SetFilter ::Request> &request,
std::shared_ptr<SetFilter ::Response> &response) { std::shared_ptr<SetFilter ::Response> &response) {
try { try {
@@ -6931,6 +7387,17 @@ void OBCameraNode::setFilterCallback(const std::shared_ptr<SetFilter ::Request>
return; return;
} }
if (normalized_request_filter_name == "EnhancedDepthFilter") {
std::string message;
if (!applyEnhancedDepthFilterConfig(request->filter_enable, request->filter_param,
request->filter_config, message)) {
fail(message);
return;
}
response->success = true;
return;
}
if (has_named_params || !has_positional_params) { if (has_named_params || !has_positional_params) {
std::string message; std::string message;
if (!applyNamedDepthFilterConfig(normalized_request_filter_name, request->filter_enable, if (!applyNamedDepthFilterConfig(normalized_request_filter_name, request->filter_enable,
@@ -6995,7 +7462,9 @@ void OBCameraNode::setFilterCallback(const std::shared_ptr<SetFilter ::Request>
hardware_noise_removal_filter_threshold_ = request->filter_param[0]; hardware_noise_removal_filter_threshold_ = request->filter_param[0];
} }
} else { } else {
fail("The filter switch setting is successful, but the filter parameter setting fails"); fail(
"The filter switch setting is successful, but the filter parameter setting "
"fails");
return; return;
} }
} }