Point Cloud Library (PCL)  1.7.2
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 ((static_cast<int> (cluster_iter->indices.size ()) >= min_pts_per_cluster_) &&
293  (static_cast<int> (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  if (input_->is_dense)
362  {
363  for (int i_point = 0; i_point < point_number; i_point++)
364  {
365  int point_index = (*indices_)[i_point];
366  neighbours.clear ();
367  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
368  point_neighbours_[point_index].swap (neighbours);
369  }
370  }
371  else
372  {
373  for (int i_point = 0; i_point < point_number; i_point++)
374  {
375  neighbours.clear ();
376  int point_index = (*indices_)[i_point];
377  if (!pcl::isFinite (input_->points[point_index]))
378  continue;
379  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
380  point_neighbours_[point_index].swap (neighbours);
381  }
382  }
383 }
384 
385 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
386 template <typename PointT, typename NormalT> void
388 {
389  int num_of_pts = static_cast<int> (indices_->size ());
390  point_labels_.resize (input_->points.size (), -1);
391 
392  std::vector< std::pair<float, int> > point_residual;
393  std::pair<float, int> pair;
394  point_residual.resize (num_of_pts, pair);
395 
396  if (normal_flag_ == true)
397  {
398  for (int i_point = 0; i_point < num_of_pts; i_point++)
399  {
400  int point_index = (*indices_)[i_point];
401  point_residual[i_point].first = normals_->points[point_index].curvature;
402  point_residual[i_point].second = point_index;
403  }
404  std::sort (point_residual.begin (), point_residual.end (), comparePair);
405  }
406  else
407  {
408  for (int i_point = 0; i_point < num_of_pts; i_point++)
409  {
410  int point_index = (*indices_)[i_point];
411  point_residual[i_point].first = 0;
412  point_residual[i_point].second = point_index;
413  }
414  }
415  int seed_counter = 0;
416  int seed = point_residual[seed_counter].second;
417 
418  int segmented_pts_num = 0;
419  int number_of_segments = 0;
420  while (segmented_pts_num < num_of_pts)
421  {
422  int pts_in_segment;
423  pts_in_segment = growRegion (seed, number_of_segments);
424  segmented_pts_num += pts_in_segment;
425  num_pts_in_segment_.push_back (pts_in_segment);
426  number_of_segments++;
427 
428  //find next point that is not segmented yet
429  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
430  {
431  int index = point_residual[i_seed].second;
432  if (point_labels_[index] == -1)
433  {
434  seed = index;
435  break;
436  }
437  }
438  }
439 }
440 
441 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
442 template <typename PointT, typename NormalT> int
443 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
444 {
445  std::queue<int> seeds;
446  seeds.push (initial_seed);
447  point_labels_[initial_seed] = segment_number;
448 
449  int num_pts_in_segment = 1;
450 
451  while (!seeds.empty ())
452  {
453  int curr_seed;
454  curr_seed = seeds.front ();
455  seeds.pop ();
456 
457  size_t i_nghbr = 0;
458  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
459  {
460  int index = point_neighbours_[curr_seed][i_nghbr];
461  if (point_labels_[index] != -1)
462  {
463  i_nghbr++;
464  continue;
465  }
466 
467  bool is_a_seed = false;
468  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
469 
470  if (belongs_to_segment == false)
471  {
472  i_nghbr++;
473  continue;
474  }
475 
476  point_labels_[index] = segment_number;
477  num_pts_in_segment++;
478 
479  if (is_a_seed)
480  {
481  seeds.push (index);
482  }
483 
484  i_nghbr++;
485  }// next neighbour
486  }// next seed
487 
488  return (num_pts_in_segment);
489 }
490 
491 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
492 template <typename PointT, typename NormalT> bool
493 pcl::RegionGrowing<PointT, NormalT>::validatePoint (int initial_seed, int point, int nghbr, bool& is_a_seed) const
494 {
495  is_a_seed = true;
496 
497  float cosine_threshold = cosf (theta_threshold_);
498  float data[4];
499 
500  data[0] = input_->points[point].data[0];
501  data[1] = input_->points[point].data[1];
502  data[2] = input_->points[point].data[2];
503  data[3] = input_->points[point].data[3];
504  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
505  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> (normals_->points[point].normal));
506 
507  //check the angle between normals
508  if (smooth_mode_flag_ == true)
509  {
510  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
511  float dot_product = fabsf (nghbr_normal.dot (initial_normal));
512  if (dot_product < cosine_threshold)
513  {
514  return (false);
515  }
516  }
517  else
518  {
519  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
520  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> (normals_->points[initial_seed].normal));
521  float dot_product = fabsf (nghbr_normal.dot (initial_seed_normal));
522  if (dot_product < cosine_threshold)
523  return (false);
524  }
525 
526  // check the curvature if needed
527  if (curvature_flag_ && normals_->points[nghbr].curvature > curvature_threshold_)
528  {
529  is_a_seed = false;
530  }
531 
532  // check the residual if needed
533  data[0] = input_->points[nghbr].data[0];
534  data[1] = input_->points[nghbr].data[1];
535  data[2] = input_->points[nghbr].data[2];
536  data[3] = input_->points[nghbr].data[3];
537  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data));
538  float residual = fabsf (initial_normal.dot (initial_point - nghbr_point));
539  if (residual_flag_ && residual > residual_threshold_)
540  is_a_seed = false;
541 
542  return (true);
543 }
544 
545 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
546 template <typename PointT, typename NormalT> void
548 {
549  int number_of_segments = static_cast<int> (num_pts_in_segment_.size ());
550  int number_of_points = static_cast<int> (input_->points.size ());
551 
552  pcl::PointIndices segment;
553  clusters_.resize (number_of_segments, segment);
554 
555  for (int i_seg = 0; i_seg < number_of_segments; i_seg++)
556  {
557  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
558  }
559 
560  std::vector<int> counter;
561  counter.resize (number_of_segments, 0);
562 
563  for (int i_point = 0; i_point < number_of_points; i_point++)
564  {
565  int segment_index = point_labels_[i_point];
566  if (segment_index != -1)
567  {
568  int point_index = counter[segment_index];
569  clusters_[segment_index].indices[point_index] = i_point;
570  counter[segment_index] = point_index + 1;
571  }
572  }
573 
574  number_of_segments_ = number_of_segments;
575 }
576 
577 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
578 template <typename PointT, typename NormalT> void
580 {
581  cluster.indices.clear ();
582 
583  bool segmentation_is_possible = initCompute ();
584  if ( !segmentation_is_possible )
585  {
586  deinitCompute ();
587  return;
588  }
589 
590  // first of all we need to find out if this point belongs to cloud
591  bool point_was_found = false;
592  int number_of_points = static_cast <int> (indices_->size ());
593  for (int point = 0; point < number_of_points; point++)
594  if ( (*indices_)[point] == index)
595  {
596  point_was_found = true;
597  break;
598  }
599 
600  if (point_was_found)
601  {
602  if (clusters_.empty ())
603  {
604  point_neighbours_.clear ();
605  point_labels_.clear ();
606  num_pts_in_segment_.clear ();
607  number_of_segments_ = 0;
608 
609  segmentation_is_possible = prepareForSegmentation ();
610  if ( !segmentation_is_possible )
611  {
612  deinitCompute ();
613  return;
614  }
615 
616  findPointNeighbours ();
617  applySmoothRegionGrowingAlgorithm ();
618  assembleRegions ();
619  }
620  // if we have already made the segmentation, then find the segment
621  // to which this point belongs
622  std::vector <pcl::PointIndices>::iterator i_segment;
623  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
624  {
625  bool segment_was_found = false;
626  for (size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
627  {
628  if (i_segment->indices[i_point] == index)
629  {
630  segment_was_found = true;
631  cluster.indices.clear ();
632  cluster.indices.reserve (i_segment->indices.size ());
633  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
634  break;
635  }
636  }
637  if (segment_was_found)
638  {
639  break;
640  }
641  }// next segment
642  }// end if point was found
643 
644  deinitCompute ();
645 }
646 
647 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
648 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
650 {
652 
653  if (!clusters_.empty ())
654  {
655  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
656 
657  srand (static_cast<unsigned int> (time (0)));
658  std::vector<unsigned char> colors;
659  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
660  {
661  colors.push_back (static_cast<unsigned char> (rand () % 256));
662  colors.push_back (static_cast<unsigned char> (rand () % 256));
663  colors.push_back (static_cast<unsigned char> (rand () % 256));
664  }
665 
666  colored_cloud->width = input_->width;
667  colored_cloud->height = input_->height;
668  colored_cloud->is_dense = input_->is_dense;
669  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
670  {
671  pcl::PointXYZRGB point;
672  point.x = *(input_->points[i_point].data);
673  point.y = *(input_->points[i_point].data + 1);
674  point.z = *(input_->points[i_point].data + 2);
675  point.r = 255;
676  point.g = 0;
677  point.b = 0;
678  colored_cloud->points.push_back (point);
679  }
680 
681  std::vector< pcl::PointIndices >::iterator i_segment;
682  int next_color = 0;
683  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
684  {
685  std::vector<int>::iterator i_point;
686  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
687  {
688  int index;
689  index = *i_point;
690  colored_cloud->points[index].r = colors[3 * next_color];
691  colored_cloud->points[index].g = colors[3 * next_color + 1];
692  colored_cloud->points[index].b = colors[3 * next_color + 2];
693  }
694  next_color++;
695  }
696  }
697 
698  return (colored_cloud);
699 }
700 
701 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
702 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
704 {
706 
707  if (!clusters_.empty ())
708  {
709  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
710 
711  srand (static_cast<unsigned int> (time (0)));
712  std::vector<unsigned char> colors;
713  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
714  {
715  colors.push_back (static_cast<unsigned char> (rand () % 256));
716  colors.push_back (static_cast<unsigned char> (rand () % 256));
717  colors.push_back (static_cast<unsigned char> (rand () % 256));
718  }
719 
720  colored_cloud->width = input_->width;
721  colored_cloud->height = input_->height;
722  colored_cloud->is_dense = input_->is_dense;
723  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
724  {
725  pcl::PointXYZRGBA point;
726  point.x = *(input_->points[i_point].data);
727  point.y = *(input_->points[i_point].data + 1);
728  point.z = *(input_->points[i_point].data + 2);
729  point.r = 255;
730  point.g = 0;
731  point.b = 0;
732  point.a = 0;
733  colored_cloud->points.push_back (point);
734  }
735 
736  std::vector< pcl::PointIndices >::iterator i_segment;
737  int next_color = 0;
738  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
739  {
740  std::vector<int>::iterator i_point;
741  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
742  {
743  int index;
744  index = *i_point;
745  colored_cloud->points[index].r = colors[3 * next_color];
746  colored_cloud->points[index].g = colors[3 * next_color + 1];
747  colored_cloud->points[index].b = colors[3 * next_color + 2];
748  }
749  next_color++;
750  }
751  }
752 
753  return (colored_cloud);
754 }
755 
756 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
757 
758 #endif // PCL_SEGMENTATION_REGION_GROWING_HPP_
float getResidualThreshold() const
Returns residual threshold.
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested.
Definition: point_tests.h:53
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...
boost::shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:428
void setMinClusterSize(int min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid...
bool getSmoothModeFlag() const
Returns the flag value.
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...
int getMinClusterSize()
Get the minimum number of points that a cluster needs to contain in order to be considered valid...
virtual ~RegionGrowing()
This destructor destroys the cloud, normals and search method used for finding KNN.
void setCurvatureThreshold(float curvature)
Allows to set curvature threshold used for testing the points.
std::vector< int > indices
Definition: PointIndices.h:19
unsigned int getNumberOfNeighbours() const
Returns the number of nearest neighbours used for KNN.
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:413
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.
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.
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
KdTree::Ptr KdTreePtr
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.
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.
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...
Normal::Ptr NormalPtr
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr getColoredCloudRGBA()
If the cloud was successfully segmented, then function returns colored cloud.
void applySmoothRegionGrowingAlgorithm()
This function implements the algorithm described in the article &quot;Segmentation of point clouds using s...
int getMaxClusterSize()
Get the maximum number of points that a cluster needs to contain in order to be considered valid...
NormalPtr getInputNormals() const
Returns normals.
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.
KdTreePtr getSearchMethod() const
Returns the pointer to the search method that is used for KNN.
bool getResidualTestFlag() const
Returns the flag that signalize if the residual test is turned on/off.
float getSmoothnessThreshold() const
Returns smoothness threshold.
virtual void setCurvatureTestFlag(bool value)
Allows to turn on/off the curvature test.
float getCurvatureThreshold() const
Returns curvature threshold.
A point structure representing Euclidean xyz coordinates, and the RGB color.
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. ...
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method that will be used for finding KNN.
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values).
Definition: point_cloud.h:418
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:415