ed_sensor_integration
sam_seg_module.cpp
Go to the documentation of this file.
2 
3 #include <filesystem>
4 #include <utility>
5 #include <sam_onnx_ros/segmentation.hpp>
6 #include <sensor_msgs/Image.h>
7 #include <sensor_msgs/PointCloud2.h>
8 #include <yolo_onnx_ros/detection.hpp>
9 
10 
12 {
13  SegmentationResult seg_result;
14 
16  std::unique_ptr<YOLO_V8> yoloDetector;
17  DL_INIT_PARAM params;
18  std::string yolo_model, sam_encoder, sam_decoder;
19  config.value("yolo_model", yolo_model);
20  std::tie(yoloDetector, params) = Initialize(yolo_model);
21 
23  std::vector<std::unique_ptr<SAM>> samSegmentors;
24  SEG::DL_INIT_PARAM params_encoder;
25  SEG::DL_INIT_PARAM params_decoder;
27  SEG::DL_RESULT res;
28  config.value("sam_encoder", sam_encoder);
29  config.value("sam_decoder", sam_decoder);
30  std::tie(samSegmentors, params_encoder, params_decoder, res, resSam) = Initialize(sam_encoder, sam_decoder);
31 
33  std::vector<DL_RESULT> resYolo;
34  resYolo = Detector(yoloDetector, img);
35 
37  for (const auto& result : resYolo)
38  {
39  res.boxes.push_back(result.box);
40  seg_result.labels.push_back(yoloDetector->classes[result.classId]);
41  seg_result.confidences.push_back(result.confidence);
42  ROS_DEBUG("Confidence: %f", result.confidence);
43  ROS_DEBUG("Class: %s", yoloDetector->classes[result.classId].c_str());
44  ROS_DEBUG("Class ID: %d", result.classId);
45  }
46 
47  SegmentAnything(samSegmentors, params_encoder, params_decoder, img, resSam, res);
48 
49  seg_result.masks = std::move(res.masks);
50  seg_result.boxes = std::move(res.boxes);
51 
52  // Verify 1:1 alignment between masks and labels.
53  // Normally guaranteed because SAM processes boxes sequentially and pushes one mask per box.
54  // If SAM failed for any box it pushes an empty placeholder (see sam_onnx_ros/src/utils.cpp),
55  // so sizes should always match. If they don't, we cannot know which label belongs to which
56  // mask — discard labels for this frame so objects are still detected but not mislabeled.
57  if (seg_result.masks.size() != seg_result.labels.size())
58  {
59  ROS_WARN("SAM produced %zu masks for %zu YOLO boxes — alignment broken, discarding labels this frame",
60  seg_result.masks.size(), seg_result.labels.size());
61  seg_result.labels.clear();
62  seg_result.confidences.clear();
63  }
64 
65  return seg_result;
66 }
67 
68 
69 void overlayMasksOnImage_(cv::Mat& rgb, const std::vector<cv::Mat>& masks)
70 {
71  // Define colors in BGR format for OpenCV (high contrast)
72  std::vector<cv::Scalar> colors = {
73  cv::Scalar(0, 0, 255), // Red
74  cv::Scalar(0, 255, 0), // Green
75  cv::Scalar(255, 0, 0), // Blue
76  cv::Scalar(0, 255, 255), // Yellow
77  cv::Scalar(255, 0, 255), // Magenta
78  cv::Scalar(255, 255, 0), // Cyan
79  cv::Scalar(128, 0, 128), // Purple
80  cv::Scalar(0, 128, 128) // Brown
81  };
82 
83  // Create a copy for the overlay (preserves original for contours)
84  cv::Mat overlay = rgb.clone();
85 
86  for (size_t i = 0; i < masks.size(); i++)
87  {
88  // Get a working copy of the mask
89  cv::Mat working_mask = masks[i].clone();
90 
91  // Check if mask needs resizing
92  if (working_mask.rows != rgb.rows || working_mask.cols != rgb.cols)
93  cv::resize(working_mask, working_mask, rgb.size(), 0, 0, cv::INTER_NEAREST);
94 
95  // Ensure the mask is binary (values 0 or 255)
96  if (cv::countNonZero((working_mask > 0) & (working_mask < 255)) > 0)
97  cv::threshold(working_mask, working_mask, 127, 255, cv::THRESH_BINARY);
98 
99  // Use a different color for each mask
100  cv::Scalar color = colors[i % colors.size()];
101 
102  // Create the colored overlay with this mask's specific color
103  cv::Mat colorMask = cv::Mat::zeros(rgb.size(), CV_8UC3);
104  colorMask.setTo(color, working_mask);
105 
106  // Add this mask's overlay to the combined overlay
107  cv::addWeighted(overlay, 1.0, colorMask, 0.2, 0, overlay);
108 
109  // Find contours of the mask - use CHAIN_APPROX_NONE for most accurate contours
111  cv::findContours(working_mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
112 
113  // Draw double contours for better visibility (outer black, inner colored)
114  cv::drawContours(rgb, contours, -1, cv::Scalar(0, 0, 0), 2); // Outer black border
115  cv::drawContours(rgb, contours, -1, color, 1); // Inner colored line
116  }
117 
118  // Apply the semi-transparent overlay with all masks
119  cv::addWeighted(rgb, 0.7, overlay, 0.3, 0, rgb);
120 }
SegmentationResult
Result of the segmentation pipeline containing masks, bounding boxes, and YOLO classification info fo...
Definition: sam_seg_module.h:19
SegmentationResult::labels
std::vector< std::string > labels
Definition: sam_seg_module.h:23
std::string
utility
sam_seg_module.h
std::vector
std::vector::size
T size(T... args)
SegmentationPipeline
SegmentationResult SegmentationPipeline(const cv::Mat &img, tue::Configuration &config)
Segmentation pipeline that processes the input image and generates segmentation masks.
Definition: sam_seg_module.cpp:11
filesystem
std::vector::clear
T clear(T... args)
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
tue::config::ReaderWriter
overlayMasksOnImage_
void overlayMasksOnImage_(cv::Mat &rgb, const std::vector< cv::Mat > &masks)
Overlay segmentation masks on the RGB image for visualization purposes.
Definition: sam_seg_module.cpp:69
SegmentationResult::masks
std::vector< cv::Mat > masks
Definition: sam_seg_module.h:21
SegmentationResult::confidences
std::vector< float > confidences
Definition: sam_seg_module.h:24
SegmentationResult::boxes
std::vector< cv::Rect > boxes
Definition: sam_seg_module.h:22
tue::config::ReaderWriter::value
bool value(const std::string &name, T &value, RequiredOrOptional opt=REQUIRED)
std::unique_ptr
config
tue::config::ReaderWriter config