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>
56template <
typename Po
intT,
typename NormalT>
60template <
typename Po
intT,
typename NormalT>
77template <
typename Po
intT,
typename NormalT>
void
91template <
typename Po
intT,
typename NormalT>
void
98template <
typename Po
intT,
typename NormalT>
bool
105template <
typename Po
intT,
typename NormalT>
void
112template <
typename Po
intT,
typename NormalT>
bool
119template <
typename Po
intT,
typename NormalT>
void
129template <
typename Po
intT,
typename NormalT>
bool
136template <
typename Po
intT,
typename NormalT>
void
146template <
typename Po
intT,
typename NormalT>
float
153template <
typename Po
intT,
typename NormalT>
void
160template <
typename Po
intT,
typename NormalT>
float
167template <
typename Po
intT,
typename NormalT>
void
174template <
typename Po
intT,
typename NormalT>
float
181template <
typename Po
intT,
typename NormalT>
void
188template <
typename Po
intT,
typename NormalT>
unsigned int
195template <
typename Po
intT,
typename NormalT>
void
209template <
typename Po
intT,
typename NormalT>
void
223template <
typename Po
intT,
typename NormalT>
void
230template <
typename Po
intT,
typename NormalT>
void
241 if ( !segmentation_is_possible )
248 if ( !segmentation_is_possible )
259 auto cluster_iter_input = clusters.begin ();
265 *cluster_iter_input = cluster;
266 ++cluster_iter_input;
270 clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
277template <
typename Po
intT,
typename NormalT>
bool
281 if (
input_->points.empty () )
313 PCL_ERROR (
"[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
323template <
typename Po
intT,
typename NormalT>
void
332 for (
const auto& point_index: (*
indices_))
341 for (
const auto& point_index: (*
indices_))
353template <
typename Po
intT,
typename NormalT>
void
356 int num_of_pts =
static_cast<int> (
indices_->size ());
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;
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;
402 seed_counter = i_seed;
410template <
typename Po
intT,
typename NormalT>
int
413 std::queue<int> seeds;
414 seeds.push (initial_seed);
417 int num_pts_in_segment = 1;
419 while (!seeds.empty ())
422 curr_seed = seeds.front ();
425 std::size_t i_nghbr = 0;
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)
445 num_pts_in_segment++;
456 return (num_pts_in_segment);
460template <
typename Po
intT,
typename NormalT>
bool
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));
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)
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));
516template <
typename Po
intT,
typename NormalT>
void
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++)
530 std::vector<int> counter(number_of_segments, 0);
532 for (std::size_t i_point = 0; i_point < number_of_points; 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;
547template <
typename Po
intT,
typename NormalT>
void
553 if ( !segmentation_is_possible )
560 bool point_was_found =
false;
561 for (
const auto& point : (*
indices_))
564 point_was_found =
true;
578 if ( !segmentation_is_possible )
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));
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));
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);
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);
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));
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);
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>;
PointCloudConstPtr input_
The input point cloud dataset.
IndicesPtr indices_
A pointer to the vector of point indices to use.
bool initCompute()
This method should get called before starting the actual computation.
bool deinitCompute()
This method should get called after finishing the actual computation.
PointCloud represents the base class in PCL for storing collections of 3D points.
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.
NormalPtr normals_
Contains normals of the points that will be segmented.
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.
KdTreePtr search_
Search method that will be used for 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()
virtual void findPointNeighbours()
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.
std::vector< int > point_labels_
Point labels that tells to which segment each point belongs.
float theta_threshold_
Threshold used for testing the smoothness between points.
float getResidualThreshold() const
Returns residual threshold.
float curvature_threshold_
Threshold used in curvature test.
unsigned int neighbour_number_
float getSmoothnessThreshold() const
Returns smoothness threshold.
bool normal_flag_
If set to true then normal/smoothness test will be done during segmentation.
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...
pcl::uindex_t max_pts_per_cluster_
Stores the maximum number of points that a cluster needs to contain in order to be considered valid.
bool residual_flag_
If set to true then residual test will be done during segmentation.
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.
float residual_threshold_
Threshold used in residual test.
std::vector< pcl::Indices > point_neighbours_
Contains neighbours of each point.
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()
bool getSmoothModeFlag() const
Returns the flag value.
pcl::uindex_t min_pts_per_cluster_
Stores the minimum number of points that a cluster needs to contain in order to be considered valid.
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
If the cloud was successfully segmented, then function returns colored cloud.
std::vector< pcl::uindex_t > num_pts_in_segment_
Tells how much points each segment contains.
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.
std::vector< pcl::PointIndices > clusters_
After the segmentation it will contain the segments.
typename Normal::Ptr NormalPtr
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.
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.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
A point structure representing Euclidean xyz coordinates, and the RGBA color.
A point structure representing Euclidean xyz coordinates, and the RGB color.