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>
69template <
typename Po
intT,
typename NormalT>
79template <
typename Po
intT,
typename NormalT>
float
86template <
typename Po
intT,
typename NormalT>
void
93template <
typename Po
intT,
typename NormalT>
float
100template <
typename Po
intT,
typename NormalT>
void
107template <
typename Po
intT,
typename NormalT>
float
114template <
typename Po
intT,
typename NormalT>
void
121template <
typename Po
intT,
typename NormalT>
unsigned int
128template <
typename Po
intT,
typename NormalT>
void
135template <
typename Po
intT,
typename NormalT>
bool
142template <
typename Po
intT,
typename NormalT>
void
149template <
typename Po
intT,
typename NormalT>
void
156template <
typename Po
intT,
typename NormalT>
void
163template <
typename Po
intT,
typename NormalT>
void
178 if ( !segmentation_is_possible )
185 if ( !segmentation_is_possible )
198 std::vector<pcl::PointIndices>::iterator cluster_iter =
clusters_.begin ();
204 cluster_iter =
clusters_.erase (cluster_iter);
217template <
typename Po
intT,
typename NormalT>
bool
221 if (
input_->points.empty () )
262 PCL_ERROR (
"[pcl::RegionGrowingRGB::prepareForSegmentation] Empty given indices!\n");
272template <
typename Po
intT,
typename NormalT>
void
275 int point_number =
static_cast<int> (
indices_->size ());
282 for (
int i_point = 0; i_point < point_number; i_point++)
284 int point_index = (*indices_)[i_point];
294template <
typename Po
intT,
typename NormalT>
void
305 std::vector<float> dist;
313template <
typename Po
intT,
typename NormalT>
void
317 float max_dist = std::numeric_limits<float>::max ();
322 for (
pcl::uindex_t i_point = 0; i_point < number_of_points; i_point++)
324 const auto point_index =
clusters_[index].indices[i_point];
328 for (std::size_t i_nghbr = 0; i_nghbr < number_of_neighbours; i_nghbr++)
333 if ( segment_index != index )
342 std::priority_queue<std::pair<float, int> > segment_neighbours;
347 segment_neighbours.push (std::make_pair (
distances[i_seg], i_seg) );
348 if (segment_neighbours.size () > nghbr_number)
349 segment_neighbours.pop ();
353 const std::size_t size = std::min<std::size_t> (segment_neighbours.size (),
static_cast<std::size_t
>(nghbr_number));
354 nghbrs.resize (size, 0);
355 dist.resize (size, 0);
357 while ( !segment_neighbours.empty () && counter < nghbr_number )
359 dist[counter] = segment_neighbours.top ().first;
360 nghbrs[counter] = segment_neighbours.top ().second;
361 segment_neighbours.pop ();
367template <
typename Po
intT,
typename NormalT>
void
371 std::vector< std::vector<unsigned int> > segment_color;
372 std::vector<unsigned int> color;
376 for (
const auto& point_index : (*
indices_))
379 segment_color[segment_index][0] += (*input_)[point_index].r;
380 segment_color[segment_index][1] += (*input_)[point_index].g;
381 segment_color[segment_index][2] += (*input_)[point_index].b;
385 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]));
386 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]));
387 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]));
392 std::vector<unsigned int> num_pts_in_homogeneous_region;
393 std::vector<int> num_seg_in_homogeneous_region;
398 int homogeneous_region_number = 0;
401 int curr_homogeneous_region = 0;
405 curr_homogeneous_region = homogeneous_region_number;
407 num_seg_in_homogeneous_region.push_back (1);
408 homogeneous_region_number++;
413 unsigned int i_nghbr = 0;
429 num_seg_in_homogeneous_region[curr_homogeneous_region] += 1;
436 segment_color.clear ();
439 std::vector< std::vector<int> > final_segments;
440 std::vector<int> region;
441 final_segments.resize (homogeneous_region_number, region);
442 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
444 final_segments[i_reg].resize (num_seg_in_homogeneous_region[i_reg], 0);
447 std::vector<int> counter;
448 counter.resize (homogeneous_region_number, 0);
452 final_segments[ index ][ counter[index] ] = i_seg;
456 std::vector< std::vector< std::pair<float, pcl::index_t> > > region_neighbours;
459 int final_segment_number = homogeneous_region_number;
460 for (
int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
464 if ( region_neighbours[i_reg].empty () )
466 int nearest_neighbour = region_neighbours[i_reg][0].second;
467 if ( region_neighbours[i_reg][0].first == std::numeric_limits<float>::max () )
470 int num_seg_in_reg = num_seg_in_homogeneous_region[i_reg];
471 for (
int i_seg = 0; i_seg < num_seg_in_reg; i_seg++)
473 int segment_index = final_segments[i_reg][i_seg];
474 final_segments[reg_index].push_back (segment_index);
477 final_segments[i_reg].clear ();
478 num_pts_in_homogeneous_region[reg_index] += num_pts_in_homogeneous_region[i_reg];
479 num_pts_in_homogeneous_region[i_reg] = 0;
480 num_seg_in_homogeneous_region[reg_index] += num_seg_in_homogeneous_region[i_reg];
481 num_seg_in_homogeneous_region[i_reg] = 0;
482 final_segment_number -= 1;
484 for (
auto& nghbr : region_neighbours[reg_index])
488 nghbr.first = std::numeric_limits<float>::max ();
492 for (
const auto& nghbr : region_neighbours[i_reg])
496 region_neighbours[reg_index].push_back (nghbr);
499 region_neighbours[i_reg].clear ();
500 std::sort (region_neighbours[reg_index].begin (), region_neighbours[reg_index].end (),
comparePair);
504 assembleRegions (num_pts_in_homogeneous_region,
static_cast<int> (num_pts_in_homogeneous_region.size ()));
510template <
typename Po
intT,
typename NormalT>
float
513 float difference = 0.0f;
514 difference += float ((first_color[0] - second_color[0]) * (first_color[0] - second_color[0]));
515 difference += float ((first_color[1] - second_color[1]) * (first_color[1] - second_color[1]));
516 difference += float ((first_color[2] - second_color[2]) * (first_color[2] - second_color[2]));
521template <
typename Po
intT,
typename NormalT>
void
524 int region_number =
static_cast<int> (regions_in.size ());
525 neighbours_out.clear ();
526 neighbours_out.resize (region_number);
528 for (
int i_reg = 0; i_reg < region_number; i_reg++)
531 for (
const auto& curr_segment : regions_in[i_reg])
534 std::pair<float, pcl::index_t> pair;
535 for (std::size_t i_nghbr = 0; i_nghbr < nghbr_number; i_nghbr++)
538 if (
segment_distances_[curr_segment][i_nghbr] == std::numeric_limits<float>::max () )
543 pair.second = segment_index;
544 neighbours_out[i_reg].push_back (pair);
548 std::sort (neighbours_out[i_reg].begin (), neighbours_out[i_reg].end (),
comparePair);
553template <
typename Po
intT,
typename NormalT>
void
559 for (
int i_seg = 0; i_seg < num_regions; i_seg++)
561 clusters_[i_seg].indices.resize (num_pts_in_region[i_seg]);
564 std::vector<int> counter;
565 counter.resize (num_regions, 0);
566 for (
const auto& point_index : (*
indices_))
570 clusters_[index].indices[ counter[index] ] = point_index;
578 std::vector<pcl::PointIndices>::iterator itr1, itr2;
584 while (!(itr1->indices.empty ()) && itr1 < itr2)
586 while ( itr2->indices.empty () && itr1 < itr2)
590 itr1->indices.swap (itr2->indices);
593 if (itr2->indices.empty ())
598template <
typename Po
intT,
typename NormalT>
bool
604 std::vector<unsigned int> point_color;
605 point_color.resize (3, 0);
606 std::vector<unsigned int> nghbr_color;
607 nghbr_color.resize (3, 0);
608 point_color[0] = (*input_)[point].r;
609 point_color[1] = (*input_)[point].g;
610 point_color[2] = (*input_)[point].b;
611 nghbr_color[0] = (*input_)[nghbr].r;
612 nghbr_color[1] = (*input_)[nghbr].g;
613 nghbr_color[2] = (*input_)[nghbr].b;
624 data[0] = (*input_)[point].data[0];
625 data[1] = (*input_)[point].data[1];
626 data[2] = (*input_)[point].data[2];
627 data[3] = (*input_)[point].data[3];
629 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data));
630 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*
normals_)[point].normal));
633 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*
normals_)[nghbr].normal));
634 float dot_product = std::abs (nghbr_normal.dot (initial_normal));
635 if (dot_product < cosine_threshold)
640 Eigen::Map<Eigen::Vector3f> nghbr_normal (
static_cast<float*
> ((*
normals_)[nghbr].normal));
641 Eigen::Map<Eigen::Vector3f> initial_seed_normal (
static_cast<float*
> ((*
normals_)[initial_seed].normal));
642 float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
643 if (dot_product < cosine_threshold)
656 data_p[0] = (*input_)[point].data[0];
657 data_p[1] = (*input_)[point].data[1];
658 data_p[2] = (*input_)[point].data[2];
659 data_p[3] = (*input_)[point].data[3];
661 data_n[0] = (*input_)[nghbr].data[0];
662 data_n[1] = (*input_)[nghbr].data[1];
663 data_n[2] = (*input_)[nghbr].data[2];
664 data_n[3] = (*input_)[nghbr].data[3];
665 Eigen::Map<Eigen::Vector3f> nghbr_point (
static_cast<float*
> (data_n));
666 Eigen::Map<Eigen::Vector3f> initial_point (
static_cast<float*
> (data_p));
667 Eigen::Map<Eigen::Vector3f> initial_normal (
static_cast<float*
> ((*
normals_)[point].normal));
668 float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
677template <
typename Po
intT,
typename NormalT>
void
683 if ( !segmentation_is_possible )
690 bool point_was_found =
false;
691 for (
const auto& point : (*
indices_))
694 point_was_found =
true;
713 if ( !segmentation_is_possible )
730 const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
731 if (it != i_segment.indices.cend())
735 cluster.
indices.reserve (i_segment.indices.size ());
736 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.
~RegionGrowingRGB()
Destructor that frees memory.
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.
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.