Swarm-SLAM  1.0.0
C-SLAM Framework
visualization_utils.cpp
Go to the documentation of this file.
2 
3 namespace cslam
4 {
5 
6 // Conversions implementations are from https://github.com/ros-perception/image_pipeline/tree/foxy/depth_image_proc
7 
8 sensor_msgs::msg::PointCloud2 create_colored_pointcloud(const std::shared_ptr<rtabmap::SensorData> & sensor_data, const std_msgs::msg::Header & header)
9 {
10  // Update camera model
11  image_geometry::PinholeCameraModel model;
12  sensor_msgs::msg::CameraInfo info_msg;
13  rtabmap_conversions::cameraModelToROS(sensor_data->cameraModels()[0], info_msg);
14  model.fromCameraInfo(info_msg);
15 
16  auto cloud_msg = std::make_shared<sensor_msgs::msg::PointCloud2>();
17  cloud_msg->header = header;
18  cloud_msg->height = sensor_data->depthRaw().rows;
19  cloud_msg->width = sensor_data->depthRaw().cols;
20  cloud_msg->is_dense = false;
21  cloud_msg->is_bigendian = false;
22 
23  if (sensor_data->depthRaw().cols != sensor_data->imageRaw().cols || sensor_data->depthRaw().rows != sensor_data->imageRaw().rows) {
24  RCLCPP_WARN(
25  rclcpp::get_logger("cslam"),
26  "Depth image size (%dx%d) doesn't match RGB image size (%dx%d)!",
27  sensor_data->depthRaw().cols, sensor_data->depthRaw().rows, sensor_data->imageRaw().cols, sensor_data->imageRaw().rows);
28  cloud_msg->height = 0;
29  cloud_msg->width = 0;
30  return *cloud_msg;
31  }
32 
33  sensor_msgs::PointCloud2Modifier pcd_modifier(*cloud_msg);
34  pcd_modifier.setPointCloud2FieldsByString(2, "xyz", "rgb");
35 
36  // Convert Depth Image to Pointcloud
37  if (sensor_data->depthRaw().type() == CV_16UC1) {
38  depth_image_to_pointcloud<uint16_t>(sensor_data, cloud_msg, model);
39  } else if (sensor_data->depthRaw().type() == CV_32FC1) {
40  depth_image_to_pointcloud<float>(sensor_data, cloud_msg, model);
41  } else {
42  // Depth image has unsupported encoding
43  return *cloud_msg;
44  }
45 
46  // Add colors to pointcloud
47  if (sensor_data->imageRaw().type() == CV_8UC3) {
48  add_rgb_to_pointcloud(sensor_data, cloud_msg);
49  } else if (sensor_data->imageRaw().type() == CV_8UC1) {
50  add_rgb_to_pointcloud(sensor_data, cloud_msg);
51  } else {
52  // RGB image has unsupported encoding
53  return *cloud_msg;
54  }
55  return *cloud_msg;
56 }
57 
58 // Handles float or uint16 depths
59 template<typename T>
61  const std::shared_ptr<rtabmap::SensorData> & sensor_data,
62  sensor_msgs::msg::PointCloud2::SharedPtr & cloud_msg,
63  const image_geometry::PinholeCameraModel & model,
64  double range_max)
65 {
66  // Use correct principal point from calibration
67  float center_x = model.cx();
68  float center_y = model.cy();
69 
70  // Combine unit conversion (if necessary) with scaling by focal length for computing (X,Y)
71  double unit_scaling = depth_image_proc::DepthTraits<T>::toMeters(T(1) );
72  float constant_x = unit_scaling / model.fx();
73  float constant_y = unit_scaling / model.fy();
74  float bad_point = std::numeric_limits<float>::quiet_NaN();
75 
76  sensor_msgs::PointCloud2Iterator<float> iter_x(*cloud_msg, "x");
77  sensor_msgs::PointCloud2Iterator<float> iter_y(*cloud_msg, "y");
78  sensor_msgs::PointCloud2Iterator<float> iter_z(*cloud_msg, "z");
79  const T * depth_row = reinterpret_cast<const T *>(&sensor_data->depthRaw().data[0]);
80  int row_step = sensor_data->depthRaw().step / sizeof(T);
81  for (int v = 0; v < static_cast<int>(cloud_msg->height); ++v, depth_row += row_step) {
82  for (int u = 0; u < static_cast<int>(cloud_msg->width); ++u, ++iter_x, ++iter_y, ++iter_z) {
83  T depth = depth_row[u];
84 
85  // Missing points denoted by NaNs
87  if (range_max != 0.0) {
89  } else {
90  *iter_x = *iter_y = *iter_z = bad_point;
91  continue;
92  }
93  }
94 
95  // Fill in XYZ
96  *iter_x = (u - center_x) * depth * constant_x;
97  *iter_y = (v - center_y) * depth * constant_y;
99  }
100  }
101 }
102 
104  const std::shared_ptr<rtabmap::SensorData> & sensor_data,
105  sensor_msgs::msg::PointCloud2::SharedPtr & cloud_msg)
106 {
107  // Supported color encodings: BGR8, MONO8
108  int red_offset, green_offset, blue_offset, color_step;
109  if (sensor_data->imageRaw().type() == CV_8UC3) {
110  red_offset = 2;
111  green_offset = 1;
112  blue_offset = 0;
113  color_step = 3;
114  } else if (sensor_data->imageRaw().type() == CV_8UC1) {
115  red_offset = 0;
116  green_offset = 0;
117  blue_offset = 0;
118  color_step = 1;
119  } else {
120  return;
121  }
122 
123  sensor_msgs::PointCloud2Iterator<uint8_t> iter_r(*cloud_msg, "r");
124  sensor_msgs::PointCloud2Iterator<uint8_t> iter_g(*cloud_msg, "g");
125  sensor_msgs::PointCloud2Iterator<uint8_t> iter_b(*cloud_msg, "b");
126  const uint8_t * rgb = &sensor_data->imageRaw().data[0];
127  int rgb_skip = sensor_data->imageRaw().step - sensor_data->imageRaw().cols * color_step;
128  for (int v = 0; v < static_cast<int>(cloud_msg->height); ++v, rgb += rgb_skip) {
129  for (int u = 0; u < static_cast<int>(cloud_msg->width); ++u,
130  rgb += color_step, ++iter_r, ++iter_g, ++iter_b)
131  {
132  *iter_r = rgb[red_offset];
133  *iter_g = rgb[green_offset];
134  *iter_b = rgb[blue_offset];
135  }
136  }
137 }
138 
139 } // namespace cslam
Definition: __init__.py:1
void depth_image_to_pointcloud(const std::shared_ptr< rtabmap::SensorData > &sensor_data, sensor_msgs::msg::PointCloud2::SharedPtr &cloud_msg, const image_geometry::PinholeCameraModel &model, double range_max=0.0)
Convert depth image to pointcloud.
sensor_msgs::msg::PointCloud2 create_colored_pointcloud(const std::shared_ptr< rtabmap::SensorData > &sensor_data, const std_msgs::msg::Header &header)
Create a colored pointcloud message.
void add_rgb_to_pointcloud(const std::shared_ptr< rtabmap::SensorData > &sensor_data, sensor_msgs::msg::PointCloud2::SharedPtr &cloud_msg)
Add color to pointcloud.