Point Cloud Library (PCL)  1.9.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 #ifndef PCL_SEGMENTATION_REGION_GROWING_HPP_
41 #define PCL_SEGMENTATION_REGION_GROWING_HPP_
42 
43 #include <pcl/segmentation/region_growing.h>
44 
45 #include <pcl/search/search.h>
46 #include <pcl/search/kdtree.h>
47 #include <pcl/point_cloud.h>
48 #include <pcl/point_types.h>
49 
50 #include <queue>
51 #include <list>
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<int>::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> int
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> int
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_ == false && residual_flag_ == false)
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_ == false && residual_flag_ == false)
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 ();
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 
275  assembleRegions ();
276 
277  clusters.resize (clusters_.size ());
278  std::vector<pcl::PointIndices>::iterator cluster_iter_input = clusters.begin ();
279  for (std::vector<pcl::PointIndices>::const_iterator cluster_iter = clusters_.begin (); cluster_iter != clusters_.end (); cluster_iter++)
280  {
281  if ((static_cast<int> (cluster_iter->indices.size ()) >= min_pts_per_cluster_) &&
282  (static_cast<int> (cluster_iter->indices.size ()) <= max_pts_per_cluster_))
283  {
284  *cluster_iter_input = *cluster_iter;
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_->points.size () != normals_->points.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_)
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  int point_number = static_cast<int> (indices_->size ());
346  std::vector<int> neighbours;
347  std::vector<float> distances;
348 
349  point_neighbours_.resize (input_->points.size (), neighbours);
350  if (input_->is_dense)
351  {
352  for (int i_point = 0; i_point < point_number; i_point++)
353  {
354  int point_index = (*indices_)[i_point];
355  neighbours.clear ();
356  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
357  point_neighbours_[point_index].swap (neighbours);
358  }
359  }
360  else
361  {
362  for (int i_point = 0; i_point < point_number; i_point++)
363  {
364  neighbours.clear ();
365  int point_index = (*indices_)[i_point];
366  if (!pcl::isFinite (input_->points[point_index]))
367  continue;
368  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
369  point_neighbours_[point_index].swap (neighbours);
370  }
371  }
372 }
373 
374 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
375 template <typename PointT, typename NormalT> void
377 {
378  int num_of_pts = static_cast<int> (indices_->size ());
379  point_labels_.resize (input_->points.size (), -1);
380 
381  std::vector< std::pair<float, int> > point_residual;
382  std::pair<float, int> pair;
383  point_residual.resize (num_of_pts, pair);
384 
385  if (normal_flag_ == true)
386  {
387  for (int i_point = 0; i_point < num_of_pts; i_point++)
388  {
389  int point_index = (*indices_)[i_point];
390  point_residual[i_point].first = normals_->points[point_index].curvature;
391  point_residual[i_point].second = point_index;
392  }
393  std::sort (point_residual.begin (), point_residual.end (), comparePair);
394  }
395  else
396  {
397  for (int i_point = 0; i_point < num_of_pts; i_point++)
398  {
399  int point_index = (*indices_)[i_point];
400  point_residual[i_point].first = 0;
401  point_residual[i_point].second = point_index;
402  }
403  }
404  int seed_counter = 0;
405  int seed = point_residual[seed_counter].second;
406 
407  int segmented_pts_num = 0;
408  int number_of_segments = 0;
409  while (segmented_pts_num < num_of_pts)
410  {
411  int pts_in_segment;
412  pts_in_segment = growRegion (seed, number_of_segments);
413  segmented_pts_num += pts_in_segment;
414  num_pts_in_segment_.push_back (pts_in_segment);
415  number_of_segments++;
416 
417  //find next point that is not segmented yet
418  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
419  {
420  int index = point_residual[i_seed].second;
421  if (point_labels_[index] == -1)
422  {
423  seed = index;
424  seed_counter = i_seed;
425  break;
426  }
427  }
428  }
429 }
430 
431 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
432 template <typename PointT, typename NormalT> int
433 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
434 {
435  std::queue<int> seeds;
436  seeds.push (initial_seed);
437  point_labels_[initial_seed] = segment_number;
438 
439  int num_pts_in_segment = 1;
440 
441  while (!seeds.empty ())
442  {
443  int curr_seed;
444  curr_seed = seeds.front ();
445  seeds.pop ();
446 
447  size_t i_nghbr = 0;
448  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
449  {
450  int index = point_neighbours_[curr_seed][i_nghbr];
451  if (point_labels_[index] != -1)
452  {
453  i_nghbr++;
454  continue;
455  }
456 
457  bool is_a_seed = false;
458  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
459 
460  if (!belongs_to_segment)
461  {
462  i_nghbr++;
463  continue;
464  }
465 
466  point_labels_[index] = segment_number;
467  num_pts_in_segment++;
468 
469  if (is_a_seed)
470  {
471  seeds.push (index);
472  }
473 
474  i_nghbr++;
475  }// next neighbour
476  }// next seed
477 
478  return (num_pts_in_segment);
479 }
480 
481 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
482 template <typename PointT, typename NormalT> bool
483 pcl::RegionGrowing<PointT, NormalT>::validatePoint (int initial_seed, int point, int nghbr, bool& is_a_seed) const
484 {
485  is_a_seed = true;
486 
487  float cosine_threshold = std::cos (theta_threshold_);
488  float data[4];
489 
490  data[0] = input_->points[point].data[0];
491  data[1] = input_->points[point].data[1];
492  data[2] = input_->points[point].data[2];
493  data[3] = input_->points[point].data[3];
494  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
495  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> (normals_->points[point].normal));
496 
497  //check the angle between normals
498  if (smooth_mode_flag_ == true)
499  {
500  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
501  float dot_product = std::abs (nghbr_normal.dot (initial_normal));
502  if (dot_product < cosine_threshold)
503  {
504  return (false);
505  }
506  }
507  else
508  {
509  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
510  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> (normals_->points[initial_seed].normal));
511  float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
512  if (dot_product < cosine_threshold)
513  return (false);
514  }
515 
516  // check the curvature if needed
517  if (curvature_flag_ && normals_->points[nghbr].curvature > curvature_threshold_)
518  {
519  is_a_seed = false;
520  }
521 
522  // check the residual if needed
523  float data_1[4];
524 
525  data_1[0] = input_->points[nghbr].data[0];
526  data_1[1] = input_->points[nghbr].data[1];
527  data_1[2] = input_->points[nghbr].data[2];
528  data_1[3] = input_->points[nghbr].data[3];
529  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
530  float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
531  if (residual_flag_ && residual > residual_threshold_)
532  is_a_seed = false;
533 
534  return (true);
535 }
536 
537 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
538 template <typename PointT, typename NormalT> void
540 {
541  int number_of_segments = static_cast<int> (num_pts_in_segment_.size ());
542  int number_of_points = static_cast<int> (input_->points.size ());
543 
544  pcl::PointIndices segment;
545  clusters_.resize (number_of_segments, segment);
546 
547  for (int i_seg = 0; i_seg < number_of_segments; i_seg++)
548  {
549  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
550  }
551 
552  std::vector<int> counter;
553  counter.resize (number_of_segments, 0);
554 
555  for (int i_point = 0; i_point < number_of_points; i_point++)
556  {
557  int segment_index = point_labels_[i_point];
558  if (segment_index != -1)
559  {
560  int point_index = counter[segment_index];
561  clusters_[segment_index].indices[point_index] = i_point;
562  counter[segment_index] = point_index + 1;
563  }
564  }
565 
566  number_of_segments_ = number_of_segments;
567 }
568 
569 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
570 template <typename PointT, typename NormalT> void
572 {
573  cluster.indices.clear ();
574 
575  bool segmentation_is_possible = initCompute ();
576  if ( !segmentation_is_possible )
577  {
578  deinitCompute ();
579  return;
580  }
581 
582  // first of all we need to find out if this point belongs to cloud
583  bool point_was_found = false;
584  int number_of_points = static_cast <int> (indices_->size ());
585  for (int point = 0; point < number_of_points; point++)
586  if ( (*indices_)[point] == index)
587  {
588  point_was_found = true;
589  break;
590  }
591 
592  if (point_was_found)
593  {
594  if (clusters_.empty ())
595  {
596  point_neighbours_.clear ();
597  point_labels_.clear ();
598  num_pts_in_segment_.clear ();
600 
601  segmentation_is_possible = prepareForSegmentation ();
602  if ( !segmentation_is_possible )
603  {
604  deinitCompute ();
605  return;
606  }
607 
610  assembleRegions ();
611  }
612  // if we have already made the segmentation, then find the segment
613  // to which this point belongs
614  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
615  {
616  bool segment_was_found = false;
617  for (size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
618  {
619  if (i_segment->indices[i_point] == index)
620  {
621  segment_was_found = true;
622  cluster.indices.clear ();
623  cluster.indices.reserve (i_segment->indices.size ());
624  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
625  break;
626  }
627  }
628  if (segment_was_found)
629  {
630  break;
631  }
632  }// next segment
633  }// end if point was found
634 
635  deinitCompute ();
636 }
637 
638 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
639 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
641 {
643 
644  if (!clusters_.empty ())
645  {
646  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
647 
648  srand (static_cast<unsigned int> (time (nullptr)));
649  std::vector<unsigned char> colors;
650  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
651  {
652  colors.push_back (static_cast<unsigned char> (rand () % 256));
653  colors.push_back (static_cast<unsigned char> (rand () % 256));
654  colors.push_back (static_cast<unsigned char> (rand () % 256));
655  }
656 
657  colored_cloud->width = input_->width;
658  colored_cloud->height = input_->height;
659  colored_cloud->is_dense = input_->is_dense;
660  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
661  {
662  pcl::PointXYZRGB point;
663  point.x = *(input_->points[i_point].data);
664  point.y = *(input_->points[i_point].data + 1);
665  point.z = *(input_->points[i_point].data + 2);
666  point.r = 255;
667  point.g = 0;
668  point.b = 0;
669  colored_cloud->points.push_back (point);
670  }
671 
672  int next_color = 0;
673  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
674  {
675  for (auto i_point = i_segment->indices.cbegin (); i_point != i_segment->indices.cend (); i_point++)
676  {
677  int index;
678  index = *i_point;
679  colored_cloud->points[index].r = colors[3 * next_color];
680  colored_cloud->points[index].g = colors[3 * next_color + 1];
681  colored_cloud->points[index].b = colors[3 * next_color + 2];
682  }
683  next_color++;
684  }
685  }
686 
687  return (colored_cloud);
688 }
689 
690 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
691 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
693 {
695 
696  if (!clusters_.empty ())
697  {
698  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
699 
700  srand (static_cast<unsigned int> (time (nullptr)));
701  std::vector<unsigned char> colors;
702  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
703  {
704  colors.push_back (static_cast<unsigned char> (rand () % 256));
705  colors.push_back (static_cast<unsigned char> (rand () % 256));
706  colors.push_back (static_cast<unsigned char> (rand () % 256));
707  }
708 
709  colored_cloud->width = input_->width;
710  colored_cloud->height = input_->height;
711  colored_cloud->is_dense = input_->is_dense;
712  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
713  {
714  pcl::PointXYZRGBA point;
715  point.x = *(input_->points[i_point].data);
716  point.y = *(input_->points[i_point].data + 1);
717  point.z = *(input_->points[i_point].data + 2);
718  point.r = 255;
719  point.g = 0;
720  point.b = 0;
721  point.a = 0;
722  colored_cloud->points.push_back (point);
723  }
724 
725  int next_color = 0;
726  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
727  {
728  for (auto i_point = i_segment->indices.cbegin (); i_point != i_segment->indices.cend (); i_point++)
729  {
730  int index = *i_point;
731  colored_cloud->points[index].r = colors[3 * next_color];
732  colored_cloud->points[index].g = colors[3 * next_color + 1];
733  colored_cloud->points[index].b = colors[3 * next_color + 2];
734  }
735  next_color++;
736  }
737  }
738 
739  return (colored_cloud);
740 }
741 
742 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
743 
744 #endif // PCL_SEGMENTATION_REGION_GROWING_HPP_
float theta_threshold_
Thershold used for testing the smoothness between points.
float residual_threshold_
Thershold used in residual test.
float curvature_threshold_
Thershold used in curvature test.
unsigned int getNumberOfNeighbours() const
Returns the number of nearest neighbours used for KNN.
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:53
float getResidualThreshold() const
Returns residual threshold.
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:423
void setSmoothModeFlag(bool value)
This function allows to turn on/off the smoothness constraint.
virtual bool prepareForSegmentation()
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
void setMaxClusterSize(int max_cluster_size)
Set the maximum number of points that a cluster needs to contain in order to be considered valid...
void setMinClusterSize(int min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid...
std::vector< int > num_pts_in_segment_
Tells how much points each segment contains.
unsigned int neighbour_number_
Number of neighbours to find.
KdTreePtr getSearchMethod() const
Returns the pointer to the search method that is used for KNN.
RegionGrowing()
Constructor that sets default values for member variables.
virtual void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
IndicesPtr indices_
A pointer to the vector of point indices to use.
Definition: pcl_base.h:154
int getMinClusterSize()
Get the minimum number of points that a cluster needs to contain in order to be considered valid...
~RegionGrowing()
This destructor destroys the cloud, normals and search method used for finding KNN.
bool residual_flag_
If set to true then residual test will be done during segmentation.
void setCurvatureThreshold(float curvature)
Allows to set curvature threshold used for testing the points.
std::vector< int > indices
Definition: PointIndices.h:19
typename KdTree::Ptr KdTreePtr
int min_pts_per_cluster_
Stores the minimum number of points that a cluster needs to contain in order to be considered valid...
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.
A point structure representing Euclidean xyz coordinates, and the RGBA color.
void setSmoothnessThreshold(float theta)
Allows to set smoothness threshold used for testing the points.
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:428
int number_of_segments_
Stores the number of segments.
bool initCompute()
This method should get called before starting the actual computation.
Definition: pcl_base.hpp:138
NormalPtr normals_
Contains normals of the points that will be segmented.
float getSmoothnessThreshold() const
Returns smoothness threshold.
int max_pts_per_cluster_
Stores the maximum number of points that a cluster needs to contain in order to be considered valid...
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:426
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
virtual void setResidualTestFlag(bool value)
Allows to turn on/off the residual test.
std::vector< pcl::PointIndices > clusters_
After the segmentation it will contain the segments.
Defines all the PCL implemented PointT point type structures.
virtual void findPointNeighbours()
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
If the cloud was successfully segmented, then function returns colored cloud.
NormalPtr getInputNormals() const
Returns normals.
float getCurvatureThreshold() const
Returns curvature threshold.
virtual bool validatePoint(int initial_seed, int point, int nghbr, bool &is_a_seed) const
This function is checking if the point with index &#39;nghbr&#39; belongs to the segment. ...
boost::shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:441
void setInputNormals(const NormalPtr &norm)
This method sets the normals.
virtual void getSegmentFromPoint(int index, pcl::PointIndices &cluster)
For a given point this function builds a segment to which it belongs and returns this segment...
bool deinitCompute()
This method should get called after finishing the actual computation.
Definition: pcl_base.hpp:171
bool getResidualTestFlag() const
Returns the flag that signalize if the residual test is turned on/off.
std::vector< int > point_labels_
Point labels that tells to which segment each point belongs.
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr getColoredCloudRGBA()
If the cloud was successfully segmented, then function returns colored cloud.
bool getSmoothModeFlag() const
Returns the flag value.
void applySmoothRegionGrowingAlgorithm()
This function implements the algorithm described in the article "Segmentation of point clouds using s...
bool smooth_mode_flag_
Flag that signalizes if the smoothness constraint will be used.
int getMaxClusterSize()
Get the maximum number of points that a cluster needs to contain in order to be considered valid...
void setResidualThreshold(float residual)
Allows to set residual threshold used for testing the points.
void assembleRegions()
This function simply assembles the regions from list of point labels.
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:431
bool normal_flag_
If set to true then normal/smoothness test will be done during segmentation.
KdTreePtr search_
Serch method that will be used for KNN.
PointCloudConstPtr input_
The input point cloud dataset.
Definition: pcl_base.h:151
virtual void setCurvatureTestFlag(bool value)
Allows to turn on/off the curvature test.
A point structure representing Euclidean xyz coordinates, and the RGB color.
bool getCurvatureTestFlag() const
Returns the flag that signalize if the curvature test is turned on/off.
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method that will be used for finding KNN.
bool curvature_flag_
If set to true then curvature test will be done during segmentation.
typename Normal::Ptr NormalPtr
std::vector< std::vector< int > > point_neighbours_
Contains neighbours of each point.