plane_extraction_nodelet.cpp
Go to the documentation of this file.
00001 
00064 //##################
00065 //#### includes ####
00066 
00067 // standard includes
00068 //--
00069 #include <sstream>
00070 #include <fstream>
00071 
00072 // ROS includes
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 //#include <tf_conversions/tf_kdl.h>
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 //#include <Eigen/StdVector>
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 //#include <cob_3d_mapping_common/reconfigureable_node.h>
00109 #include <dynamic_reconfigure/server.h>
00110 #include <cob_3d_segmentation/plane_extraction_nodeletConfig.h>
00111 
00112 
00113 // ROS message includes
00114 //#include <sensor_msgs/PointCloud2.h>
00115 #include <cob_3d_mapping_msgs/GetPlane.h>
00116 #include <cob_3d_mapping_msgs/ShapeArray.h>
00117 
00118 // external includes
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 //using namespace cob_3d_features;
00130 using namespace cob_3d_mapping;
00131 
00132 //####################
00133 //#### nodelet class ####
00134 class PlaneExtractionNodelet : public nodelet::Nodelet//, protected Reconfigurable_Node<plane_extraction_nodeletConfig>
00135 {
00136 public:
00137   typedef pcl::PointXYZRGB Point;
00138   // Constructor
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     // void
00149   }
00150 
00151   // Destructor
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     //pe.setClusteringParamMaxClusterSize (config.max_cluster_size);
00172     //pe.setNormalEstimationParamRadius (config.normal_radius);
00173     //pe.setSegmentationParamNormalDistanceWeight (normal_distance_weight_);
00174     //pe.setSegmentationParamMaxIterations (max_iterations_);
00175     //pe.setSegmentationParamDistanceThreshold (distance_threshold_);
00176   }
00177 
00178 
00186   void onInit()
00187   {
00188     //PCLNodelet::onInit();
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     //as_= new actionlib::SimpleActionServer<cob_3d_mapping_msgs::PlaneExtractionAction>(n_, "plane_extraction", boost::bind(&PlaneExtractionNodelet::actionCallback, this, _1), false);
00198     //as_->start();
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     //boost::mutex::scoped_lock l2(m_mutex_pointCloudSubCallback);
00237 
00238     //ROS_INFO("Extract plane callback");
00239     boost::mutex::scoped_try_lock lock(mutex_);
00240     if(!lock)
00241     //if(!lock.owns_lock())
00242     {
00243       //ROS_INFO(" pointCloudSubCallback not owning lock");
00244       return;
00245     }
00246     // Downsample input
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     //if(pc_in->header.frame_id!="/map")
00256     {
00257       //ROS_INFO("transforming pc");
00258       //pcl_ros::transformPointCloud ("/map", pc_in->header.stamp, *pc_in, "/map", pc_trans, tf_listener_);
00259       pcl_ros::transformPointCloud (target_frame_, *pc_in, pc_trans, tf_listener_);
00260     }
00261     /*else
00262       ROS_INFO(" pointCloudSubCallback owns lock");*/
00263     //TODO: mode action or topic
00264     //extractPlane(pc_in);
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         //ROS_INFO("%d planes published so far", ctr_);
00283       }
00284 
00285       //publishShapeArray(v_cloud_hull, v_hull_polygons, v_coefficients_plane, pc_in->header);
00286     }
00287 
00288   }
00289 
00299   /*void
00300   actionCallback(const cob_3d_mapping_msgs::PlaneExtractionGoalConstPtr &goal)
00301   {
00302     //boost::mutex::scoped_lock l1(m_mutex_actionCallback);
00303 
00304     ROS_INFO("action callback");
00305     boost::mutex::scoped_lock lock(mutex_);
00306 
00307     feedback_.currentStep.data = std::string("plane extraction");
00308     std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > > v_cloud_hull;
00309     std::vector<std::vector<pcl::Vertices> > v_hull_polygons;
00310     std::vector<pcl::ModelCoefficients> v_coefficients_plane;
00311     extractPlane(pc_cur_.makeShared(), v_cloud_hull, v_hull_polygons, v_coefficients_plane);
00312     if(v_cloud_hull.size() == 0)
00313     {
00314       as_->setAborted();
00315       return;
00316     }
00317     pcl::copyPointCloud(pc_cur_, pc_plane_);
00318     // only save dominant plane
00319     StampedTransform transform;
00320     try
00321     {
00322       tf_listener_.waitForTransform("/map", "/head_cam3d_link", pc_cur_.header.stamp, ros::Duration(2));
00323       tf_listener_.lookupTransform("/map", "/head_cam3d_link", pc_cur_.header.stamp, transform);
00324     }
00325     catch (tf::TransformException& ex)
00326     {
00327       ROS_ERROR("[plane_extraction] : %s",ex.what());
00328     }
00329     Eigen::Affine3d ad;
00330     tf::transformTFToEigen(transform, ad);
00331 
00332     Eigen::Vector3f rob_pose = ad.translation().cast<float>();//(bt_rob_pose.x(),bt_rob_pose.y(),bt_rob_pose.z());
00333     ROS_INFO("Rob pose: (%f,%f,%f)", rob_pose(0),rob_pose(1),rob_pose(2));
00334     unsigned int idx = 0;
00335     pe.findClosestTable(v_cloud_hull, v_coefficients_plane, rob_pose, idx);
00336     ROS_INFO("Hull %d size: %d", idx, (unsigned int)v_cloud_hull[idx].size());
00337     pcl::copyPointCloud(v_cloud_hull[idx], hull_);
00338     plane_coeffs_ = v_coefficients_plane[idx];
00339     as_->setSucceeded(result_);
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     //p.polygons.resize(hull_polygons.size());
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       //p.id_ = 0;//ctr;
00399       std::vector<float> color(4);
00400       color[0] = color[3] = 1;
00401       color[1] = color[2] = 0;
00402       //p.d_ =  v_coefficients_plane[i].values[3];
00403       //p.computePose();
00404       //std::vector<Eigen::Vector2f> pts;
00405       pcl::PointCloud<pcl::PointXYZ> hull;
00406       //pcl::transformPointCloud(v_cloud_hull[i], hull_tr, p.pose_);
00407       for(unsigned int j=0; j<v_cloud_hull[i].size(); j++)
00408       {
00409         //Eigen::Vector2f pt(hull_tr[j].x, hull_tr[j].y);
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       //std::vector<std::vector<Eigen::Vector2f> > hull;
00417       //hull.push_back(pts);
00418       //p.contours_.push_back(pts);
00419       //p.holes_.push_back(false);
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       //std::cout << "normal: " << v_coefficients_plane[i].values[0] << ","  << v_coefficients_plane[i].values[1] << "," << v_coefficients_plane[i].values[2] << std::endl;
00433       //std::cout << "d: " << v_coefficients_plane[i].values[3] << std::endl << std::endl;
00434       //s.points.resize(v_hull_polygons[i].size());
00435       //ROS_INFO("poly size: %d",v_hull_polygons[i].size());
00436       //ROS_INFO("%d,%d,%d",i,v_hull_polygons[i][0].vertices.size(),v_cloud_hull[i].size());
00437      /* for(unsigned int j=0; j<v_hull_polygons[i].size(); j++)
00438       {
00439         //ROS_INFO("j: %d", j);
00440         cob_3d_mapping_msgs::Shape s;
00441         s.header = header;
00442         s.header.frame_id = target_frame_;
00443         s.type = cob_3d_mapping_msgs::Shape::PLANE;
00444         s.params.resize(4);
00445         for(unsigned int c=0; c<4; c++)
00446           s.params[c] = v_coefficients_plane[i].values[c];
00447         s.color.r = 1;
00448         s.color.a = 1;
00449         if (v_hull_polygons[i][j].vertices.size()==0) continue;
00450         pcl::PointCloud<pcl::PointXYZ> pc;
00451         for(unsigned int k=0; k<v_hull_polygons[i][j].vertices.size(); k++)
00452         {
00453           //ROS_INFO("k: %d", k);
00454           int idx = v_hull_polygons[i][j].vertices[k];
00455           pcl::PointXYZ p;
00456           p.x = v_cloud_hull[i].points[idx].x;
00457           p.y = v_cloud_hull[i].points[idx].y;
00458           p.z = v_cloud_hull[i].points[idx].z;
00459           if(p.x<0.001 && p.x>-0.001) std::cout << p.y << "," << p.z << std::endl;
00460           pc.points.push_back(p);
00461         }
00462         sensor_msgs::PointCloud2 pc_msg;
00463         pcl::toROSMsg(pc, pc_msg);
00464         s.points.push_back(pc_msg);
00465         s.holes.push_back(false);
00466         sa.shapes.push_back(s);
00467       }
00468     }*/
00469     //std::cout << sa.shapes[0].params[0] << "," << sa.shapes[1].params[0] << std::endl;
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     //create the marker in the table reference frame
00502     //the caller is responsible for setting the pose of the marker to match
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     //marker.points.push_back(pt);
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   // create messages that are used to published feedback/result
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   //unsigned int min_cluster_size_;       /// parameter for cluster size
00559   //std::string file_path_;
00560   //bool save_to_file_;
00561   bool mode_action_;
00562   //int plane_constraint_;                /// constraint parameter for PlaneExtraction (pe)
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)


cob_3d_segmentation
Author(s): Georg Arbeiter
autogenerated on Wed Aug 26 2015 11:03:03