color_laser.cpp
Go to the documentation of this file.
1 
34 #include <functional>
35 
38 
39 //
40 // Anonymous namespace for locally scoped symbols
41 namespace {
42 
43  const uint32_t laser_cloud_step = 16;
44 
45 } // namespace
46 
47 namespace multisense_ros {
48 
49 ColorLaser::ColorLaser(ros::NodeHandle& nh, const std::string &tf_prefix):
50  node_handle_(nh),
51  image_channels_(3),
52  tf_prefix_(tf_prefix)
53 {
54  //
55  // Initialize point cloud structure
56 
57  color_laser_pointcloud_ = initialize_pointcloud<float>(true, "/left_camera_optical_frame", "rgb");
58 
59  color_laser_publisher_ = nh.advertise<sensor_msgs::PointCloud2>("lidar_points2_color",
60  10,
61  std::bind(&ColorLaser::startStreaming, this),
62  std::bind(&ColorLaser::stopStreaming, this));
63 
64 }
65 
67  const sensor_msgs::Image::ConstPtr& message
68 )
69 {
70  std::lock_guard<std::mutex> lock(data_lock_);
71 
72  //
73  // Images are assumed to be 8 bit.
74 
75  image_channels_ = message->data.size() / (message->height * message->width);
76 
77  if (image_channels_ > 3)
78  {
79  ROS_ERROR("Unsupported number of color channels: %d", image_channels_);
80  }
81 
82  color_image_ = *message;
83 }
84 
86  const sensor_msgs::CameraInfo::ConstPtr& message
87 )
88 {
89  std::lock_guard<std::mutex> lock(data_lock_);
90 
91  camera_info_ = *message;
92 }
93 
95  sensor_msgs::PointCloud2::Ptr message
96 )
97 {
98  std::lock_guard<std::mutex> lock(data_lock_);
99 
100  //
101  // Make sure the associated camera_info/color image is within 2 seconds
102  // of the current point cloud message
103 
104  if (message->header.stamp - color_image_.header.stamp > ros::Duration(2) ||
105  message->header.stamp - camera_info_.header.stamp > ros::Duration(2))
106  {
107  return;
108  }
109 
110  color_laser_pointcloud_.header = message->header;
111 
112  //
113  // Here we assume that our the sizeof our intensity field is the same as
114  // the sizeof our new rgb color field.
115 
116  color_laser_pointcloud_.data.resize(message->data.size());
117  float* colorPointCloudDataP = reinterpret_cast<float*>(&(color_laser_pointcloud_.data[0]));
118 
119  //
120  // Iterate over all the points in the point cloud, Use the camera projection
121  // matrix to project each point into the left camera image,
122  // colorize the point with the corresponding image point in the left
123  // camera. If the point does not project into the camera image
124  // do not add it to the point cloud.
125 
126  float* pointCloudDataP = reinterpret_cast<float*>(&(message->data[0]));
127 
128  const uint32_t height = message->height;
129  const uint32_t width = message->width;
130  const uint32_t cloudStep = message->point_step / message->fields.size();
131 
132  uint32_t validPoints = 0;
133  for( uint32_t index = 0 ; index < height * width ; ++index, pointCloudDataP += cloudStep)
134  {
135  float x = pointCloudDataP[0];
136  float y = pointCloudDataP[1];
137  float z = pointCloudDataP[2];
138 
139  //
140  // Invalid points from the laser will have a distance of 60m.
141  // Since these points have the laser calibration applied to them
142  // add in a 2m buffer for filtering out invalid points
143 
144  if (sqrt(x * x + y * y * z * z) > 58.0)
145  {
146  continue;
147  }
148 
149  //
150  // Compute the (u,v) camera coordinates corresponding to our laser
151  // point
152 
153  //
154  // (fx*x + cx*z)/z
155  const double u = (camera_info_.P[0] * x + camera_info_.P[2] * z) / z;
156  //
157  // (fy*y + cy*z)/z
158  const double v = (camera_info_.P[5] * y + camera_info_.P[6] * z) / z;
159 
160  //
161  // If our computed (u, v) point projects into the image use its
162  // color value and add it to the color pointcloud message
163 
164  if (u < color_image_.width && v < color_image_.height && u >= 0.0 && v >= 0.0)
165  {
166 
167  colorPointCloudDataP[0] = x;
168  colorPointCloudDataP[1] = y;
169  colorPointCloudDataP[2] = z;
170 
171  uint8_t* colorChannelP = reinterpret_cast<uint8_t*>(&colorPointCloudDataP[3]);
172 
173  //
174  // Image data is assumed to be BRG and stored continuously in memory
175  // both of which are the case for color images from the MultiSense
176 
177  uint8_t* imageDataP = &color_image_.data[(image_channels_ * static_cast<size_t>(v) * color_image_.width) +
178  (image_channels_ * static_cast<size_t>(u))];
179 
180  switch(image_channels_)
181  {
182  case 3:
183  colorChannelP[2] = imageDataP[2];
184  colorChannelP[1] = imageDataP[1];
185  colorChannelP[0] = imageDataP[0];
186  break;
187  case 2:
188  colorChannelP[1] = imageDataP[1];
189  colorChannelP[0] = imageDataP[0];
190  break;
191  case 1:
192  colorChannelP[0] = imageDataP[0];
193  colorChannelP[2] = imageDataP[0];
194  colorChannelP[1] = imageDataP[0];
195  break;
196  }
197 
198  colorPointCloudDataP += cloudStep;
199  ++validPoints;
200  }
201 
202  }
203 
204  color_laser_pointcloud_.data.resize(validPoints * laser_cloud_step);
205  color_laser_pointcloud_.width = validPoints;
206  color_laser_pointcloud_.row_step = validPoints * laser_cloud_step;
207 
209 }
210 
212 {
213  if (color_image_sub_.getNumPublishers() == 0 &&
216  {
217  color_image_sub_ = node_handle_.subscribe("image_rect_color",
218  10,
220  this);
221 
222  camera_info_sub_ = node_handle_.subscribe("camera_info",
223  10,
225  this);
226 
227  laser_pointcloud_sub_ = node_handle_.subscribe("lidar_points2",
228  10,
230  this);
231  }
232 
233 }
234 
236 {
238  {
242  }
243 }
244 
245 } // namespace
246 
247 int main(int argc, char** argv)
248 {
249  try
250  {
251  ros::init(argc, argv, "color_laser_publisher");
252 
253  ros::NodeHandle nh;
254  ros::NodeHandle nh_private("~");
255 
256  std::string tf_prefix;
257  nh_private.param<std::string>("tf_prefix", tf_prefix, "multisense");
258 
259  multisense_ros::ColorLaser colorLaserPublisher(nh, tf_prefix);
260 
261  ros::spin();
262  }
263  catch(std::exception& e)
264  {
265  ROS_ERROR("%s", e.what());
266  return 1;
267  }
268 
269  return 0;
270 }
ros::Subscriber color_image_sub_
Definition: color_laser.h:91
ros::Publisher color_laser_publisher_
Definition: color_laser.h:86
void publish(const boost::shared_ptr< M > &message) const
sensor_msgs::Image color_image_
Definition: color_laser.h:78
int main(int argc, char **argv)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
sensor_msgs::CameraInfo camera_info_
Definition: color_laser.h:79
ROSCPP_DECL void spin(Spinner &spinner)
void laserPointCloudCallback(sensor_msgs::PointCloud2::Ptr message)
Definition: color_laser.cpp:94
ros::Subscriber laser_pointcloud_sub_
Definition: color_laser.h:92
void cameraInfoCallback(const sensor_msgs::CameraInfo::ConstPtr &message)
Definition: color_laser.cpp:85
bool param(const std::string &param_name, T &param_val, const T &default_val) const
uint32_t getNumPublishers() const
ros::NodeHandle node_handle_
Definition: color_laser.h:98
void colorImageCallback(const sensor_msgs::Image::ConstPtr &message)
Definition: color_laser.cpp:66
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ColorLaser(ros::NodeHandle &nh, const std::string &tf_prefix)
Definition: color_laser.cpp:49
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
uint32_t getNumSubscribers() const
ros::Subscriber camera_info_sub_
Definition: color_laser.h:93
sensor_msgs::PointCloud2 color_laser_pointcloud_
Definition: color_laser.h:81
#define ROS_ERROR(...)


multisense_ros
Author(s):
autogenerated on Sun Mar 14 2021 02:34:55