Point Cloud Library (PCL)  1.14.1-dev
region_growing.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the copyright holder(s) nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Author : Sergey Ushakov
36  * Email : mine_all_mine@bk.ru
37  *
38  */
39 
40 #pragma once
41 
42 #include <pcl/segmentation/region_growing.h>
43 
44 #include <pcl/point_cloud.h>
45 #include <pcl/point_types.h>
46 #include <pcl/common/point_tests.h> // for pcl::isFinite
47 #include <pcl/console/print.h> // for PCL_ERROR
48 #include <pcl/search/search.h>
49 #include <pcl/search/kdtree.h>
50 
51 #include <queue>
52 #include <cmath>
53 #include <ctime>
54 
55 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56 template <typename PointT, typename NormalT>
58 
59 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
60 template <typename PointT, typename NormalT>
62 {
63  point_neighbours_.clear ();
64  point_labels_.clear ();
65  num_pts_in_segment_.clear ();
66  clusters_.clear ();
67 }
68 
69 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70 template <typename PointT, typename NormalT> pcl::uindex_t
72 {
73  return (min_pts_per_cluster_);
74 }
75 
76 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
77 template <typename PointT, typename NormalT> void
79 {
80  min_pts_per_cluster_ = min_cluster_size;
81 }
82 
83 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
84 template <typename PointT, typename NormalT> pcl::uindex_t
86 {
87  return (max_pts_per_cluster_);
88 }
89 
90 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
91 template <typename PointT, typename NormalT> void
93 {
94  max_pts_per_cluster_ = max_cluster_size;
95 }
96 
97 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
98 template <typename PointT, typename NormalT> bool
100 {
101  return (smooth_mode_flag_);
102 }
103 
104 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
105 template <typename PointT, typename NormalT> void
107 {
108  smooth_mode_flag_ = value;
109 }
110 
111 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112 template <typename PointT, typename NormalT> bool
114 {
115  return (curvature_flag_);
116 }
117 
118 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
119 template <typename PointT, typename NormalT> void
121 {
122  curvature_flag_ = value;
123 
124  if (!curvature_flag_ && !residual_flag_)
125  residual_flag_ = true;
126 }
127 
128 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129 template <typename PointT, typename NormalT> bool
131 {
132  return (residual_flag_);
133 }
134 
135 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136 template <typename PointT, typename NormalT> void
138 {
139  residual_flag_ = value;
140 
141  if (!curvature_flag_ && !residual_flag_)
142  curvature_flag_ = true;
143 }
144 
145 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
146 template <typename PointT, typename NormalT> float
148 {
149  return (theta_threshold_);
150 }
151 
152 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
153 template <typename PointT, typename NormalT> void
155 {
156  theta_threshold_ = theta;
157 }
158 
159 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 template <typename PointT, typename NormalT> float
162 {
163  return (residual_threshold_);
164 }
165 
166 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
167 template <typename PointT, typename NormalT> void
169 {
170  residual_threshold_ = residual;
171 }
172 
173 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
174 template <typename PointT, typename NormalT> float
176 {
177  return (curvature_threshold_);
178 }
179 
180 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
181 template <typename PointT, typename NormalT> void
183 {
184  curvature_threshold_ = curvature;
185 }
186 
187 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
188 template <typename PointT, typename NormalT> unsigned int
190 {
191  return (neighbour_number_);
192 }
193 
194 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195 template <typename PointT, typename NormalT> void
197 {
198  neighbour_number_ = neighbour_number;
199 }
200 
201 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
202 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::KdTreePtr
204 {
205  return (search_);
206 }
207 
208 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
209 template <typename PointT, typename NormalT> void
211 {
212  search_ = tree;
213 }
214 
215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
216 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::NormalPtr
218 {
219  return (normals_);
220 }
221 
222 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
223 template <typename PointT, typename NormalT> void
225 {
226  normals_ = norm;
227 }
228 
229 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
230 template <typename PointT, typename NormalT> void
231 pcl::RegionGrowing<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
232 {
233  clusters_.clear ();
234  clusters.clear ();
235  point_neighbours_.clear ();
236  point_labels_.clear ();
237  num_pts_in_segment_.clear ();
238  number_of_segments_ = 0;
239 
240  bool segmentation_is_possible = initCompute ();
241  if ( !segmentation_is_possible )
242  {
243  deinitCompute ();
244  return;
245  }
246 
247  segmentation_is_possible = prepareForSegmentation ();
248  if ( !segmentation_is_possible )
249  {
250  deinitCompute ();
251  return;
252  }
253 
254  findPointNeighbours ();
255  applySmoothRegionGrowingAlgorithm ();
256  assembleRegions ();
257 
258  clusters.resize (clusters_.size ());
259  auto cluster_iter_input = clusters.begin ();
260  for (const auto& cluster : clusters_)
261  {
262  if ((cluster.indices.size () >= min_pts_per_cluster_) &&
263  (cluster.indices.size () <= max_pts_per_cluster_))
264  {
265  *cluster_iter_input = cluster;
266  ++cluster_iter_input;
267  }
268  }
269 
270  clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
271  clusters.resize(clusters_.size());
272 
273  deinitCompute ();
274 }
275 
276 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
277 template <typename PointT, typename NormalT> bool
279 {
280  // if user forgot to pass point cloud or if it is empty
281  if ( input_->points.empty () )
282  return (false);
283 
284  // if user forgot to pass normals or the sizes of point and normal cloud are different
285  if ( !normals_ || input_->size () != normals_->size () )
286  return (false);
287 
288  // if residual test is on then we need to check if all needed parameters were correctly initialized
289  if (residual_flag_)
290  {
291  if (residual_threshold_ <= 0.0f)
292  return (false);
293  }
294 
295  // if curvature test is on ...
296  // if (curvature_flag_)
297  // {
298  // in this case we do not need to check anything that related to it
299  // so we simply commented it
300  // }
301 
302  // from here we check those parameters that are always valuable
303  if (neighbour_number_ == 0)
304  return (false);
305 
306  // if user didn't set search method
307  if (!search_)
308  search_.reset (new pcl::search::KdTree<PointT>);
309 
310  if (indices_)
311  {
312  if (indices_->empty ())
313  PCL_ERROR ("[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
314  search_->setInputCloud (input_, indices_);
315  }
316  else
317  search_->setInputCloud (input_);
318 
319  return (true);
320 }
321 
322 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
323 template <typename PointT, typename NormalT> void
325 {
326  pcl::Indices neighbours;
327  std::vector<float> distances;
328 
329  point_neighbours_.resize (input_->size (), neighbours);
330  if (input_->is_dense)
331  {
332  for (const auto& point_index: (*indices_))
333  {
334  neighbours.clear ();
335  search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
336  point_neighbours_[point_index].swap (neighbours);
337  }
338  }
339  else
340  {
341  for (const auto& point_index: (*indices_))
342  {
343  if (!pcl::isFinite ((*input_)[point_index]))
344  continue;
345  neighbours.clear ();
346  search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
347  point_neighbours_[point_index].swap (neighbours);
348  }
349  }
350 }
351 
352 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
353 template <typename PointT, typename NormalT> void
355 {
356  int num_of_pts = static_cast<int> (indices_->size ());
357  point_labels_.resize (input_->size (), -1);
358 
359  std::vector< std::pair<float, int> > point_residual;
360  std::pair<float, int> pair;
361  point_residual.resize (num_of_pts, pair);
362 
363  if (normal_flag_)
364  {
365  for (int i_point = 0; i_point < num_of_pts; i_point++)
366  {
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;
370  }
371  std::sort (point_residual.begin (), point_residual.end (), comparePair);
372  }
373  else
374  {
375  for (int i_point = 0; i_point < num_of_pts; i_point++)
376  {
377  const auto point_index = (*indices_)[i_point];
378  point_residual[i_point].first = 0;
379  point_residual[i_point].second = point_index;
380  }
381  }
382  int seed_counter = 0;
383  int seed = point_residual[seed_counter].second;
384 
385  int segmented_pts_num = 0;
386  int number_of_segments = 0;
387  while (segmented_pts_num < num_of_pts)
388  {
389  int pts_in_segment;
390  pts_in_segment = growRegion (seed, number_of_segments);
391  segmented_pts_num += pts_in_segment;
392  num_pts_in_segment_.push_back (pts_in_segment);
393  number_of_segments++;
394 
395  //find next point that is not segmented yet
396  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
397  {
398  int index = point_residual[i_seed].second;
399  if (point_labels_[index] == -1)
400  {
401  seed = index;
402  seed_counter = i_seed;
403  break;
404  }
405  }
406  }
407 }
408 
409 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
410 template <typename PointT, typename NormalT> int
411 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
412 {
413  std::queue<int> seeds;
414  seeds.push (initial_seed);
415  point_labels_[initial_seed] = segment_number;
416 
417  int num_pts_in_segment = 1;
418 
419  while (!seeds.empty ())
420  {
421  int curr_seed;
422  curr_seed = seeds.front ();
423  seeds.pop ();
424 
425  std::size_t i_nghbr = 0;
426  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
427  {
428  int index = point_neighbours_[curr_seed][i_nghbr];
429  if (point_labels_[index] != -1)
430  {
431  i_nghbr++;
432  continue;
433  }
434 
435  bool is_a_seed = false;
436  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
437 
438  if (!belongs_to_segment)
439  {
440  i_nghbr++;
441  continue;
442  }
443 
444  point_labels_[index] = segment_number;
445  num_pts_in_segment++;
446 
447  if (is_a_seed)
448  {
449  seeds.push (index);
450  }
451 
452  i_nghbr++;
453  }// next neighbour
454  }// next seed
455 
456  return (num_pts_in_segment);
457 }
458 
459 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
460 template <typename PointT, typename NormalT> bool
462 {
463  is_a_seed = true;
464 
465  float cosine_threshold = std::cos (theta_threshold_);
466  float data[4];
467 
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));
474 
475  //check the angle between normals
476  if (smooth_mode_flag_)
477  {
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)
481  {
482  return (false);
483  }
484  }
485  else
486  {
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)
491  return (false);
492  }
493 
494  // check the curvature if needed
495  if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
496  {
497  is_a_seed = false;
498  }
499 
500  // check the residual if needed
501  float data_1[4];
502 
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));
509  if (residual_flag_ && residual > residual_threshold_)
510  is_a_seed = false;
511 
512  return (true);
513 }
514 
515 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
516 template <typename PointT, typename NormalT> void
518 {
519  const auto number_of_segments = num_pts_in_segment_.size ();
520  const auto number_of_points = input_->size ();
521 
522  pcl::PointIndices segment;
523  clusters_.resize (number_of_segments, segment);
524 
525  for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
526  {
527  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
528  }
529 
530  std::vector<int> counter(number_of_segments, 0);
531 
532  for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
533  {
534  const auto segment_index = point_labels_[i_point];
535  if (segment_index != -1)
536  {
537  const auto point_index = counter[segment_index];
538  clusters_[segment_index].indices[point_index] = i_point;
539  counter[segment_index] = point_index + 1;
540  }
541  }
542 
543  number_of_segments_ = number_of_segments;
544 }
545 
546 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
547 template <typename PointT, typename NormalT> void
549 {
550  cluster.indices.clear ();
551 
552  bool segmentation_is_possible = initCompute ();
553  if ( !segmentation_is_possible )
554  {
555  deinitCompute ();
556  return;
557  }
558 
559  // first of all we need to find out if this point belongs to cloud
560  bool point_was_found = false;
561  for (const auto& point : (*indices_))
562  if (point == index)
563  {
564  point_was_found = true;
565  break;
566  }
567 
568  if (point_was_found)
569  {
570  if (clusters_.empty ())
571  {
572  point_neighbours_.clear ();
573  point_labels_.clear ();
574  num_pts_in_segment_.clear ();
575  number_of_segments_ = 0;
576 
577  segmentation_is_possible = prepareForSegmentation ();
578  if ( !segmentation_is_possible )
579  {
580  deinitCompute ();
581  return;
582  }
583 
584  findPointNeighbours ();
585  applySmoothRegionGrowingAlgorithm ();
586  assembleRegions ();
587  }
588  // if we have already made the segmentation, then find the segment
589  // to which this point belongs
590  for (const auto& i_segment : clusters_)
591  {
592  const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
593  if (it != i_segment.indices.cend())
594  {
595  // if segment was found
596  cluster.indices.clear ();
597  cluster.indices.reserve (i_segment.indices.size ());
598  std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.indices));
599  break;
600  }
601  }// next segment
602  }// end if point was found
603 
604  deinitCompute ();
605 }
606 
607 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
608 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
610 {
612 
613  if (!clusters_.empty ())
614  {
615  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
616 
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++)
620  {
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));
624  }
625 
626  colored_cloud->width = input_->width;
627  colored_cloud->height = input_->height;
628  colored_cloud->is_dense = input_->is_dense;
629  for (const auto& i_point: *input_)
630  {
631  pcl::PointXYZRGB point;
632  point.x = *(i_point.data);
633  point.y = *(i_point.data + 1);
634  point.z = *(i_point.data + 2);
635  point.r = 255;
636  point.g = 0;
637  point.b = 0;
638  colored_cloud->points.push_back (point);
639  }
640 
641  int next_color = 0;
642  for (const auto& i_segment : clusters_)
643  {
644  for (const auto& index : (i_segment.indices))
645  {
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];
649  }
650  next_color++;
651  }
652  }
653 
654  return (colored_cloud);
655 }
656 
657 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
658 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
660 {
662 
663  if (!clusters_.empty ())
664  {
665  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGBA>);
666 
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++)
670  {
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));
674  }
675 
676  colored_cloud->width = input_->width;
677  colored_cloud->height = input_->height;
678  colored_cloud->is_dense = input_->is_dense;
679  for (const auto& i_point: *input_)
680  {
681  pcl::PointXYZRGBA point;
682  point.x = *(i_point.data);
683  point.y = *(i_point.data + 1);
684  point.z = *(i_point.data + 2);
685  point.r = 255;
686  point.g = 0;
687  point.b = 0;
688  point.a = 0;
689  colored_cloud->points.push_back (point);
690  }
691 
692  int next_color = 0;
693  for (const auto& i_segment : clusters_)
694  {
695  for (const auto& index : (i_segment.indices))
696  {
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];
700  }
701  next_color++;
702  }
703  }
704 
705  return (colored_cloud);
706 }
707 
708 #define PCL_INSTANTIATE_RegionGrowing(T) template class PCL_EXPORTS pcl::RegionGrowing<T, pcl::Normal>;
709 
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
Definition: point_cloud.h:403
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:398
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:400
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:413
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:395
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.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
Definition: kdtree.h:62
Defines all the PCL implemented PointT point type structures.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
Definition: types.h:120
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...
Definition: point_tests.h:55
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition: types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition: types.h:133
A point structure representing Euclidean xyz coordinates, and the RGBA color.
A point structure representing Euclidean xyz coordinates, and the RGB color.