color_laser.cpp
Go to the documentation of this file.
00001 
00034 #include <arpa/inet.h>
00035 
00036 #include <multisense_ros/color_laser.h>
00037 
00038 //
00039 // Anonymous namespace for locally scoped symbols
00040 namespace {
00041 
00042     const uint32_t laser_cloud_step = 16;
00043 
00044 } // namespace
00045 
00046 namespace multisense_ros {
00047 
00048 ColorLaser::ColorLaser(
00049     ros::NodeHandle& nh
00050 ):
00051     color_image_(),
00052     camera_info_(),
00053     color_laser_pointcloud_(),
00054     color_laser_publisher_(),
00055     color_image_sub_(),
00056     laser_pointcloud_sub_(),
00057     camera_info_sub_(),
00058     node_handle_(nh),
00059     data_lock_(),
00060     image_channels_(3)
00061 {
00062     //
00063     // Initialize point cloud structure
00064 
00065     color_laser_pointcloud_.is_bigendian    = (htonl(1) == 1);
00066     color_laser_pointcloud_.is_dense        = true;
00067     color_laser_pointcloud_.height          = 1;
00068     color_laser_pointcloud_.point_step      = laser_cloud_step;
00069 
00070     color_laser_pointcloud_.fields.resize(4);
00071     color_laser_pointcloud_.fields[0].name     = "x";
00072     color_laser_pointcloud_.fields[0].offset   = 0;
00073     color_laser_pointcloud_.fields[0].count    = 1;
00074     color_laser_pointcloud_.fields[0].datatype = sensor_msgs::PointField::FLOAT32;
00075     color_laser_pointcloud_.fields[1].name     = "y";
00076     color_laser_pointcloud_.fields[1].offset   = 4;
00077     color_laser_pointcloud_.fields[1].count    = 1;
00078     color_laser_pointcloud_.fields[1].datatype = sensor_msgs::PointField::FLOAT32;
00079     color_laser_pointcloud_.fields[2].name     = "z";
00080     color_laser_pointcloud_.fields[2].offset   = 8;
00081     color_laser_pointcloud_.fields[2].count    = 1;
00082     color_laser_pointcloud_.fields[2].datatype = sensor_msgs::PointField::FLOAT32;
00083     color_laser_pointcloud_.fields[3].name     = "rgb";
00084     color_laser_pointcloud_.fields[3].offset   = 12;
00085     color_laser_pointcloud_.fields[3].count    = 1;
00086     color_laser_pointcloud_.fields[3].datatype = sensor_msgs::PointField::FLOAT32;
00087 
00088     color_laser_publisher_ = nh.advertise<sensor_msgs::PointCloud2>("lidar_points2_color",
00089                                                                    10,
00090                                                                    boost::bind(&ColorLaser::startStreaming, this),
00091                                                                    boost::bind(&ColorLaser::stopStreaming, this));
00092 
00093 }
00094 
00095 ColorLaser::~ColorLaser()
00096 {
00097 }
00098 
00099 void ColorLaser::colorImageCallback(
00100     const sensor_msgs::Image::ConstPtr& message
00101 )
00102 {
00103     boost::mutex::scoped_lock lock(data_lock_);
00104 
00105     //
00106     // Images are assumed to be 8 bit.
00107 
00108     image_channels_ = message->data.size() / (message->height * message->width);
00109 
00110     if (image_channels_ > 3)
00111     {
00112         ROS_ERROR("Unsupported number of color channels: %d", image_channels_);
00113     }
00114 
00115     color_image_ = *message;
00116 }
00117 
00118 void ColorLaser::cameraInfoCallback(
00119     const sensor_msgs::CameraInfo::ConstPtr& message
00120 )
00121 {
00122     boost::mutex::scoped_lock lock(data_lock_);
00123 
00124     camera_info_ = *message;
00125 }
00126 
00127 void ColorLaser::laserPointCloudCallback(
00128     sensor_msgs::PointCloud2::Ptr message
00129 )
00130 {
00131     boost::mutex::scoped_lock lock(data_lock_);
00132 
00133     //
00134     // Make sure the associated camera_info/color image is within 2 seconds
00135     // of the current point cloud message
00136 
00137     if (message->header.stamp - color_image_.header.stamp > ros::Duration(2) ||
00138         message->header.stamp - camera_info_.header.stamp > ros::Duration(2))
00139     {
00140         return;
00141     }
00142 
00143     color_laser_pointcloud_.header = message->header;
00144 
00145     //
00146     // Here we assume that our the sizeof our intensity field is the same as
00147     // the sizeof our new rgb color field.
00148 
00149     color_laser_pointcloud_.data.resize(message->data.size());
00150     float* colorPointCloudDataP = reinterpret_cast<float*>(&(color_laser_pointcloud_.data[0]));
00151 
00152     //
00153     // Iterate over all the points in the point cloud, Use the camera projection
00154     // matrix to project each point into the left camera image,
00155     // colorize the point with the corresponding image point in the left
00156     // camera. If the point does not project into the camera image
00157     // do not add it to the point cloud.
00158 
00159     float* pointCloudDataP = reinterpret_cast<float*>(&(message->data[0]));
00160 
00161     uint32_t height = message->height;
00162     uint32_t width = message->width;
00163     uint32_t cloudStep = message->point_step / message->fields.size();
00164 
00165     uint32_t validPoints = 0;
00166     for( uint32_t index = 0 ; index < height * width ;
00167             ++index, pointCloudDataP += cloudStep)
00168     {
00169         float x = pointCloudDataP[0];
00170         float y = pointCloudDataP[1];
00171         float z = pointCloudDataP[2];
00172 
00173         //
00174         // Invalid points from the laser will have a distance of 60m.
00175         // Since these points have the laser calibration applied to them
00176         // add in a 2m buffer for filtering out invalid points
00177 
00178         if (sqrt(pow(x,2) + pow(y,2) + pow(z,2)) > 58.0)
00179         {
00180             continue;
00181         }
00182 
00183 
00184         //
00185         // Compute the (u,v) camera coordinates corresponding to our laser
00186         // point
00187 
00188         //
00189         // (fx*x + cx*z)/z
00190         uint32_t u = (camera_info_.P[0] * x + camera_info_.P[2] * z) / z;
00191         //
00192         // (fy*y + cy*z)/z
00193         uint32_t v = (camera_info_.P[5] * y + camera_info_.P[6] * z) / z;
00194 
00195 
00196 
00197         //
00198         // If our computed (u, v) point projects into the image use its
00199         // color value and add it to the color pointcloud message
00200 
00201         if (u < color_image_.width && v < color_image_.height && u >= 0 && v >= 0)
00202         {
00203 
00204             colorPointCloudDataP[0] = x;
00205             colorPointCloudDataP[1] = y;
00206             colorPointCloudDataP[2] = z;
00207 
00208             uint8_t* colorChannelP = reinterpret_cast<uint8_t*>(&colorPointCloudDataP[3]);
00209 
00210             //
00211             // Image data is assumed to be BRG and stored continuously in memory
00212             // both of which are the case for color images from the MultiSense
00213 
00214             uint8_t* imageDataP = &color_image_.data[(image_channels_ * v * color_image_.width) + (image_channels_ * u)];
00215 
00216             switch(image_channels_)
00217             {
00218                 case 3:
00219                     colorChannelP[2] = imageDataP[2];
00220                 case 2:
00221                     colorChannelP[1] = imageDataP[1];
00222                 case 1:
00223                     colorChannelP[0] = imageDataP[0];
00224             }
00225 
00226             //
00227             // If we are dealing with a grayscale image then copy
00228             // the intensity value to all 3 channels
00229 
00230             if (image_channels_ == 1)
00231             {
00232                 colorChannelP[2] = imageDataP[0];
00233                 colorChannelP[1] = imageDataP[0];
00234             }
00235 
00236             colorPointCloudDataP += cloudStep;
00237             ++validPoints;
00238         }
00239 
00240     }
00241 
00242     color_laser_pointcloud_.data.resize(validPoints * laser_cloud_step);
00243     color_laser_pointcloud_.width = validPoints;
00244     color_laser_pointcloud_.row_step = validPoints * laser_cloud_step;
00245 
00246     color_laser_publisher_.publish(color_laser_pointcloud_);
00247 }
00248 
00249 void ColorLaser::startStreaming()
00250 {
00251     if (color_image_sub_.getNumPublishers() == 0 &&
00252         camera_info_sub_.getNumPublishers() == 0 &&
00253         laser_pointcloud_sub_.getNumPublishers() == 0)
00254     {
00255         color_image_sub_      = node_handle_.subscribe("image_rect_color",
00256                                                       10,
00257                                                       &multisense_ros::ColorLaser::colorImageCallback,
00258                                                       this);
00259 
00260         camera_info_sub_      = node_handle_.subscribe("camera_info",
00261                                                       10,
00262                                                       &multisense_ros::ColorLaser::cameraInfoCallback,
00263                                                       this);
00264 
00265         laser_pointcloud_sub_ = node_handle_.subscribe("lidar_points2",
00266                                                       10,
00267                                                       &multisense_ros::ColorLaser::laserPointCloudCallback,
00268                                                       this);
00269     }
00270 
00271 }
00272 
00273 void ColorLaser::stopStreaming()
00274 {
00275     if (color_laser_publisher_.getNumSubscribers() == 0)
00276     {
00277         color_image_sub_.shutdown();
00278         camera_info_sub_.shutdown();
00279         laser_pointcloud_sub_.shutdown();
00280     }
00281 }
00282 
00283 } // namespace
00284 
00285 int main(int argc, char** argv)
00286 {
00287 
00288     try
00289     {
00290         ros::init(argc, argv, "color_laser_publisher");
00291 
00292         ros::NodeHandle nh;
00293 
00294         multisense_ros::ColorLaser colorLaserPublisher(nh);
00295 
00296         ros::spin();
00297     }
00298     catch(std::exception& e)
00299     {
00300         ROS_ERROR("%s", e.what());
00301         return 1;
00302     }
00303 
00304     return 0;
00305 }
00306 
00307 


multisense_ros
Author(s):
autogenerated on Mon Oct 9 2017 03:06:27