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 }
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
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
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
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
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
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
00240 return surfaces_objects_vec->size() == surface_vec.size();
00241 }
00242 }