Point Cloud Library (PCL)  1.15.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/auto.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 (indices_)
307  {
308  if (indices_->empty ())
309  PCL_ERROR ("[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
310  if (!search_)
311  search_.reset (pcl::search::autoSelectMethod<PointT>(input_, indices_, true, pcl::search::Purpose::many_knn_search));
312  else
313  search_->setInputCloud (input_, indices_);
314  }
315  else
316  {
317  if (!search_)
318  search_.reset (pcl::search::autoSelectMethod<PointT>(input_, true, pcl::search::Purpose::many_knn_search));
319  else
320  search_->setInputCloud (input_);
321  }
322 
323  return (true);
324 }
325 
326 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
327 template <typename PointT, typename NormalT> void
329 {
330  pcl::Indices neighbours;
331  std::vector<float> distances;
332 
333  point_neighbours_.resize (input_->size (), neighbours);
334  if (input_->is_dense)
335  {
336  for (const auto& point_index: (*indices_))
337  {
338  neighbours.clear ();
339  search_->nearestKSearch ((*input_)[point_index], neighbour_number_, neighbours, distances);
340  point_neighbours_[point_index].swap (neighbours);
341  }
342  }
343  else
344  {
345  for (const auto& point_index: (*indices_))
346  {
347  if (!pcl::isFinite ((*input_)[point_index]))
348  continue;
349  neighbours.clear ();
350  search_->nearestKSearch ((*input_)[point_index], neighbour_number_, neighbours, distances);
351  point_neighbours_[point_index].swap (neighbours);
352  }
353  }
354 }
355 
356 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
357 template <typename PointT, typename NormalT> void
359 {
360  int num_of_pts = static_cast<int> (indices_->size ());
361  point_labels_.resize (input_->size (), -1);
362 
363  std::vector< std::pair<float, int> > point_residual;
364  std::pair<float, int> pair;
365  point_residual.resize (num_of_pts, pair);
366 
367  if (normal_flag_)
368  {
369  for (int i_point = 0; i_point < num_of_pts; i_point++)
370  {
371  const auto point_index = (*indices_)[i_point];
372  point_residual[i_point].first = (*normals_)[point_index].curvature;
373  point_residual[i_point].second = point_index;
374  }
375  std::sort (point_residual.begin (), point_residual.end (), comparePair);
376  }
377  else
378  {
379  for (int i_point = 0; i_point < num_of_pts; i_point++)
380  {
381  const auto point_index = (*indices_)[i_point];
382  point_residual[i_point].first = 0;
383  point_residual[i_point].second = point_index;
384  }
385  }
386  int seed_counter = 0;
387  int seed = point_residual[seed_counter].second;
388 
389  int segmented_pts_num = 0;
390  int number_of_segments = 0;
391  while (segmented_pts_num < num_of_pts)
392  {
393  int pts_in_segment;
394  pts_in_segment = growRegion (seed, number_of_segments);
395  segmented_pts_num += pts_in_segment;
396  num_pts_in_segment_.push_back (pts_in_segment);
397  number_of_segments++;
398 
399  //find next point that is not segmented yet
400  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
401  {
402  int index = point_residual[i_seed].second;
403  if (point_labels_[index] == -1)
404  {
405  seed = index;
406  seed_counter = i_seed;
407  break;
408  }
409  }
410  }
411 }
412 
413 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
414 template <typename PointT, typename NormalT> int
415 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
416 {
417  std::queue<int> seeds;
418  seeds.push (initial_seed);
419  point_labels_[initial_seed] = segment_number;
420 
421  int num_pts_in_segment = 1;
422 
423  while (!seeds.empty ())
424  {
425  int curr_seed;
426  curr_seed = seeds.front ();
427  seeds.pop ();
428 
429  std::size_t i_nghbr = 0;
430  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
431  {
432  int index = point_neighbours_[curr_seed][i_nghbr];
433  if (point_labels_[index] != -1)
434  {
435  i_nghbr++;
436  continue;
437  }
438 
439  bool is_a_seed = false;
440  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
441 
442  if (!belongs_to_segment)
443  {
444  i_nghbr++;
445  continue;
446  }
447 
448  point_labels_[index] = segment_number;
449  num_pts_in_segment++;
450 
451  if (is_a_seed)
452  {
453  seeds.push (index);
454  }
455 
456  i_nghbr++;
457  }// next neighbour
458  }// next seed
459 
460  return (num_pts_in_segment);
461 }
462 
463 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
464 template <typename PointT, typename NormalT> bool
466 {
467  is_a_seed = true;
468 
469  float cosine_threshold = std::cos (theta_threshold_);
470  float data[4];
471 
472  data[0] = (*input_)[point].data[0];
473  data[1] = (*input_)[point].data[1];
474  data[2] = (*input_)[point].data[2];
475  data[3] = (*input_)[point].data[3];
476  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
477  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
478 
479  //check the angle between normals
480  if (smooth_mode_flag_)
481  {
482  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
483  float dot_product = std::abs (nghbr_normal.dot (initial_normal));
484  if (dot_product < cosine_threshold)
485  {
486  return (false);
487  }
488  }
489  else
490  {
491  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
492  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> ((*normals_)[initial_seed].normal));
493  float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
494  if (dot_product < cosine_threshold)
495  return (false);
496  }
497 
498  // check the curvature if needed
499  if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
500  {
501  is_a_seed = false;
502  }
503 
504  // check the residual if needed
505  float data_1[4];
506 
507  data_1[0] = (*input_)[nghbr].data[0];
508  data_1[1] = (*input_)[nghbr].data[1];
509  data_1[2] = (*input_)[nghbr].data[2];
510  data_1[3] = (*input_)[nghbr].data[3];
511  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
512  float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
513  if (residual_flag_ && residual > residual_threshold_)
514  is_a_seed = false;
515 
516  return (true);
517 }
518 
519 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
520 template <typename PointT, typename NormalT> void
522 {
523  const auto number_of_segments = num_pts_in_segment_.size ();
524  const auto number_of_points = input_->size ();
525 
526  pcl::PointIndices segment;
527  clusters_.resize (number_of_segments, segment);
528 
529  for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
530  {
531  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
532  }
533 
534  std::vector<int> counter(number_of_segments, 0);
535 
536  for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
537  {
538  const auto segment_index = point_labels_[i_point];
539  if (segment_index != -1)
540  {
541  const auto point_index = counter[segment_index];
542  clusters_[segment_index].indices[point_index] = i_point;
543  counter[segment_index] = point_index + 1;
544  }
545  }
546 
547  number_of_segments_ = number_of_segments;
548 }
549 
550 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
551 template <typename PointT, typename NormalT> void
553 {
554  cluster.indices.clear ();
555 
556  bool segmentation_is_possible = initCompute ();
557  if ( !segmentation_is_possible )
558  {
559  deinitCompute ();
560  return;
561  }
562 
563  // first of all we need to find out if this point belongs to cloud
564  bool point_was_found = false;
565  for (const auto& point : (*indices_))
566  if (point == index)
567  {
568  point_was_found = true;
569  break;
570  }
571 
572  if (point_was_found)
573  {
574  if (clusters_.empty ())
575  {
576  point_neighbours_.clear ();
577  point_labels_.clear ();
578  num_pts_in_segment_.clear ();
579  number_of_segments_ = 0;
580 
581  segmentation_is_possible = prepareForSegmentation ();
582  if ( !segmentation_is_possible )
583  {
584  deinitCompute ();
585  return;
586  }
587 
588  findPointNeighbours ();
589  applySmoothRegionGrowingAlgorithm ();
590  assembleRegions ();
591  }
592  // if we have already made the segmentation, then find the segment
593  // to which this point belongs
594  for (const auto& i_segment : clusters_)
595  {
596  const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
597  if (it != i_segment.indices.cend())
598  {
599  // if segment was found
600  cluster.indices.clear ();
601  cluster.indices.reserve (i_segment.indices.size ());
602  std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.indices));
603  break;
604  }
605  }// next segment
606  }// end if point was found
607 
608  deinitCompute ();
609 }
610 
611 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
612 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
614 {
616 
617  if (!clusters_.empty ())
618  {
619  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
620 
621  srand (static_cast<unsigned int> (time (nullptr)));
622  std::vector<unsigned char> colors;
623  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
624  {
625  colors.push_back (static_cast<unsigned char> (rand () % 256));
626  colors.push_back (static_cast<unsigned char> (rand () % 256));
627  colors.push_back (static_cast<unsigned char> (rand () % 256));
628  }
629 
630  colored_cloud->width = input_->width;
631  colored_cloud->height = input_->height;
632  colored_cloud->is_dense = input_->is_dense;
633  for (const auto& i_point: *input_)
634  {
635  pcl::PointXYZRGB point;
636  point.x = *(i_point.data);
637  point.y = *(i_point.data + 1);
638  point.z = *(i_point.data + 2);
639  point.r = 255;
640  point.g = 0;
641  point.b = 0;
642  colored_cloud->points.push_back (point);
643  }
644 
645  int next_color = 0;
646  for (const auto& i_segment : clusters_)
647  {
648  for (const auto& index : (i_segment.indices))
649  {
650  (*colored_cloud)[index].r = colors[3 * next_color];
651  (*colored_cloud)[index].g = colors[3 * next_color + 1];
652  (*colored_cloud)[index].b = colors[3 * next_color + 2];
653  }
654  next_color++;
655  }
656  }
657 
658  return (colored_cloud);
659 }
660 
661 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
662 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
664 {
666 
667  if (!clusters_.empty ())
668  {
669  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGBA>);
670 
671  srand (static_cast<unsigned int> (time (nullptr)));
672  std::vector<unsigned char> colors;
673  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
674  {
675  colors.push_back (static_cast<unsigned char> (rand () % 256));
676  colors.push_back (static_cast<unsigned char> (rand () % 256));
677  colors.push_back (static_cast<unsigned char> (rand () % 256));
678  }
679 
680  colored_cloud->width = input_->width;
681  colored_cloud->height = input_->height;
682  colored_cloud->is_dense = input_->is_dense;
683  for (const auto& i_point: *input_)
684  {
685  pcl::PointXYZRGBA point;
686  point.x = *(i_point.data);
687  point.y = *(i_point.data + 1);
688  point.z = *(i_point.data + 2);
689  point.r = 255;
690  point.g = 0;
691  point.b = 0;
692  point.a = 0;
693  colored_cloud->points.push_back (point);
694  }
695 
696  int next_color = 0;
697  for (const auto& i_segment : clusters_)
698  {
699  for (const auto& index : (i_segment.indices))
700  {
701  (*colored_cloud)[index].r = colors[3 * next_color];
702  (*colored_cloud)[index].g = colors[3 * next_color + 1];
703  (*colored_cloud)[index].b = colors[3 * next_color + 2];
704  }
705  next_color++;
706  }
707  }
708 
709  return (colored_cloud);
710 }
711 
712 #define PCL_INSTANTIATE_RegionGrowing(T) template class PCL_EXPORTS pcl::RegionGrowing<T, pcl::Normal>;
713 
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:404
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:399
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:401
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:414
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:396
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.
Defines all the PCL implemented PointT point type structures.
@ 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.
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.