Point Cloud Library (PCL)  1.8.0
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 ();
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 
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_)
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  float data_1[4];
534 
535  data_1[0] = input_->points[nghbr].data[0];
536  data_1[1] = input_->points[nghbr].data[1];
537  data_1[2] = input_->points[nghbr].data[2];
538  data_1[3] = input_->points[nghbr].data[3];
539  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
540  float residual = fabsf (initial_normal.dot (initial_point - nghbr_point));
541  if (residual_flag_ && residual > residual_threshold_)
542  is_a_seed = false;
543 
544  return (true);
545 }
546 
547 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
548 template <typename PointT, typename NormalT> void
550 {
551  int number_of_segments = static_cast<int> (num_pts_in_segment_.size ());
552  int number_of_points = static_cast<int> (input_->points.size ());
553 
554  pcl::PointIndices segment;
555  clusters_.resize (number_of_segments, segment);
556 
557  for (int i_seg = 0; i_seg < number_of_segments; i_seg++)
558  {
559  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
560  }
561 
562  std::vector<int> counter;
563  counter.resize (number_of_segments, 0);
564 
565  for (int i_point = 0; i_point < number_of_points; i_point++)
566  {
567  int segment_index = point_labels_[i_point];
568  if (segment_index != -1)
569  {
570  int point_index = counter[segment_index];
571  clusters_[segment_index].indices[point_index] = i_point;
572  counter[segment_index] = point_index + 1;
573  }
574  }
575 
576  number_of_segments_ = number_of_segments;
577 }
578 
579 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
580 template <typename PointT, typename NormalT> void
582 {
583  cluster.indices.clear ();
584 
585  bool segmentation_is_possible = initCompute ();
586  if ( !segmentation_is_possible )
587  {
588  deinitCompute ();
589  return;
590  }
591 
592  // first of all we need to find out if this point belongs to cloud
593  bool point_was_found = false;
594  int number_of_points = static_cast <int> (indices_->size ());
595  for (int point = 0; point < number_of_points; point++)
596  if ( (*indices_)[point] == index)
597  {
598  point_was_found = true;
599  break;
600  }
601 
602  if (point_was_found)
603  {
604  if (clusters_.empty ())
605  {
606  point_neighbours_.clear ();
607  point_labels_.clear ();
608  num_pts_in_segment_.clear ();
610 
611  segmentation_is_possible = prepareForSegmentation ();
612  if ( !segmentation_is_possible )
613  {
614  deinitCompute ();
615  return;
616  }
617 
620  assembleRegions ();
621  }
622  // if we have already made the segmentation, then find the segment
623  // to which this point belongs
624  std::vector <pcl::PointIndices>::iterator i_segment;
625  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
626  {
627  bool segment_was_found = false;
628  for (size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
629  {
630  if (i_segment->indices[i_point] == index)
631  {
632  segment_was_found = true;
633  cluster.indices.clear ();
634  cluster.indices.reserve (i_segment->indices.size ());
635  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
636  break;
637  }
638  }
639  if (segment_was_found)
640  {
641  break;
642  }
643  }// next segment
644  }// end if point was found
645 
646  deinitCompute ();
647 }
648 
649 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
650 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
652 {
654 
655  if (!clusters_.empty ())
656  {
657  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
658 
659  srand (static_cast<unsigned int> (time (0)));
660  std::vector<unsigned char> colors;
661  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
662  {
663  colors.push_back (static_cast<unsigned char> (rand () % 256));
664  colors.push_back (static_cast<unsigned char> (rand () % 256));
665  colors.push_back (static_cast<unsigned char> (rand () % 256));
666  }
667 
668  colored_cloud->width = input_->width;
669  colored_cloud->height = input_->height;
670  colored_cloud->is_dense = input_->is_dense;
671  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
672  {
673  pcl::PointXYZRGB point;
674  point.x = *(input_->points[i_point].data);
675  point.y = *(input_->points[i_point].data + 1);
676  point.z = *(input_->points[i_point].data + 2);
677  point.r = 255;
678  point.g = 0;
679  point.b = 0;
680  colored_cloud->points.push_back (point);
681  }
682 
683  std::vector< pcl::PointIndices >::iterator i_segment;
684  int next_color = 0;
685  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
686  {
687  std::vector<int>::iterator i_point;
688  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
689  {
690  int index;
691  index = *i_point;
692  colored_cloud->points[index].r = colors[3 * next_color];
693  colored_cloud->points[index].g = colors[3 * next_color + 1];
694  colored_cloud->points[index].b = colors[3 * next_color + 2];
695  }
696  next_color++;
697  }
698  }
699 
700  return (colored_cloud);
701 }
702 
703 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
704 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
706 {
708 
709  if (!clusters_.empty ())
710  {
711  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
712 
713  srand (static_cast<unsigned int> (time (0)));
714  std::vector<unsigned char> colors;
715  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
716  {
717  colors.push_back (static_cast<unsigned char> (rand () % 256));
718  colors.push_back (static_cast<unsigned char> (rand () % 256));
719  colors.push_back (static_cast<unsigned char> (rand () % 256));
720  }
721 
722  colored_cloud->width = input_->width;
723  colored_cloud->height = input_->height;
724  colored_cloud->is_dense = input_->is_dense;
725  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
726  {
727  pcl::PointXYZRGBA point;
728  point.x = *(input_->points[i_point].data);
729  point.y = *(input_->points[i_point].data + 1);
730  point.z = *(input_->points[i_point].data + 2);
731  point.r = 255;
732  point.g = 0;
733  point.b = 0;
734  point.a = 0;
735  colored_cloud->points.push_back (point);
736  }
737 
738  std::vector< pcl::PointIndices >::iterator i_segment;
739  int next_color = 0;
740  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
741  {
742  std::vector<int>::iterator i_point;
743  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
744  {
745  int index;
746  index = *i_point;
747  colored_cloud->points[index].r = colors[3 * next_color];
748  colored_cloud->points[index].g = colors[3 * next_color + 1];
749  colored_cloud->points[index].b = colors[3 * next_color + 2];
750  }
751  next_color++;
752  }
753  }
754 
755  return (colored_cloud);
756 }
757 
758 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
759 
760 #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:54
float getResidualThreshold() const
Returns residual threshold.
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
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:153
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.
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
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:415
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:139
NormalPtr normals_
Contains normals of the points that will be segmented.
boost::shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:428
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:413
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.
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. ...
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
bool deinitCompute()
This method should get called after finishing the actual computation.
Definition: pcl_base.hpp:174
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).
Definition: point_cloud.h:418
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:150
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.
std::vector< std::vector< int > > point_neighbours_
Contains neighbours of each point.