37 #include "jsk_recognition_msgs/ModelCoefficientsArray.h"
38 #include <pcl/segmentation/impl/organized_multi_plane_segmentation.hpp>
39 #include <pcl/filters/extract_indices.h>
40 #include <pcl/kdtree/kdtree_flann.h>
42 #include <Eigen/StdVector>
43 #include <pcl/surface/convex_hull.h>
44 #include <pcl/filters/project_inliers.h>
45 #include <pcl/features/integral_image_normal.h>
50 #include <boost/format.hpp>
51 #include <pcl/common/centroid.h>
52 #include <visualization_msgs/Marker.h>
55 #include <pcl/sample_consensus/method_types.h>
56 #include <pcl/sample_consensus/model_types.h>
57 #include <pcl/segmentation/sac_segmentation.h>
58 #include <pcl/surface/convex_hull.h>
60 #include <jsk_topic_tools/color_utils.h>
67 ConnectionBasedNodelet::onInit();
70 pcl::console::setVerbosityLevel(pcl::console::L_ERROR);
77 getName() +
"::NormalEstimation",
83 getName() +
"::PlaneSegmentation",
89 pnh_->param(
"vital_rate", vital_rate, 1.0);
91 new jsk_topic_tools::VitalChecker(1 / vital_rate));
93 new jsk_topic_tools::VitalChecker(1 / vital_rate));
99 pub_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_,
"output", 1);
100 polygon_pub_ = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_,
"output_polygon", 1);
102 = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_,
"output_coefficients", 1);
103 org_pub_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_,
"output_nonconnected", 1);
105 = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_,
"output_nonconnected_polygon", 1);
107 = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_,
108 "output_nonconnected_coefficients", 1);
110 refined_pub_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_,
111 "output_refined", 1);
113 = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_,
"output_refined_polygon", 1);
115 = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_,
116 "output_refined_coefficients", 1);
119 = advertise<visualization_msgs::Marker>(*pnh_,
120 "debug_connection_map", 1);
124 = advertise<sensor_msgs::PointCloud2>(*pnh_,
"output_normal", 1);
127 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
128 dynamic_reconfigure::Server<Config>::CallbackType
f =
131 srv_->setCallback (
f);
142 const std::vector<pcl::ModelCoefficients>& coefficients,
143 std::vector<pcl::ModelCoefficients>& output_coefficients)
150 Eigen::Vector3f
p = plane.getPointOnPlane();
151 Eigen::Vector3f
n = plane.getNormal();
153 output_coefficients[
i] = plane_coefficient;
157 pcl::ModelCoefficients new_coefficient;
159 output_coefficients[
i] = new_coefficient;
166 sub_ = pnh_->subscribe(
"input", 1,
192 =
config.ransac_refine_outlier_distance_threshold;
199 const pcl::PointCloud<PointT>::Ptr&
input,
200 const std::vector<pcl::ModelCoefficients>& model_coefficients,
201 const std::vector<pcl::PointIndices>& boundary_indices,
204 NODELET_DEBUG(
"size of model_coefficients: %lu", model_coefficients.size());
205 if (model_coefficients.size() == 0) {
209 if (model_coefficients.size() == 1) {
210 connection_map[0]= std::vector<int>();
214 pcl::ExtractIndices<PointT> extract;
215 extract.setInputCloud(
input);
216 for (
size_t i = 0;
i < model_coefficients.size();
i++) {
218 connection_map[
i] = std::vector<int>();
219 connection_map[
i].push_back(i);
220 for (
size_t j = i + 1; j < model_coefficients.size(); j++) {
222 pcl::ModelCoefficients a_coefficient = model_coefficients[
i];
223 pcl::ModelCoefficients b_coefficient = model_coefficients[j];
224 Eigen::Vector3f a_normal(a_coefficient.values[0], a_coefficient.values[1], a_coefficient.values[2]);
225 Eigen::Vector3f b_normal(b_coefficient.values[0], b_coefficient.values[1], b_coefficient.values[2]);
226 double a_distance = a_coefficient.values[3];
227 double b_distance = b_coefficient.values[3];
229 if (a_normal.norm() != 1.0) {
230 a_distance = a_distance / a_normal.norm();
231 a_normal = a_normal / a_normal.norm();
233 if (b_normal.norm() != 1.0) {
234 b_distance = b_distance / b_normal.norm();
235 b_normal = b_normal / b_normal.norm();
237 double theta = fabs(acos(a_normal.dot(b_normal)));
239 if (theta > M_PI / 2.0) {
249 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 12 )
250 pcl::PointIndices::Ptr a_indices
251 = std::make_shared<pcl::PointIndices>(boundary_indices[i]);
252 pcl::PointIndices::Ptr b_indices
253 = std::make_shared<pcl::PointIndices>(boundary_indices[j]);
255 pcl::PointIndices::Ptr a_indices
256 = boost::make_shared<pcl::PointIndices>(boundary_indices[i]);
257 pcl::PointIndices::Ptr b_indices
258 = boost::make_shared<pcl::PointIndices>(boundary_indices[j]);
260 pcl::PointCloud<PointT> a_cloud, b_cloud;
261 extract.setIndices(a_indices);
262 extract.filter(a_cloud);
263 extract.setIndices(b_indices);
264 extract.filter(b_cloud);
265 if (a_cloud.points.size() > 0) {
266 pcl::KdTreeFLANN<PointT> kdtree;
267 kdtree.setInputCloud(a_cloud.makeShared());
269 for (
size_t pi = 0; pi < b_cloud.points.size(); pi++) {
271 std::vector<int> k_indices;
272 std::vector<float> k_sqr_distances;
273 if (kdtree.radiusSearch(
281 connection_map[
i].push_back(j);
289 const std::vector<pcl::PointIndices>& inlier_indices,
290 const std_msgs::Header&
header,
291 jsk_recognition_msgs::ClusterPointIndices& output_indices)
293 for (
size_t i = 0;
i < inlier_indices.size();
i++) {
294 pcl::PointIndices inlier = inlier_indices[
i];
296 one_indices.header =
header;
297 one_indices.indices = inlier.indices;
298 output_indices.cluster_indices.push_back(one_indices);
303 const pcl::PointCloud<PointT>&
input,
304 geometry_msgs::Polygon&
polygon)
306 for (
size_t i = 0;
i <
input.points.size();
i++) {
307 geometry_msgs::Point32
point;
316 const pcl::PointCloud<PointT>::Ptr&
input,
317 const std_msgs::Header&
header,
318 const std::vector<pcl::PointIndices>& inlier_indices,
319 const std::vector<pcl::PointIndices>& boundary_indices,
320 const std::vector<pcl::ModelCoefficients>& model_coefficients,
322 std::vector<pcl::PointIndices>& output_indices,
323 std::vector<pcl::ModelCoefficients>& output_coefficients,
324 std::vector<pcl::PointCloud<PointT> >& output_boundary_clouds)
326 std::vector<std::set<int> > cloud_sets;
328 for (jsk_recognition_utils::IntegerGraphMap::const_iterator it = connection_map.begin();
329 it != connection_map.end();
331 int from_index = it->first;
332 std::stringstream ss;
333 ss <<
"connection map: " << from_index <<
" [";
334 for (
size_t i = 0;
i < it->second.size();
i++) {
342 for (
size_t i = 0;
i < cloud_sets.size();
i++) {
343 pcl::PointIndices one_indices;
344 pcl::PointIndices one_boundaries;
345 std::vector<float> new_coefficients;
346 new_coefficients.resize(4, 0);
347 for (std::set<int>::iterator it = cloud_sets[i].
begin();
348 it != cloud_sets[
i].end();
351 new_coefficients = model_coefficients[*it].values;
352 pcl::PointIndices inlier = inlier_indices[*it];
353 pcl::PointIndices boundary_inlier = boundary_indices[*it];
358 if (one_indices.indices.size() == 0) {
362 double norm =
sqrt(new_coefficients[0] * new_coefficients[0]
363 + new_coefficients[1] * new_coefficients[1]
364 + new_coefficients[2] * new_coefficients[2]);
365 new_coefficients[0] /= norm;
366 new_coefficients[1] /= norm;
367 new_coefficients[2] /= norm;
368 new_coefficients[3] /= norm;
371 pcl::ModelCoefficients pcl_new_coefficients;
372 pcl_new_coefficients.values = new_coefficients;
374 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 12 )
375 pcl::PointIndices::Ptr indices_ptr
376 = std::make_shared<pcl::PointIndices>(one_boundaries);
377 pcl::ModelCoefficients::Ptr coefficients_ptr
378 = std::make_shared<pcl::ModelCoefficients>(pcl_new_coefficients);
380 pcl::PointIndices::Ptr indices_ptr
381 = boost::make_shared<pcl::PointIndices>(one_boundaries);
382 pcl::ModelCoefficients::Ptr coefficients_ptr
383 = boost::make_shared<pcl::ModelCoefficients>(pcl_new_coefficients);
386 = jsk_recognition_utils::convexFromCoefficientsAndInliers<PointT>(
387 input, indices_ptr, coefficients_ptr);
389 pcl::PointCloud<PointT> chull_output;
390 convex->boundariesToPointCloud<
PointT>(chull_output);
391 output_indices.push_back(one_indices);
392 output_coefficients.push_back(pcl_new_coefficients);
393 output_boundary_clouds.push_back(chull_output);
406 pcl::PointCloud<PointT>::Ptr
input,
407 pcl::PointCloud<pcl::Normal>::Ptr normal,
408 PlanarRegionVector& regions,
409 std::vector<pcl::ModelCoefficients>& model_coefficients,
410 std::vector<pcl::PointIndices>& inlier_indices,
411 pcl::PointCloud<pcl::Label>::Ptr& labels,
412 std::vector<pcl::PointIndices>& label_indices,
413 std::vector<pcl::PointIndices>& boundary_indices)
416 pcl::OrganizedMultiPlaneSegmentation<PointT, pcl::Normal, pcl::Label> mps;
421 mps.setInputCloud(
input);
422 mps.setInputNormals(normal);
425 mps.segmentAndRefine(
426 regions, model_coefficients, inlier_indices,
427 labels, label_indices, boundary_indices);
432 const std_msgs::Header&
header,
433 const pcl::PointCloud<PointT>::Ptr
input,
437 const std::vector<pcl::PointIndices>& inlier_indices,
438 const std::vector<pcl::PointCloud<PointT> >& boundaries,
439 const std::vector<pcl::ModelCoefficients>& model_coefficients)
441 jsk_recognition_msgs::ClusterPointIndices indices;
442 jsk_recognition_msgs::ModelCoefficientsArray coefficients_array;
443 jsk_recognition_msgs::PolygonArray polygon_array;
445 polygon_array.header =
header;
446 coefficients_array.header =
header;
457 for (
size_t i = 0;
i < boundaries.size();
i++) {
458 geometry_msgs::PolygonStamped
polygon;
459 pcl::PointCloud<PointT> boundary_cloud = boundaries[
i];
462 polygon_array.polygons.push_back(
polygon);
469 for (
size_t i = 0;
i < model_coefficients.size();
i++) {
471 coefficient.values = model_coefficients[
i].values;
472 coefficient.header =
header;
473 coefficients_array.coefficients.push_back(coefficient);
479 const std_msgs::Header&
header,
480 const pcl::PointCloud<PointT>::Ptr
input,
484 const std::vector<pcl::PointIndices>& inlier_indices,
485 const std::vector<pcl::PointIndices>& boundary_indices,
486 const std::vector<pcl::ModelCoefficients>& model_coefficients)
489 std::vector<pcl::PointCloud<PointT> > boundaries;
490 pcl::ExtractIndices<PointT> extract;
491 extract.setInputCloud(
input);
492 for (
size_t i = 0;
i < boundary_indices.size();
i++) {
493 pcl::PointCloud<PointT> boundary_cloud;
494 pcl::PointIndices boundary_one_indices = boundary_indices[
i];
495 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 12 )
496 pcl::PointIndices::Ptr indices_ptr = std::make_shared<pcl::PointIndices>(boundary_indices[i]);
498 pcl::PointIndices::Ptr indices_ptr = boost::make_shared<pcl::PointIndices>(boundary_indices[i]);
500 extract.setIndices(indices_ptr);
501 extract.filter(boundary_cloud);
502 boundaries.push_back(boundary_cloud);
507 inlier_indices, boundaries, model_coefficients);
512 const pcl::PointCloud<PointT>::Ptr cloud,
513 const std::vector<pcl::PointIndices>& inliers,
514 const std_msgs::Header&
header)
519 visualization_msgs::Marker connection_marker;
520 connection_marker.type = visualization_msgs::Marker::LINE_LIST;
521 connection_marker.scale.x = 0.01;
522 connection_marker.header =
header;
523 connection_marker.pose.orientation.w = 1.0;
524 connection_marker.color = jsk_topic_tools::colorCategory20(0);
530 for (
size_t i = 0;
i < inliers.size();
i++) {
531 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 12 )
532 pcl::PointIndices::Ptr target_inliers
533 = std::make_shared<pcl::PointIndices>(inliers[
i]);
535 pcl::PointIndices::Ptr target_inliers
536 = boost::make_shared<pcl::PointIndices>(inliers[
i]);
538 pcl::PointCloud<PointT>::Ptr target_cloud (
new pcl::PointCloud<PointT>);
539 Eigen::Vector4f centroid;
540 pcl::ExtractIndices<PointT>
ex;
542 ex.setIndices(target_inliers);
543 ex.filter(*target_cloud);
544 pcl::compute3DCentroid(*target_cloud, centroid);
545 Eigen::Vector3f centroid_3f(centroid[0], centroid[1], centroid[2]);
546 centroids.push_back(centroid_3f);
549 for (jsk_recognition_utils::IntegerGraphMap::iterator it = connection_map.begin();
550 it != connection_map.end();
553 int from_index = it->first;
554 std::vector<int> the_connection_map = connection_map[from_index];
555 for (
size_t j = 0; j < the_connection_map.size(); j++) {
556 int to_index = the_connection_map[j];
558 Eigen::Vector3f from_point = centroids[from_index];
559 Eigen::Vector3f to_point = centroids[to_index];
560 geometry_msgs::Point from_point_ros, to_point_ros;
561 jsk_recognition_utils::pointFromVectorToXYZ<Eigen::Vector3f, geometry_msgs::Point>(
562 from_point, from_point_ros);
563 jsk_recognition_utils::pointFromVectorToXYZ<Eigen::Vector3f, geometry_msgs::Point>(
564 to_point, to_point_ros);
565 connection_marker.points.push_back(from_point_ros);
566 connection_marker.points.push_back(to_point_ros);
567 connection_marker.colors.push_back(jsk_topic_tools::colorCategory20(from_index));
568 connection_marker.colors.push_back(jsk_topic_tools::colorCategory20(from_index));
575 pcl::PointCloud<PointT>::Ptr
input,
576 pcl::PointCloud<pcl::Normal>::Ptr normal,
577 const std_msgs::Header&
header)
580 std::vector<pcl::ModelCoefficients> model_coefficients;
581 std::vector<pcl::PointIndices> inlier_indices;
582 pcl::PointCloud<pcl::Label>::Ptr
labels (
new pcl::PointCloud<pcl::Label>());
583 std::vector<pcl::PointIndices> label_indices;
584 std::vector<pcl::PointIndices> boundary_indices;
590 inlier_indices, labels, label_indices,
592 std::vector<pcl::ModelCoefficients> fixed_model_coefficients;
594 model_coefficients = fixed_model_coefficients;
600 inlier_indices, boundary_indices, model_coefficients);
609 std::vector<pcl::PointIndices> output_nonrefined_indices;
610 std::vector<pcl::ModelCoefficients> output_nonrefined_coefficients;
611 std::vector<pcl::PointCloud<PointT> > output_nonrefined_boundary_clouds;
617 output_nonrefined_indices,
618 output_nonrefined_coefficients,
619 output_nonrefined_boundary_clouds);
620 std::vector<pcl::ModelCoefficients> fixed_output_nonrefined_coefficients;
622 output_nonrefined_coefficients = fixed_output_nonrefined_coefficients;
626 output_nonrefined_indices,
627 output_nonrefined_boundary_clouds,
628 output_nonrefined_coefficients);
633 std::vector<pcl::PointIndices> refined_inliers;
634 std::vector<pcl::ModelCoefficients> refined_coefficients;
635 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> refined_convexes;
637 input, output_nonrefined_indices, output_nonrefined_coefficients,
638 refined_inliers, refined_coefficients, refined_convexes);
639 std::vector<pcl::PointCloud<PointT> > refined_boundary_clouds;
640 for (
size_t i = 0;
i < refined_convexes.size();
i++) {
641 pcl::PointCloud<PointT> refined_boundary;
642 refined_convexes[
i]->boundariesToPointCloud(refined_boundary);
643 refined_boundary_clouds.push_back(refined_boundary);
645 std::vector<pcl::ModelCoefficients> fixed_refined_coefficients;
647 refined_coefficients = fixed_refined_coefficients;
651 refined_inliers, refined_boundary_clouds, refined_coefficients);
656 const pcl::PointCloud<PointT>::Ptr
input,
657 const std::vector<pcl::PointIndices>& input_indices,
658 const std::vector<pcl::ModelCoefficients>& input_coefficients,
659 std::vector<pcl::PointIndices>& output_indices,
660 std::vector<pcl::ModelCoefficients>& output_coefficients,
661 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr>& output_convexes)
663 jsk_topic_tools::ScopedTimer timer
665 for (
size_t i = 0;
i < input_indices.size();
i++) {
666 #if ( PCL_MAJOR_VERSION >= 1 && PCL_MINOR_VERSION >= 12 )
667 pcl::PointIndices::Ptr input_indices_ptr
668 = std::make_shared<pcl::PointIndices>(input_indices[i]);
670 pcl::PointIndices::Ptr input_indices_ptr
671 = boost::make_shared<pcl::PointIndices>(input_indices[i]);
673 Eigen::Vector3f normal(input_coefficients[i].values[0],
674 input_coefficients[i].values[1],
675 input_coefficients[i].values[2]);
680 pcl::SACSegmentation<PointT> seg;
681 seg.setOptimizeCoefficients (
true);
682 seg.setModelType (pcl::SACMODEL_PERPENDICULAR_PLANE);
683 seg.setMethodType (pcl::SAC_RANSAC);
685 seg.setInputCloud(
input);
686 seg.setIndices(input_indices_ptr);
687 seg.setMaxIterations (10000);
689 seg.setEpsAngle(pcl::deg2rad(20.0));
690 pcl::PointIndices::Ptr refined_inliers (
new pcl::PointIndices);
691 pcl::ModelCoefficients::Ptr refined_coefficients(
new pcl::ModelCoefficients);
692 seg.segment(*refined_inliers, *refined_coefficients);
693 if (refined_inliers->indices.size() > 0) {
698 input, refined_inliers, refined_coefficients);
701 double area = convex->area();
704 output_convexes.push_back(convex);
705 output_indices.push_back(*refined_inliers);
706 output_coefficients.push_back(*refined_coefficients);
714 pcl::PointCloud<pcl::Normal>::Ptr output)
717 pcl::IntegralImageNormalEstimation<PointT, pcl::Normal> ne;
719 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
722 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
725 ne.setNormalEstimationMethod (ne.AVERAGE_DEPTH_CHANGE);
728 NODELET_FATAL(
"unknown estimation method, force to use COVARIANCE_MATRIX: %d",
730 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
734 ne.setBorderPolicy(pcl::IntegralImageNormalEstimation<PointT, pcl::Normal>::BORDER_POLICY_IGNORE);
737 ne.setBorderPolicy(pcl::IntegralImageNormalEstimation<PointT, pcl::Normal>::BORDER_POLICY_MIRROR);
743 ne.setInputCloud(
input);
748 (
const sensor_msgs::PointCloud2::ConstPtr&
msg)
754 pcl::PointCloud<PointT>::Ptr
input(
new pcl::PointCloud<PointT>());
755 pcl::PointCloud<pcl::Normal>::Ptr normal(
new pcl::PointCloud<pcl::Normal>());
763 sensor_msgs::PointCloud2 normal_ros_cloud;
765 normal_ros_cloud.header =
msg->header;
781 if (connection_status_ == jsk_topic_tools::SUBSCRIBED) {
788 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"NormalEstimation running");
789 jsk_topic_tools::addDiagnosticInformation(
793 stat.
add(
"Estimation Method",
"AVERAGE_3D_GRADIENT");
796 stat.
add(
"Estimation Method",
"COVARIANCE_MATRIX");
799 stat.
add(
"Estimation Method",
"AVERAGE_DEPTH_CHANGE");
802 stat.
add(
"Border Policy",
"ignore");
805 stat.
add(
"Border Policy",
"mirror");
810 stat.
add(
"Depth Dependent Smooting",
"Enabled");
813 stat.
add(
"Depth Dependent Smooting",
"Disabled");
816 stat.
add(
"Publish Normal",
"Enabled");
819 stat.
add(
"Publish Normal",
"Disabled");
823 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
824 (boost::format(
"NormalEstimation not running for %f sec")
828 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
829 "NormalEstimation is not subscribed");
834 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
835 "NormalEstimation is not activated");
842 if (connection_status_ == jsk_topic_tools::SUBSCRIBED) {
849 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
850 "PlaneSegmentation running");
851 jsk_topic_tools::addDiagnosticInformation(
854 jsk_topic_tools::addDiagnosticInformation(
863 stat.
add(
"Use RANSAC refinement",
"True");
864 stat.
add(
"RANSAC refinement distance threshold",
868 stat.
add(
"Use RANSAC refinement",
"False");
871 stat.
add(
"Number of original segmented planes (Avg.)",
873 stat.
add(
"Number of connected segmented planes (Avg.)",
877 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
878 (boost::format(
"PlaneSegmentation not running for %f sec")
882 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
883 "PlaneSegmentation is not subscribed");