point_cloud.cpp
Go to the documentation of this file.
1 #include "point_cloud.hpp"
2 
3 #include <sstream>
5 
6 #include <opencv2/imgproc.hpp>
7 
8 using namespace astra_ros;
9 
10 namespace
11 {
12 
13  struct __attribute__((packed)) Rgb
14  {
15  std::uint8_t r;
16  std::uint8_t g;
17  std::uint8_t b;
18  };
19 
20  template<typename T>
21  struct RowView
22  {
23  RowView(const std::uint8_t *const data)
24  : data(reinterpret_cast<const T *>(data))
25  {
26  }
27 
28  const T &getColumn(const std::size_t column) const noexcept
29  {
30  return data[column];
31  }
32 
33  inline const T &operator[] (const std::size_t column) const noexcept
34  {
35  return getColumn(column);
36  }
37 
38  const T *data;
39  };
40 
41  template<typename T>
42  struct ImageView
43  {
44  ImageView(const std::uint8_t *const data, const std::size_t step)
45  : data(data)
46  , step(step)
47  {
48  }
49 
50  inline RowView<T> getRow(const std::size_t row) const noexcept
51  {
52  return RowView<T>(data + row * step);
53  }
54 
55  inline RowView<T> operator[] (const std::size_t row) const noexcept
56  {
57  return getRow(row);
58  }
59 
60  const std::uint8_t *data;
61  std::size_t step;
62  };
63 
64 
65 }
66 
67 bool astra_ros::defaultMask(const std::size_t x, const std::size_t y)
68 {
69  return true;
70 }
71 
72 sensor_msgs::PointCloud astra_ros::toPointCloud(const sensor_msgs::Image &rgb, const sensor_msgs::Image &registered_depth, const sensor_msgs::CameraInfo &camera_info, const std::function<bool (const std::size_t x, const std::size_t y)> &mask)
73 {
74  using namespace sensor_msgs::image_encodings;
75 
76  // K = [fx 0 cx
77  // 0 fy cy
78  // 0 0 1 ]
79  const double fx = camera_info.K[0];
80  const double fy = camera_info.K[4];
81  const double cx = camera_info.K[2];
82  const double cy = camera_info.K[5];
83 
84  if (rgb.encoding != RGB8)
85  {
86  throw std::runtime_error("Expected RGB image to be RGB8 encoded");
87  }
88 
89  if (registered_depth.encoding != MONO16)
90  {
91  throw std::runtime_error("Expected registered depth image to be MONO16 encoded");
92  }
93 
94  if (rgb.height != registered_depth.height || rgb.width != registered_depth.width)
95  {
96  std::ostringstream o;
97  o << "Size mismatch. RGB image was (" << rgb.width << ", " << rgb.height << ")"
98  << ", but registered depth image was (" << registered_depth.width << ", " << registered_depth.height << ")";
99 
100  throw std::runtime_error(o.str());
101  }
102 
103  if (rgb.height * rgb.step != rgb.data.size())
104  {
105  throw std::runtime_error("RGB image is malformed. height * step != size");
106  }
107 
108  if (registered_depth.height * registered_depth.step != registered_depth.data.size())
109  {
110  throw std::runtime_error("Registered depth image is malformed. height * step != size");
111  }
112 
113  const std::size_t rgb_pixel_size = bitDepth(rgb.encoding) * numChannels(rgb.encoding);
114  const std::size_t depth_pixel_size = bitDepth(rgb.encoding) * numChannels(rgb.encoding);
115 
116  // cv::Mat undistorted;
117  // cv::undistort(cv::Mat(rgb.height, rgb.width, CV_8UC3, rgb.data.data()), undistorted, )
118 
119  sensor_msgs::ChannelFloat32 rgb_channel;
120  rgb_channel.name = "rgb";
121 
122  sensor_msgs::PointCloud ret;
123 
124  const ImageView<Rgb> rgb_view(rgb.data.data(), rgb.step);
125  const ImageView<std::uint16_t> depth_view(registered_depth.data.data(), registered_depth.step);
126 
127  for (std::size_t y = 0; y < rgb.height; ++y)
128  {
129  const RowView<Rgb> rgb_row_view = rgb_view[y];
130  const RowView<std::uint16_t> depth_row_view = depth_view[y];
131 
132  for (std::size_t x = 0; x < rgb.width; ++x)
133  {
134  // Should we process this pixel?
135  if (!mask(x, y)) continue;
136 
137  std::uint16_t depth_pixel = depth_row_view[x];
138 
139  // Invalid depth pixel
140  if (!depth_pixel) continue;
141 
142  // Detect if endianness differs from architecture. If so, we need to swap
143  // the high and low byte.
144  #ifdef ASTRA_ROS_BIG_ENDIAN
145  const bool swap_bytes = !registered_depth.is_bigendian;
146  #else
147  const bool swap_bytes = registered_depth.is_bigendian;
148  #endif
149 
150  if (swap_bytes)
151  {
152  depth_pixel = ((depth_pixel & 0x00FF) << 8) | ((depth_pixel & 0xFF00) << 0);
153  }
154 
155  const double depth_meters = depth_pixel / 1000.0;
156 
157  const double dx = x - cx;
158 
159  // Y axis is flipped (pinhole camera model)
160  const double dy = y - cy;
161 
162  const double dx_over_z = dx / fx;
163  const double dy_over_z = dy / fy;
164 
165  const double dx_over_z2 = dx_over_z * dx_over_z;
166  const double dy_over_z2 = dy_over_z * dy_over_z;
167 
168  geometry_msgs::Point32 point;
169  point.z = depth_meters / sqrt(1.0 + dx_over_z2 + dy_over_z2);
170  point.x = dx_over_z * point.z;
171  point.y = dy_over_z * point.z;
172 
173  // std::cout << "px: " << x << ", py: "<< y << ", point = " << point << std::endl;
174 
175  ret.points.push_back(point);
176 
177  const Rgb &pixel = rgb_row_view[x];
178 
179  // The channel requires the RGB data to be packed in the bottom 24 bits
180  // of a float. Bleh.
181  const std::uint32_t rgb_data = (pixel.r << 16) | (pixel.g << 8) | (pixel.b << 0);
182  rgb_channel.values.push_back(*reinterpret_cast<const float *>(&rgb_data));
183  }
184  }
185 
186  ret.channels.push_back(rgb_channel);
187  return ret;
188 
189 }
sensor_msgs::image_encodings
astra_ros::Rgb
Definition: color.hpp:60
image_encodings.h
astra_ros::Rgb::g
float g
Definition: color.hpp:71
astra_ros::Rgb::r
float r
Definition: color.hpp:69
step
unsigned int step
RGB8
const std::string RGB8
astra_ros::toPointCloud
sensor_msgs::PointCloud toPointCloud(const sensor_msgs::Image &rgb, const sensor_msgs::Image &registered_depth, const sensor_msgs::CameraInfo &camera_info, const std::function< bool(const std::size_t x, const std::size_t y)> &mask=defaultMask)
Definition: point_cloud.cpp:72
point_cloud.hpp
astra_ros::defaultMask
bool defaultMask(const std::size_t x, const std::size_t y)
Definition: point_cloud.cpp:67
MONO16
const std::string MONO16
astra_ros::Rgb::b
float b
Definition: color.hpp:73
astra_ros
Definition: Device.hpp:14


astra_ros
Author(s): Braden McDorman
autogenerated on Wed Mar 2 2022 00:53:06