plane_extraction.cpp
Go to the documentation of this file.
00001 
00064 //##################
00065 //#### includes ####
00066 
00067 // standard includes
00068 //--
00069 #include <sstream>
00070 
00071 // ROS includes
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 // external includes
00081 //#include <boost/timer.hpp>
00082 #include "cob_3d_mapping_common/stop_watch.h"
00083 
00084 // internal includes
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   //normal_distance_weight_(0.05),
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   // Init clustering of full cloud
00115   cluster_.setClusterTolerance (cluster_tolerance_);
00116   cluster_.setMinClusterSize (min_plane_size_);
00117   cluster_.setSearchMethod (tree);
00118 
00119   // Init clustering of planes
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   //normal_estimator_.setSearchMethod(tree);
00130 
00131   seg_.setOptimizeCoefficients (true);
00132   //seg_.setNormalDistanceWeight (normal_distance_weight_);
00133   //seg_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
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   //TODO: parameters
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         //std::cout << "Plane is not horizontal: " << coefficients_plane << std::endl;
00157         validPlane = false;
00158       }
00159       //else
00160       //std::cout << "Plane is horizontal: " << coefficients_plane << std::endl;
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 //input should be point cloud that is amplitude filetered, statistical outlier filtered, voxel filtered, coordinate system should be /map
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   //ROS_INFO("pc_in size: %d" , pc_in->size());
00202   // Extract Eucledian clusters
00203 
00204   std::vector<pcl::PointIndices> clusters;
00205   cluster_.setInputCloud (pc_in);
00206   cluster_.extract (clusters);
00207   //extractClusters (pc_in, clusters);
00208   ROS_DEBUG ("Number of clusters found: %d", (int)clusters.size ());
00209   //ROS_INFO("Clustering took %f s", t.precisionStop());
00210   //t.precisionStart();
00211 
00212   // Estimate point normals
00213   //normal_estimator_.setInputCloud(pc_in);
00214   //normalEstimator.setNumberOfThreads(4);
00215   //pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal> ());
00216   //normal_estimator_.compute(*cloud_normals);
00217   //ROS_INFO("Normal estimation took %f s", t.precisionStop());
00218   //t.precisionStart();
00219 
00220   seg_.setInputCloud (pc_in);
00221   //seg_.setInputNormals (cloud_normals);
00222 
00223   proj_.setInputCloud (pc_in);
00224 
00225   // Go through all clusters and search for planes
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     // Extract cluster points
00231     /*pcl::PointCloud<Point> cluster;
00232     extract_.setInputCloud (pc_in);
00233     extract_.setIndices (boost::make_shared<const pcl::PointIndices> (clusters[i]));
00234     extract_.setNegative (false);
00235     extract_.filter (cluster);
00236     ROS_INFO("Extraction1 took %f s", t.precisionStop());
00237     t.precisionStart();*/
00238     /*pcl::PointCloud<Point>::Ptr cluster_ptr = cluster.makeShared();
00239     if(save_to_file_)
00240     {
00241       ss.str("");
00242       ss.clear();
00243       ss << file_path_ << "/planes/cluster_" << ctr_ << ".pcd";
00244       pcl::io::savePCDFileASCII (ss.str(), cluster);
00245     }*/
00246 
00247     // Find plane
00248     pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices ());
00249     //pcl::PointIndices::Ptr clusters_ptr(&clusters[i]);
00250     //pcl::PointIndices::Ptr consider_in_cluster(new pcl::PointIndices ());
00251     //for(unsigned int idx_ctr=0; idx_ctr < clusters[i].indices.size(); idx_ctr++)
00252     //  consider_in_cluster->indices.push_back(clusters[i].indices[idx_ctr]);
00253     int ctr = 0;
00254     // iterate over cluster to find all planes until cluster is too small
00255     while(clusters[i].indices.size() > min_plane_size_)
00256     {
00257       //ROS_INFO("Cluster size: %d", (int)consider_in_cluster->indices.size());
00258 
00259       seg_.setIndices(boost::make_shared<const pcl::PointIndices> (clusters[i]));
00260       // Obtain the plane inliers and coefficients
00261       pcl::ModelCoefficients coefficients_plane;
00262       seg_.segment (*inliers_plane, coefficients_plane);
00263 
00264       // Evaluate plane
00265       if (coefficients_plane.values.size () <=3)
00266       {
00267         //ROS_INFO("Failed to detect plane in scan, skipping cluster");
00268         break;
00269       }
00270       //TODO: parameter
00271       if ( inliers_plane->indices.size() < min_plane_size_)
00272       {
00273         //std::cout << "Plane coefficients: " << *coefficients_plane << std::endl;
00274         //ROS_INFO("Plane detection has %d inliers, below min threshold of %d, skipping cluster", (int)inliers_plane->indices.size(), 150);
00275         break;
00276       }
00277       bool validPlane = false;
00278       validPlane = isValidPlane (coefficients_plane);
00279       //std::cout << " Plane valid = " << validPlane << std::endl;
00280 
00281       if(validPlane)
00282       {
00283         // Extract plane points, only needed for storing bag file
00284         ROS_DEBUG("Plane has %d inliers", (int)inliers_plane->indices.size());
00285         /*pcl::PointCloud<Point> dominant_plane;
00286         extract_.setInputCloud(pc_in);
00287         extract_.setIndices(inliers_plane);
00288         extract_.filter(dominant_plane);
00289         if(save_to_file_)
00290         {
00291           ss.str("");
00292           ss.clear();
00293           ss << file_path_ << "/planes/plane_" << ctr_ << "_" << ctr << ".pcd";
00294           pcl::io::savePCDFileASCII (ss.str(), dominant_plane);
00295         }*/
00296 
00297         // Project the model inliers
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         /*std::cout << "projected: " << cloud_projected->size() << std::endl;
00317         std::cout << "inliers_plane: " << inliers_plane->indices.size() << std::endl;*/
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           //else std::cout << "plane cluster has " << plane_cluster_ptr->size() << " points" << std::endl;
00327 
00328           // <evaluation_stuff>
00329           extracted_planes_indices_.push_back(std::vector<int>());
00330           //std::cout << "plane_cluster: " << plane_clusters[j].indices.size() << std::endl;
00331           for (size_t idx = 0; idx < plane_clusters[j].indices.size(); ++idx)
00332           {
00333             //std::cout << plane_clusters[j].indices[idx] << " ";
00334             extracted_planes_indices_.back().push_back(inliers_plane->indices[ plane_clusters[j].indices[idx] ]);
00335           }
00336           // </evaluation_stuff>
00337 
00338           // Create a Concave Hull representation of the projected inliers
00339           pcl::PointCloud<Point> cloud_hull;
00340           std::vector< pcl::Vertices > hull_polygons;
00341           chull_.setInputCloud (plane_cluster_ptr);
00342           //TODO: parameter
00343 
00344           chull_.reconstruct (cloud_hull, hull_polygons);
00345           /*std::cout << "Hull: " << cloud_hull.size() << ", " << hull_polygons[0].vertices.size()
00346             << ", "<< plane_cluster_ptr->size() << std::endl;*/
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               //ROS_WARN("\tC%d size: %d", z,hull_polygons[z].vertices.size());
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               //ROS_INFO("Size indices: %d", hull_poly_indices.indices.size());
00364               extract_2.setIndices(boost::make_shared<const pcl::PointIndices> (hull_poly_indices));
00365               extract_2.filter(cloud_hull_2);
00366               //ROS_INFO("Hull 2 size: %d", cloud_hull_2.size());
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               //ROS_INFO("Verts size: %d", verts.vertices.size());
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             //ROS_INFO("Hull size: %d", cloud_hull.size());
00381             //ROS_INFO("Verts size: %d", hull_polygons[0].vertices.size());
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       // Remove plane inliers from indices vector
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       //ctr_++;
00407     }
00408     //ROS_INFO("Plane estimation took %f s", t.precisionStop());
00409     //t.precisionStart();
00410     /*if(clusters[i].indices.size() >0 )
00411     {
00412       if(save_to_file_)
00413       {
00414         ss.str("");
00415         ss.clear();
00416         ss << file_path_ << "/planes/rem_pts_" << ctr_ << "_" << ctr << ".pcd";
00417         if(consider_in_cluster->indices.size() == cluster_ptr->size())
00418           pcl::io::savePCDFileASCII (ss.str(), *cluster_ptr);
00419         else
00420         {
00421           pcl::PointCloud<Point> remaining_pts;
00422           extract_.setInputCloud (cluster_ptr);
00423           extract_.setIndices (consider_in_cluster);
00424           extract_.filter (remaining_pts);
00425           pcl::io::savePCDFileASCII (ss.str(), remaining_pts);
00426         }
00427       }
00428     }*/
00429     ctr_++;
00430   }
00431   double step_time = t.precisionStop();
00432   //ROS_INFO("Plane extraction took %f", step_time);
00433   time += step_time;
00434   //ROS_INFO("[plane extraction] Accumulated time at step %d: %f s", ctr, time);
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    //pcl::visualization::CloudViewer viewer(" All Extracted planes");
00450    pcl::PointCloud<Point>::Ptr all_planes (new pcl::PointCloud<Point>);
00451    pcl::io::loadPCDFile (ss.str (), *all_planes);
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 //TODO: move to semantics
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     //if(fabs(v_coefficients_plane[i].values[3])>0.5 && fabs(v_coefficients_plane[i].values[3])<1.2)
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       //for(unsigned int j=0; j<v_cloud_hull[i].size(); j++)
00496       //{
00497       //  Eigen::Vector3f p = v_cloud_hull[i].points[j].getVector3fMap();
00498       //  d += fabs((p-robot_pose).norm());
00499       //}
00500       //d /= v_cloud_hull[i].size();
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 }


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