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/auto.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)
308 if (indices_->empty ())
309 PCL_ERROR (
"[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
313 search_->setInputCloud (input_, indices_);
320 search_->setInputCloud (input_);
327 template <
typename Po
intT,
typename NormalT>
void
331 std::vector<float> distances;
333 point_neighbours_.resize (input_->size (), neighbours);
334 if (input_->is_dense)
336 for (
const auto& point_index: (*indices_))
339 search_->nearestKSearch ((*input_)[point_index], neighbour_number_, neighbours, distances);
340 point_neighbours_[point_index].swap (neighbours);
345 for (
const auto& point_index: (*indices_))
350 search_->nearestKSearch ((*input_)[point_index], neighbour_number_, neighbours, distances);
351 point_neighbours_[point_index].swap (neighbours);
357 template <
typename Po
intT,
typename NormalT>
void
360 int num_of_pts =
static_cast<int> (indices_->size ());
361 point_labels_.resize (input_->size (), -1);
363 std::vector< std::pair<float, int> > point_residual;
364 std::pair<float, int> pair;
365 point_residual.resize (num_of_pts, pair);
369 for (
int i_point = 0; i_point < num_of_pts; i_point++)
371 const auto point_index = (*indices_)[i_point];
372 point_residual[i_point].first = (*normals_)[point_index].curvature;
373 point_residual[i_point].second = point_index;
375 std::sort (point_residual.begin (), point_residual.end (),
comparePair);
379 for (
int i_point = 0; i_point < num_of_pts; i_point++)
381 const auto point_index = (*indices_)[i_point];
382 point_residual[i_point].first = 0;
383 point_residual[i_point].second = point_index;
386 int seed_counter = 0;
387 int seed = point_residual[seed_counter].second;
389 int segmented_pts_num = 0;
390 int number_of_segments = 0;
391 while (segmented_pts_num < num_of_pts)
394 pts_in_segment = growRegion (seed, number_of_segments);
395 segmented_pts_num += pts_in_segment;
396 num_pts_in_segment_.push_back (pts_in_segment);
397 number_of_segments++;
400 for (
int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
402 int index = point_residual[i_seed].second;
403 if (point_labels_[index] == -1)
406 seed_counter = i_seed;
414 template <
typename Po
intT,
typename NormalT>
int
417 std::queue<int> seeds;
418 seeds.push (initial_seed);
419 point_labels_[initial_seed] = segment_number;
421 int num_pts_in_segment = 1;
423 while (!seeds.empty ())
426 curr_seed = seeds.front ();
429 std::size_t i_nghbr = 0;
430 while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
432 int index = point_neighbours_[curr_seed][i_nghbr];
433 if (point_labels_[index] != -1)
439 bool is_a_seed =
false;
440 bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
442 if (!belongs_to_segment)
448 point_labels_[index] = segment_number;
449 num_pts_in_segment++;
460 return (num_pts_in_segment);
464 template <
typename Po
intT,
typename NormalT>
bool
469 float cosine_threshold = std::cos (theta_threshold_);
472 data[0] = (*input_)[point].data[0];
473 data[1] = (*input_)[point].data[1];
474 data[2] = (*input_)[point].data[2];
475 data[3] = (*input_)[point].data[3];
476 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data));
477 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*normals_)[point].normal));
480 if (smooth_mode_flag_)
482 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
483 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
484 if (dot_product < cosine_threshold)
491 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
492 Eigen::Map<Eigen::Vector3f> initial_seed_normal (
static_cast<float*
> ((*normals_)[initial_seed].normal));
493 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
494 if (dot_product < cosine_threshold)
499 if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
507 data_1[0] = (*input_)[nghbr].data[0];
508 data_1[1] = (*input_)[nghbr].data[1];
509 data_1[2] = (*input_)[nghbr].data[2];
510 data_1[3] = (*input_)[nghbr].data[3];
511 Eigen::Map<Eigen::Vector3f> nghbr_point (
static_cast<float*
> (data_1));
512 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
513 if (residual_flag_ && residual > residual_threshold_)
520 template <
typename Po
intT,
typename NormalT>
void
523 const auto number_of_segments = num_pts_in_segment_.size ();
524 const auto number_of_points = input_->size ();
527 clusters_.resize (number_of_segments, segment);
529 for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
531 clusters_[i_seg].
indices.resize ( num_pts_in_segment_[i_seg], 0);
534 std::vector<int> counter(number_of_segments, 0);
536 for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
538 const auto segment_index = point_labels_[i_point];
539 if (segment_index != -1)
541 const auto point_index = counter[segment_index];
542 clusters_[segment_index].indices[point_index] = i_point;
543 counter[segment_index] = point_index + 1;
547 number_of_segments_ = number_of_segments;
551 template <
typename Po
intT,
typename NormalT>
void
556 bool segmentation_is_possible = initCompute ();
557 if ( !segmentation_is_possible )
564 bool point_was_found =
false;
565 for (
const auto& point : (*indices_))
568 point_was_found =
true;
574 if (clusters_.empty ())
576 point_neighbours_.clear ();
577 point_labels_.clear ();
578 num_pts_in_segment_.clear ();
579 number_of_segments_ = 0;
581 segmentation_is_possible = prepareForSegmentation ();
582 if ( !segmentation_is_possible )
588 findPointNeighbours ();
589 applySmoothRegionGrowingAlgorithm ();
594 for (
const auto& i_segment : clusters_)
596 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
597 if (it != i_segment.indices.cend())
601 cluster.
indices.reserve (i_segment.indices.size ());
602 std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.
indices));
617 if (!clusters_.empty ())
621 srand (
static_cast<unsigned int> (time (
nullptr)));
622 std::vector<unsigned char> colors;
623 for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
625 colors.push_back (
static_cast<unsigned char> (rand () % 256));
626 colors.push_back (
static_cast<unsigned char> (rand () % 256));
627 colors.push_back (
static_cast<unsigned char> (rand () % 256));
630 colored_cloud->
width = input_->width;
631 colored_cloud->
height = input_->height;
632 colored_cloud->
is_dense = input_->is_dense;
633 for (
const auto& i_point: *input_)
636 point.x = *(i_point.data);
637 point.y = *(i_point.data + 1);
638 point.z = *(i_point.data + 2);
642 colored_cloud->
points.push_back (point);
646 for (
const auto& i_segment : clusters_)
648 for (
const auto& index : (i_segment.indices))
650 (*colored_cloud)[index].r = colors[3 * next_color];
651 (*colored_cloud)[index].g = colors[3 * next_color + 1];
652 (*colored_cloud)[index].b = colors[3 * next_color + 2];
658 return (colored_cloud);
667 if (!clusters_.empty ())
671 srand (
static_cast<unsigned int> (time (
nullptr)));
672 std::vector<unsigned char> colors;
673 for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
675 colors.push_back (
static_cast<unsigned char> (rand () % 256));
676 colors.push_back (
static_cast<unsigned char> (rand () % 256));
677 colors.push_back (
static_cast<unsigned char> (rand () % 256));
680 colored_cloud->
width = input_->width;
681 colored_cloud->
height = input_->height;
682 colored_cloud->
is_dense = input_->is_dense;
683 for (
const auto& i_point: *input_)
686 point.x = *(i_point.data);
687 point.y = *(i_point.data + 1);
688 point.z = *(i_point.data + 2);
693 colored_cloud->
points.push_back (point);
697 for (
const auto& i_segment : clusters_)
699 for (
const auto& index : (i_segment.indices))
701 (*colored_cloud)[index].r = colors[3 * next_color];
702 (*colored_cloud)[index].g = colors[3 * next_color + 1];
703 (*colored_cloud)[index].b = colors[3 * next_color + 2];
709 return (colored_cloud);
712 #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.
Defines all the PCL implemented PointT point type structures.
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
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.