40 #ifndef PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
41 #define PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
43 #include <pcl/console/print.h>
44 #include <pcl/segmentation/region_growing_rgb.h>
45 #include <pcl/search/search.h>
46 #include <pcl/search/auto.h>
51 template <
typename Po
intT,
typename NormalT>
54 segment_neighbours_ (0),
55 segment_distances_ (0),
65 template <
typename Po
intT,
typename NormalT>
68 point_distances_.clear ();
69 segment_neighbours_.clear ();
70 segment_distances_.clear ();
71 segment_labels_.clear ();
75 template <
typename Po
intT,
typename NormalT>
float
78 return (powf (color_p2p_threshold_, 0.5f));
82 template <
typename Po
intT,
typename NormalT>
void
85 color_p2p_threshold_ = thresh * thresh;
89 template <
typename Po
intT,
typename NormalT>
float
92 return (powf (color_r2r_threshold_, 0.5f));
96 template <
typename Po
intT,
typename NormalT>
void
99 color_r2r_threshold_ = thresh * thresh;
103 template <
typename Po
intT,
typename NormalT>
float
106 return (powf (distance_threshold_, 0.5f));
110 template <
typename Po
intT,
typename NormalT>
void
113 distance_threshold_ = thresh * thresh;
117 template <
typename Po
intT,
typename NormalT>
unsigned int
120 return (region_neighbour_number_);
124 template <
typename Po
intT,
typename NormalT>
void
127 region_neighbour_number_ = nghbr_number;
131 template <
typename Po
intT,
typename NormalT>
bool
134 return (normal_flag_);
138 template <
typename Po
intT,
typename NormalT>
void
141 normal_flag_ = value;
145 template <
typename Po
intT,
typename NormalT>
void
148 curvature_flag_ = value;
152 template <
typename Po
intT,
typename NormalT>
void
155 residual_flag_ = value;
159 template <
typename Po
intT,
typename NormalT>
void
164 point_neighbours_.clear ();
165 point_labels_.clear ();
166 num_pts_in_segment_.clear ();
167 point_distances_.clear ();
168 segment_neighbours_.clear ();
169 segment_distances_.clear ();
170 segment_labels_.clear ();
171 number_of_segments_ = 0;
173 bool segmentation_is_possible = initCompute ();
174 if ( !segmentation_is_possible )
180 segmentation_is_possible = prepareForSegmentation ();
181 if ( !segmentation_is_possible )
187 findPointNeighbours ();
188 applySmoothRegionGrowingAlgorithm ();
191 findSegmentNeighbours ();
192 applyRegionMergingAlgorithm ();
194 auto cluster_iter = clusters_.begin ();
195 while (cluster_iter != clusters_.end ())
197 if (cluster_iter->indices.size () < min_pts_per_cluster_ ||
198 cluster_iter->indices.size () > max_pts_per_cluster_)
200 cluster_iter = clusters_.erase (cluster_iter);
206 clusters.reserve (clusters_.size ());
207 std::copy (clusters_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
213 template <
typename Po
intT,
typename NormalT>
bool
217 if ( input_->points.empty () )
225 if ( !normals_ || input_->size () != normals_->size () )
232 if (residual_threshold_ <= 0.0f)
244 if ( region_neighbour_number_ == 0 || color_p2p_threshold_ < 0.0f || color_r2r_threshold_ < 0.0f || distance_threshold_ < 0.0f )
248 if (neighbour_number_ == 0)
253 if (indices_->empty ())
254 PCL_ERROR (
"[pcl::RegionGrowingRGB::prepareForSegmentation] Empty given indices!\n");
258 search_->setInputCloud (input_, indices_);
265 search_->setInputCloud (input_);
272 template <
typename Po
intT,
typename NormalT>
void
276 std::vector<float> distances;
278 point_neighbours_.resize (input_->size (), neighbours);
279 point_distances_.resize (input_->size (), distances);
281 for (
const auto& point_index: (*indices_))
285 search_->nearestKSearch ((*input_)[point_index], region_neighbour_number_, neighbours, distances);
286 point_neighbours_[point_index].swap (neighbours);
287 point_distances_[point_index].swap (distances);
292 template <
typename Po
intT,
typename NormalT>
void
296 std::vector<float> distances;
297 segment_neighbours_.resize (number_of_segments_, neighbours);
298 segment_distances_.resize (number_of_segments_, distances);
300 for (
int i_seg = 0; i_seg < number_of_segments_; i_seg++)
303 std::vector<float> dist;
304 findRegionsKNN (i_seg, region_neighbour_number_, nghbrs, dist);
305 segment_neighbours_[i_seg].swap (nghbrs);
306 segment_distances_[i_seg].swap (dist);
311 template <
typename Po
intT,
typename NormalT>
void
314 std::vector<float> distances;
315 float max_dist = std::numeric_limits<float>::max ();
316 distances.resize (clusters_.size (), max_dist);
318 const auto number_of_points = num_pts_in_segment_[index];
320 for (
pcl::uindex_t i_point = 0; i_point < number_of_points; i_point++)
322 const auto point_index = clusters_[index].indices[i_point];
323 const auto number_of_neighbours = point_neighbours_[point_index].size ();
326 for (std::size_t i_nghbr = 0; i_nghbr < number_of_neighbours; i_nghbr++)
329 const pcl::index_t segment_index = point_labels_[ point_neighbours_[point_index][i_nghbr] ];
331 if ( segment_index != index )
334 if (distances[segment_index] > point_distances_[point_index][i_nghbr])
335 distances[segment_index] = point_distances_[point_index][i_nghbr];
340 std::priority_queue<std::pair<float, int> > segment_neighbours;
341 for (
int i_seg = 0; i_seg < number_of_segments_; i_seg++)
343 if (distances[i_seg] < max_dist)
345 segment_neighbours.emplace (distances[i_seg], i_seg);
346 if (segment_neighbours.size () > nghbr_number)
347 segment_neighbours.pop ();
351 const std::size_t size = std::min<std::size_t> (segment_neighbours.size (),
static_cast<std::size_t
>(nghbr_number));
352 nghbrs.resize (size, 0);
353 dist.resize (size, 0);
355 while ( !segment_neighbours.empty () && counter < nghbr_number )
357 dist[counter] = segment_neighbours.top ().first;
358 nghbrs[counter] = segment_neighbours.top ().second;
359 segment_neighbours.pop ();
365 template <
typename Po
intT,
typename NormalT>
void
369 std::vector< std::vector<unsigned int> > segment_color;
370 std::vector<unsigned int> color;
372 segment_color.resize (number_of_segments_, color);
374 for (
const auto& point_index : (*indices_))
376 int segment_index = point_labels_[point_index];
377 segment_color[segment_index][0] += (*input_)[point_index].r;
378 segment_color[segment_index][1] += (*input_)[point_index].g;
379 segment_color[segment_index][2] += (*input_)[point_index].b;
381 for (
int i_seg = 0; i_seg < number_of_segments_; i_seg++)
383 segment_color[i_seg][0] =
static_cast<unsigned int> (
static_cast<float> (segment_color[i_seg][0]) /
static_cast<float> (num_pts_in_segment_[i_seg]));
384 segment_color[i_seg][1] =
static_cast<unsigned int> (
static_cast<float> (segment_color[i_seg][1]) /
static_cast<float> (num_pts_in_segment_[i_seg]));
385 segment_color[i_seg][2] =
static_cast<unsigned int> (
static_cast<float> (segment_color[i_seg][2]) /
static_cast<float> (num_pts_in_segment_[i_seg]));
390 std::vector<unsigned int> num_pts_in_homogeneous_region;
391 std::vector<int> num_seg_in_homogeneous_region;
393 segment_labels_.resize (number_of_segments_, -1);
395 float dist_thresh = distance_threshold_;
396 int homogeneous_region_number = 0;
397 for (
int i_seg = 0; i_seg < number_of_segments_; i_seg++)
399 int curr_homogeneous_region = 0;
400 if (segment_labels_[i_seg] == -1)
402 segment_labels_[i_seg] = homogeneous_region_number;
403 curr_homogeneous_region = homogeneous_region_number;
404 num_pts_in_homogeneous_region.push_back (num_pts_in_segment_[i_seg]);
405 num_seg_in_homogeneous_region.push_back (1);
406 homogeneous_region_number++;
409 curr_homogeneous_region = segment_labels_[i_seg];
411 unsigned int i_nghbr = 0;
412 while ( i_nghbr < region_neighbour_number_ && i_nghbr < segment_neighbours_[i_seg].size () )
414 int index = segment_neighbours_[i_seg][i_nghbr];
415 if (segment_distances_[i_seg][i_nghbr] > dist_thresh)
420 if ( segment_labels_[index] == -1 )
422 float difference = calculateColorimetricalDifference (segment_color[i_seg], segment_color[index]);
423 if (difference < color_r2r_threshold_)
425 segment_labels_[index] = curr_homogeneous_region;
426 num_pts_in_homogeneous_region[curr_homogeneous_region] += num_pts_in_segment_[index];
427 num_seg_in_homogeneous_region[curr_homogeneous_region] += 1;
434 segment_color.clear ();
437 std::vector< std::vector<int> > final_segments;
438 std::vector<int> region;
439 final_segments.resize (homogeneous_region_number, region);
440 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
442 final_segments[i_reg].resize (num_seg_in_homogeneous_region[i_reg], 0);
445 std::vector<int> counter;
446 counter.resize (homogeneous_region_number, 0);
447 for (
int i_seg = 0; i_seg < number_of_segments_; i_seg++)
449 int index = segment_labels_[i_seg];
450 final_segments[ index ][ counter[index] ] = i_seg;
454 std::vector< std::vector< std::pair<float, pcl::index_t> > > region_neighbours;
455 findRegionNeighbours (region_neighbours, final_segments);
457 int final_segment_number = homogeneous_region_number;
458 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
460 if (num_pts_in_homogeneous_region[i_reg] < min_pts_per_cluster_)
462 if ( region_neighbours[i_reg].empty () )
464 int nearest_neighbour = region_neighbours[i_reg][0].second;
465 if ( region_neighbours[i_reg][0].first == std::numeric_limits<float>::max () )
467 int reg_index = segment_labels_[nearest_neighbour];
468 int num_seg_in_reg = num_seg_in_homogeneous_region[i_reg];
469 for (
int i_seg = 0; i_seg < num_seg_in_reg; i_seg++)
471 int segment_index = final_segments[i_reg][i_seg];
472 final_segments[reg_index].push_back (segment_index);
473 segment_labels_[segment_index] = reg_index;
475 final_segments[i_reg].clear ();
476 num_pts_in_homogeneous_region[reg_index] += num_pts_in_homogeneous_region[i_reg];
477 num_pts_in_homogeneous_region[i_reg] = 0;
478 num_seg_in_homogeneous_region[reg_index] += num_seg_in_homogeneous_region[i_reg];
479 num_seg_in_homogeneous_region[i_reg] = 0;
480 final_segment_number -= 1;
482 const auto filtered_region_neighbours_reg_index_end = std::remove_if (
483 region_neighbours[reg_index].begin (),
484 region_neighbours[reg_index].end (),
485 [
this, reg_index] (
const auto& nghbr) {
return segment_labels_[ nghbr.second ] == reg_index; });
486 const auto filtered_region_neighbours_reg_index_size =
std::distance (
487 region_neighbours[reg_index].begin (), filtered_region_neighbours_reg_index_end);
488 region_neighbours[reg_index].resize (filtered_region_neighbours_reg_index_size);
490 for (
const auto& nghbr : region_neighbours[i_reg])
492 if ( segment_labels_[ nghbr.second ] != reg_index )
494 region_neighbours[reg_index].push_back (nghbr);
497 region_neighbours[i_reg].clear ();
499 region_neighbours[reg_index].begin (),
500 std::next (region_neighbours[reg_index].begin (), filtered_region_neighbours_reg_index_size),
501 region_neighbours[reg_index].end (),
506 assembleRegions (num_pts_in_homogeneous_region,
static_cast<int> (num_pts_in_homogeneous_region.size ()));
508 number_of_segments_ = final_segment_number;
512 template <
typename Po
intT,
typename NormalT>
float
515 float difference = 0.0f;
516 difference +=
static_cast<float>((first_color[0] - second_color[0]) * (first_color[0] - second_color[0]));
517 difference +=
static_cast<float>((first_color[1] - second_color[1]) * (first_color[1] - second_color[1]));
518 difference +=
static_cast<float>((first_color[2] - second_color[2]) * (first_color[2] - second_color[2]));
523 template <
typename Po
intT,
typename NormalT>
void
526 int region_number =
static_cast<int> (regions_in.size ());
527 neighbours_out.clear ();
528 neighbours_out.resize (region_number);
530 for (
int i_reg = 0; i_reg < region_number; i_reg++)
532 neighbours_out[i_reg].reserve (regions_in[i_reg].size () * region_neighbour_number_);
533 for (
const auto& curr_segment : regions_in[i_reg])
535 const std::size_t nghbr_number = segment_neighbours_[curr_segment].size ();
536 std::pair<float, pcl::index_t> pair;
537 for (std::size_t i_nghbr = 0; i_nghbr < nghbr_number; i_nghbr++)
539 const auto segment_index = segment_neighbours_[curr_segment][i_nghbr];
540 if ( segment_distances_[curr_segment][i_nghbr] == std::numeric_limits<float>::max () )
542 if (segment_labels_[segment_index] != i_reg)
544 pair.first = segment_distances_[curr_segment][i_nghbr];
545 pair.second = segment_index;
546 neighbours_out[i_reg].push_back (pair);
550 std::sort (neighbours_out[i_reg].begin (), neighbours_out[i_reg].end (),
comparePair);
555 template <
typename Po
intT,
typename NormalT>
void
560 clusters_.resize (num_regions, segment);
561 for (
int i_seg = 0; i_seg < num_regions; i_seg++)
563 clusters_[i_seg].
indices.resize (num_pts_in_region[i_seg]);
566 std::vector<int> counter;
567 counter.resize (num_regions, 0);
568 for (
const auto& point_index : (*indices_))
570 int index = point_labels_[point_index];
571 index = segment_labels_[index];
572 clusters_[index].indices[ counter[index] ] = point_index;
577 if (clusters_.empty ())
580 std::vector<pcl::PointIndices>::iterator itr1, itr2;
581 itr1 = clusters_.begin ();
582 itr2 = clusters_.end () - 1;
586 while (!(itr1->indices.empty ()) && itr1 < itr2)
588 while ( itr2->indices.empty () && itr1 < itr2)
592 itr1->indices.swap (itr2->indices);
595 if (itr2->indices.empty ())
596 clusters_.erase (itr2, clusters_.end ());
600 template <
typename Po
intT,
typename NormalT>
bool
606 std::vector<unsigned int> point_color;
607 point_color.resize (3, 0);
608 std::vector<unsigned int> nghbr_color;
609 nghbr_color.resize (3, 0);
610 point_color[0] = (*input_)[point].r;
611 point_color[1] = (*input_)[point].g;
612 point_color[2] = (*input_)[point].b;
613 nghbr_color[0] = (*input_)[nghbr].r;
614 nghbr_color[1] = (*input_)[nghbr].g;
615 nghbr_color[2] = (*input_)[nghbr].b;
616 float difference = calculateColorimetricalDifference (point_color, nghbr_color);
617 if (difference > color_p2p_threshold_)
620 float cosine_threshold = std::cos (theta_threshold_);
626 data[0] = (*input_)[point].data[0];
627 data[1] = (*input_)[point].data[1];
628 data[2] = (*input_)[point].data[2];
629 data[3] = (*input_)[point].data[3];
631 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data));
632 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*normals_)[point].normal));
633 if (smooth_mode_flag_ ==
true)
635 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
636 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
637 if (dot_product < cosine_threshold)
642 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*normals_)[nghbr].normal));
643 Eigen::Map<Eigen::Vector3f> initial_seed_normal (
static_cast<float*
> ((*normals_)[initial_seed].normal));
644 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
645 if (dot_product < cosine_threshold)
651 if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
658 data_p[0] = (*input_)[point].data[0];
659 data_p[1] = (*input_)[point].data[1];
660 data_p[2] = (*input_)[point].data[2];
661 data_p[3] = (*input_)[point].data[3];
663 data_n[0] = (*input_)[nghbr].data[0];
664 data_n[1] = (*input_)[nghbr].data[1];
665 data_n[2] = (*input_)[nghbr].data[2];
666 data_n[3] = (*input_)[nghbr].data[3];
667 Eigen::Map<Eigen::Vector3f> nghbr_point (
static_cast<float*
> (data_n));
668 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data_p));
669 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*normals_)[point].normal));
670 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
671 if (residual > residual_threshold_)
679 template <
typename Po
intT,
typename NormalT>
void
684 bool segmentation_is_possible = initCompute ();
685 if ( !segmentation_is_possible )
692 bool point_was_found =
false;
693 for (
const auto& point : (*indices_))
696 point_was_found =
true;
702 if (clusters_.empty ())
705 point_neighbours_.clear ();
706 point_labels_.clear ();
707 num_pts_in_segment_.clear ();
708 point_distances_.clear ();
709 segment_neighbours_.clear ();
710 segment_distances_.clear ();
711 segment_labels_.clear ();
712 number_of_segments_ = 0;
714 segmentation_is_possible = prepareForSegmentation ();
715 if ( !segmentation_is_possible )
721 findPointNeighbours ();
722 applySmoothRegionGrowingAlgorithm ();
725 findSegmentNeighbours ();
726 applyRegionMergingAlgorithm ();
730 for (
const auto& i_segment : clusters_)
732 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
733 if (it != i_segment.indices.cend())
737 cluster.
indices.reserve (i_segment.indices.size ());
738 std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.
indices));
bool curvature_flag_
If set to true then curvature test will be done during segmentation.
bool normal_flag_
If set to true then normal/smoothness test will be done during segmentation.
bool residual_flag_
If set to true then residual test will be done during segmentation.
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.
void assembleRegions()
This function simply assembles the regions from list of point labels.
void getSegmentFromPoint(index_t index, pcl::PointIndices &cluster) override
For a given point this function builds a segment to which it belongs and returns this segment.
void setDistanceThreshold(float thresh)
Allows to set distance threshold.
void setRegionColorThreshold(float thresh)
This method specifies the threshold value for color test between the regions.
float getPointColorThreshold() const
Returns the color threshold value used for testing if points belong to the same region.
bool prepareForSegmentation() override
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
void findRegionNeighbours(std::vector< std::vector< std::pair< float, pcl::index_t > > > &neighbours_out, std::vector< std::vector< int > > ®ions_in)
This method assembles the array containing neighbours of each homogeneous region.
void applyRegionMergingAlgorithm()
This function implements the merging algorithm described in the article "Color-based segmentation of ...
unsigned int getNumberOfRegionNeighbours() const
Returns the number of nearest neighbours used for searching K nearest segments.
void setCurvatureTestFlag(bool value) override
Allows to turn on/off the curvature test.
void extract(std::vector< pcl::PointIndices > &clusters) override
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
void setNormalTestFlag(bool value)
Allows to turn on/off the smoothness test.
void setNumberOfRegionNeighbours(unsigned int nghbr_number)
This method allows to set the number of neighbours that is used for finding neighbouring segments.
float calculateColorimetricalDifference(std::vector< unsigned int > &first_color, std::vector< unsigned int > &second_color) const
This method calculates the colorimetrical difference between two points.
float getDistanceThreshold() const
Returns the distance threshold.
bool getNormalTestFlag() const
Returns the flag that signalize if the smoothness test is turned on/off.
void findRegionsKNN(pcl::index_t index, pcl::uindex_t nghbr_number, Indices &nghbrs, std::vector< float > &dist)
This method finds K nearest neighbours of the given segment.
RegionGrowingRGB()
Constructor that sets default values for member variables.
void setResidualTestFlag(bool value) override
Allows to turn on/off the residual test.
~RegionGrowingRGB() override
Destructor that frees memory.
void findPointNeighbours() override
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
float getRegionColorThreshold() const
Returns the color threshold value used for testing if regions can be merged.
void findSegmentNeighbours()
This method simply calls the findRegionsKNN for each segment and saves the results for later use.
void setPointColorThreshold(float thresh)
This method specifies the threshold value for color test between the points.
bool validatePoint(index_t initial_seed, index_t point, index_t nghbr, bool &is_a_seed) const override
This function is checking if the point with index 'nghbr' belongs to the segment.
float distance(const PointT &p1, const PointT &p2)
@ 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.
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.