Point Cloud Library (PCL)  1.9.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 ();
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  seed_counter = i_seed;
436  break;
437  }
438  }
439  }
440 }
441 
442 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
443 template <typename PointT, typename NormalT> int
444 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
445 {
446  std::queue<int> seeds;
447  seeds.push (initial_seed);
448  point_labels_[initial_seed] = segment_number;
449 
450  int num_pts_in_segment = 1;
451 
452  while (!seeds.empty ())
453  {
454  int curr_seed;
455  curr_seed = seeds.front ();
456  seeds.pop ();
457 
458  size_t i_nghbr = 0;
459  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
460  {
461  int index = point_neighbours_[curr_seed][i_nghbr];
462  if (point_labels_[index] != -1)
463  {
464  i_nghbr++;
465  continue;
466  }
467 
468  bool is_a_seed = false;
469  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
470 
471  if (belongs_to_segment == false)
472  {
473  i_nghbr++;
474  continue;
475  }
476 
477  point_labels_[index] = segment_number;
478  num_pts_in_segment++;
479 
480  if (is_a_seed)
481  {
482  seeds.push (index);
483  }
484 
485  i_nghbr++;
486  }// next neighbour
487  }// next seed
488 
489  return (num_pts_in_segment);
490 }
491 
492 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
493 template <typename PointT, typename NormalT> bool
494 pcl::RegionGrowing<PointT, NormalT>::validatePoint (int initial_seed, int point, int nghbr, bool& is_a_seed) const
495 {
496  is_a_seed = true;
497 
498  float cosine_threshold = cosf (theta_threshold_);
499  float data[4];
500 
501  data[0] = input_->points[point].data[0];
502  data[1] = input_->points[point].data[1];
503  data[2] = input_->points[point].data[2];
504  data[3] = input_->points[point].data[3];
505  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
506  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> (normals_->points[point].normal));
507 
508  //check the angle between normals
509  if (smooth_mode_flag_ == true)
510  {
511  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
512  float dot_product = fabsf (nghbr_normal.dot (initial_normal));
513  if (dot_product < cosine_threshold)
514  {
515  return (false);
516  }
517  }
518  else
519  {
520  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> (normals_->points[nghbr].normal));
521  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> (normals_->points[initial_seed].normal));
522  float dot_product = fabsf (nghbr_normal.dot (initial_seed_normal));
523  if (dot_product < cosine_threshold)
524  return (false);
525  }
526 
527  // check the curvature if needed
528  if (curvature_flag_ && normals_->points[nghbr].curvature > curvature_threshold_)
529  {
530  is_a_seed = false;
531  }
532 
533  // check the residual if needed
534  float data_1[4];
535 
536  data_1[0] = input_->points[nghbr].data[0];
537  data_1[1] = input_->points[nghbr].data[1];
538  data_1[2] = input_->points[nghbr].data[2];
539  data_1[3] = input_->points[nghbr].data[3];
540  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
541  float residual = fabsf (initial_normal.dot (initial_point - nghbr_point));
542  if (residual_flag_ && residual > residual_threshold_)
543  is_a_seed = false;
544 
545  return (true);
546 }
547 
548 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
549 template <typename PointT, typename NormalT> void
551 {
552  int number_of_segments = static_cast<int> (num_pts_in_segment_.size ());
553  int number_of_points = static_cast<int> (input_->points.size ());
554 
555  pcl::PointIndices segment;
556  clusters_.resize (number_of_segments, segment);
557 
558  for (int i_seg = 0; i_seg < number_of_segments; i_seg++)
559  {
560  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
561  }
562 
563  std::vector<int> counter;
564  counter.resize (number_of_segments, 0);
565 
566  for (int i_point = 0; i_point < number_of_points; i_point++)
567  {
568  int segment_index = point_labels_[i_point];
569  if (segment_index != -1)
570  {
571  int point_index = counter[segment_index];
572  clusters_[segment_index].indices[point_index] = i_point;
573  counter[segment_index] = point_index + 1;
574  }
575  }
576 
577  number_of_segments_ = number_of_segments;
578 }
579 
580 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
581 template <typename PointT, typename NormalT> void
583 {
584  cluster.indices.clear ();
585 
586  bool segmentation_is_possible = initCompute ();
587  if ( !segmentation_is_possible )
588  {
589  deinitCompute ();
590  return;
591  }
592 
593  // first of all we need to find out if this point belongs to cloud
594  bool point_was_found = false;
595  int number_of_points = static_cast <int> (indices_->size ());
596  for (int point = 0; point < number_of_points; point++)
597  if ( (*indices_)[point] == index)
598  {
599  point_was_found = true;
600  break;
601  }
602 
603  if (point_was_found)
604  {
605  if (clusters_.empty ())
606  {
607  point_neighbours_.clear ();
608  point_labels_.clear ();
609  num_pts_in_segment_.clear ();
611 
612  segmentation_is_possible = prepareForSegmentation ();
613  if ( !segmentation_is_possible )
614  {
615  deinitCompute ();
616  return;
617  }
618 
621  assembleRegions ();
622  }
623  // if we have already made the segmentation, then find the segment
624  // to which this point belongs
625  std::vector <pcl::PointIndices>::iterator i_segment;
626  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
627  {
628  bool segment_was_found = false;
629  for (size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
630  {
631  if (i_segment->indices[i_point] == index)
632  {
633  segment_was_found = true;
634  cluster.indices.clear ();
635  cluster.indices.reserve (i_segment->indices.size ());
636  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
637  break;
638  }
639  }
640  if (segment_was_found)
641  {
642  break;
643  }
644  }// next segment
645  }// end if point was found
646 
647  deinitCompute ();
648 }
649 
650 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
651 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
653 {
655 
656  if (!clusters_.empty ())
657  {
658  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
659 
660  srand (static_cast<unsigned int> (time (0)));
661  std::vector<unsigned char> colors;
662  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
663  {
664  colors.push_back (static_cast<unsigned char> (rand () % 256));
665  colors.push_back (static_cast<unsigned char> (rand () % 256));
666  colors.push_back (static_cast<unsigned char> (rand () % 256));
667  }
668 
669  colored_cloud->width = input_->width;
670  colored_cloud->height = input_->height;
671  colored_cloud->is_dense = input_->is_dense;
672  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
673  {
674  pcl::PointXYZRGB point;
675  point.x = *(input_->points[i_point].data);
676  point.y = *(input_->points[i_point].data + 1);
677  point.z = *(input_->points[i_point].data + 2);
678  point.r = 255;
679  point.g = 0;
680  point.b = 0;
681  colored_cloud->points.push_back (point);
682  }
683 
684  std::vector< pcl::PointIndices >::iterator i_segment;
685  int next_color = 0;
686  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
687  {
688  std::vector<int>::iterator i_point;
689  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
690  {
691  int index;
692  index = *i_point;
693  colored_cloud->points[index].r = colors[3 * next_color];
694  colored_cloud->points[index].g = colors[3 * next_color + 1];
695  colored_cloud->points[index].b = colors[3 * next_color + 2];
696  }
697  next_color++;
698  }
699  }
700 
701  return (colored_cloud);
702 }
703 
704 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
705 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
707 {
709 
710  if (!clusters_.empty ())
711  {
712  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
713 
714  srand (static_cast<unsigned int> (time (0)));
715  std::vector<unsigned char> colors;
716  for (size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
717  {
718  colors.push_back (static_cast<unsigned char> (rand () % 256));
719  colors.push_back (static_cast<unsigned char> (rand () % 256));
720  colors.push_back (static_cast<unsigned char> (rand () % 256));
721  }
722 
723  colored_cloud->width = input_->width;
724  colored_cloud->height = input_->height;
725  colored_cloud->is_dense = input_->is_dense;
726  for (size_t i_point = 0; i_point < input_->points.size (); i_point++)
727  {
728  pcl::PointXYZRGBA point;
729  point.x = *(input_->points[i_point].data);
730  point.y = *(input_->points[i_point].data + 1);
731  point.z = *(input_->points[i_point].data + 2);
732  point.r = 255;
733  point.g = 0;
734  point.b = 0;
735  point.a = 0;
736  colored_cloud->points.push_back (point);
737  }
738 
739  std::vector< pcl::PointIndices >::iterator i_segment;
740  int next_color = 0;
741  for (i_segment = clusters_.begin (); i_segment != clusters_.end (); i_segment++)
742  {
743  std::vector<int>::iterator i_point;
744  for (i_point = i_segment->indices.begin (); i_point != i_segment->indices.end (); i_point++)
745  {
746  int index;
747  index = *i_point;
748  colored_cloud->points[index].r = colors[3 * next_color];
749  colored_cloud->points[index].g = colors[3 * next_color + 1];
750  colored_cloud->points[index].b = colors[3 * next_color + 2];
751  }
752  next_color++;
753  }
754  }
755 
756  return (colored_cloud);
757 }
758 
759 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
760 
761 #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 in any of their floating point fields)...
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.