Point Cloud Library (PCL)  1.7.1
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 <time.h>
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  if (search_ != 0)
83  search_.reset ();
84  if (normals_ != 0)
85  normals_.reset ();
86 
87  point_neighbours_.clear ();
88  point_labels_.clear ();
89  num_pts_in_segment_.clear ();
90  clusters_.clear ();
91 }
92 
93 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
94 template <typename PointT, typename NormalT> int
96 {
97  return (min_pts_per_cluster_);
98 }
99 
100 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
101 template <typename PointT, typename NormalT> void
103 {
104  min_pts_per_cluster_ = min_cluster_size;
105 }
106 
107 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
108 template <typename PointT, typename NormalT> int
110 {
111  return (max_pts_per_cluster_);
112 }
113 
114 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
115 template <typename PointT, typename NormalT> void
117 {
118  max_pts_per_cluster_ = max_cluster_size;
119 }
120 
121 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
122 template <typename PointT, typename NormalT> bool
124 {
125  return (smooth_mode_flag_);
126 }
127 
128 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129 template <typename PointT, typename NormalT> void
131 {
132  smooth_mode_flag_ = value;
133 }
134 
135 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136 template <typename PointT, typename NormalT> bool
138 {
139  return (curvature_flag_);
140 }
141 
142 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143 template <typename PointT, typename NormalT> void
145 {
146  curvature_flag_ = value;
147 
148  if (curvature_flag_ == false && residual_flag_ == false)
149  residual_flag_ = true;
150 }
151 
152 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
153 template <typename PointT, typename NormalT> bool
155 {
156  return (residual_flag_);
157 }
158 
159 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 template <typename PointT, typename NormalT> void
162 {
163  residual_flag_ = value;
164 
165  if (curvature_flag_ == false && residual_flag_ == false)
166  curvature_flag_ = true;
167 }
168 
169 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
170 template <typename PointT, typename NormalT> float
172 {
173  return (theta_threshold_);
174 }
175 
176 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177 template <typename PointT, typename NormalT> void
179 {
180  theta_threshold_ = theta;
181 }
182 
183 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
184 template <typename PointT, typename NormalT> float
186 {
187  return (residual_threshold_);
188 }
189 
190 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
191 template <typename PointT, typename NormalT> void
193 {
194  residual_threshold_ = residual;
195 }
196 
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198 template <typename PointT, typename NormalT> float
200 {
201  return (curvature_threshold_);
202 }
203 
204 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205 template <typename PointT, typename NormalT> void
207 {
208  curvature_threshold_ = curvature;
209 }
210 
211 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
212 template <typename PointT, typename NormalT> unsigned int
214 {
215  return (neighbour_number_);
216 }
217 
218 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
219 template <typename PointT, typename NormalT> void
221 {
222  neighbour_number_ = neighbour_number;
223 }
224 
225 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
226 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::KdTreePtr
228 {
229  return (search_);
230 }
231 
232 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
233 template <typename PointT, typename NormalT> void
235 {
236  if (search_ != 0)
237  search_.reset ();
238 
239  search_ = tree;
240 }
241 
242 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
243 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::NormalPtr
245 {
246  return (normals_);
247 }
248 
249 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
250 template <typename PointT, typename NormalT> void
252 {
253  if (normals_ != 0)
254  normals_.reset ();
255 
256  normals_ = norm;
257 }
258 
259 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
260 template <typename PointT, typename NormalT> void
261 pcl::RegionGrowing<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
262 {
263  clusters_.clear ();
264  clusters.clear ();
265  point_neighbours_.clear ();
266  point_labels_.clear ();
267  num_pts_in_segment_.clear ();
268  number_of_segments_ = 0;
269 
270  bool segmentation_is_possible = initCompute ();
271  if ( !segmentation_is_possible )
272  {
273  deinitCompute ();
274  return;
275  }
276 
277  segmentation_is_possible = prepareForSegmentation ();
278  if ( !segmentation_is_possible )
279  {
280  deinitCompute ();
281  return;
282  }
283 
284  findPointNeighbours ();
285  applySmoothRegionGrowingAlgorithm ();
286  assembleRegions ();
287 
288  clusters.resize (clusters_.size ());
289  std::vector<pcl::PointIndices>::iterator cluster_iter_input = clusters.begin ();
290  for (std::vector<pcl::PointIndices>::const_iterator cluster_iter = clusters_.begin (); cluster_iter != clusters_.end (); cluster_iter++)
291  {
292  if ((cluster_iter->indices.size () >= min_pts_per_cluster_) &&
293  (cluster_iter->indices.size () <= max_pts_per_cluster_))
294  {
295  *cluster_iter_input = *cluster_iter;
296  cluster_iter_input++;
297  }
298  }
299 
300  clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
301  clusters.resize(clusters_.size());
302 
303  deinitCompute ();
304 }
305 
306 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
307 template <typename PointT, typename NormalT> bool
309 {
310  // if user forgot to pass point cloud or if it is empty
311  if ( input_->points.size () == 0 )
312  return (false);
313 
314  // if user forgot to pass normals or the sizes of point and normal cloud are different
315  if ( normals_ == 0 || input_->points.size () != normals_->points.size () )
316  return (false);
317 
318  // if residual test is on then we need to check if all needed parameters were correctly initialized
319  if (residual_flag_)
320  {
321  if (residual_threshold_ <= 0.0f)
322  return (false);
323  }
324 
325  // if curvature test is on ...
326  // if (curvature_flag_)
327  // {
328  // in this case we do not need to check anything that related to it
329  // so we simply commented it
330  // }
331 
332  // from here we check those parameters that are always valuable
333  if (neighbour_number_ == 0)
334  return (false);
335 
336  // if user didn't set search method
337  if (!search_)
338  search_.reset (new pcl::search::KdTree<PointT>);
339 
340  if (indices_)
341  {
342  if (indices_->empty ())
343  PCL_ERROR ("[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
344  search_->setInputCloud (input_, indices_);
345  }
346  else
347  search_->setInputCloud (input_);
348 
349  return (true);
350 }
351 
352 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
353 template <typename PointT, typename NormalT> void
355 {
356  int point_number = static_cast<int> (indices_->size ());
357  std::vector<int> neighbours;
358  std::vector<float> distances;
359 
360  point_neighbours_.resize (input_->points.size (), neighbours);
361 
362  for (int i_point = 0; i_point < point_number; i_point++)
363  {
364  int point_index = (*indices_)[i_point];
365  neighbours.clear ();
366  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
367  point_neighbours_[point_index].swap (neighbours);
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_->points.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_ == true)
383  {
384  for (int i_point = 0; i_point < num_of_pts; i_point++)
385  {
386  int point_index = (*indices_)[i_point];
387  point_residual[i_point].first = normals_->points[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  int 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  break;
422  }
423  }
424  }
425 }
426 
427 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
428 template <typename PointT, typename NormalT> int
429 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
430 {
431  std::queue<int> seeds;
432  seeds.push (initial_seed);
433  point_labels_[initial_seed] = segment_number;
434 
435  int num_pts_in_segment = 1;
436 
437  while (!seeds.empty ())
438  {
439  int curr_seed;
440  curr_seed = seeds.front ();
441  seeds.pop ();
442 
443  size_t i_nghbr = 0;
444  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
445  {
446  int index = point_neighbours_[curr_seed][i_nghbr];
447  if (point_labels_[index] != -1)
448  {
449  i_nghbr++;
450  continue;
451  }
452 
453  bool is_a_seed = false;
454  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
455 
456  if (belongs_to_segment == false)
457  {
458  i_nghbr++;
459  continue;
460  }
461 
462  point_labels_[index] = segment_number;
463  num_pts_in_segment++;
464 
465  if (is_a_seed)
466  {
467  seeds.push (index);
468  }
469 
470  i_nghbr++;
471  }// next neighbour
472  }// next seed
473 
474  return (num_pts_in_segment);
475 }
476 
477 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
478 template <typename PointT, typename NormalT> bool
479 pcl::RegionGrowing<PointT, NormalT>::validatePoint (int initial_seed, int point, int nghbr, bool& is_a_seed) const
480 {
481  is_a_seed = true;
482 
483  float cosine_threshold = cosf (theta_threshold_);
484  float data[4];
485 
486  data[0] = input_->points[point].data[0];
487  data[1] = input_->points[point].data[1];
488  data[2] = input_->points[point].data[2];
489  data[3] = input_->points[point].data[3];
490  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
491  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> (normals_->points[point].normal));
492 
493  //check the angle between normals
494  if (smooth_mode_flag_ == true)
495  {
496  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
497  float dot_product = fabsf (nghbr_normal.dot (initial_normal));
498  if (dot_product < cosine_threshold)
499  {
500  return (false);
501  }
502  }
503  else
504  {
505  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
506  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> (normals_->points[initial_seed].normal));
507  float dot_product = fabsf (nghbr_normal.dot (initial_seed_normal));
508  if (dot_product < cosine_threshold)
509  return (false);
510  }
511 
512  // check the curvature if needed
513  if (curvature_flag_ && normals_->points[nghbr].curvature > curvature_threshold_)
514  {
515  is_a_seed = false;
516  }
517 
518  // check the residual if needed
519  data[0] = input_->points[nghbr].data[0];
520  data[1] = input_->points[nghbr].data[1];
521  data[2] = input_->points[nghbr].data[2];
522  data[3] = input_->points[nghbr].data[3];
523  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data));
524  float residual = fabsf (initial_normal.dot (initial_point - nghbr_point));
525  if (residual_flag_ && residual > residual_threshold_)
526  is_a_seed = false;
527 
528  return (true);
529 }
530 
531 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
532 template <typename PointT, typename NormalT> void
534 {
535  int number_of_segments = static_cast<int> (num_pts_in_segment_.size ());
536  int number_of_points = static_cast<int> (input_->points.size ());
537 
538  pcl::PointIndices segment;
539  clusters_.resize (number_of_segments, segment);
540 
541  for (int i_seg = 0; i_seg < number_of_segments; i_seg++)
542  {
543  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
544  }
545 
546  std::vector<int> counter;
547  counter.resize (number_of_segments, 0);
548 
549  for (int i_point = 0; i_point < number_of_points; i_point++)
550  {
551  int segment_index = point_labels_[i_point];
552  if (segment_index != -1)
553  {
554  int point_index = counter[segment_index];
555  clusters_[segment_index].indices[point_index] = i_point;
556  counter[segment_index] = point_index + 1;
557  }
558  }
559 
560  number_of_segments_ = number_of_segments;
561 }
562 
563 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
564 template <typename PointT, typename NormalT> void
566 {
567  cluster.indices.clear ();
568 
569  bool segmentation_is_possible = initCompute ();
570  if ( !segmentation_is_possible )
571  {
572  deinitCompute ();
573  return;
574  }
575 
576  // first of all we need to find out if this point belongs to cloud
577  bool point_was_found = false;
578  int number_of_points = static_cast <int> (indices_->size ());
579  for (size_t point = 0; point < number_of_points; point++)
580  if ( (*indices_)[point] == index)
581  {
582  point_was_found = true;
583  break;
584  }
585 
586  if (point_was_found)
587  {
588  if (clusters_.empty ())
589  {
590  point_neighbours_.clear ();
591  point_labels_.clear ();
592  num_pts_in_segment_.clear ();
593  number_of_segments_ = 0;
594 
595  segmentation_is_possible = prepareForSegmentation ();
596  if ( !segmentation_is_possible )
597  {
598  deinitCompute ();
599  return;
600  }
601 
602  findPointNeighbours ();
603  applySmoothRegionGrowingAlgorithm ();
604  assembleRegions ();
605  }
606  // if we have already made the segmentation, then find the segment
607  // to which this point belongs
608  std::vector <pcl::PointIndices>::iterator i_segment;
609  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
610  {
611  bool segment_was_found = false;
612  for (size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
613  {
614  if (i_segment->indices[i_point] == index)
615  {
616  segment_was_found = true;
617  cluster.indices.clear ();
618  cluster.indices.reserve (i_segment->indices.size ());
619  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
620  break;
621  }
622  }
623  if (segment_was_found)
624  {
625  break;
626  }
627  }// next segment
628  }// end if point was found
629 
630  deinitCompute ();
631 }
632 
633 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
634 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
636 {
638 
639  if (!clusters_.empty ())
640  {
641  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
642 
643  srand (static_cast<unsigned int> (time (0)));
644  std::vector<unsigned char> colors;
645  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
646  {
647  colors.push_back (static_cast<unsigned char> (rand () % 256));
648  colors.push_back (static_cast<unsigned char> (rand () % 256));
649  colors.push_back (static_cast<unsigned char> (rand () % 256));
650  }
651 
652  colored_cloud->width = input_->width;
653  colored_cloud->height = input_->height;
654  colored_cloud->is_dense = input_->is_dense;
655  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
656  {
657  pcl::PointXYZRGB point;
658  point.x = *(input_->points[i_point].data);
659  point.y = *(input_->points[i_point].data + 1);
660  point.z = *(input_->points[i_point].data + 2);
661  point.r = 255;
662  point.g = 0;
663  point.b = 0;
664  colored_cloud->points.push_back (point);
665  }
666 
667  std::vector< pcl::PointIndices >::iterator i_segment;
668  int next_color = 0;
669  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
670  {
671  std::vector<int>::iterator i_point;
672  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
673  {
674  int index;
675  index = *i_point;
676  colored_cloud->points[index].r = colors[3 * next_color];
677  colored_cloud->points[index].g = colors[3 * next_color + 1];
678  colored_cloud->points[index].b = colors[3 * next_color + 2];
679  }
680  next_color++;
681  }
682  }
683 
684  return (colored_cloud);
685 }
686 
687 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
688 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
690 {
692 
693  if (!clusters_.empty ())
694  {
695  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
696 
697  srand (static_cast<unsigned int> (time (0)));
698  std::vector<unsigned char> colors;
699  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
700  {
701  colors.push_back (static_cast<unsigned char> (rand () % 256));
702  colors.push_back (static_cast<unsigned char> (rand () % 256));
703  colors.push_back (static_cast<unsigned char> (rand () % 256));
704  }
705 
706  colored_cloud->width = input_->width;
707  colored_cloud->height = input_->height;
708  colored_cloud->is_dense = input_->is_dense;
709  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
710  {
711  pcl::PointXYZRGBA point;
712  point.x = *(input_->points[i_point].data);
713  point.y = *(input_->points[i_point].data + 1);
714  point.z = *(input_->points[i_point].data + 2);
715  point.r = 255;
716  point.g = 0;
717  point.b = 0;
718  point.a = 0;
719  colored_cloud->points.push_back (point);
720  }
721 
722  std::vector< pcl::PointIndices >::iterator i_segment;
723  int next_color = 0;
724  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
725  {
726  std::vector<int>::iterator i_point;
727  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
728  {
729  int index;
730  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 getCurvatureThreshold() const
Returns curvature threshold.
bool getCurvatureTestFlag() const
Returns the flag that signalize if the curvature test is turned on/off.
virtual ~RegionGrowing()
This destructor destroys the cloud, normals and search method used for finding KNN.
void setSmoothModeFlag(bool value)
This function allows to turn on/off the smoothness constraint.
bool getSmoothModeFlag() const
Returns the flag value.
virtual void setCurvatureTestFlag(bool value)
Allows to turn on/off the curvature test.
virtual bool prepareForSegmentation()
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
float getSmoothnessThreshold() const
Returns smoothness threshold.
void setInputNormals(const NormalPtr &norm)
This method sets the normals.
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
If the cloud was successfully segmented, then function returns colored cloud.
virtual void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:415
boost::shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:428
float getResidualThreshold() const
Returns residual threshold.
RegionGrowing()
Constructor that sets default values for member variables.
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method that will be used for finding KNN.
bool getResidualTestFlag() const
Returns the flag that signalize if the residual test is turned on/off.
void setMinClusterSize(int min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid...
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 is_dense
True if no points are invalid (e.g., have NaN or Inf values).
Definition: point_cloud.h:418
KdTreePtr getSearchMethod() const
Returns the pointer to the search method that is used for KNN.
void setSmoothnessThreshold(float theta)
Allows to set smoothness threshold used for testing the points.
virtual bool validatePoint(int initial_seed, int point, int nghbr, bool &is_a_seed) const
This function is checking if the point with index 'nghbr' belongs to the segment. ...
A point structure representing Euclidean xyz coordinates, and the RGBA color.
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.
KdTree::Ptr KdTreePtr
NormalPtr getInputNormals() const
Returns normals.
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
std::vector< int > indices
Definition: PointIndices.h:19
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr getColoredCloudRGBA()
If the cloud was successfully segmented, then function returns colored cloud.
A point structure representing Euclidean xyz coordinates, and the RGB color.
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 setNumberOfNeighbours(unsigned int neighbour_number)
Allows to set the number of neighbours.
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:413
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
Normal::Ptr NormalPtr
void setCurvatureThreshold(float curvature)
Allows to set curvature threshold used for testing the points.
int growRegion(int initial_seed, int segment_number)
This method grows a segment for the given seed point.
unsigned int getNumberOfNeighbours() const
Returns the number of nearest neighbours used for KNN.
int getMinClusterSize()
Get the minimum number of points that a cluster needs to contain in order to be considered valid...
void assembleRegions()
This function simply assembles the regions from list of point labels.
virtual void findPointNeighbours()
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
void applySmoothRegionGrowingAlgorithm()
This function implements the algorithm described in the article "Segmentation of point clouds using s...
virtual void setResidualTestFlag(bool value)
Allows to turn on/off the residual test.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
Definition: kdtree.h:62