dominant_plane_segmentation.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  */
00035 
00036 #include <boost/thread/thread.hpp>
00037 #include <boost/date_time/posix_time/posix_time.hpp>
00038 
00039 #include <pcl/apps/dominant_plane_segmentation.h>
00040 #include <pcl/visualization/pcl_visualizer.h>
00041 #include <pcl/features/integral_image_normal.h>
00042 #include <pcl/common/time.h>
00043 
00044 template<typename PointType> void
00045 pcl::apps::DominantPlaneSegmentation<PointType>::compute_table_plane ()
00046 {
00047   // Has the input dataset been set already?
00048   if (!input_)
00049   {
00050     PCL_WARN ("[pcl::apps::DominantPlaneSegmentation] No input dataset given!\n");
00051     return;
00052   }
00053 
00054   CloudConstPtr cloud_;
00055   CloudPtr cloud_filtered_ (new Cloud ());
00056   CloudPtr cloud_downsampled_ (new Cloud ());
00057   pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ (new pcl::PointCloud<pcl::Normal> ());
00058   pcl::PointIndices::Ptr table_inliers_ (new pcl::PointIndices ());
00059   pcl::ModelCoefficients::Ptr table_coefficients_ (new pcl::ModelCoefficients ());
00060   CloudPtr table_projected_ (new Cloud ());
00061   CloudPtr table_hull_ (new Cloud ());
00062 
00063   typename pcl::search::KdTree<PointType>::Ptr normals_tree_ (new pcl::search::KdTree<PointType>);
00064 
00065   // Normal estimation parameters
00066   n3d_.setKSearch (k_);
00067   n3d_.setSearchMethod (normals_tree_);
00068 
00069   // Table model fitting parameters
00070   seg_.setDistanceThreshold (sac_distance_threshold_);
00071   seg_.setMaxIterations (2000);
00072   seg_.setNormalDistanceWeight (0.1);
00073   seg_.setOptimizeCoefficients (true);
00074   seg_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00075   seg_.setMethodType (pcl::SAC_RANSAC);
00076   seg_.setProbability (0.99);
00077 
00078   proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00079   bb_cluster_proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00080 
00081   // ---[ PassThroughFilter
00082   pass_.setFilterLimits (min_z_bounds_, max_z_bounds_);
00083   pass_.setFilterFieldName ("z");
00084   pass_.setInputCloud (input_);
00085   pass_.filter (*cloud_filtered_);
00086 
00087   if (int (cloud_filtered_->points.size ()) < k_)
00088   {
00089     PCL_WARN ("[DominantPlaneSegmentation] Filtering returned %zu points! Aborting.",
00090         cloud_filtered_->points.size ());
00091     return;
00092   }
00093 
00094   // Downsample the point cloud
00095   grid_.setLeafSize (downsample_leaf_, downsample_leaf_, downsample_leaf_);
00096   grid_.setDownsampleAllData (false);
00097   grid_.setInputCloud (cloud_filtered_);
00098   grid_.filter (*cloud_downsampled_);
00099 
00100   // ---[ Estimate the point normals
00101   n3d_.setInputCloud (cloud_downsampled_);
00102   n3d_.compute (*cloud_normals_);
00103 
00104   // ---[ Perform segmentation
00105   seg_.setInputCloud (cloud_downsampled_);
00106   seg_.setInputNormals (cloud_normals_);
00107   seg_.segment (*table_inliers_, *table_coefficients_);
00108 
00109   if (table_inliers_->indices.size () == 0)
00110   {
00111     PCL_WARN ("[DominantPlaneSegmentation] No Plane Inliers points! Aborting.");
00112     return;
00113   }
00114 
00115   // ---[ Extract the plane
00116   proj_.setInputCloud (cloud_downsampled_);
00117   proj_.setIndices (table_inliers_);
00118   proj_.setModelCoefficients (table_coefficients_);
00119   proj_.filter (*table_projected_);
00120 
00121   // ---[ Estimate the convex hull
00122   std::vector<pcl::Vertices> polygons;
00123   CloudPtr table_hull (new Cloud ());
00124   hull_.setInputCloud (table_projected_);
00125   hull_.reconstruct (*table_hull, polygons);
00126 
00127   // Compute the plane coefficients
00128   Eigen::Vector4f model_coefficients;
00129   EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00130 
00131   model_coefficients[0] = table_coefficients_->values[0];
00132   model_coefficients[1] = table_coefficients_->values[1];
00133   model_coefficients[2] = table_coefficients_->values[2];
00134   model_coefficients[3] = table_coefficients_->values[3];
00135 
00136   // Need to flip the plane normal towards the viewpoint
00137   Eigen::Vector4f vp (0, 0, 0, 0);
00138   // See if we need to flip any plane normals
00139   vp -= table_hull->points[0].getVector4fMap ();
00140   vp[3] = 0;
00141   // Dot product between the (viewpoint - point) and the plane normal
00142   float cos_theta = vp.dot (model_coefficients);
00143   // Flip the plane normal
00144   if (cos_theta < 0)
00145   {
00146     model_coefficients *= -1;
00147     model_coefficients[3] = 0;
00148     // Hessian form (D = nc . p_plane (centroid here) + p)
00149     model_coefficients[3] = -1 * (model_coefficients.dot (table_hull->points[0].getVector4fMap ()));
00150   }
00151 
00152   //Set table_coeffs
00153   table_coeffs_ = model_coefficients;
00154 }
00155 
00156 template<typename PointType> void
00157 pcl::apps::DominantPlaneSegmentation<PointType>::compute_fast (std::vector<CloudPtr> & clusters)
00158 {
00159   // Has the input dataset been set already?
00160   if (!input_)
00161   {
00162     PCL_WARN ("[pcl::apps::DominantPlaneSegmentation] No input dataset given!\n");
00163     return;
00164   }
00165 
00166   // Is the input dataset organized?
00167   if (input_->is_dense)
00168   {
00169     PCL_WARN ("[pcl::apps::DominantPlaneSegmentation] compute_fast can only be used with organized point clouds!\n");
00170     return;
00171   }
00172 
00173   CloudConstPtr cloud_;
00174   CloudPtr cloud_filtered_ (new Cloud ());
00175   CloudPtr cloud_downsampled_ (new Cloud ());
00176   pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ (new pcl::PointCloud<pcl::Normal> ());
00177   pcl::PointIndices::Ptr table_inliers_ (new pcl::PointIndices ());
00178   pcl::ModelCoefficients::Ptr table_coefficients_ (new pcl::ModelCoefficients ());
00179   CloudPtr table_projected_ (new Cloud ());
00180   CloudPtr table_hull_ (new Cloud ());
00181   CloudPtr cloud_objects_ (new Cloud ());
00182   CloudPtr cluster_object_ (new Cloud ());
00183 
00184   typename pcl::search::KdTree<PointType>::Ptr normals_tree_ (new pcl::search::KdTree<PointType>);
00185   typename pcl::search::KdTree<PointType>::Ptr clusters_tree_ (new pcl::search::KdTree<PointType>);
00186   clusters_tree_->setEpsilon (1);
00187 
00188   // Normal estimation parameters
00189   n3d_.setKSearch (k_);
00190   n3d_.setSearchMethod (normals_tree_);
00191 
00192   // Table model fitting parameters
00193   seg_.setDistanceThreshold (sac_distance_threshold_);
00194   seg_.setMaxIterations (2000);
00195   seg_.setNormalDistanceWeight (0.1);
00196   seg_.setOptimizeCoefficients (true);
00197   seg_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00198   seg_.setMethodType (pcl::SAC_RANSAC);
00199   seg_.setProbability (0.99);
00200 
00201   proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00202   bb_cluster_proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00203 
00204   prism_.setHeightLimits (object_min_height_, object_max_height_);
00205 
00206   // Clustering parameters
00207   cluster_.setClusterTolerance (object_cluster_tolerance_);
00208   cluster_.setMinClusterSize (object_cluster_min_size_);
00209   cluster_.setSearchMethod (clusters_tree_);
00210 
00211   // ---[ PassThroughFilter
00212   pass_.setFilterLimits (min_z_bounds_, max_z_bounds_);
00213   pass_.setFilterFieldName ("z");
00214   pass_.setInputCloud (input_);
00215   pass_.filter (*cloud_filtered_);
00216 
00217   if (int (cloud_filtered_->points.size ()) < k_)
00218   {
00219     PCL_WARN ("[DominantPlaneSegmentation] Filtering returned %zu points! Aborting.",
00220         cloud_filtered_->points.size ());
00221     return;
00222   }
00223 
00224   // Downsample the point cloud
00225   grid_.setLeafSize (downsample_leaf_, downsample_leaf_, downsample_leaf_);
00226   grid_.setDownsampleAllData (false);
00227   grid_.setInputCloud (cloud_filtered_);
00228   grid_.filter (*cloud_downsampled_);
00229 
00230   // ---[ Estimate the point normals
00231   n3d_.setInputCloud (cloud_downsampled_);
00232   n3d_.compute (*cloud_normals_);
00233 
00234   // ---[ Perform segmentation
00235   seg_.setInputCloud (cloud_downsampled_);
00236   seg_.setInputNormals (cloud_normals_);
00237   seg_.segment (*table_inliers_, *table_coefficients_);
00238 
00239   if (table_inliers_->indices.size () == 0)
00240   {
00241     PCL_WARN ("[DominantPlaneSegmentation] No Plane Inliers points! Aborting.");
00242     return;
00243   }
00244 
00245   // ---[ Extract the plane
00246   proj_.setInputCloud (cloud_downsampled_);
00247   proj_.setIndices (table_inliers_);
00248   proj_.setModelCoefficients (table_coefficients_);
00249   proj_.filter (*table_projected_);
00250 
00251   // ---[ Estimate the convex hull
00252   std::vector<pcl::Vertices> polygons;
00253   CloudPtr table_hull (new Cloud ());
00254   hull_.setInputCloud (table_projected_);
00255   hull_.reconstruct (*table_hull, polygons);
00256 
00257   // Compute the plane coefficients
00258   Eigen::Vector4f model_coefficients;
00259   EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00260 
00261   model_coefficients[0] = table_coefficients_->values[0];
00262   model_coefficients[1] = table_coefficients_->values[1];
00263   model_coefficients[2] = table_coefficients_->values[2];
00264   model_coefficients[3] = table_coefficients_->values[3];
00265 
00266   // Need to flip the plane normal towards the viewpoint
00267   Eigen::Vector4f vp (0, 0, 0, 0);
00268   // See if we need to flip any plane normals
00269   vp -= table_hull->points[0].getVector4fMap ();
00270   vp[3] = 0;
00271   // Dot product between the (viewpoint - point) and the plane normal
00272   float cos_theta = vp.dot (model_coefficients);
00273   // Flip the plane normal
00274   if (cos_theta < 0)
00275   {
00276     model_coefficients *= -1;
00277     model_coefficients[3] = 0;
00278     // Hessian form (D = nc . p_plane (centroid here) + p)
00279     model_coefficients[3] = -1 * (model_coefficients.dot (table_hull->points[0].getVector4fMap ()));
00280   }
00281 
00282   //Set table_coeffs
00283   table_coeffs_ = model_coefficients;
00284 
00285   // ---[ Get the objects on top of the table
00286   pcl::PointIndices cloud_object_indices;
00287   prism_.setInputCloud (input_);
00288   prism_.setInputPlanarHull (table_hull);
00289   prism_.segment (cloud_object_indices);
00290 
00291   pcl::ExtractIndices<PointType> extract_object_indices;
00292   extract_object_indices.setInputCloud (input_);
00293   extract_object_indices.setIndices (boost::make_shared<const pcl::PointIndices> (cloud_object_indices));
00294   extract_object_indices.filter (*cloud_objects_);
00295 
00296   //create new binary pointcloud with intensity values (0 and 1), 0 for non-object pixels and 1 otherwise
00297   pcl::PointCloud<pcl::PointXYZI>::Ptr binary_cloud (new pcl::PointCloud<pcl::PointXYZI>);
00298 
00299   {
00300     binary_cloud->width = input_->width;
00301     binary_cloud->height = input_->height;
00302     binary_cloud->points.resize (input_->points.size ());
00303     binary_cloud->is_dense = input_->is_dense;
00304 
00305     size_t idx;
00306     for (size_t i = 0; i < cloud_object_indices.indices.size (); ++i)
00307     {
00308       idx = cloud_object_indices.indices[i];
00309       binary_cloud->points[idx].getVector4fMap () = input_->points[idx].getVector4fMap ();
00310       binary_cloud->points[idx].intensity = 1.0;
00311     }
00312   }
00313 
00314   //connected components on the binary image
00315 
00316   std::map<float, float> connected_labels;
00317   float c_intensity = 0.1f;
00318   float intensity_incr = 0.1f;
00319 
00320   {
00321 
00322     int wsize = wsize_;
00323     for (int i = 0; i < int (binary_cloud->width); i++)
00324     {
00325       for (int j = 0; j < int (binary_cloud->height); j++)
00326       {
00327         if (binary_cloud->at (i, j).intensity != 0)
00328         {
00329           //check neighboring pixels, first left and then top
00330           //be aware of margins
00331 
00332           if ((i - 1) < 0 && (j - 1) < 0)
00333           {
00334             //top-left pixel
00335             (*binary_cloud) (i, j).intensity = c_intensity;
00336           }
00337           else
00338           {
00339             if ((j - 1) < 0)
00340             {
00341               //top-row, check on the left of pixel to assign a new label or not
00342               int left = check ((*binary_cloud) (i - 1, j), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00343               if (left)
00344               {
00345                 //Nothing found on the left, check bigger window
00346 
00347                 bool found = false;
00348                 for (int kk = 2; kk < wsize && !found; kk++)
00349                 {
00350                   if ((i - kk) < 0)
00351                     continue;
00352 
00353                   int left = check ((*binary_cloud) (i - kk, j), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00354                   if (left == 0)
00355                   {
00356                     found = true;
00357                   }
00358                 }
00359 
00360                 if (!found)
00361                 {
00362                   c_intensity += intensity_incr;
00363                   (*binary_cloud) (i, j).intensity = c_intensity;
00364                 }
00365 
00366               }
00367             }
00368             else
00369             {
00370               if ((i - 1) == 0)
00371               {
00372                 //check only top
00373                 int top = check ((*binary_cloud) (i, j - 1), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00374                 if (top)
00375                 {
00376                   bool found = false;
00377                   for (int kk = 2; kk < wsize && !found; kk++)
00378                   {
00379                     if ((j - kk) < 0)
00380                       continue;
00381 
00382                     int top = check ((*binary_cloud) (i, j - kk), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00383                     if (top == 0)
00384                     {
00385                       found = true;
00386                     }
00387                   }
00388 
00389                   if (!found)
00390                   {
00391                     c_intensity += intensity_incr;
00392                     (*binary_cloud) (i, j).intensity = c_intensity;
00393                   }
00394                 }
00395 
00396               }
00397               else
00398               {
00399                 //check left and top
00400                 int left = check ((*binary_cloud) (i - 1, j), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00401                 int top = check ((*binary_cloud) (i, j - 1), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00402 
00403                 if (left == 0 && top == 0)
00404                 {
00405                   //both top and left had labels, check if they are different
00406                   //if they are, take the smallest one and mark labels to be connected..
00407 
00408                   if ((*binary_cloud) (i - 1, j).intensity != (*binary_cloud) (i, j - 1).intensity)
00409                   {
00410                     float smaller_intensity = (*binary_cloud) (i - 1, j).intensity;
00411                     float bigger_intensity = (*binary_cloud) (i, j - 1).intensity;
00412 
00413                     if ((*binary_cloud) (i - 1, j).intensity > (*binary_cloud) (i, j - 1).intensity)
00414                     {
00415                       smaller_intensity = (*binary_cloud) (i, j - 1).intensity;
00416                       bigger_intensity = (*binary_cloud) (i - 1, j).intensity;
00417                     }
00418 
00419                     connected_labels[bigger_intensity] = smaller_intensity;
00420                     (*binary_cloud) (i, j).intensity = smaller_intensity;
00421                   }
00422                 }
00423 
00424                 if (left == 1 && top == 1)
00425                 {
00426                   //if none had labels, increment c_intensity
00427                   //search first on bigger window
00428                   bool found = false;
00429                   for (int dist = 2; dist < wsize && !found; dist++)
00430                   {
00431                     if (((i - dist) < 0) || ((j - dist) < 0))
00432                       continue;
00433 
00434                     int left = check ((*binary_cloud) (i - dist, j), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00435                     int top = check ((*binary_cloud) (i, j - dist), (*binary_cloud) (i, j), c_intensity, object_cluster_tolerance_);
00436 
00437                     if (left == 0 && top == 0)
00438                     {
00439                       if ((*binary_cloud) (i - dist, j).intensity != (*binary_cloud) (i, j - dist).intensity)
00440                       {
00441                         float smaller_intensity = (*binary_cloud) (i - dist, j).intensity;
00442                         float bigger_intensity = (*binary_cloud) (i, j - dist).intensity;
00443 
00444                         if ((*binary_cloud) (i - dist, j).intensity > (*binary_cloud) (i, j - dist).intensity)
00445                         {
00446                           smaller_intensity = (*binary_cloud) (i, j - dist).intensity;
00447                           bigger_intensity = (*binary_cloud) (i - dist, j).intensity;
00448                         }
00449 
00450                         connected_labels[bigger_intensity] = smaller_intensity;
00451                         (*binary_cloud) (i, j).intensity = smaller_intensity;
00452                         found = true;
00453                       }
00454                     }
00455                     else if (left == 0 || top == 0)
00456                     {
00457                       //one had label
00458                       found = true;
00459                     }
00460                   }
00461 
00462                   if (!found)
00463                   {
00464                     //none had label in the bigger window
00465                     c_intensity += intensity_incr;
00466                     (*binary_cloud) (i, j).intensity = c_intensity;
00467                   }
00468                 }
00469               }
00470             }
00471           }
00472 
00473         }
00474       }
00475     }
00476   }
00477 
00478   std::map<float, pcl::PointIndices> clusters_map;
00479 
00480   {
00481     std::map<float, float>::iterator it;
00482 
00483     for (int i = 0; i < int (binary_cloud->width); i++)
00484     {
00485       for (int j = 0; j < int (binary_cloud->height); j++)
00486       {
00487         if (binary_cloud->at (i, j).intensity != 0)
00488         {
00489           //check if this is a root label...
00490           it = connected_labels.find (binary_cloud->at (i, j).intensity);
00491           while (it != connected_labels.end ())
00492           {
00493             //the label is on the list, change pixel intensity until it has a root label
00494             (*binary_cloud) (i, j).intensity = (*it).second;
00495             it = connected_labels.find (binary_cloud->at (i, j).intensity);
00496           }
00497 
00498           std::map<float, pcl::PointIndices>::iterator it_indices;
00499           it_indices = clusters_map.find (binary_cloud->at (i, j).intensity);
00500           if (it_indices == clusters_map.end ())
00501           {
00502             pcl::PointIndices indices;
00503             clusters_map[binary_cloud->at (i, j).intensity] = indices;
00504           }
00505 
00506           clusters_map[binary_cloud->at (i, j).intensity].indices.push_back (static_cast<int> (j * binary_cloud->width + i));
00507         }
00508       }
00509     }
00510   }
00511 
00512   clusters.resize (clusters_map.size ());
00513 
00514   std::map<float, pcl::PointIndices>::iterator it_indices;
00515   int k = 0;
00516   for (it_indices = clusters_map.begin (); it_indices != clusters_map.end (); it_indices++)
00517   {
00518 
00519     if (int ((*it_indices).second.indices.size ()) >= object_cluster_min_size_)
00520     {
00521 
00522       clusters[k] = CloudPtr (new Cloud ());
00523       pcl::copyPointCloud (*input_, (*it_indices).second.indices, *clusters[k]);
00524       k++;
00525       indices_clusters_.push_back((*it_indices).second);
00526     }
00527   }
00528 
00529   clusters.resize (k);
00530 
00531 }
00532 
00533 template<typename PointType> void
00534 pcl::apps::DominantPlaneSegmentation<PointType>::compute (std::vector<CloudPtr> & clusters)
00535 {
00536 
00537   // Has the input dataset been set already?
00538   if (!input_)
00539   {
00540     PCL_WARN ("[pcl::apps::DominantPlaneSegmentation] No input dataset given!\n");
00541     return;
00542   }
00543 
00544   CloudConstPtr cloud_;
00545   CloudPtr cloud_filtered_ (new Cloud ());
00546   CloudPtr cloud_downsampled_ (new Cloud ());
00547   pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ (new pcl::PointCloud<pcl::Normal> ());
00548   pcl::PointIndices::Ptr table_inliers_ (new pcl::PointIndices ());
00549   pcl::ModelCoefficients::Ptr table_coefficients_ (new pcl::ModelCoefficients ());
00550   CloudPtr table_projected_ (new Cloud ());
00551   CloudPtr table_hull_ (new Cloud ());
00552   CloudPtr cloud_objects_ (new Cloud ());
00553   CloudPtr cluster_object_ (new Cloud ());
00554 
00555   typename pcl::search::KdTree<PointType>::Ptr normals_tree_ (new pcl::search::KdTree<PointType>);
00556   typename pcl::search::KdTree<PointType>::Ptr clusters_tree_ (new pcl::search::KdTree<PointType>);
00557   clusters_tree_->setEpsilon (1);
00558 
00559   // Normal estimation parameters
00560   n3d_.setKSearch (k_);
00561   n3d_.setSearchMethod (normals_tree_);
00562 
00563   // Table model fitting parameters
00564   seg_.setDistanceThreshold (sac_distance_threshold_);
00565   seg_.setMaxIterations (2000);
00566   seg_.setNormalDistanceWeight (0.1);
00567   seg_.setOptimizeCoefficients (true);
00568   seg_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00569   seg_.setMethodType (pcl::SAC_RANSAC);
00570   seg_.setProbability (0.99);
00571 
00572   proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00573   bb_cluster_proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00574 
00575   prism_.setHeightLimits (object_min_height_, object_max_height_);
00576 
00577   // Clustering parameters
00578   cluster_.setClusterTolerance (object_cluster_tolerance_);
00579   cluster_.setMinClusterSize (object_cluster_min_size_);
00580   cluster_.setSearchMethod (clusters_tree_);
00581 
00582   // ---[ PassThroughFilter
00583   pass_.setFilterLimits (min_z_bounds_, max_z_bounds_);
00584   pass_.setFilterFieldName ("z");
00585   pass_.setInputCloud (input_);
00586   pass_.filter (*cloud_filtered_);
00587 
00588   if (int (cloud_filtered_->points.size ()) < k_)
00589   {
00590     PCL_WARN ("[DominantPlaneSegmentation] Filtering returned %zu points! Aborting.",
00591         cloud_filtered_->points.size ());
00592     return;
00593   }
00594 
00595   // Downsample the point cloud
00596   grid_.setLeafSize (downsample_leaf_, downsample_leaf_, downsample_leaf_);
00597   grid_.setDownsampleAllData (false);
00598   grid_.setInputCloud (cloud_filtered_);
00599   grid_.filter (*cloud_downsampled_);
00600 
00601   PCL_INFO ("[DominantPlaneSegmentation] Number of points left after filtering (%f -> %f): %zu out of %zu\n",
00602       min_z_bounds_, max_z_bounds_, cloud_downsampled_->points.size (), input_->points.size ());
00603 
00604   // ---[ Estimate the point normals
00605   n3d_.setInputCloud (cloud_downsampled_);
00606   n3d_.compute (*cloud_normals_);
00607 
00608   PCL_INFO ("[DominantPlaneSegmentation] %zu normals estimated. \n", cloud_normals_->points.size ());
00609 
00610   // ---[ Perform segmentation
00611   seg_.setInputCloud (cloud_downsampled_);
00612   seg_.setInputNormals (cloud_normals_);
00613   seg_.segment (*table_inliers_, *table_coefficients_);
00614 
00615   if (table_inliers_->indices.size () == 0)
00616   {
00617     PCL_WARN ("[DominantPlaneSegmentation] No Plane Inliers points! Aborting.");
00618     return;
00619   }
00620 
00621   // ---[ Extract the plane
00622   proj_.setInputCloud (cloud_downsampled_);
00623   proj_.setIndices (table_inliers_);
00624   proj_.setModelCoefficients (table_coefficients_);
00625   proj_.filter (*table_projected_);
00626 
00627   // ---[ Estimate the convex hull
00628   std::vector<pcl::Vertices> polygons;
00629   CloudPtr table_hull (new Cloud ());
00630   hull_.setInputCloud (table_projected_);
00631   hull_.reconstruct (*table_hull, polygons);
00632 
00633   // Compute the plane coefficients
00634   Eigen::Vector4f model_coefficients;
00635   EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00636 
00637   model_coefficients[0] = table_coefficients_->values[0];
00638   model_coefficients[1] = table_coefficients_->values[1];
00639   model_coefficients[2] = table_coefficients_->values[2];
00640   model_coefficients[3] = table_coefficients_->values[3];
00641 
00642   // Need to flip the plane normal towards the viewpoint
00643   Eigen::Vector4f vp (0, 0, 0, 0);
00644   // See if we need to flip any plane normals
00645   vp -= table_hull->points[0].getVector4fMap ();
00646   vp[3] = 0;
00647   // Dot product between the (viewpoint - point) and the plane normal
00648   float cos_theta = vp.dot (model_coefficients);
00649   // Flip the plane normal
00650   if (cos_theta < 0)
00651   {
00652     model_coefficients *= -1;
00653     model_coefficients[3] = 0;
00654     // Hessian form (D = nc . p_plane (centroid here) + p)
00655     model_coefficients[3] = -1 * (model_coefficients.dot (table_hull->points[0].getVector4fMap ()));
00656   }
00657 
00658   //Set table_coeffs
00659   table_coeffs_ = model_coefficients;
00660 
00661   // ---[ Get the objects on top of the table
00662   pcl::PointIndices cloud_object_indices;
00663   prism_.setInputCloud (cloud_downsampled_);
00664   prism_.setInputPlanarHull (table_hull);
00665   prism_.segment (cloud_object_indices);
00666 
00667   pcl::ExtractIndices<PointType> extract_object_indices;
00668   extract_object_indices.setInputCloud (cloud_downsampled_);
00669   extract_object_indices.setIndices (boost::make_shared<const pcl::PointIndices> (cloud_object_indices));
00670   extract_object_indices.filter (*cloud_objects_);
00671 
00672   if (cloud_objects_->points.size () == 0)
00673     return;
00674 
00675   //down_.reset(new Cloud(*cloud_downsampled_));
00676 
00677   // ---[ Split the objects into Euclidean clusters
00678   std::vector<pcl::PointIndices> clusters2;
00679   cluster_.setInputCloud (cloud_downsampled_);
00680   cluster_.setIndices (boost::make_shared<const pcl::PointIndices> (cloud_object_indices));
00681   cluster_.extract (clusters2);
00682 
00683   PCL_INFO ("[DominantPlaneSegmentation::compute()] Number of clusters found matching the given constraints: %zu.\n",
00684       clusters2.size ());
00685 
00686   clusters.resize (clusters2.size ());
00687 
00688   for (size_t i = 0; i < clusters2.size (); ++i)
00689   {
00690     clusters[i] = CloudPtr (new Cloud ());
00691     pcl::copyPointCloud (*cloud_downsampled_, clusters2[i].indices, *clusters[i]);
00692   }
00693 }
00694 
00695 template<typename PointType>
00696 void
00697 pcl::apps::DominantPlaneSegmentation<PointType>::compute_full (std::vector<CloudPtr> & clusters)
00698 {
00699 
00700   // Has the input dataset been set already?
00701   if (!input_)
00702   {
00703     PCL_WARN ("[pcl::apps::DominantPlaneSegmentation] No input dataset given!\n");
00704     return;
00705   }
00706 
00707   CloudConstPtr cloud_;
00708   CloudPtr cloud_filtered_ (new Cloud ());
00709   CloudPtr cloud_downsampled_ (new Cloud ());
00710   pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ (new pcl::PointCloud<pcl::Normal> ());
00711   pcl::PointIndices::Ptr table_inliers_ (new pcl::PointIndices ());
00712   pcl::ModelCoefficients::Ptr table_coefficients_ (new pcl::ModelCoefficients ());
00713   CloudPtr table_projected_ (new Cloud ());
00714   CloudPtr table_hull_ (new Cloud ());
00715   CloudPtr cloud_objects_ (new Cloud ());
00716   CloudPtr cluster_object_ (new Cloud ());
00717 
00718   typename pcl::search::KdTree<PointType>::Ptr normals_tree_ (new pcl::search::KdTree<PointType>);
00719   typename pcl::search::KdTree<PointType>::Ptr clusters_tree_ (new pcl::search::KdTree<PointType>);
00720   clusters_tree_->setEpsilon (1);
00721 
00722   // Normal estimation parameters
00723   n3d_.setKSearch (10);
00724   n3d_.setSearchMethod (normals_tree_);
00725 
00726   // Table model fitting parameters
00727   seg_.setDistanceThreshold (sac_distance_threshold_);
00728   seg_.setMaxIterations (2000);
00729   seg_.setNormalDistanceWeight (0.1);
00730   seg_.setOptimizeCoefficients (true);
00731   seg_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00732   seg_.setMethodType (pcl::SAC_MSAC);
00733   seg_.setProbability (0.98);
00734 
00735   proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00736   bb_cluster_proj_.setModelType (pcl::SACMODEL_NORMAL_PLANE);
00737 
00738   prism_.setHeightLimits (object_min_height_, object_max_height_);
00739 
00740   // Clustering parameters
00741   cluster_.setClusterTolerance (object_cluster_tolerance_);
00742   cluster_.setMinClusterSize (object_cluster_min_size_);
00743   cluster_.setSearchMethod (clusters_tree_);
00744 
00745   // ---[ PassThroughFilter
00746   pass_.setFilterLimits (min_z_bounds_, max_z_bounds_);
00747   pass_.setFilterFieldName ("z");
00748   pass_.setInputCloud (input_);
00749   pass_.filter (*cloud_filtered_);
00750 
00751   if (int (cloud_filtered_->points.size ()) < k_)
00752   {
00753     PCL_WARN ("[DominantPlaneSegmentation] Filtering returned %zu points! Aborting.",
00754         cloud_filtered_->points.size ());
00755     return;
00756   }
00757 
00758   // Downsample the point cloud
00759   grid_.setLeafSize (downsample_leaf_, downsample_leaf_, downsample_leaf_);
00760   grid_.setDownsampleAllData (false);
00761   grid_.setInputCloud (cloud_filtered_);
00762   grid_.filter (*cloud_downsampled_);
00763 
00764   PCL_INFO ("[DominantPlaneSegmentation] Number of points left after filtering&downsampling (%f -> %f): %zu out of %zu\n",
00765       min_z_bounds_, max_z_bounds_, cloud_downsampled_->points.size (), input_->points.size ());
00766 
00767   // ---[ Estimate the point normals
00768   n3d_.setInputCloud (cloud_downsampled_);
00769   n3d_.compute (*cloud_normals_);
00770 
00771   PCL_INFO ("[DominantPlaneSegmentation] %zu normals estimated. \n", cloud_normals_->points.size ());
00772 
00773   // ---[ Perform segmentation
00774   seg_.setInputCloud (cloud_downsampled_);
00775   seg_.setInputNormals (cloud_normals_);
00776   seg_.segment (*table_inliers_, *table_coefficients_);
00777 
00778   if (table_inliers_->indices.size () == 0)
00779   {
00780     PCL_WARN ("[DominantPlaneSegmentation] No Plane Inliers points! Aborting.");
00781     return;
00782   }
00783 
00784   // ---[ Extract the plane
00785   proj_.setInputCloud (cloud_downsampled_);
00786   proj_.setIndices (table_inliers_);
00787   proj_.setModelCoefficients (table_coefficients_);
00788   proj_.filter (*table_projected_);
00789 
00790   // ---[ Estimate the convex hull
00791   std::vector<pcl::Vertices> polygons;
00792   CloudPtr table_hull (new Cloud ());
00793   hull_.setInputCloud (table_projected_);
00794   hull_.reconstruct (*table_hull, polygons);
00795 
00796   // Compute the plane coefficients
00797   Eigen::Vector4f model_coefficients;
00798   EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00799 
00800   model_coefficients[0] = table_coefficients_->values[0];
00801   model_coefficients[1] = table_coefficients_->values[1];
00802   model_coefficients[2] = table_coefficients_->values[2];
00803   model_coefficients[3] = table_coefficients_->values[3];
00804 
00805   // Need to flip the plane normal towards the viewpoint
00806   Eigen::Vector4f vp (0, 0, 0, 0);
00807   // See if we need to flip any plane normals
00808   vp -= table_hull->points[0].getVector4fMap ();
00809   vp[3] = 0;
00810   // Dot product between the (viewpoint - point) and the plane normal
00811   float cos_theta = vp.dot (model_coefficients);
00812   // Flip the plane normal
00813   if (cos_theta < 0)
00814   {
00815     model_coefficients *= -1;
00816     model_coefficients[3] = 0;
00817     // Hessian form (D = nc . p_plane (centroid here) + p)
00818     model_coefficients[3] = -1 * (model_coefficients.dot (table_hull->points[0].getVector4fMap ()));
00819   }
00820 
00821   //Set table_coeffs
00822   table_coeffs_ = model_coefficients;
00823 
00824   // ---[ Get the objects on top of the table
00825   pcl::PointIndices cloud_object_indices;
00826   prism_.setInputCloud (cloud_filtered_);
00827   prism_.setInputPlanarHull (table_hull);
00828   prism_.segment (cloud_object_indices);
00829 
00830   pcl::ExtractIndices<PointType> extract_object_indices;
00831   extract_object_indices.setInputCloud (cloud_downsampled_);
00832   extract_object_indices.setIndices (boost::make_shared<const pcl::PointIndices> (cloud_object_indices));
00833   extract_object_indices.filter (*cloud_objects_);
00834 
00835   if (cloud_objects_->points.size () == 0)
00836     return;
00837 
00838   // ---[ Split the objects into Euclidean clusters
00839   std::vector<pcl::PointIndices> clusters2;
00840   cluster_.setInputCloud (cloud_filtered_);
00841   cluster_.setIndices (boost::make_shared<const pcl::PointIndices> (cloud_object_indices));
00842   cluster_.extract (clusters2);
00843 
00844   PCL_INFO ("[DominantPlaneSegmentation::compute_full()] Number of clusters found matching the given constraints: %zu.\n",
00845       clusters2.size ());
00846 
00847   clusters.resize (clusters2.size ());
00848 
00849   for (size_t i = 0; i < clusters2.size (); ++i)
00850   {
00851     clusters[i] = CloudPtr (new Cloud ());
00852     pcl::copyPointCloud (*cloud_filtered_, clusters2[i].indices, *clusters[i]);
00853   }
00854 }
00855 
00856 #define PCL_INSTANTIATE_DominantPlaneSegmentation(T) template class PCL_EXPORTS pcl::apps::DominantPlaneSegmentation<T>;


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:14:49