Go to the documentation of this file.00001
00064
00065
00066
00067
00068
00069 #include <sstream>
00070
00071
00072 #include <ros/console.h>
00073 #include <pcl/io/pcd_io.h>
00074 #include <pcl/kdtree/kdtree.h>
00075 #include <pcl/ModelCoefficients.h>
00076 #include <pcl/sample_consensus/method_types.h>
00077 #include <pcl/sample_consensus/model_types.h>
00078 #include <pcl/filters/voxel_grid.h>
00079
00080
00081
00082 #include "cob_3d_mapping_common/stop_watch.h"
00083
00084
00085 #include "cob_3d_segmentation/plane_extraction.h"
00086
00087 #ifdef PCL_VERSION_COMPARE //fuerte
00088 #include <pcl/common/eigen.h>
00089 #include <pcl/common/centroid.h>
00090 #include <pcl/kdtree/kdtree_flann.h>
00091 #endif
00092
00093
00094 PlaneExtraction::PlaneExtraction()
00095 : ctr_(0),
00096 file_path_("/tmp"),
00097 save_to_file_(false),
00098 plane_constraint_(NONE),
00099 cluster_tolerance_(0.06),
00100 min_plane_size_(50),
00101 radius_(0.1),
00102
00103 max_iterations_(100),
00104 distance_threshold_(0.04),
00105 alpha_(0.2)
00106 {
00107 #ifdef PCL_VERSION_COMPARE //fuerte
00108 pcl::search::KdTree<Point>::Ptr tree (new pcl::search::KdTree<Point>());
00109 #else //electric
00110 pcl::KdTreeFLANN<Point>::Ptr tree (new pcl::KdTreeFLANN<Point> ());
00111 #endif
00112
00113
00114
00115 cluster_.setClusterTolerance (cluster_tolerance_);
00116 cluster_.setMinClusterSize (min_plane_size_);
00117 cluster_.setSearchMethod (tree);
00118
00119
00120 #ifdef PCL_VERSION_COMPARE //fuerte
00121 pcl::search::KdTree<Point>::Ptr clusters_plane_tree (new pcl::search::KdTree<Point>());
00122 #else //electric
00123 pcl::KdTreeFLANN<Point>::Ptr clusters_plane_tree (new pcl::KdTreeFLANN<Point> ());
00124 #endif
00125 cluster_plane_.setClusterTolerance (cluster_tolerance_);
00126 cluster_plane_.setMinClusterSize (min_plane_size_);
00127 cluster_plane_.setSearchMethod (clusters_plane_tree);
00128
00129
00130
00131 seg_.setOptimizeCoefficients (true);
00132
00133
00134 seg_.setModelType (pcl::SACMODEL_PLANE);
00135 seg_.setMethodType (pcl::SAC_RANSAC);
00136 seg_.setMaxIterations (max_iterations_);
00137 seg_.setDistanceThreshold (distance_threshold_);
00138
00139 proj_.setModelType (pcl::SACMODEL_PLANE);
00140
00141 chull_.setAlpha (alpha_);
00142 }
00143
00144 bool
00145 PlaneExtraction::isValidPlane (const pcl::ModelCoefficients& coefficients_plane)
00146 {
00147
00148 bool validPlane = true;
00149 switch (plane_constraint_)
00150 {
00151 case HORIZONTAL:
00152 {
00153 if (fabs (coefficients_plane.values[0]) > 0.12 || fabs (coefficients_plane.values[1]) > 0.12
00154 || fabs (coefficients_plane.values[2]) < 0.9)
00155 {
00156
00157 validPlane = false;
00158 }
00159
00160
00161 break;
00162 }
00163 case VERTICAL:
00164 {
00165 if (fabs (coefficients_plane.values[2]) > 0.1)
00166 validPlane = false;
00167 break;
00168 }
00169 case NONE:
00170 {
00171 validPlane = true;
00172 break;
00173 }
00174 default:
00175 break;
00176 }
00177 return validPlane;
00178 }
00179
00180
00181 void
00182 PlaneExtraction::extractPlanes(const pcl::PointCloud<Point>::ConstPtr& pc_in,
00183 std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > >& v_cloud_hull,
00184 std::vector<std::vector<pcl::Vertices> >& v_hull_polygons,
00185 std::vector<pcl::ModelCoefficients>& v_coefficients_plane)
00186 {
00187 static int ctr=0;
00188 static double time=0;
00189 PrecisionStopWatch t;
00190 t.precisionStart();
00191 std::stringstream ss;
00192 ROS_DEBUG("Extract planes");
00193 ROS_DEBUG("Saving files: %d", save_to_file_);
00194 if(save_to_file_)
00195 {
00196 ss.str("");
00197 ss.clear();
00198 ss << file_path_ << "/planes/pc_" << ctr_ << ".pcd";
00199 pcl::io::savePCDFileASCII (ss.str(), *pc_in);
00200 }
00201
00202
00203
00204 std::vector<pcl::PointIndices> clusters;
00205 cluster_.setInputCloud (pc_in);
00206 cluster_.extract (clusters);
00207
00208 ROS_DEBUG ("Number of clusters found: %d", (int)clusters.size ());
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 seg_.setInputCloud (pc_in);
00221
00222
00223 proj_.setInputCloud (pc_in);
00224
00225
00226 extracted_planes_indices_.clear();
00227 for(unsigned int i = 0; i < clusters.size(); ++i)
00228 {
00229 ROS_DEBUG("Processing cluster no. %u", i);
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices ());
00249
00250
00251
00252
00253 int ctr = 0;
00254
00255 while(clusters[i].indices.size() > min_plane_size_)
00256 {
00257
00258
00259 seg_.setIndices(boost::make_shared<const pcl::PointIndices> (clusters[i]));
00260
00261 pcl::ModelCoefficients coefficients_plane;
00262 seg_.segment (*inliers_plane, coefficients_plane);
00263
00264
00265 if (coefficients_plane.values.size () <=3)
00266 {
00267
00268 break;
00269 }
00270
00271 if ( inliers_plane->indices.size() < min_plane_size_)
00272 {
00273
00274
00275 break;
00276 }
00277 bool validPlane = false;
00278 validPlane = isValidPlane (coefficients_plane);
00279
00280
00281 if(validPlane)
00282 {
00283
00284 ROS_DEBUG("Plane has %d inliers", (int)inliers_plane->indices.size());
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 pcl::PointCloud<Point>::Ptr cloud_projected (new pcl::PointCloud<Point>);
00299
00300 proj_.setModelCoefficients (boost::make_shared<pcl::ModelCoefficients>(coefficients_plane));
00301 proj_.setIndices(inliers_plane);
00302 proj_.filter (*cloud_projected);
00303 if(save_to_file_)
00304 {
00305 ss.str("");
00306 ss.clear();
00307 ss << file_path_ << "/planes/plane_pr_" << ctr_ << "_" << ctr << ".pcd";
00308 pcl::io::savePCDFileASCII (ss.str(), *cloud_projected);
00309 }
00310
00311 std::vector<pcl::PointIndices> plane_clusters;
00312 cluster_plane_.setInputCloud (cloud_projected);
00313 cluster_plane_.extract (plane_clusters);
00314
00315 extract_.setInputCloud(cloud_projected);
00316
00317
00318 for(unsigned int j=0; j<plane_clusters.size(); j++)
00319 {
00320 pcl::PointCloud<Point> plane_cluster;
00321 extract_.setIndices(boost::make_shared<const pcl::PointIndices> (plane_clusters[j]));
00322 extract_.filter(plane_cluster);
00323 pcl::PointCloud<Point>::Ptr plane_cluster_ptr = plane_cluster.makeShared();
00324
00325 if(plane_cluster_ptr->size() < min_plane_size_) continue;
00326
00327
00328
00329 extracted_planes_indices_.push_back(std::vector<int>());
00330
00331 for (size_t idx = 0; idx < plane_clusters[j].indices.size(); ++idx)
00332 {
00333
00334 extracted_planes_indices_.back().push_back(inliers_plane->indices[ plane_clusters[j].indices[idx] ]);
00335 }
00336
00337
00338
00339 pcl::PointCloud<Point> cloud_hull;
00340 std::vector< pcl::Vertices > hull_polygons;
00341 chull_.setInputCloud (plane_cluster_ptr);
00342
00343
00344 chull_.reconstruct (cloud_hull, hull_polygons);
00345
00346
00347 if(hull_polygons.size() > 1)
00348 {
00349 extracted_planes_indices_.pop_back();
00350 continue;
00351 ROS_WARN("Extracted Polygon %d contours, separating ...", hull_polygons.size());
00352 pcl::PointCloud<Point>::Ptr cloud_hull_ptr = cloud_hull.makeShared();
00353 pcl::ExtractIndices<Point> extract_2;
00354 extract_2.setInputCloud(cloud_hull_ptr);
00355 for( unsigned int z=0; z<hull_polygons.size(); z++)
00356 {
00357
00358 pcl::PointCloud<Point> cloud_hull_2;
00359 std::vector< pcl::Vertices > hull_polygons_2;
00360 pcl::PointIndices hull_poly_indices;
00361 for (unsigned int x=0; x<hull_polygons[z].vertices.size(); x++)
00362 hull_poly_indices.indices.push_back(hull_polygons[z].vertices[x]);
00363
00364 extract_2.setIndices(boost::make_shared<const pcl::PointIndices> (hull_poly_indices));
00365 extract_2.filter(cloud_hull_2);
00366
00367 pcl::Vertices verts;
00368 for(unsigned int y=0; y<cloud_hull_2.size(); y++)
00369 verts.vertices.push_back(y);
00370 verts.vertices.push_back(0);
00371
00372 hull_polygons_2.push_back(verts);
00373 v_cloud_hull.push_back(cloud_hull_2);
00374 v_hull_polygons.push_back(hull_polygons_2);
00375 v_coefficients_plane.push_back(coefficients_plane);
00376 }
00377 }
00378 else
00379 {
00380
00381
00382 v_cloud_hull.push_back(cloud_hull);
00383 v_hull_polygons.push_back(hull_polygons);
00384 v_coefficients_plane.push_back(coefficients_plane);
00385 }
00386 ROS_DEBUG("v_cloud_hull size: %d", (unsigned int)v_cloud_hull.size());
00387
00388 if(save_to_file_)
00389 {
00390 saveHulls(cloud_hull, hull_polygons, ctr);
00391 }
00392 ctr++;
00393 }
00394
00395 }
00396
00397
00398 for(unsigned int idx_ctr1=0; idx_ctr1 < clusters[i].indices.size(); idx_ctr1++)
00399 {
00400 for(unsigned int idx_ctr2=0; idx_ctr2 < inliers_plane->indices.size(); idx_ctr2++)
00401 {
00402 if(clusters[i].indices[idx_ctr1] == inliers_plane->indices[idx_ctr2])
00403 clusters[i].indices.erase(clusters[i].indices.begin()+idx_ctr1);
00404 }
00405 }
00406
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 ctr_++;
00430 }
00431 double step_time = t.precisionStop();
00432
00433 time += step_time;
00434
00435 ctr++;
00436 return;
00437 }
00438
00439 void
00440 PlaneExtraction::dumpToPCDFileAllPlanes (pcl::PointCloud<Point>::Ptr dominant_plane_ptr)
00441 {
00442
00443 extracted_planes_.header.frame_id = dominant_plane_ptr->header.frame_id;
00444 extracted_planes_ += *dominant_plane_ptr;
00445 std::stringstream ss;
00446 ss << file_path_ << "/planes/all_planes.pcd";
00447 pcl::io::savePCDFileASCII (ss.str (), extracted_planes_);
00448
00449
00450
00451
00452
00453 }
00454 void
00455 PlaneExtraction::saveHulls(pcl::PointCloud<Point>& cloud_hull,
00456 std::vector< pcl::Vertices >& hull_polygons,
00457 int plane_ctr)
00458 {
00459 for(unsigned int i=0; i<hull_polygons.size(); i++)
00460 {
00461 pcl::PointCloud<Point> hull_part;
00462 for(unsigned int j=0; j<hull_polygons[i].vertices.size(); j++)
00463 {
00464 int idx = hull_polygons[i].vertices[j];
00465 hull_part.points.push_back(cloud_hull.points[idx]);
00466 }
00467 std::stringstream ss;
00468 ss << file_path_ << "/planes/hull_" << ctr_ << "_" << plane_ctr << "_" << i << ".pcd";
00469 pcl::io::savePCDFileASCII (ss.str(), hull_part);
00470 }
00471 }
00472
00473
00474
00475 void
00476 PlaneExtraction::findClosestTable(std::vector<pcl::PointCloud<Point>, Eigen::aligned_allocator<pcl::PointCloud<Point> > >& v_cloud_hull,
00477 std::vector<pcl::ModelCoefficients>& v_coefficients_plane,
00478 Eigen::Vector3f& robot_pose,
00479 unsigned int& idx)
00480 {
00481 std::vector<unsigned int> table_candidates;
00482 for(unsigned int i=0; i<v_cloud_hull.size(); i++)
00483 {
00484
00485 table_candidates.push_back(i);
00486 }
00487 if(table_candidates.size()>0)
00488 {
00489 for(unsigned int i=0; i<table_candidates.size(); i++)
00490 {
00491 double d_min = 1000;
00492 double d = d_min;
00493 Eigen::Vector4f centroid;
00494 pcl::compute3DCentroid(v_cloud_hull[i], centroid);
00495
00496
00497
00498
00499
00500
00501 Eigen::Vector3f centroid3 = centroid.head(3);
00502 d = fabs((centroid3-robot_pose).norm());
00503 ROS_INFO("d: %f", d);
00504 if(d<d_min)
00505 {
00506 d_min = d;
00507 idx = table_candidates[i];
00508 }
00509 }
00510 }
00511 }