00001
00013
00014 #include "rail_segmentation/Segmenter.h"
00015
00016
00017 #include <pcl_ros/transforms.h>
00018 #include <ros/package.h>
00019 #include <sensor_msgs/point_cloud_conversion.h>
00020 #include <sensor_msgs/image_encodings.h>
00021 #include <tf2/LinearMath/Matrix3x3.h>
00022
00023
00024 #include <pcl/common/common.h>
00025 #include <pcl/filters/extract_indices.h>
00026 #include <pcl/filters/passthrough.h>
00027 #include <pcl/filters/project_inliers.h>
00028 #include <pcl/filters/voxel_grid.h>
00029 #include <pcl/ModelCoefficients.h>
00030 #include <pcl/segmentation/sac_segmentation.h>
00031 #include <pcl/segmentation/extract_clusters.h>
00032
00033
00034 #include <yaml-cpp/yaml.h>
00035
00036
00037 #include <fstream>
00038
00039 using namespace std;
00040 using namespace rail::segmentation;
00041
00042 Segmenter::Segmenter() : private_node_("~"), tf2_(tf_buffer_)
00043 {
00044
00045 first_pc_in_ = false;
00046
00047
00048 debug_ = DEFAULT_DEBUG;
00049 string point_cloud_topic("/camera/depth_registered/points");
00050 string zones_file(ros::package::getPath("rail_segmentation") + "/config/zones.yaml");
00051 min_cluster_size_ = DEFAULT_MIN_CLUSTER_SIZE;
00052 max_cluster_size_ = DEFAULT_MAX_CLUSTER_SIZE;
00053
00054
00055 private_node_.getParam("debug", debug_);
00056 private_node_.getParam("point_cloud_topic", point_cloud_topic);
00057 private_node_.getParam("zones_config", zones_file);
00058 private_node_.getParam("min_cluster_size", min_cluster_size_);
00059 private_node_.getParam("max_cluster_size", max_cluster_size_);
00060
00061
00062 segment_srv_ = private_node_.advertiseService("segment", &Segmenter::segmentCallback, this);
00063 clear_srv_ = private_node_.advertiseService("clear", &Segmenter::clearCallback, this);
00064 remove_object_srv_ = private_node_.advertiseService("remove_object", &Segmenter::removeObjectCallback, this);
00065 segmented_objects_pub_ = private_node_.advertise<rail_manipulation_msgs::SegmentedObjectList>(
00066 "segmented_objects", 1, true
00067 );
00068 markers_pub_ = private_node_.advertise<visualization_msgs::MarkerArray>("markers", 1, true);
00069 point_cloud_sub_ = node_.subscribe(point_cloud_topic, 1, &Segmenter::pointCloudCallback, this);
00070
00071 if (debug_)
00072 {
00073 debug_pc_pub_ = private_node_.advertise<pcl::PointCloud<pcl::PointXYZRGB> >("debug_pc", 1, true);
00074 debug_img_pub_ = private_node_.advertise<sensor_msgs::Image>("debug_img", 1, true);
00075 }
00076
00077
00078 #ifdef YAMLCPP_GT_0_5_0
00079
00080 YAML::Node zones_config = YAML::LoadFile(zones_file);
00081 for (size_t i = 0; i < zones_config.size(); i++)
00082 {
00083 YAML::Node cur = zones_config[i];
00084
00085 SegmentationZone zone(cur["name"].as<string>(), cur["parent_frame_id"].as<string>(),
00086 cur["child_frame_id"].as<string>(), cur["bounding_frame_id"].as<string>(),
00087 cur["segmentation_frame_id"].as<string>());
00088
00089
00090 if (cur["remove_surface"].IsDefined())
00091 {
00092 zone.setRemoveSurface(cur["remove_surface"].as<bool>());
00093 }
00094
00095
00096 if (cur["roll_min"].IsDefined())
00097 {
00098 zone.setRollMin(cur["roll_min"].as<double>());
00099 }
00100 if (cur["roll_max"].IsDefined())
00101 {
00102 zone.setRollMax(cur["roll_max"].as<double>());
00103 }
00104 if (cur["pitch_min"].IsDefined())
00105 {
00106 zone.setPitchMin(cur["pitch_min"].as<double>());
00107 }
00108 if (cur["pitch_max"].IsDefined())
00109 {
00110 zone.setPitchMax(cur["pitch_max"].as<double>());
00111 }
00112 if (cur["yaw_min"].IsDefined())
00113 {
00114 zone.setYawMin(cur["yaw_min"].as<double>());
00115 }
00116 if (cur["yaw_max"].IsDefined())
00117 {
00118 zone.setYawMax(cur["yaw_max"].as<double>());
00119 }
00120 if (cur["x_min"].IsDefined())
00121 {
00122 zone.setXMin(cur["x_min"].as<double>());
00123 }
00124 if (cur["x_max"].IsDefined())
00125 {
00126 zone.setXMax(cur["x_max"].as<double>());
00127 }
00128 if (cur["y_min"].IsDefined())
00129 {
00130 zone.setYMin(cur["y_min"].as<double>());
00131 }
00132 if (cur["y_max"].IsDefined())
00133 {
00134 zone.setYMax(cur["y_max"].as<double>());
00135 }
00136 if (cur["z_min"].IsDefined())
00137 {
00138 zone.setZMin(cur["z_min"].as<double>());
00139 }
00140 if (cur["z_max"].IsDefined())
00141 {
00142 zone.setZMax(cur["z_max"].as<double>());
00143 }
00144
00145 zones_.push_back(zone);
00146 }
00147 #else
00148
00149 ifstream fin(zones_file.c_str());
00150 YAML::Parser zones_parser(fin);
00151 YAML::Node zones_config;
00152 zones_parser.GetNextDocument(zones_config);
00153 for (size_t i = 0; i < zones_config.size(); i++)
00154 {
00155
00156 string name, parent_frame_id, child_frame_id, bounding_frame_id, segmentation_frame_id;
00157 zones_config[i]["name"] >> name;
00158 zones_config[i]["parent_frame_id"] >> parent_frame_id;
00159 zones_config[i]["child_frame_id"] >> child_frame_id;
00160 zones_config[i]["bounding_frame_id"] >> bounding_frame_id;
00161 zones_config[i]["segmentation_frame_id"] >> segmentation_frame_id;
00162
00163
00164 SegmentationZone zone(name, parent_frame_id, child_frame_id, bounding_frame_id, segmentation_frame_id);
00165
00166
00167 if (zones_config[i].FindValue("remove_surface") != NULL)
00168 {
00169 bool remove_surface;
00170 zones_config[i]["remove_surface"] >> remove_surface;
00171 zone.setRemoveSurface(remove_surface);
00172 }
00173
00174
00175 if (zones_config[i].FindValue("roll_min") != NULL)
00176 {
00177 double roll_min;
00178 zones_config[i]["roll_min"] >> roll_min;
00179 zone.setRollMin(roll_min);
00180 }
00181 if (zones_config[i].FindValue("roll_max") != NULL)
00182 {
00183 double roll_max;
00184 zones_config[i]["roll_max"] >> roll_max;
00185 zone.setRollMax(roll_max);
00186 }
00187 if (zones_config[i].FindValue("pitch_min") != NULL)
00188 {
00189 double pitch_min;
00190 zones_config[i]["pitch_min"] >> pitch_min;
00191 zone.setPitchMin(pitch_min);
00192 }
00193 if (zones_config[i].FindValue("pitch_max") != NULL)
00194 {
00195 double pitch_max;
00196 zones_config[i]["pitch_max"] >> pitch_max;
00197 zone.setPitchMax(pitch_max);
00198 }
00199 if (zones_config[i].FindValue("yaw_min") != NULL)
00200 {
00201 double yaw_min;
00202 zones_config[i]["yaw_min"] >> yaw_min;
00203 zone.setYawMin(yaw_min);
00204 }
00205 if (zones_config[i].FindValue("yaw_max") != NULL)
00206 {
00207 double yaw_max;
00208 zones_config[i]["yaw_max"] >> yaw_max;
00209 zone.setYawMax(yaw_max);
00210 }
00211 if (zones_config[i].FindValue("x_min") != NULL)
00212 {
00213 double x_min;
00214 zones_config[i]["x_min"] >> x_min;
00215 zone.setXMin(x_min);
00216 }
00217 if (zones_config[i].FindValue("x_max") != NULL)
00218 {
00219 double x_max;
00220 zones_config[i]["x_max"] >> x_max;
00221 zone.setXMax(x_max);
00222 }
00223 if (zones_config[i].FindValue("y_min") != NULL)
00224 {
00225 double y_min;
00226 zones_config[i]["y_min"] >> y_min;
00227 zone.setYMin(y_min);
00228 }
00229 if (zones_config[i].FindValue("y_max") != NULL)
00230 {
00231 double y_max;
00232 zones_config[i]["y_max"] >> y_max;
00233 zone.setYMax(y_max);
00234 }
00235 if (zones_config[i].FindValue("z_min") != NULL)
00236 {
00237 double z_min;
00238 zones_config[i]["z_min"] >> z_min;
00239 zone.setZMin(z_min);
00240 }
00241 if (zones_config[i].FindValue("z_max") != NULL)
00242 {
00243 double z_max;
00244 zones_config[i]["z_max"] >> z_max;
00245 zone.setZMax(z_max);
00246 }
00247
00248 zones_.push_back(zone);
00249 }
00250 #endif
00251
00252
00253 if (zones_.size() > 0)
00254 {
00255 ROS_INFO("%d segmenation zone(s) parsed.", (int) zones_.size());
00256 ROS_INFO("Segmenter Successfully Initialized");
00257 okay_ = true;
00258 } else
00259 {
00260 ROS_ERROR("No valid segmenation zones defined. Check %s.", zones_file.c_str());
00261 okay_ = false;
00262 }
00263 }
00264
00265 bool Segmenter::okay() const
00266 {
00267 return okay_;
00268 }
00269
00270 void Segmenter::pointCloudCallback(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc)
00271 {
00272
00273 boost::mutex::scoped_lock lock(pc_mutex_);
00274
00275 first_pc_in_ = true;
00276 pc_ = pc;
00277 }
00278
00279 const SegmentationZone &Segmenter::getCurrentZone() const
00280 {
00281
00282 for (size_t i = 0; i < zones_.size(); i++)
00283 {
00284
00285 geometry_msgs::TransformStamped tf = tf_buffer_.lookupTransform(zones_[i].getParentFrameID(),
00286 zones_[i].getChildFrameID(), ros::Time(0));
00287
00288
00289 tf2::Matrix3x3 mat(tf2::Quaternion(tf.transform.rotation.x, tf.transform.rotation.y, tf.transform.rotation.z,
00290 tf.transform.rotation.w));
00291 double roll, pitch, yaw;
00292 mat.getRPY(roll, pitch, yaw);
00293
00294
00295 if (roll >= zones_[i].getRollMin() && pitch >= zones_[i].getPitchMin() && yaw >= zones_[i].getYawMin() &&
00296 roll <= zones_[i].getRollMax() && pitch <= zones_[i].getPitchMax() && yaw <= zones_[i].getYawMax())
00297 {
00298 return zones_[i];
00299 }
00300 }
00301
00302 ROS_WARN("Current state not in a valid segmentation zone. Defaulting to first zone.");
00303 return zones_[0];
00304 }
00305
00306 bool Segmenter::removeObjectCallback(rail_segmentation::RemoveObject::Request &req,
00307 rail_segmentation::RemoveObject::Response &res)
00308 {
00309
00310 boost::mutex::scoped_lock lock(msg_mutex_);
00311
00312 if (req.index < object_list_.objects.size() && req.index < markers_.markers.size())
00313 {
00314
00315 object_list_.objects.erase(object_list_.objects.begin() + req.index);
00316
00317 object_list_.header.seq++;
00318 object_list_.header.stamp = ros::Time::now();
00319 object_list_.cleared = false;
00320
00321 segmented_objects_pub_.publish(object_list_);
00322
00323 markers_.markers[req.index].action = visualization_msgs::Marker::DELETE;
00324 markers_pub_.publish(markers_);
00325 markers_.markers.erase(markers_.markers.begin() + req.index);
00326 return true;
00327 } else
00328 {
00329 ROS_ERROR("Attempted to remove index %d from list of size %ld.", req.index, object_list_.objects.size());
00330 return false;
00331 }
00332 }
00333
00334 bool Segmenter::clearCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
00335 {
00336
00337 boost::mutex::scoped_lock lock(msg_mutex_);
00338
00339 object_list_.objects.clear();
00340 object_list_.cleared = true;
00341
00342 object_list_.header.seq++;
00343 object_list_.header.stamp = ros::Time::now();
00344
00345 segmented_objects_pub_.publish(object_list_);
00346
00347 for (size_t i = 0; i < markers_.markers.size(); i++)
00348 {
00349 markers_.markers[i].action = visualization_msgs::Marker::DELETE;
00350 }
00351 markers_pub_.publish(markers_);
00352 markers_.markers.clear();
00353 return true;
00354 }
00355
00356 bool Segmenter::segmentCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
00357 {
00358
00359 {
00360 boost::mutex::scoped_lock lock(pc_mutex_);
00361 if (!first_pc_in_)
00362 {
00363 ROS_WARN("No point cloud received yet. Ignoring segmentation request.");
00364 return false;
00365 }
00366 }
00367
00368
00369 this->clearCallback(req, res);
00370
00371
00372 const SegmentationZone &zone = this->getCurrentZone();
00373 ROS_INFO("Segmenting in zone '%s'.", zone.getName().c_str());
00374
00375
00376 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed_pc(new pcl::PointCloud<pcl::PointXYZRGB>);
00377
00378 {
00379 boost::mutex::scoped_lock lock(pc_mutex_);
00380
00381 pcl_ros::transformPointCloud(zone.getBoundingFrameID(), ros::Time(0), *pc_, pc_->header.frame_id,
00382 *transformed_pc, tf_);
00383 transformed_pc->header.frame_id = zone.getBoundingFrameID();
00384 transformed_pc->header.seq = pc_->header.seq;
00385 transformed_pc->header.stamp = pc_->header.stamp;
00386 }
00387
00388
00389 pcl::IndicesPtr filter_indices(new vector<int>);
00390 filter_indices->resize(transformed_pc->points.size());
00391 for (size_t i = 0; i < transformed_pc->points.size(); i++)
00392 {
00393 filter_indices->at(i) = i;
00394 }
00395
00396
00397 double z_min = zone.getZMin();
00398 if (zone.getRemoveSurface())
00399 {
00400 double z_surface = this->findSurface(transformed_pc, filter_indices, zone.getZMin(), zone.getZMax(),
00401 filter_indices);
00402
00403 z_min = max(zone.getZMin(), z_surface + SURFACE_REMOVAL_PADDING);
00404 }
00405
00406
00407 pcl::ConditionOr<pcl::PointXYZRGB>::Ptr bounds(new pcl::ConditionOr<pcl::PointXYZRGB>);
00408 if (z_min > -numeric_limits<double>::infinity())
00409 {
00410 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00411 new pcl::FieldComparison<pcl::PointXYZRGB>("z", pcl::ComparisonOps::LE, z_min))
00412 );
00413 }
00414 if (zone.getZMax() < numeric_limits<double>::infinity())
00415 {
00416 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00417 new pcl::FieldComparison<pcl::PointXYZRGB>("z", pcl::ComparisonOps::GE, zone.getZMax()))
00418 );
00419 }
00420 if (zone.getYMin() > -numeric_limits<double>::infinity())
00421 {
00422 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00423 new pcl::FieldComparison<pcl::PointXYZRGB>("y", pcl::ComparisonOps::LE, zone.getYMin()))
00424 );
00425 }
00426 if (zone.getYMax() < numeric_limits<double>::infinity())
00427 {
00428 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00429 new pcl::FieldComparison<pcl::PointXYZRGB>("y", pcl::ComparisonOps::GE, zone.getYMax()))
00430 );
00431 }
00432 if (zone.getXMin() > -numeric_limits<double>::infinity())
00433 {
00434 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00435 new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::LE, zone.getXMin()))
00436 );
00437 }
00438 if (zone.getXMax() < numeric_limits<double>::infinity())
00439 {
00440 bounds->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr(
00441 new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::GE, zone.getXMax()))
00442 );
00443 }
00444
00445
00446 this->inverseBound(transformed_pc, filter_indices, bounds, filter_indices);
00447
00448
00449 if (debug_)
00450 {
00451 pcl::PointCloud<pcl::PointXYZRGB>::Ptr debug_pc(new pcl::PointCloud<pcl::PointXYZRGB>);
00452 this->extract(transformed_pc, filter_indices, debug_pc);
00453 debug_pc_pub_.publish(debug_pc);
00454 }
00455
00456
00457 vector<pcl::PointIndices> clusters;
00458 this->extractClusters(transformed_pc, filter_indices, clusters);
00459
00460 if (clusters.size() > 0)
00461 {
00462
00463 boost::mutex::scoped_lock lock(msg_mutex_);
00464
00465 for (size_t i = 0; i < clusters.size(); i++)
00466 {
00467
00468 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZRGB>);
00469 for (size_t j = 0; j < clusters[i].indices.size(); j++)
00470 {
00471 cluster->points.push_back(transformed_pc->points[clusters[i].indices[j]]);
00472 }
00473 cluster->width = cluster->points.size();
00474 cluster->height = 1;
00475 cluster->is_dense = true;
00476 cluster->header.frame_id = transformed_pc->header.frame_id;
00477
00478
00479 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed_cluster(new pcl::PointCloud<pcl::PointXYZRGB>);
00480 pcl::PCLPointCloud2::Ptr converted(new pcl::PCLPointCloud2);
00481 if (zone.getBoundingFrameID() != zone.getSegmentationFrameID())
00482 {
00483
00484 pcl_ros::transformPointCloud(zone.getSegmentationFrameID(), ros::Time(0), *cluster, cluster->header.frame_id,
00485 *transformed_cluster, tf_);
00486 transformed_cluster->header.frame_id = zone.getSegmentationFrameID();
00487 transformed_cluster->header.seq = cluster->header.seq;
00488 transformed_cluster->header.stamp = cluster->header.stamp;
00489 pcl::toPCLPointCloud2(*transformed_cluster, *converted);
00490 } else
00491 {
00492 pcl::toPCLPointCloud2(*cluster, *converted);
00493 }
00494
00495
00496 rail_manipulation_msgs::SegmentedObject segmented_object;
00497 segmented_object.recognized = false;
00498
00499
00500 segmented_object.image = this->createImage(transformed_pc, clusters[i]);
00501
00502
00503 if (debug_)
00504 {
00505 debug_img_pub_.publish(segmented_object.image);
00506 }
00507
00508
00509 pcl_conversions::fromPCL(*converted, segmented_object.point_cloud);
00510 segmented_object.point_cloud.header.stamp = ros::Time::now();
00511
00512 segmented_object.marker = this->createMarker(converted);
00513 segmented_object.marker.id = i;
00514
00515
00516 Eigen::Vector4f centroid;
00517 if (zone.getBoundingFrameID() != zone.getSegmentationFrameID())
00518 {
00519 pcl::compute3DCentroid(*transformed_cluster, centroid);
00520 } else
00521 {
00522 pcl::compute3DCentroid(*cluster, centroid);
00523 }
00524 segmented_object.centroid.x = centroid[0];
00525 segmented_object.centroid.y = centroid[1];
00526 segmented_object.centroid.z = centroid[2];
00527
00528
00529 Eigen::Vector4f min_pt, max_pt;
00530 pcl::getMinMax3D(*cluster, min_pt, max_pt);
00531 segmented_object.width = max_pt[0] - min_pt[0];
00532 segmented_object.depth = max_pt[1] - min_pt[1];
00533 segmented_object.height = max_pt[2] - min_pt[2];
00534
00535
00536 segmented_object.center.x = (max_pt[0] + min_pt[0]) / 2.0;
00537 segmented_object.center.y = (max_pt[1] + min_pt[1]) / 2.0;
00538 segmented_object.center.z = (max_pt[2] + min_pt[2]) / 2.0;
00539
00540
00541 pcl::PointCloud<pcl::PointXYZRGB>::Ptr projected_cluster(new pcl::PointCloud<pcl::PointXYZRGB>);
00542
00543 pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
00544 coefficients->values.resize(4);
00545 coefficients->values[0] = 0;
00546 coefficients->values[1] = 0;
00547 coefficients->values[2] = 1.0;
00548 coefficients->values[3] = 0;
00549 pcl::ProjectInliers<pcl::PointXYZRGB> proj;
00550 proj.setModelType(pcl::SACMODEL_PLANE);
00551 if (zone.getBoundingFrameID() != zone.getSegmentationFrameID())
00552 {
00553 proj.setInputCloud(transformed_cluster);
00554 } else
00555 {
00556 proj.setInputCloud(cluster);
00557 }
00558 proj.setModelCoefficients(coefficients);
00559 proj.filter(*projected_cluster);
00560
00561
00562 Eigen::Vector4f projected_centroid;
00563 Eigen::Matrix3f covariance_matrix;
00564 pcl::compute3DCentroid(*projected_cluster, projected_centroid);
00565 pcl::computeCovarianceMatrixNormalized(*projected_cluster, projected_centroid, covariance_matrix);
00566 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance_matrix, Eigen::ComputeEigenvectors);
00567 Eigen::Matrix3f eigen_vectors = eigen_solver.eigenvectors();
00568 eigen_vectors.col(2) = eigen_vectors.col(0).cross(eigen_vectors.col(1));
00569
00570 const Eigen::Quaternionf qfinal(eigen_vectors);
00571
00572
00573 tf::Quaternion tf_quat;
00574 tf_quat.setValue(qfinal.x(), qfinal.y(), qfinal.z(), qfinal.w());
00575 double r, p, y;
00576 tf::Matrix3x3 m(tf_quat);
00577 m.getRPY(r, p, y);
00578 double angle = r + y;
00579 while (angle < -M_PI)
00580 {
00581 angle += 2 * M_PI;
00582 }
00583 while (angle > M_PI)
00584 {
00585 angle -= 2 * M_PI;
00586 }
00587 segmented_object.orientation = tf::createQuaternionMsgFromYaw(angle);
00588
00589
00590 object_list_.objects.push_back(segmented_object);
00591
00592 markers_.markers.push_back(segmented_object.marker);
00593 }
00594
00595
00596 object_list_.header.seq++;
00597 object_list_.header.stamp = ros::Time::now();
00598 object_list_.header.frame_id = zone.getSegmentationFrameID();
00599 object_list_.cleared = false;
00600 segmented_objects_pub_.publish(object_list_);
00601
00602
00603 markers_pub_.publish(markers_);
00604 } else
00605 {
00606 ROS_WARN("No segmented objects found.");
00607 }
00608
00609 return true;
00610 }
00611
00612 double Segmenter::findSurface(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00613 const pcl::IndicesConstPtr &indices_in, const double z_min, const double z_max,
00614 const pcl::IndicesPtr &indices_out) const
00615 {
00616
00617 pcl::SACSegmentation<pcl::PointXYZRGB> plane_seg;
00618
00619 plane_seg.setOptimizeCoefficients(true);
00620 plane_seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
00621 plane_seg.setAxis(Eigen::Vector3f(0, 0, 1));
00622 plane_seg.setEpsAngle(SAC_EPS_ANGLE);
00623 plane_seg.setMethodType(pcl::SAC_RANSAC);
00624 plane_seg.setMaxIterations(SAC_MAX_ITERATIONS);
00625 plane_seg.setDistanceThreshold(SAC_DISTANCE_THRESHOLD);
00626
00627
00628 pcl::PointCloud<pcl::PointXYZRGB>::Ptr pc_copy(new pcl::PointCloud<pcl::PointXYZRGB>(*in));
00629 plane_seg.setInputCloud(pc_copy);
00630 plane_seg.setIndices(indices_in);
00631
00632
00633 while (true)
00634 {
00635
00636 pcl::PointIndices::Ptr inliers_ptr(new pcl::PointIndices);
00637
00638
00639 pcl::ModelCoefficients coefficients;
00640 plane_seg.segment(*inliers_ptr, coefficients);
00641
00642
00643 if (inliers_ptr->indices.size() == 0)
00644 {
00645 ROS_WARN("Could not find a surface above %fm and below %fm.", z_min, z_max);
00646 *indices_out = *indices_in;
00647 return -numeric_limits<double>::infinity();
00648 }
00649
00650
00651 pcl::PointCloud<pcl::PointXYZRGB> plane;
00652 pcl::ExtractIndices<pcl::PointXYZRGB> extract(true);
00653 extract.setInputCloud(pc_copy);
00654 extract.setIndices(inliers_ptr);
00655 extract.setNegative(false);
00656 extract.filter(plane);
00657 extract.setKeepOrganized(true);
00658 plane_seg.setIndices(extract.getRemovedIndices());
00659
00660
00661 double height = this->averageZ(plane.points);
00662 if (height >= z_min && height <= z_max)
00663 {
00664 ROS_INFO("Surface found at %fm.", height);
00665 *indices_out = *plane_seg.getIndices();
00666 return height;
00667 }
00668 }
00669 }
00670
00671 void Segmenter::extractClusters(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00672 const pcl::IndicesConstPtr &indices_in, vector<pcl::PointIndices> &clusters) const
00673 {
00674
00675 pcl::IndicesPtr valid(new vector<int>);
00676 for (size_t i = 0; i < indices_in->size(); i++)
00677 {
00678 if (pcl_isfinite(in->points[indices_in->at(i)].x) & pcl_isfinite(in->points[indices_in->at(i)].y) &
00679 pcl_isfinite(in->points[indices_in->at(i)].z))
00680 {
00681 valid->push_back(indices_in->at(i));
00682 }
00683 }
00684
00685 pcl::EuclideanClusterExtraction<pcl::PointXYZRGB> seg;
00686 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr kd_tree(new pcl::search::KdTree<pcl::PointXYZRGB>);
00687 kd_tree->setInputCloud(in);
00688 seg.setClusterTolerance(CLUSTER_TOLERANCE);
00689 seg.setMinClusterSize(min_cluster_size_);
00690 seg.setMaxClusterSize(max_cluster_size_);
00691 seg.setSearchMethod(kd_tree);
00692 seg.setInputCloud(in);
00693 seg.setIndices(valid);
00694 seg.extract(clusters);
00695 }
00696
00697 sensor_msgs::Image Segmenter::createImage(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00698 const pcl::PointIndices &cluster) const
00699 {
00700
00701 int row_min = numeric_limits<int>::max();
00702 int row_max = numeric_limits<int>::min();
00703 int col_min = numeric_limits<int>::max();
00704 int col_max = numeric_limits<int>::min();
00705
00706 for (size_t i = 0; i < cluster.indices.size(); i++)
00707 {
00708
00709 int row = cluster.indices[i] / in->width;
00710 int col = cluster.indices[i] - (row * in->width);
00711
00712 if (row < row_min)
00713 {
00714 row_min = row;
00715 } else if (row > row_max)
00716 {
00717 row_max = row;
00718 }
00719 if (col < col_min)
00720 {
00721 col_min = col;
00722 } else if (col > col_max)
00723 {
00724 col_max = col;
00725 }
00726 }
00727
00728
00729 sensor_msgs::Image msg;
00730
00731
00732 msg.header.frame_id = in->header.frame_id;
00733 msg.header.stamp = ros::Time::now();
00734 msg.width = col_max - col_min;
00735 msg.height = row_max - row_min;
00736
00737 msg.step = 3 * msg.width;
00738 msg.data.resize(msg.step * msg.height);
00739 msg.encoding = sensor_msgs::image_encodings::BGR8;
00740
00741
00742 for (int h = 0; h < msg.height; h++)
00743 {
00744 for (int w = 0; w < msg.width; w++)
00745 {
00746
00747 const pcl::PointXYZRGB &point = in->at(col_min + w, row_min + h);
00748
00749 int index = (msg.step * h) + (w * 3);
00750 msg.data[index] = point.b;
00751 msg.data[index + 1] = point.g;
00752 msg.data[index + 2] = point.r;
00753 }
00754 }
00755
00756 return msg;
00757 }
00758
00759 visualization_msgs::Marker Segmenter::createMarker(const pcl::PCLPointCloud2::ConstPtr &pc) const
00760 {
00761 visualization_msgs::Marker marker;
00762
00763 marker.header.frame_id = pc->header.frame_id;
00764
00765
00766 marker.pose.position.x = 0.0;
00767 marker.pose.position.y = 0.0;
00768 marker.pose.position.z = 0.0;
00769 marker.pose.orientation.x = 0.0;
00770 marker.pose.orientation.y = 0.0;
00771 marker.pose.orientation.z = 0.0;
00772 marker.pose.orientation.w = 1.0;
00773
00774
00775 marker.scale.x = MARKER_SCALE;
00776 marker.scale.y = MARKER_SCALE;
00777 marker.scale.z = MARKER_SCALE;
00778
00779
00780 marker.type = visualization_msgs::Marker::CUBE_LIST;
00781 marker.color.a = 1.0;
00782
00783
00784 pcl::PCLPointCloud2 downsampled;
00785 pcl::VoxelGrid<pcl::PCLPointCloud2> voxel_grid;
00786 voxel_grid.setInputCloud(pc);
00787 voxel_grid.setLeafSize(DOWNSAMPLE_LEAF_SIZE, DOWNSAMPLE_LEAF_SIZE, DOWNSAMPLE_LEAF_SIZE);
00788 voxel_grid.filter(downsampled);
00789
00790
00791 sensor_msgs::PointCloud2 pc2_msg;
00792 pcl_conversions::fromPCL(downsampled, pc2_msg);
00793 sensor_msgs::PointCloud pc_msg;
00794 sensor_msgs::convertPointCloud2ToPointCloud(pc2_msg, pc_msg);
00795
00796
00797 marker.points.resize(pc_msg.points.size());
00798 int r = 0, g = 0, b = 0;
00799 for (size_t j = 0; j < pc_msg.points.size(); j++)
00800 {
00801 marker.points[j].x = pc_msg.points[j].x;
00802 marker.points[j].y = pc_msg.points[j].y;
00803 marker.points[j].z = pc_msg.points[j].z;
00804
00805
00806 uint32_t rgb = *reinterpret_cast<int *>(&pc_msg.channels[0].values[j]);
00807 r += (int) ((rgb >> 16) & 0x0000ff);
00808 g += (int) ((rgb >> 8) & 0x0000ff);
00809 b += (int) ((rgb) & 0x0000ff);
00810 }
00811
00812
00813 marker.color.r = ((float) r / (float) pc_msg.points.size()) / 255.0;
00814 marker.color.g = ((float) g / (float) pc_msg.points.size()) / 255.0;
00815 marker.color.b = ((float) b / (float) pc_msg.points.size()) / 255.0;
00816 marker.color.a = 1.0;
00817
00818 return marker;
00819 }
00820
00821 void Segmenter::extract(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in, const pcl::IndicesConstPtr &indices_in,
00822 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &out) const
00823 {
00824 pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00825 extract.setInputCloud(in);
00826 extract.setIndices(indices_in);
00827 extract.filter(*out);
00828 }
00829
00830 void Segmenter::inverseBound(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00831 const pcl::IndicesConstPtr &indices_in,
00832 const pcl::ConditionBase<pcl::PointXYZRGB>::Ptr &conditions,
00833 const pcl::IndicesPtr &indices_out) const
00834 {
00835
00836 pcl::PointCloud<pcl::PointXYZRGB> tmp;
00837 pcl::ConditionalRemoval<pcl::PointXYZRGB> removal(conditions, true);
00838 removal.setInputCloud(in);
00839 removal.setIndices(indices_in);
00840 removal.filter(tmp);
00841 *indices_out = *removal.getRemovedIndices();
00842 }
00843
00844 double Segmenter::averageZ(const vector<pcl::PointXYZRGB, Eigen::aligned_allocator<pcl::PointXYZRGB> > &v) const
00845 {
00846 double avg = 0.0;
00847 for (size_t i = 0; i < v.size(); i++)
00848 {
00849 avg += v[i].z;
00850 }
00851 return (avg / (double) v.size());
00852 }