00001 
00064 
00065 
00066 
00067 
00068 
00069 #include <sstream>
00070 #include <fstream>
00071 
00072 
00073 #include <ros/ros.h>
00074 #include <pluginlib/class_list_macros.h>
00075 #include <nodelet/nodelet.h>
00076 #include <pcl/io/io.h>
00077 #include <pcl/io/pcd_io.h>
00078 #include <pcl/point_types.h>
00079 #include <pcl/registration/icp.h>
00080 #include <tf/transform_listener.h>
00081 #include <tf_conversions/tf_eigen.h>
00082 
00083 #include <pcl_ros/transforms.h>
00084 #include <pcl_ros/point_cloud.h>
00085 #include <visualization_msgs/Marker.h>
00086 #include <actionlib/server/simple_action_server.h>
00087 
00088 #include "pcl/point_types.h"
00089 #include "pcl/ModelCoefficients.h"
00090 #include "pcl/sample_consensus/method_types.h"
00091 #include "pcl/sample_consensus/model_types.h"
00092 #include "pcl/segmentation/sac_segmentation.h"
00093 #include "pcl/filters/extract_indices.h"
00094 #include "pcl/features/normal_3d_omp.h"
00095 #include "pcl/kdtree/kdtree.h"
00096 #include "pcl/filters/project_inliers.h"
00097 #include "pcl/surface/concave_hull.h"
00098 #include <pcl/segmentation/extract_clusters.h>
00099 #include <pcl/segmentation/extract_polygonal_prism_data.h>
00100 #include "pcl/filters/voxel_grid.h"
00101 
00102 #include <pcl/common/eigen.h>
00103 #include <pcl/common/centroid.h>
00104 #include <pcl_conversions/pcl_conversions.h>
00105 #include <ros/console.h>
00106 
00107 
00108 
00109 #include <dynamic_reconfigure/server.h>
00110 #include <cob_3d_segmentation/plane_extraction_nodeletConfig.h>
00111 
00112 
00113 
00114 
00115 #include <cob_3d_mapping_msgs/GetPlane.h>
00116 #include <cob_3d_mapping_msgs/ShapeArray.h>
00117 
00118 
00119 #include <boost/timer.hpp>
00120 #include <boost/numeric/ublas/matrix.hpp>
00121 
00122 #include "cob_3d_segmentation/plane_extraction.h"
00123 #include "cob_3d_mapping_msgs/PlaneExtractionAction.h"
00124 #include <cob_3d_mapping_common/polygon.h>
00125 #include <cob_3d_mapping_common/ros_msg_conversions.h>
00126 
00127 
00128 using namespace tf;
00129 
00130 using namespace cob_3d_mapping;
00131 
00132 
00133 
00134 class PlaneExtractionNodelet : public nodelet::Nodelet
00135 {
00136 public:
00137   typedef pcl::PointXYZRGB Point;
00138   
00139   PlaneExtractionNodelet()
00140   : as_(0),
00141     ctr_(0),
00142     mode_action_(false),
00143     target_frame_("/map"),
00144     vox_leaf_size_(0.04),
00145     passthrough_min_z_(-0.1),
00146     passthrough_max_z_(2.0)
00147   {
00148     
00149   }
00150 
00151   
00152   virtual
00153   ~PlaneExtractionNodelet()
00154   {
00155     if(as_) delete as_;
00156   }
00157 
00158   void dynReconfCallback(cob_3d_segmentation::plane_extraction_nodeletConfig &config, uint32_t level)
00159   {
00160     mode_action_ = config.mode_action;
00161     target_frame_ = config.target_frame;
00162     passthrough_min_z_ = config.passthrough_min_z;
00163     passthrough_max_z_ = config.passthrough_max_z;
00164 
00165     pe.setFilePath(config.file_path);
00166     pe.setSaveToFile(config.save_to_file);
00167     pe.setPlaneConstraint((PlaneConstraint)config.plane_constraint);
00168     pe.setClusterTolerance (config.cluster_tolerance);
00169     pe.setMinPlaneSize (config.min_plane_size);
00170     pe.setAlpha(config.alpha);
00171     
00172     
00173     
00174     
00175     
00176   }
00177 
00178 
00186   void onInit()
00187   {
00188     
00189     n_ = getNodeHandle();
00190 
00191     config_server_ = boost::shared_ptr<dynamic_reconfigure::Server<cob_3d_segmentation::plane_extraction_nodeletConfig> >(new dynamic_reconfigure::Server<cob_3d_segmentation::plane_extraction_nodeletConfig>(getPrivateNodeHandle()));
00192     config_server_->setCallback(boost::bind(&PlaneExtractionNodelet::dynReconfCallback, this, _1, _2));
00193     point_cloud_sub_ = n_.subscribe("point_cloud2", 1, &PlaneExtractionNodelet::pointCloudSubCallback, this);
00194     viz_marker_pub_ = n_.advertise<visualization_msgs::Marker>("visualization_marker",10);
00195     shape_array_pub_ = n_.advertise<cob_3d_mapping_msgs::ShapeArray>("shape_array",1);
00196 
00197     
00198     
00199 
00200     get_plane_ = n_.advertiseService("get_plane", &PlaneExtractionNodelet::srvCallback, this);
00201   }
00202 
00203 
00216   void extractPlane(const pcl::PointCloud<Point>::Ptr& pc_in,
00217                     std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > >& v_cloud_hull,
00218                     std::vector<std::vector<pcl::Vertices> >& v_hull_polygons,
00219                     std::vector<pcl::ModelCoefficients>& v_coefficients_plane)
00220   {
00221     pe.extractPlanes(pc_in, v_cloud_hull, v_hull_polygons, v_coefficients_plane);
00222   }
00223 
00233   void
00234   pointCloudSubCallback(const pcl::PointCloud<Point>::Ptr& pc_in)
00235   {
00236     
00237 
00238     
00239     boost::mutex::scoped_try_lock lock(mutex_);
00240     if(!lock)
00241     
00242     {
00243       
00244       return;
00245     }
00246     
00247     pcl::VoxelGrid<Point> voxel;
00248     voxel.setInputCloud(pc_in);
00249     voxel.setLeafSize (vox_leaf_size_, vox_leaf_size_, vox_leaf_size_);
00250     voxel.setFilterFieldName("z");
00251     voxel.setFilterLimits(passthrough_min_z_, passthrough_max_z_);
00252     pcl::PointCloud<Point>::Ptr pc_vox = pcl::PointCloud<Point>::Ptr(new pcl::PointCloud<Point>);
00253     voxel.filter(*pc_vox);
00254     pcl::PointCloud<Point> pc_trans;
00255     
00256     {
00257       
00258       
00259       pcl_ros::transformPointCloud (target_frame_, *pc_in, pc_trans, tf_listener_);
00260     }
00261     
00262 
00263     
00264     
00265     if(mode_action_)
00266       pcl::copyPointCloud(pc_trans, pc_cur_);
00267     else
00268     {
00269       std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > > v_cloud_hull;
00270       std::vector<std::vector<pcl::Vertices> > v_hull_polygons;
00271       std::vector<pcl::ModelCoefficients> v_coefficients_plane;
00272       extractPlane(pc_trans.makeShared(), v_cloud_hull, v_hull_polygons, v_coefficients_plane);
00273 
00274       std_msgs::Header header;
00275       pcl_conversions::fromPCL(pc_in->header, header);
00276       publishShapeArray(v_cloud_hull, v_hull_polygons, v_coefficients_plane, header);
00277       for(unsigned int i = 0; i < v_cloud_hull.size(); i++)
00278       {
00279         pcl_conversions::fromPCL(pc_in->header, header);
00280         publishMarker(v_cloud_hull[i], header, 0, 0, 1);
00281         ctr_++;
00282         
00283       }
00284 
00285       
00286     }
00287 
00288   }
00289 
00299   
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00352   bool
00353   srvCallback(cob_3d_mapping_msgs::GetPlane::Request &req, cob_3d_mapping_msgs::GetPlane::Response &res)
00354   {
00355     boost::mutex::scoped_lock lock(mutex_);
00356     sensor_msgs::PointCloud2 pc_out, hull_out;
00357     pcl::toROSMsg(pc_plane_, pc_out);
00358     pcl::toROSMsg(hull_, hull_out);
00359     res.pc = pc_out;
00360     res.hull = hull_out;
00361     res.plane_coeffs.resize(4);
00362     res.plane_coeffs[0].data = plane_coeffs_.values[0];
00363     res.plane_coeffs[1].data = plane_coeffs_.values[1];
00364     res.plane_coeffs[2].data = plane_coeffs_.values[2];
00365     res.plane_coeffs[3].data = plane_coeffs_.values[3];
00366     ROS_INFO("Hull size: %d", res.hull.width*res.hull.height);
00367     return true;
00368   }
00369 
00382   void
00383   publishShapeArray(std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > >& v_cloud_hull,
00384                     std::vector<std::vector<pcl::Vertices> >& v_hull_polygons,
00385                     std::vector<pcl::ModelCoefficients>& v_coefficients_plane,
00386                     std_msgs::Header header)
00387   {
00388     cob_3d_mapping_msgs::ShapeArray sa;
00389     
00390     sa.header = header;
00391     sa.header.frame_id = target_frame_;
00392     unsigned int ctr = 0;
00393     for(unsigned int i=0; i<v_cloud_hull.size(); i++)
00394     {
00395       Eigen::Vector3f normal;
00396       for(unsigned int c=0; c<3; c++)
00397         normal[c] = v_coefficients_plane[i].values[c];
00398       
00399       std::vector<float> color(4);
00400       color[0] = color[3] = 1;
00401       color[1] = color[2] = 0;
00402       
00403       
00404       
00405       pcl::PointCloud<pcl::PointXYZ> hull;
00406       
00407       for(unsigned int j=0; j<v_cloud_hull[i].size(); j++)
00408       {
00409         
00410         pcl::PointXYZ pt;
00411         pt.x = v_cloud_hull[i][j].x;
00412         pt.y = v_cloud_hull[i][j].y;
00413         pt.z = v_cloud_hull[i][j].z;
00414         hull.push_back(pt);
00415       }
00416       
00417       
00418       
00419       
00420       std::vector<bool> holes(1, false);
00421       std::vector<pcl::PointCloud<pcl::PointXYZ> > hull_v(1, hull);
00422       Polygon p(0, normal, hull_v[0].points[0].getVector3fMap(), hull_v, holes, color);
00423 
00424       cob_3d_mapping_msgs::Shape s;
00425       s.header = header;
00426       s.header.frame_id = target_frame_;
00427       toROSMsg(p, s);
00428       sa.shapes.push_back(s);
00429       ctr++;
00430     }
00431 
00432       
00433       
00434       
00435       
00436       
00437      
00438 
00439 
00440 
00441 
00442 
00443 
00444 
00445 
00446 
00447 
00448 
00449 
00450 
00451 
00452 
00453 
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469     
00470     shape_array_pub_.publish(sa);
00471   }
00472 
00486   void
00487   publishMarker(pcl::PointCloud<Point>& cloud_hull,
00488                 std_msgs::Header header,
00489                 float r, float g, float b)
00490   {
00491     if(cloud_hull.points.size()==0) return;
00492     visualization_msgs::Marker marker;
00493     marker.action = visualization_msgs::Marker::ADD;
00494     marker.type = visualization_msgs::Marker::POINTS;
00495     marker.lifetime = ros::Duration();
00496     marker.header = header;
00497     marker.header.frame_id = target_frame_;
00498     marker.id = ctr_;
00499 
00500 
00501     
00502     
00503 
00504     marker.scale.x = 0.02;
00505     marker.scale.y = 0.02;
00506     marker.scale.z = 1;
00507 
00508     geometry_msgs::Point pt;
00509 
00510     for(unsigned int i = 0; i < cloud_hull.points.size(); ++i)
00511     {
00512       pt.x = cloud_hull.points[i].x;
00513       pt.y = cloud_hull.points[i].y;
00514       pt.z = cloud_hull.points[i].z;
00515 
00516       marker.points.push_back(pt);
00517     }
00518     pt.x = cloud_hull.points[0].x;
00519     pt.y = cloud_hull.points[0].y;
00520     pt.z = cloud_hull.points[0].z;
00521 
00522     
00523 
00524     marker.color.r = r;
00525     marker.color.g = g;
00526     marker.color.b = b;
00527     marker.color.a = 1.0;
00528 
00529     viz_marker_pub_.publish(marker);
00530   }
00531 
00532   ros::NodeHandle n_;
00533 
00534 
00535 protected:
00536   ros::Subscriber point_cloud_sub_;
00537   ros::Publisher viz_marker_pub_;
00538   ros::Publisher shape_array_pub_;
00539   boost::shared_ptr<dynamic_reconfigure::Server<cob_3d_segmentation::plane_extraction_nodeletConfig> > config_server_;
00540 
00541   ros::ServiceServer get_plane_;
00542 
00543   actionlib::SimpleActionServer<cob_3d_mapping_msgs::PlaneExtractionAction>* as_;
00544   std::string action_name_;
00545   
00546   cob_3d_mapping_msgs::PlaneExtractionFeedback feedback_;
00547   cob_3d_mapping_msgs::PlaneExtractionResult result_;
00548   boost::mutex mutex_;
00549 
00550   PlaneExtraction pe;                   
00551   pcl::PointCloud<Point> pc_cur_;       
00552   pcl::PointCloud<Point> pc_plane_;     
00553   pcl::PointCloud<Point> hull_;         
00554   pcl::ModelCoefficients plane_coeffs_; 
00555 
00556   TransformListener tf_listener_;
00557   int ctr_;                             
00558   
00559   
00560   
00561   bool mode_action_;
00562   
00563   std::string target_frame_;
00564 
00565   double vox_leaf_size_;                                
00566   double passthrough_min_z_;
00567   double passthrough_max_z_;
00568 };
00569 
00570 PLUGINLIB_DECLARE_CLASS(cob_3d_segmentation, PlaneExtractionNodelet, PlaneExtractionNodelet, nodelet::Nodelet)