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/kdtree.h>
51template <
typename Po
intT,
typename NormalT>
65template <
typename Po
intT,
typename NormalT>
75template <
typename Po
intT,
typename NormalT>
float
82template <
typename Po
intT,
typename NormalT>
void
89template <
typename Po
intT,
typename NormalT>
float
96template <
typename Po
intT,
typename NormalT>
void
103template <
typename Po
intT,
typename NormalT>
float
110template <
typename Po
intT,
typename NormalT>
void
117template <
typename Po
intT,
typename NormalT>
unsigned int
124template <
typename Po
intT,
typename NormalT>
void
131template <
typename Po
intT,
typename NormalT>
bool
138template <
typename Po
intT,
typename NormalT>
void
145template <
typename Po
intT,
typename NormalT>
void
152template <
typename Po
intT,
typename NormalT>
void
159template <
typename Po
intT,
typename NormalT>
void
174 if ( !segmentation_is_possible )
181 if ( !segmentation_is_possible )
200 cluster_iter =
clusters_.erase (cluster_iter);
213template <
typename Po
intT,
typename NormalT>
bool
217 if (
input_->points.empty () )
258 PCL_ERROR (
"[pcl::RegionGrowingRGB::prepareForSegmentation] Empty given indices!\n");
268template <
typename Po
intT,
typename NormalT>
void
277 for (
const auto& point_index: (*
indices_))
288template <
typename Po
intT,
typename NormalT>
void
299 std::vector<float> dist;
307template <
typename Po
intT,
typename NormalT>
void
311 float max_dist = std::numeric_limits<float>::max ();
316 for (
pcl::uindex_t i_point = 0; i_point < number_of_points; i_point++)
318 const auto point_index =
clusters_[index].indices[i_point];
322 for (std::size_t i_nghbr = 0; i_nghbr < number_of_neighbours; i_nghbr++)
327 if ( segment_index != index )
336 std::priority_queue<std::pair<float, int> > segment_neighbours;
341 segment_neighbours.emplace (
distances[i_seg], i_seg);
342 if (segment_neighbours.size () > nghbr_number)
343 segment_neighbours.pop ();
347 const std::size_t size = std::min<std::size_t> (segment_neighbours.size (),
static_cast<std::size_t
>(nghbr_number));
348 nghbrs.resize (size, 0);
349 dist.resize (size, 0);
351 while ( !segment_neighbours.empty () && counter < nghbr_number )
353 dist[counter] = segment_neighbours.top ().first;
354 nghbrs[counter] = segment_neighbours.top ().second;
355 segment_neighbours.pop ();
361template <
typename Po
intT,
typename NormalT>
void
365 std::vector< std::vector<unsigned int> > segment_color;
366 std::vector<unsigned int> color;
370 for (
const auto& point_index : (*
indices_))
373 segment_color[segment_index][0] += (*input_)[point_index].r;
374 segment_color[segment_index][1] += (*input_)[point_index].g;
375 segment_color[segment_index][2] += (*input_)[point_index].b;
379 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]));
380 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]));
381 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]));
386 std::vector<unsigned int> num_pts_in_homogeneous_region;
387 std::vector<int> num_seg_in_homogeneous_region;
392 int homogeneous_region_number = 0;
395 int curr_homogeneous_region = 0;
399 curr_homogeneous_region = homogeneous_region_number;
401 num_seg_in_homogeneous_region.push_back (1);
402 homogeneous_region_number++;
407 unsigned int i_nghbr = 0;
423 num_seg_in_homogeneous_region[curr_homogeneous_region] += 1;
430 segment_color.clear ();
433 std::vector< std::vector<int> > final_segments;
434 std::vector<int> region;
435 final_segments.resize (homogeneous_region_number, region);
436 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
438 final_segments[i_reg].resize (num_seg_in_homogeneous_region[i_reg], 0);
441 std::vector<int> counter;
442 counter.resize (homogeneous_region_number, 0);
446 final_segments[ index ][ counter[index] ] = i_seg;
450 std::vector< std::vector< std::pair<float, pcl::index_t> > > region_neighbours;
453 int final_segment_number = homogeneous_region_number;
454 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
458 if ( region_neighbours[i_reg].empty () )
460 int nearest_neighbour = region_neighbours[i_reg][0].second;
461 if ( region_neighbours[i_reg][0].first == std::numeric_limits<float>::max () )
464 int num_seg_in_reg = num_seg_in_homogeneous_region[i_reg];
465 for (
int i_seg = 0; i_seg < num_seg_in_reg; i_seg++)
467 int segment_index = final_segments[i_reg][i_seg];
468 final_segments[reg_index].push_back (segment_index);
471 final_segments[i_reg].clear ();
472 num_pts_in_homogeneous_region[reg_index] += num_pts_in_homogeneous_region[i_reg];
473 num_pts_in_homogeneous_region[i_reg] = 0;
474 num_seg_in_homogeneous_region[reg_index] += num_seg_in_homogeneous_region[i_reg];
475 num_seg_in_homogeneous_region[i_reg] = 0;
476 final_segment_number -= 1;
478 for (
auto& nghbr : region_neighbours[reg_index])
482 nghbr.first = std::numeric_limits<float>::max ();
486 for (
const auto& nghbr : region_neighbours[i_reg])
490 region_neighbours[reg_index].push_back (nghbr);
493 region_neighbours[i_reg].clear ();
494 std::sort (region_neighbours[reg_index].begin (), region_neighbours[reg_index].end (),
comparePair);
498 assembleRegions (num_pts_in_homogeneous_region,
static_cast<int> (num_pts_in_homogeneous_region.size ()));
504template <
typename Po
intT,
typename NormalT>
float
507 float difference = 0.0f;
508 difference +=
static_cast<float>((first_color[0] - second_color[0]) * (first_color[0] - second_color[0]));
509 difference +=
static_cast<float>((first_color[1] - second_color[1]) * (first_color[1] - second_color[1]));
510 difference +=
static_cast<float>((first_color[2] - second_color[2]) * (first_color[2] - second_color[2]));
515template <
typename Po
intT,
typename NormalT>
void
518 int region_number =
static_cast<int> (regions_in.size ());
519 neighbours_out.clear ();
520 neighbours_out.resize (region_number);
522 for (
int i_reg = 0; i_reg < region_number; i_reg++)
525 for (
const auto& curr_segment : regions_in[i_reg])
528 std::pair<float, pcl::index_t> pair;
529 for (std::size_t i_nghbr = 0; i_nghbr < nghbr_number; i_nghbr++)
532 if (
segment_distances_[curr_segment][i_nghbr] == std::numeric_limits<float>::max () )
537 pair.second = segment_index;
538 neighbours_out[i_reg].push_back (pair);
542 std::sort (neighbours_out[i_reg].begin (), neighbours_out[i_reg].end (),
comparePair);
547template <
typename Po
intT,
typename NormalT>
void
553 for (
int i_seg = 0; i_seg < num_regions; i_seg++)
555 clusters_[i_seg].indices.resize (num_pts_in_region[i_seg]);
558 std::vector<int> counter;
559 counter.resize (num_regions, 0);
560 for (
const auto& point_index : (*
indices_))
564 clusters_[index].indices[ counter[index] ] = point_index;
572 std::vector<pcl::PointIndices>::iterator itr1, itr2;
578 while (!(itr1->indices.empty ()) && itr1 < itr2)
580 while ( itr2->indices.empty () && itr1 < itr2)
584 itr1->indices.swap (itr2->indices);
587 if (itr2->indices.empty ())
592template <
typename Po
intT,
typename NormalT>
bool
598 std::vector<unsigned int> point_color;
599 point_color.resize (3, 0);
600 std::vector<unsigned int> nghbr_color;
601 nghbr_color.resize (3, 0);
602 point_color[0] = (*input_)[point].r;
603 point_color[1] = (*input_)[point].g;
604 point_color[2] = (*input_)[point].b;
605 nghbr_color[0] = (*input_)[nghbr].r;
606 nghbr_color[1] = (*input_)[nghbr].g;
607 nghbr_color[2] = (*input_)[nghbr].b;
618 data[0] = (*input_)[point].data[0];
619 data[1] = (*input_)[point].data[1];
620 data[2] = (*input_)[point].data[2];
621 data[3] = (*input_)[point].data[3];
623 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data));
624 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*
normals_)[point].normal));
627 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*
normals_)[nghbr].normal));
628 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
629 if (dot_product < cosine_threshold)
634 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*
normals_)[nghbr].normal));
635 Eigen::Map<Eigen::Vector3f> initial_seed_normal (
static_cast<float*
> ((*
normals_)[initial_seed].normal));
636 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
637 if (dot_product < cosine_threshold)
650 data_p[0] = (*input_)[point].data[0];
651 data_p[1] = (*input_)[point].data[1];
652 data_p[2] = (*input_)[point].data[2];
653 data_p[3] = (*input_)[point].data[3];
655 data_n[0] = (*input_)[nghbr].data[0];
656 data_n[1] = (*input_)[nghbr].data[1];
657 data_n[2] = (*input_)[nghbr].data[2];
658 data_n[3] = (*input_)[nghbr].data[3];
659 Eigen::Map<Eigen::Vector3f> nghbr_point (
static_cast<float*
> (data_n));
660 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data_p));
661 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*
normals_)[point].normal));
662 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
671template <
typename Po
intT,
typename NormalT>
void
677 if ( !segmentation_is_possible )
684 bool point_was_found =
false;
685 for (
const auto& point : (*
indices_))
688 point_was_found =
true;
707 if ( !segmentation_is_possible )
724 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
725 if (it != i_segment.indices.cend())
729 cluster.
indices.reserve (i_segment.indices.size ());
730 std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.
indices));
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.
std::vector< int > point_labels_
float curvature_threshold_
unsigned int neighbour_number_
pcl::uindex_t max_pts_per_cluster_
float residual_threshold_
std::vector< pcl::Indices > point_neighbours_
void applySmoothRegionGrowingAlgorithm()
pcl::uindex_t min_pts_per_cluster_
std::vector< pcl::uindex_t > num_pts_in_segment_
std::vector< pcl::PointIndices > clusters_
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...
std::vector< std::vector< float > > point_distances_
Stores distances for the point neighbours from point_neighbours_.
std::vector< pcl::Indices > segment_neighbours_
Stores the neighboures for the corresponding segments.
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.
float color_r2r_threshold_
Thershold used in color test for regions.
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...
float distance_threshold_
Threshold that tells which points we need to assume neighbouring.
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.
std::vector< std::vector< float > > segment_distances_
Stores distances for the segment neighbours from segment_neighbours_.
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.
unsigned int region_neighbour_number_
Number of neighbouring segments to find.
float color_p2p_threshold_
Thershold used in color test for points.
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 ...
std::vector< int > segment_labels_
Stores new indices for segments that were obtained at the region growing stage.
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.
void assembleRegions(std::vector< unsigned int > &num_pts_in_region, int num_regions)
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...
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.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.