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)