segmentation.cpp
Go to the documentation of this file.
00001 #include "surface_perception/segmentation.h"
00002 
00003 #include <vector>
00004 
00005 #include "Eigen/Eigen"
00006 #include "eigen_conversions/eigen_msg.h"
00007 #include "pcl/common/angles.h"
00008 #include "pcl/sample_consensus/method_types.h"
00009 #include "pcl/sample_consensus/model_types.h"
00010 #include "pcl/segmentation/extract_clusters.h"
00011 #include "ros/ros.h"
00012 
00013 #include "surface_perception/object.h"
00014 #include "surface_perception/shape_extraction.h"
00015 #include "surface_perception/surface.h"
00016 #include "surface_perception/surface_objects.h"
00017 #include "surface_perception/typedefs.h"
00018 
00019 #include "surface_perception/surface_finder.h"
00020 
00021 namespace {
00022 bool SurfaceComparator(const surface_perception::Surface& s1,
00023                        const surface_perception::Surface& s2) {
00024   return s1.pose_stamped.pose.position.z < s2.pose_stamped.pose.position.z;
00025 }
00026 
00027 }  // Anonymous namespace
00028 
00029 namespace surface_perception {
00030 Segmentation::Segmentation()
00031     : cloud_(),
00032       indices_(new pcl::PointIndices),
00033       horizontal_tolerance_degrees_(10),
00034       margin_above_surface_(0.005),
00035       cluster_distance_(0.01),
00036       max_point_distance_(0.005),
00037       min_cluster_size_(10),
00038       max_cluster_size_(10000),
00039       min_surface_size_(5000),
00040       min_surface_exploration_iteration_(1000) {}
00041 
00042 void Segmentation::set_input_cloud(
00043     pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud) {
00044   cloud_ = cloud;
00045 }
00046 
00047 void Segmentation::set_indices(pcl::PointIndices::Ptr indices) {
00048   indices_ = indices;
00049 }
00050 
00051 void Segmentation::set_horizontal_tolerance_degrees(double degrees) {
00052   horizontal_tolerance_degrees_ = degrees;
00053 }
00054 void Segmentation::set_margin_above_surface(double margin) {
00055   margin_above_surface_ = margin;
00056 }
00057 void Segmentation::set_cluster_distance(double cluster_distance) {
00058   cluster_distance_ = cluster_distance;
00059 }
00060 void Segmentation::set_min_cluster_size(int min_cluster_size) {
00061   min_cluster_size_ = min_cluster_size;
00062 }
00063 void Segmentation::set_max_cluster_size(int max_cluster_size) {
00064   max_cluster_size_ = max_cluster_size;
00065 }
00066 void Segmentation::set_min_surface_size(int min_surface_size) {
00067   min_surface_size_ = min_surface_size;
00068 }
00069 void Segmentation::set_min_surface_exploration_iteration(
00070     int min_surface_exploration_iteration) {
00071   min_surface_exploration_iteration_ = min_surface_exploration_iteration;
00072 }
00073 void Segmentation::set_max_point_distance(double max_point_distance) {
00074   max_point_distance_ = max_point_distance;
00075 }
00076 
00077 bool Segmentation::Segment(std::vector<SurfaceObjects>* surfaces) const {
00078   std::vector<Surface> surface_vec;
00079   bool success = FindSurfaces(cloud_, indices_, max_point_distance_,
00080                               horizontal_tolerance_degrees_, min_surface_size_,
00081                               min_surface_exploration_iteration_, &surface_vec);
00082   if (!success) {
00083     ROS_ERROR("Failed to find any surface.");
00084     return false;
00085   }
00086 
00087   success = FindObjectsOnSurfaces(
00088       cloud_, indices_, surface_vec, margin_above_surface_, cluster_distance_,
00089       min_cluster_size_, max_cluster_size_, surfaces);
00090 
00091   if (!success) {
00092     ROS_ERROR("Failed to cluster objects.");
00093     return false;
00094   }
00095   return true;
00096 }
00097 
00098 bool FindSurfaces(PointCloudC::Ptr cloud, pcl::PointIndices::Ptr indices,
00099                   double max_point_distance,
00100                   double horizontal_tolerance_degrees, int min_surface_size,
00101                   int min_surface_exploration_iteration,
00102                   std::vector<Surface>* surfaces) {
00103   SurfaceFinder surfaceFinder;
00104   std::vector<pcl::PointIndices::Ptr> indices_vec;
00105   std::vector<pcl::ModelCoefficients> coeffs_vec;
00106   surfaceFinder.set_cloud(cloud);
00107   surfaceFinder.set_cloud_indices(indices);
00108   surfaceFinder.set_min_iteration(min_surface_exploration_iteration);
00109   surfaceFinder.set_surface_point_threshold(min_surface_size);
00110   surfaceFinder.set_angle_tolerance_degree(horizontal_tolerance_degrees);
00111   surfaceFinder.set_max_point_distance(max_point_distance);
00112   surfaceFinder.ExploreSurfaces(&indices_vec, &coeffs_vec);
00113 
00114   if (indices_vec.size() == 0 || coeffs_vec.size() == 0) {
00115     ROS_INFO("Warning: no surface found.");
00116     return false;
00117   }
00118 
00119   for (size_t i = 0; i < indices_vec.size() && i < coeffs_vec.size(); i++) {
00120     Surface surface;
00121     surface.coefficients.reset(new pcl::ModelCoefficients);
00122     surface.coefficients->values = coeffs_vec[i].values;
00123     surface.pose_stamped.header.frame_id = cloud->header.frame_id;
00124     if (FitBox(cloud, indices_vec[i], surface.coefficients,
00125                &surface.pose_stamped.pose, &surface.dimensions)) {
00126       // Adjust the center of surface
00127       double offset = surface.coefficients->values[0] *
00128                           surface.pose_stamped.pose.position.x +
00129                       surface.coefficients->values[1] *
00130                           surface.pose_stamped.pose.position.y +
00131                       surface.coefficients->values[2] *
00132                           surface.pose_stamped.pose.position.z +
00133                       surface.coefficients->values[3];
00134       surface.pose_stamped.pose.position.z -= offset;
00135       surfaces->push_back(surface);
00136     }
00137   }
00138 
00139   return true;
00140 }
00141 
00142 bool GetSceneAboveSurface(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud,
00143                           pcl::PointIndices::Ptr indices,
00144                           const pcl::ModelCoefficients& coefficients,
00145                           double margin_above_surface, float height_limit,
00146                           pcl::PointIndices::Ptr above_surface_indices) {
00147   if (coefficients.values.size() < 4) {
00148     return false;
00149   }
00150 
00151   // Build custom indices based on margin_above_surface.
00152   double a = coefficients.values[0];
00153   double b = coefficients.values[1];
00154   double c = coefficients.values[2];
00155   double d = coefficients.values[3];
00156 
00157   if (indices && indices->indices.size() > 0) {
00158     for (size_t i = 0; i < indices->indices.size(); ++i) {
00159       size_t index = indices->indices[i];
00160       const PointC& pt = cloud->points[index];
00161       float val = a * pt.x + b * pt.y + c * pt.z + d;
00162       if (val >= margin_above_surface &&
00163           height_limit - pt.z > margin_above_surface) {
00164         above_surface_indices->indices.push_back(index);
00165       }
00166     }
00167   } else {
00168     for (size_t i = 0; i < cloud->size(); ++i) {
00169       const PointC& pt = cloud->points[i];
00170       float val = a * pt.x + b * pt.y + c * pt.z + d;
00171       if (val >= margin_above_surface &&
00172           height_limit - pt.z > margin_above_surface) {
00173         above_surface_indices->indices.push_back(i);
00174       }
00175     }
00176   }
00177 
00178   if (above_surface_indices->indices.size() == 0) {
00179     return false;
00180   }
00181   return true;
00182 }
00183 
00184 bool FindObjectsOnSurfaces(PointCloudC::Ptr cloud, pcl::PointIndicesPtr indices,
00185                            const std::vector<Surface>& surface_vec,
00186                            double margin_above_surface, double cluster_distance,
00187                            int min_cluster_size, int max_cluster_size,
00188                            std::vector<SurfaceObjects>* surfaces_objects_vec) {
00189   // Copy the vector and sort by height
00190   std::vector<Surface> surfaces = surface_vec;
00191   std::sort(surfaces.begin(), surfaces.end(), SurfaceComparator);
00192   std::vector<pcl::PointIndices::Ptr> above_surface_indices_vec;
00193 
00194   // Obtain indices between each horizontal surfaces
00195   for (size_t i = 0; i < surfaces.size(); i++) {
00196     float height_limit = std::numeric_limits<float>::max();
00197     pcl::PointIndices::Ptr above_surface_indices(new pcl::PointIndices);
00198     if (i != (surfaces.size() - 1)) {
00199       // Estimate the height using information computed through FitBox
00200       height_limit = surfaces[i + 1].pose_stamped.pose.position.z -
00201                      surfaces[i + 1].dimensions.z / 2.0;
00202     }
00203 
00204     GetSceneAboveSurface(cloud, indices, *surfaces[i].coefficients,
00205                          margin_above_surface, height_limit,
00206                          above_surface_indices);
00207     above_surface_indices_vec.push_back(above_surface_indices);
00208   }
00209 
00210   for (size_t i = 0; i < above_surface_indices_vec.size(); i++) {
00211     SurfaceObjects surface_objects;
00212     surface_objects.surface = surfaces[i];
00213 
00214     if (above_surface_indices_vec[i]->indices.size() > 0) {
00215       pcl::EuclideanClusterExtraction<PointC> euclid;
00216       euclid.setInputCloud(cloud);
00217       euclid.setIndices(above_surface_indices_vec[i]);
00218       euclid.setClusterTolerance(cluster_distance);
00219       euclid.setMinClusterSize(min_cluster_size);
00220       euclid.setMaxClusterSize(max_cluster_size);
00221       std::vector<pcl::PointIndices> object_indices;
00222       euclid.extract(object_indices);
00223 
00224       for (size_t j = 0; j < object_indices.size(); j++) {
00225         Object object;
00226         object.cloud = cloud;
00227         object.indices.reset(new pcl::PointIndices(object_indices[j]));
00228         object.pose_stamped.header.frame_id = cloud->header.frame_id;
00229 
00230         if (FitBoxOnSurface(cloud, object.indices, surfaces[i],
00231                             &object.pose_stamped.pose, &object.dimensions)) {
00232           surface_objects.objects.push_back(object);
00233         }
00234       }
00235     }
00236     surfaces_objects_vec->push_back(surface_objects);
00237   }
00238 
00239   // Check if the function processes the correct number of surfaces
00240   return surfaces_objects_vec->size() == surface_vec.size();
00241 }
00242 }  // namespace surface_perception


surface_perception
Author(s): Yu-Tang Peng
autogenerated on Thu Jun 6 2019 17:36:21