Point Cloud Library (PCL)  1.13.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  min_pts_per_cluster_ (1),
59  max_pts_per_cluster_ (std::numeric_limits<pcl::uindex_t>::max ()),
60  smooth_mode_flag_ (true),
61  curvature_flag_ (true),
62  residual_flag_ (false),
63  theta_threshold_ (30.0f / 180.0f * static_cast<float> (M_PI)),
64  residual_threshold_ (0.05f),
65  curvature_threshold_ (0.05f),
66  neighbour_number_ (30),
67  search_ (),
68  normals_ (),
69  point_neighbours_ (0),
70  point_labels_ (0),
71  normal_flag_ (true),
72  num_pts_in_segment_ (0),
73  clusters_ (0),
74  number_of_segments_ (0)
75 {
76 }
77 
78 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
79 template <typename PointT, typename NormalT>
81 {
82  point_neighbours_.clear ();
83  point_labels_.clear ();
84  num_pts_in_segment_.clear ();
85  clusters_.clear ();
86 }
87 
88 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89 template <typename PointT, typename NormalT> pcl::uindex_t
91 {
92  return (min_pts_per_cluster_);
93 }
94 
95 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
96 template <typename PointT, typename NormalT> void
98 {
99  min_pts_per_cluster_ = min_cluster_size;
100 }
101 
102 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103 template <typename PointT, typename NormalT> pcl::uindex_t
105 {
106  return (max_pts_per_cluster_);
107 }
108 
109 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110 template <typename PointT, typename NormalT> void
112 {
113  max_pts_per_cluster_ = max_cluster_size;
114 }
115 
116 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117 template <typename PointT, typename NormalT> bool
119 {
120  return (smooth_mode_flag_);
121 }
122 
123 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
124 template <typename PointT, typename NormalT> void
126 {
127  smooth_mode_flag_ = value;
128 }
129 
130 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131 template <typename PointT, typename NormalT> bool
133 {
134  return (curvature_flag_);
135 }
136 
137 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138 template <typename PointT, typename NormalT> void
140 {
141  curvature_flag_ = value;
142 
143  if (!curvature_flag_ && !residual_flag_)
144  residual_flag_ = true;
145 }
146 
147 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
148 template <typename PointT, typename NormalT> bool
150 {
151  return (residual_flag_);
152 }
153 
154 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
155 template <typename PointT, typename NormalT> void
157 {
158  residual_flag_ = value;
159 
160  if (!curvature_flag_ && !residual_flag_)
161  curvature_flag_ = true;
162 }
163 
164 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
165 template <typename PointT, typename NormalT> float
167 {
168  return (theta_threshold_);
169 }
170 
171 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172 template <typename PointT, typename NormalT> void
174 {
175  theta_threshold_ = theta;
176 }
177 
178 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
179 template <typename PointT, typename NormalT> float
181 {
182  return (residual_threshold_);
183 }
184 
185 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
186 template <typename PointT, typename NormalT> void
188 {
189  residual_threshold_ = residual;
190 }
191 
192 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193 template <typename PointT, typename NormalT> float
195 {
196  return (curvature_threshold_);
197 }
198 
199 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 template <typename PointT, typename NormalT> void
202 {
203  curvature_threshold_ = curvature;
204 }
205 
206 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
207 template <typename PointT, typename NormalT> unsigned int
209 {
210  return (neighbour_number_);
211 }
212 
213 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
214 template <typename PointT, typename NormalT> void
216 {
217  neighbour_number_ = neighbour_number;
218 }
219 
220 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
221 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::KdTreePtr
223 {
224  return (search_);
225 }
226 
227 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
228 template <typename PointT, typename NormalT> void
230 {
231  search_ = tree;
232 }
233 
234 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
235 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::NormalPtr
237 {
238  return (normals_);
239 }
240 
241 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
242 template <typename PointT, typename NormalT> void
244 {
245  normals_ = norm;
246 }
247 
248 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
249 template <typename PointT, typename NormalT> void
250 pcl::RegionGrowing<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
251 {
252  clusters_.clear ();
253  clusters.clear ();
254  point_neighbours_.clear ();
255  point_labels_.clear ();
256  num_pts_in_segment_.clear ();
257  number_of_segments_ = 0;
258 
259  bool segmentation_is_possible = initCompute ();
260  if ( !segmentation_is_possible )
261  {
262  deinitCompute ();
263  return;
264  }
265 
266  segmentation_is_possible = prepareForSegmentation ();
267  if ( !segmentation_is_possible )
268  {
269  deinitCompute ();
270  return;
271  }
272 
273  findPointNeighbours ();
274  applySmoothRegionGrowingAlgorithm ();
275  assembleRegions ();
276 
277  clusters.resize (clusters_.size ());
278  auto cluster_iter_input = clusters.begin ();
279  for (const auto& cluster : clusters_)
280  {
281  if ((cluster.indices.size () >= min_pts_per_cluster_) &&
282  (cluster.indices.size () <= max_pts_per_cluster_))
283  {
284  *cluster_iter_input = cluster;
285  ++cluster_iter_input;
286  }
287  }
288 
289  clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
290  clusters.resize(clusters_.size());
291 
292  deinitCompute ();
293 }
294 
295 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
296 template <typename PointT, typename NormalT> bool
298 {
299  // if user forgot to pass point cloud or if it is empty
300  if ( input_->points.empty () )
301  return (false);
302 
303  // if user forgot to pass normals or the sizes of point and normal cloud are different
304  if ( !normals_ || input_->size () != normals_->size () )
305  return (false);
306 
307  // if residual test is on then we need to check if all needed parameters were correctly initialized
308  if (residual_flag_)
309  {
310  if (residual_threshold_ <= 0.0f)
311  return (false);
312  }
313 
314  // if curvature test is on ...
315  // if (curvature_flag_)
316  // {
317  // in this case we do not need to check anything that related to it
318  // so we simply commented it
319  // }
320 
321  // from here we check those parameters that are always valuable
322  if (neighbour_number_ == 0)
323  return (false);
324 
325  // if user didn't set search method
326  if (!search_)
327  search_.reset (new pcl::search::KdTree<PointT>);
328 
329  if (indices_)
330  {
331  if (indices_->empty ())
332  PCL_ERROR ("[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
333  search_->setInputCloud (input_, indices_);
334  }
335  else
336  search_->setInputCloud (input_);
337 
338  return (true);
339 }
340 
341 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
342 template <typename PointT, typename NormalT> void
344 {
345  pcl::Indices neighbours;
346  std::vector<float> distances;
347 
348  point_neighbours_.resize (input_->size (), neighbours);
349  if (input_->is_dense)
350  {
351  for (const auto& point_index: (*indices_))
352  {
353  neighbours.clear ();
354  search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
355  point_neighbours_[point_index].swap (neighbours);
356  }
357  }
358  else
359  {
360  for (const auto& point_index: (*indices_))
361  {
362  if (!pcl::isFinite ((*input_)[point_index]))
363  continue;
364  neighbours.clear ();
365  search_->nearestKSearch (point_index, neighbour_number_, neighbours, distances);
366  point_neighbours_[point_index].swap (neighbours);
367  }
368  }
369 }
370 
371 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
372 template <typename PointT, typename NormalT> void
374 {
375  int num_of_pts = static_cast<int> (indices_->size ());
376  point_labels_.resize (input_->size (), -1);
377 
378  std::vector< std::pair<float, int> > point_residual;
379  std::pair<float, int> pair;
380  point_residual.resize (num_of_pts, pair);
381 
382  if (normal_flag_)
383  {
384  for (int i_point = 0; i_point < num_of_pts; i_point++)
385  {
386  const auto point_index = (*indices_)[i_point];
387  point_residual[i_point].first = (*normals_)[point_index].curvature;
388  point_residual[i_point].second = point_index;
389  }
390  std::sort (point_residual.begin (), point_residual.end (), comparePair);
391  }
392  else
393  {
394  for (int i_point = 0; i_point < num_of_pts; i_point++)
395  {
396  const auto point_index = (*indices_)[i_point];
397  point_residual[i_point].first = 0;
398  point_residual[i_point].second = point_index;
399  }
400  }
401  int seed_counter = 0;
402  int seed = point_residual[seed_counter].second;
403 
404  int segmented_pts_num = 0;
405  int number_of_segments = 0;
406  while (segmented_pts_num < num_of_pts)
407  {
408  int pts_in_segment;
409  pts_in_segment = growRegion (seed, number_of_segments);
410  segmented_pts_num += pts_in_segment;
411  num_pts_in_segment_.push_back (pts_in_segment);
412  number_of_segments++;
413 
414  //find next point that is not segmented yet
415  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
416  {
417  int index = point_residual[i_seed].second;
418  if (point_labels_[index] == -1)
419  {
420  seed = index;
421  seed_counter = i_seed;
422  break;
423  }
424  }
425  }
426 }
427 
428 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
429 template <typename PointT, typename NormalT> int
430 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
431 {
432  std::queue<int> seeds;
433  seeds.push (initial_seed);
434  point_labels_[initial_seed] = segment_number;
435 
436  int num_pts_in_segment = 1;
437 
438  while (!seeds.empty ())
439  {
440  int curr_seed;
441  curr_seed = seeds.front ();
442  seeds.pop ();
443 
444  std::size_t i_nghbr = 0;
445  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
446  {
447  int index = point_neighbours_[curr_seed][i_nghbr];
448  if (point_labels_[index] != -1)
449  {
450  i_nghbr++;
451  continue;
452  }
453 
454  bool is_a_seed = false;
455  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
456 
457  if (!belongs_to_segment)
458  {
459  i_nghbr++;
460  continue;
461  }
462 
463  point_labels_[index] = segment_number;
464  num_pts_in_segment++;
465 
466  if (is_a_seed)
467  {
468  seeds.push (index);
469  }
470 
471  i_nghbr++;
472  }// next neighbour
473  }// next seed
474 
475  return (num_pts_in_segment);
476 }
477 
478 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
479 template <typename PointT, typename NormalT> bool
481 {
482  is_a_seed = true;
483 
484  float cosine_threshold = std::cos (theta_threshold_);
485  float data[4];
486 
487  data[0] = (*input_)[point].data[0];
488  data[1] = (*input_)[point].data[1];
489  data[2] = (*input_)[point].data[2];
490  data[3] = (*input_)[point].data[3];
491  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
492  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
493 
494  //check the angle between normals
495  if (smooth_mode_flag_)
496  {
497  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
498  float dot_product = std::abs (nghbr_normal.dot (initial_normal));
499  if (dot_product < cosine_threshold)
500  {
501  return (false);
502  }
503  }
504  else
505  {
506  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
507  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> ((*normals_)[initial_seed].normal));
508  float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
509  if (dot_product < cosine_threshold)
510  return (false);
511  }
512 
513  // check the curvature if needed
514  if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
515  {
516  is_a_seed = false;
517  }
518 
519  // check the residual if needed
520  float data_1[4];
521 
522  data_1[0] = (*input_)[nghbr].data[0];
523  data_1[1] = (*input_)[nghbr].data[1];
524  data_1[2] = (*input_)[nghbr].data[2];
525  data_1[3] = (*input_)[nghbr].data[3];
526  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
527  float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
528  if (residual_flag_ && residual > residual_threshold_)
529  is_a_seed = false;
530 
531  return (true);
532 }
533 
534 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
535 template <typename PointT, typename NormalT> void
537 {
538  const auto number_of_segments = num_pts_in_segment_.size ();
539  const auto number_of_points = input_->size ();
540 
541  pcl::PointIndices segment;
542  clusters_.resize (number_of_segments, segment);
543 
544  for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
545  {
546  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
547  }
548 
549  std::vector<int> counter(number_of_segments, 0);
550 
551  for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
552  {
553  const auto segment_index = point_labels_[i_point];
554  if (segment_index != -1)
555  {
556  const auto point_index = counter[segment_index];
557  clusters_[segment_index].indices[point_index] = i_point;
558  counter[segment_index] = point_index + 1;
559  }
560  }
561 
562  number_of_segments_ = number_of_segments;
563 }
564 
565 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
566 template <typename PointT, typename NormalT> void
568 {
569  cluster.indices.clear ();
570 
571  bool segmentation_is_possible = initCompute ();
572  if ( !segmentation_is_possible )
573  {
574  deinitCompute ();
575  return;
576  }
577 
578  // first of all we need to find out if this point belongs to cloud
579  bool point_was_found = false;
580  for (const auto& point : (*indices_))
581  if (point == index)
582  {
583  point_was_found = true;
584  break;
585  }
586 
587  if (point_was_found)
588  {
589  if (clusters_.empty ())
590  {
591  point_neighbours_.clear ();
592  point_labels_.clear ();
593  num_pts_in_segment_.clear ();
594  number_of_segments_ = 0;
595 
596  segmentation_is_possible = prepareForSegmentation ();
597  if ( !segmentation_is_possible )
598  {
599  deinitCompute ();
600  return;
601  }
602 
603  findPointNeighbours ();
604  applySmoothRegionGrowingAlgorithm ();
605  assembleRegions ();
606  }
607  // if we have already made the segmentation, then find the segment
608  // to which this point belongs
609  for (const auto& i_segment : clusters_)
610  {
611  const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
612  if (it != i_segment.indices.cend())
613  {
614  // if segment was found
615  cluster.indices.clear ();
616  cluster.indices.reserve (i_segment.indices.size ());
617  std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.indices));
618  break;
619  }
620  }// next segment
621  }// end if point was found
622 
623  deinitCompute ();
624 }
625 
626 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
627 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
629 {
631 
632  if (!clusters_.empty ())
633  {
634  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
635 
636  srand (static_cast<unsigned int> (time (nullptr)));
637  std::vector<unsigned char> colors;
638  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
639  {
640  colors.push_back (static_cast<unsigned char> (rand () % 256));
641  colors.push_back (static_cast<unsigned char> (rand () % 256));
642  colors.push_back (static_cast<unsigned char> (rand () % 256));
643  }
644 
645  colored_cloud->width = input_->width;
646  colored_cloud->height = input_->height;
647  colored_cloud->is_dense = input_->is_dense;
648  for (const auto& i_point: *input_)
649  {
650  pcl::PointXYZRGB point;
651  point.x = *(i_point.data);
652  point.y = *(i_point.data + 1);
653  point.z = *(i_point.data + 2);
654  point.r = 255;
655  point.g = 0;
656  point.b = 0;
657  colored_cloud->points.push_back (point);
658  }
659 
660  int next_color = 0;
661  for (const auto& i_segment : clusters_)
662  {
663  for (const auto& index : (i_segment.indices))
664  {
665  (*colored_cloud)[index].r = colors[3 * next_color];
666  (*colored_cloud)[index].g = colors[3 * next_color + 1];
667  (*colored_cloud)[index].b = colors[3 * next_color + 2];
668  }
669  next_color++;
670  }
671  }
672 
673  return (colored_cloud);
674 }
675 
676 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
677 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
679 {
681 
682  if (!clusters_.empty ())
683  {
684  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGBA>);
685 
686  srand (static_cast<unsigned int> (time (nullptr)));
687  std::vector<unsigned char> colors;
688  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
689  {
690  colors.push_back (static_cast<unsigned char> (rand () % 256));
691  colors.push_back (static_cast<unsigned char> (rand () % 256));
692  colors.push_back (static_cast<unsigned char> (rand () % 256));
693  }
694 
695  colored_cloud->width = input_->width;
696  colored_cloud->height = input_->height;
697  colored_cloud->is_dense = input_->is_dense;
698  for (const auto& i_point: *input_)
699  {
700  pcl::PointXYZRGBA point;
701  point.x = *(i_point.data);
702  point.y = *(i_point.data + 1);
703  point.z = *(i_point.data + 2);
704  point.r = 255;
705  point.g = 0;
706  point.b = 0;
707  point.a = 0;
708  colored_cloud->points.push_back (point);
709  }
710 
711  int next_color = 0;
712  for (const auto& i_segment : clusters_)
713  {
714  for (const auto& index : (i_segment.indices))
715  {
716  (*colored_cloud)[index].r = colors[3 * next_color];
717  (*colored_cloud)[index].g = colors[3 * next_color + 1];
718  (*colored_cloud)[index].b = colors[3 * next_color + 2];
719  }
720  next_color++;
721  }
722  }
723 
724  return (colored_cloud);
725 }
726 
727 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
728 
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
#define M_PI
Definition: pcl_macros.h:201
A point structure representing Euclidean xyz coordinates, and the RGBA color.
A point structure representing Euclidean xyz coordinates, and the RGB color.