42 #include <pcl/segmentation/region_growing.h>
44 #include <pcl/point_cloud.h>
46 #include <pcl/common/point_tests.h>
47 #include <pcl/console/print.h>
48 #include <pcl/search/search.h>
49 #include <pcl/search/kdtree.h>
56 template <
typename Po
intT,
typename NormalT>
60 template <
typename Po
intT,
typename NormalT>
63 point_neighbours_.clear ();
64 point_labels_.clear ();
65 num_pts_in_segment_.clear ();
73 return (min_pts_per_cluster_);
77 template <
typename Po
intT,
typename NormalT>
void
80 min_pts_per_cluster_ = min_cluster_size;
87 return (max_pts_per_cluster_);
91 template <
typename Po
intT,
typename NormalT>
void
94 max_pts_per_cluster_ = max_cluster_size;
98 template <
typename Po
intT,
typename NormalT>
bool
101 return (smooth_mode_flag_);
105 template <
typename Po
intT,
typename NormalT>
void
108 smooth_mode_flag_ = value;
112 template <
typename Po
intT,
typename NormalT>
bool
115 return (curvature_flag_);
119 template <
typename Po
intT,
typename NormalT>
void
122 curvature_flag_ = value;
124 if (!curvature_flag_ && !residual_flag_)
125 residual_flag_ =
true;
129 template <
typename Po
intT,
typename NormalT>
bool
132 return (residual_flag_);
136 template <
typename Po
intT,
typename NormalT>
void
139 residual_flag_ = value;
141 if (!curvature_flag_ && !residual_flag_)
142 curvature_flag_ =
true;
146 template <
typename Po
intT,
typename NormalT>
float
149 return (theta_threshold_);
153 template <
typename Po
intT,
typename NormalT>
void
156 theta_threshold_ = theta;
160 template <
typename Po
intT,
typename NormalT>
float
163 return (residual_threshold_);
167 template <
typename Po
intT,
typename NormalT>
void
170 residual_threshold_ = residual;
174 template <
typename Po
intT,
typename NormalT>
float
177 return (curvature_threshold_);
181 template <
typename Po
intT,
typename NormalT>
void
184 curvature_threshold_ = curvature;
188 template <
typename Po
intT,
typename NormalT>
unsigned int
191 return (neighbour_number_);
195 template <
typename Po
intT,
typename NormalT>
void
198 neighbour_number_ = neighbour_number;
209 template <
typename Po
intT,
typename NormalT>
void
223 template <
typename Po
intT,
typename NormalT>
void
230 template <
typename Po
intT,
typename NormalT>
void
235 point_neighbours_.clear ();
236 point_labels_.clear ();
237 num_pts_in_segment_.clear ();
238 number_of_segments_ = 0;
240 bool segmentation_is_possible = initCompute ();
241 if ( !segmentation_is_possible )
247 segmentation_is_possible = prepareForSegmentation ();
248 if ( !segmentation_is_possible )
254 findPointNeighbours ();
255 applySmoothRegionGrowingAlgorithm ();
258 clusters.resize (clusters_.size ());
259 auto cluster_iter_input = clusters.begin ();
260 for (
const auto& cluster : clusters_)
262 if ((cluster.indices.size () >= min_pts_per_cluster_) &&
263 (cluster.indices.size () <= max_pts_per_cluster_))
265 *cluster_iter_input = cluster;
266 ++cluster_iter_input;
270 clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
271 clusters.resize(clusters_.size());
277 template <
typename Po
intT,
typename NormalT>
bool
281 if ( input_->points.empty () )
285 if ( !normals_ || input_->size () != normals_->size () )
291 if (residual_threshold_ <= 0.0f)
303 if (neighbour_number_ == 0)
312 if (indices_->empty ())
313 PCL_ERROR (
"[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
314 search_->setInputCloud (input_, indices_);
317 search_->setInputCloud (input_);
323 template <
typename Po
intT,
typename NormalT>
void
327 std::vector<float> distances;
329 point_neighbours_.resize (input_->size (), neighbours);
330 if (input_->is_dense)
332 for (
const auto& point_index: (*indices_))
335 search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
336 point_neighbours_[point_index].swap (neighbours);
341 for (
const auto& point_index: (*indices_))
346 search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
347 point_neighbours_[point_index].swap (neighbours);
353 template <
typename Po
intT,
typename NormalT>
void
356 int num_of_pts =
static_cast<int> (indices_->size ());
357 point_labels_.resize (input_->size (), -1);
359 std::vector< std::pair<float, int> > point_residual;
360 std::pair<float, int> pair;
361 point_residual.resize (num_of_pts, pair);
365 for (
int i_point = 0; i_point < num_of_pts; i_point++)
367 const auto point_index = (*indices_)[i_point];
368 point_residual[i_point].first = (*normals_)[point_index].curvature;
369 point_residual[i_point].second = point_index;
371 std::sort (point_residual.begin (), point_residual.end (),
comparePair);
375 for (
int i_point = 0; i_point < num_of_pts; i_point++)
377 const auto point_index = (*indices_)[i_point];
378 point_residual[i_point].first = 0;
379 point_residual[i_point].second = point_index;
382 int seed_counter = 0;
383 int seed = point_residual[seed_counter].second;
385 int segmented_pts_num = 0;
386 int number_of_segments = 0;
387 while (segmented_pts_num < num_of_pts)
390 pts_in_segment = growRegion (seed, number_of_segments);
391 segmented_pts_num += pts_in_segment;
392 num_pts_in_segment_.push_back (pts_in_segment);
393 number_of_segments++;
396 for (
int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
398 int index = point_residual[i_seed].second;
399 if (point_labels_[index] == -1)
402 seed_counter = i_seed;
410 template <
typename Po
intT,
typename NormalT>
int
413 std::queue<int> seeds;
414 seeds.push (initial_seed);
415 point_labels_[initial_seed] = segment_number;
417 int num_pts_in_segment = 1;
419 while (!seeds.empty ())
422 curr_seed = seeds.front ();
425 std::size_t i_nghbr = 0;
426 while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
428 int index = point_neighbours_[curr_seed][i_nghbr];
429 if (point_labels_[index] != -1)
435 bool is_a_seed =
false;
436 bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
438 if (!belongs_to_segment)
444 point_labels_[index] = segment_number;
445 num_pts_in_segment++;
456 return (num_pts_in_segment);
460 template <
typename Po
intT,
typename NormalT>
bool
465 float cosine_threshold = std::cos (theta_threshold_);
468 data[0] = (*input_)[point].data[0];
469 data[1] = (*input_)[point].data[1];
470 data[2] = (*input_)[point].data[2];
471 data[3] = (*input_)[point].data[3];
472 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data));
473 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*normals_)[point].normal));
476 if (smooth_mode_flag_)
478 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
479 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
480 if (dot_product < cosine_threshold)
487 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
488 Eigen::Map<Eigen::Vector3f> initial_seed_normal (
static_cast<float*
> ((*normals_)[initial_seed].normal));
489 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
490 if (dot_product < cosine_threshold)
495 if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
503 data_1[0] = (*input_)[nghbr].data[0];
504 data_1[1] = (*input_)[nghbr].data[1];
505 data_1[2] = (*input_)[nghbr].data[2];
506 data_1[3] = (*input_)[nghbr].data[3];
507 Eigen::Map<Eigen::Vector3f> nghbr_point (
static_cast<float*
> (data_1));
508 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
509 if (residual_flag_ && residual > residual_threshold_)
516 template <
typename Po
intT,
typename NormalT>
void
519 const auto number_of_segments = num_pts_in_segment_.size ();
520 const auto number_of_points = input_->size ();
523 clusters_.resize (number_of_segments, segment);
525 for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
527 clusters_[i_seg].
indices.resize ( num_pts_in_segment_[i_seg], 0);
530 std::vector<int> counter(number_of_segments, 0);
532 for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
534 const auto segment_index = point_labels_[i_point];
535 if (segment_index != -1)
537 const auto point_index = counter[segment_index];
538 clusters_[segment_index].indices[point_index] = i_point;
539 counter[segment_index] = point_index + 1;
543 number_of_segments_ = number_of_segments;
547 template <
typename Po
intT,
typename NormalT>
void
552 bool segmentation_is_possible = initCompute ();
553 if ( !segmentation_is_possible )
560 bool point_was_found =
false;
561 for (
const auto& point : (*indices_))
564 point_was_found =
true;
570 if (clusters_.empty ())
572 point_neighbours_.clear ();
573 point_labels_.clear ();
574 num_pts_in_segment_.clear ();
575 number_of_segments_ = 0;
577 segmentation_is_possible = prepareForSegmentation ();
578 if ( !segmentation_is_possible )
584 findPointNeighbours ();
585 applySmoothRegionGrowingAlgorithm ();
590 for (
const auto& i_segment : clusters_)
592 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
593 if (it != i_segment.indices.cend())
597 cluster.
indices.reserve (i_segment.indices.size ());
598 std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.
indices));
613 if (!clusters_.empty ())
617 srand (
static_cast<unsigned int> (time (
nullptr)));
618 std::vector<unsigned char> colors;
619 for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
621 colors.push_back (
static_cast<unsigned char> (rand () % 256));
622 colors.push_back (
static_cast<unsigned char> (rand () % 256));
623 colors.push_back (
static_cast<unsigned char> (rand () % 256));
626 colored_cloud->
width = input_->width;
627 colored_cloud->
height = input_->height;
628 colored_cloud->
is_dense = input_->is_dense;
629 for (
const auto& i_point: *input_)
632 point.x = *(i_point.data);
633 point.y = *(i_point.data + 1);
634 point.z = *(i_point.data + 2);
638 colored_cloud->
points.push_back (point);
642 for (
const auto& i_segment : clusters_)
644 for (
const auto& index : (i_segment.indices))
646 (*colored_cloud)[index].r = colors[3 * next_color];
647 (*colored_cloud)[index].g = colors[3 * next_color + 1];
648 (*colored_cloud)[index].b = colors[3 * next_color + 2];
654 return (colored_cloud);
663 if (!clusters_.empty ())
667 srand (
static_cast<unsigned int> (time (
nullptr)));
668 std::vector<unsigned char> colors;
669 for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
671 colors.push_back (
static_cast<unsigned char> (rand () % 256));
672 colors.push_back (
static_cast<unsigned char> (rand () % 256));
673 colors.push_back (
static_cast<unsigned char> (rand () % 256));
676 colored_cloud->
width = input_->width;
677 colored_cloud->
height = input_->height;
678 colored_cloud->
is_dense = input_->is_dense;
679 for (
const auto& i_point: *input_)
682 point.x = *(i_point.data);
683 point.y = *(i_point.data + 1);
684 point.z = *(i_point.data + 2);
689 colored_cloud->
points.push_back (point);
693 for (
const auto& i_segment : clusters_)
695 for (
const auto& index : (i_segment.indices))
697 (*colored_cloud)[index].r = colors[3 * next_color];
698 (*colored_cloud)[index].g = colors[3 * next_color + 1];
699 (*colored_cloud)[index].b = colors[3 * next_color + 2];
705 return (colored_cloud);
708 #define PCL_INSTANTIATE_RegionGrowing(T) template class PCL_EXPORTS pcl::RegionGrowing<T, pcl::Normal>;
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
std::uint32_t width
The point cloud width (if organized as an image-structure).
std::uint32_t height
The point cloud height (if organized as an image-structure).
shared_ptr< PointCloud< PointT > > Ptr
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
bool getResidualTestFlag() const
Returns the flag that signalize if the residual test is turned on/off.
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr getColoredCloudRGBA()
If the cloud was successfully segmented, then function returns colored cloud.
void setResidualThreshold(float residual)
Allows to set residual threshold used for testing the points.
~RegionGrowing() override
This destructor destroys the cloud, normals and search method used for finding KNN.
virtual void setCurvatureTestFlag(bool value)
Allows to turn on/off the curvature test.
typename KdTree::Ptr KdTreePtr
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method that will be used for finding KNN.
void setInputNormals(const NormalPtr &norm)
This method sets the normals.
pcl::uindex_t getMinClusterSize()
Get the minimum number of points that a cluster needs to contain in order to be considered valid.
RegionGrowing()
Constructor that sets default values for member variables.
int growRegion(int initial_seed, int segment_number)
This method grows a segment for the given seed point.
void setNumberOfNeighbours(unsigned int neighbour_number)
Allows to set the number of neighbours.
virtual bool prepareForSegmentation()
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
virtual void findPointNeighbours()
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
NormalPtr getInputNormals() const
Returns normals.
float getCurvatureThreshold() const
Returns curvature threshold.
void setMinClusterSize(pcl::uindex_t min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid.
float getResidualThreshold() const
Returns residual threshold.
float getSmoothnessThreshold() const
Returns smoothness threshold.
KdTreePtr getSearchMethod() const
Returns the pointer to the search method that is used for KNN.
virtual void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
unsigned int getNumberOfNeighbours() const
Returns the number of nearest neighbours used for KNN.
bool getCurvatureTestFlag() const
Returns the flag that signalize if the curvature test is turned on/off.
void setSmoothnessThreshold(float theta)
Allows to set smoothness threshold used for testing the points.
pcl::uindex_t getMaxClusterSize()
Get the maximum number of points that a cluster needs to contain in order to be considered valid.
virtual void getSegmentFromPoint(pcl::index_t index, pcl::PointIndices &cluster)
For a given point this function builds a segment to which it belongs and returns this segment.
virtual void setResidualTestFlag(bool value)
Allows to turn on/off the residual test.
void setMaxClusterSize(pcl::uindex_t max_cluster_size)
Set the maximum number of points that a cluster needs to contain in order to be considered valid.
void setCurvatureThreshold(float curvature)
Allows to set curvature threshold used for testing the points.
void applySmoothRegionGrowingAlgorithm()
This function implements the algorithm described in the article "Segmentation of point clouds using s...
bool getSmoothModeFlag() const
Returns the flag value.
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
If the cloud was successfully segmented, then function returns colored cloud.
virtual bool validatePoint(pcl::index_t initial_seed, pcl::index_t point, pcl::index_t nghbr, bool &is_a_seed) const
This function is checking if the point with index 'nghbr' belongs to the segment.
void setSmoothModeFlag(bool value)
This function allows to turn on/off the smoothness constraint.
typename Normal::Ptr NormalPtr
void assembleRegions()
This function simply assembles the regions from list of point labels.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
Defines all the PCL implemented PointT point type structures.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested return true if f...
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
IndicesAllocator<> Indices
Type used for indices in PCL.
A point structure representing Euclidean xyz coordinates, and the RGBA color.
A point structure representing Euclidean xyz coordinates, and the RGB color.