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 }