Point Cloud Library (PCL)  1.11.1-dev
region_growing.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the copyright holder(s) nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Author : Sergey Ushakov
36  * Email : mine_all_mine@bk.ru
37  *
38  */
39 
40 #pragma once
41 
42 #include <pcl/segmentation/region_growing.h>
43 
44 #include <pcl/point_cloud.h>
45 #include <pcl/point_types.h>
46 #include <pcl/common/point_tests.h> // for pcl::isFinite
47 #include <pcl/console/print.h> // for PCL_ERROR
48 #include <pcl/search/search.h>
49 #include <pcl/search/kdtree.h>
50 
51 #include <queue>
52 #include <list>
53 #include <cmath>
54 #include <ctime>
55 
56 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
57 template <typename PointT, typename NormalT>
59  min_pts_per_cluster_ (1),
60  max_pts_per_cluster_ (std::numeric_limits<int>::max ()),
61  smooth_mode_flag_ (true),
62  curvature_flag_ (true),
63  residual_flag_ (false),
64  theta_threshold_ (30.0f / 180.0f * static_cast<float> (M_PI)),
65  residual_threshold_ (0.05f),
66  curvature_threshold_ (0.05f),
67  neighbour_number_ (30),
68  search_ (),
69  normals_ (),
70  point_neighbours_ (0),
71  point_labels_ (0),
72  normal_flag_ (true),
73  num_pts_in_segment_ (0),
74  clusters_ (0),
75  number_of_segments_ (0)
76 {
77 }
78 
79 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80 template <typename PointT, typename NormalT>
82 {
83  point_neighbours_.clear ();
84  point_labels_.clear ();
85  num_pts_in_segment_.clear ();
86  clusters_.clear ();
87 }
88 
89 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
90 template <typename PointT, typename NormalT> int
92 {
93  return (min_pts_per_cluster_);
94 }
95 
96 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
97 template <typename PointT, typename NormalT> void
99 {
100  min_pts_per_cluster_ = min_cluster_size;
101 }
102 
103 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
104 template <typename PointT, typename NormalT> int
106 {
107  return (max_pts_per_cluster_);
108 }
109 
110 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111 template <typename PointT, typename NormalT> void
113 {
114  max_pts_per_cluster_ = max_cluster_size;
115 }
116 
117 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
118 template <typename PointT, typename NormalT> bool
120 {
121  return (smooth_mode_flag_);
122 }
123 
124 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
125 template <typename PointT, typename NormalT> void
127 {
128  smooth_mode_flag_ = value;
129 }
130 
131 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
132 template <typename PointT, typename NormalT> bool
134 {
135  return (curvature_flag_);
136 }
137 
138 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 template <typename PointT, typename NormalT> void
141 {
142  curvature_flag_ = value;
143 
144  if (curvature_flag_ == false && residual_flag_ == false)
145  residual_flag_ = true;
146 }
147 
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 template <typename PointT, typename NormalT> bool
151 {
152  return (residual_flag_);
153 }
154 
155 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
156 template <typename PointT, typename NormalT> void
158 {
159  residual_flag_ = value;
160 
161  if (curvature_flag_ == false && residual_flag_ == false)
162  curvature_flag_ = true;
163 }
164 
165 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
166 template <typename PointT, typename NormalT> float
168 {
169  return (theta_threshold_);
170 }
171 
172 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
173 template <typename PointT, typename NormalT> void
175 {
176  theta_threshold_ = theta;
177 }
178 
179 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
180 template <typename PointT, typename NormalT> float
182 {
183  return (residual_threshold_);
184 }
185 
186 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
187 template <typename PointT, typename NormalT> void
189 {
190  residual_threshold_ = residual;
191 }
192 
193 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194 template <typename PointT, typename NormalT> float
196 {
197  return (curvature_threshold_);
198 }
199 
200 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201 template <typename PointT, typename NormalT> void
203 {
204  curvature_threshold_ = curvature;
205 }
206 
207 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
208 template <typename PointT, typename NormalT> unsigned int
210 {
211  return (neighbour_number_);
212 }
213 
214 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
215 template <typename PointT, typename NormalT> void
217 {
218  neighbour_number_ = neighbour_number;
219 }
220 
221 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
222 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::KdTreePtr
224 {
225  return (search_);
226 }
227 
228 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
229 template <typename PointT, typename NormalT> void
231 {
232  search_ = tree;
233 }
234 
235 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
236 template <typename PointT, typename NormalT> typename pcl::RegionGrowing<PointT, NormalT>::NormalPtr
238 {
239  return (normals_);
240 }
241 
242 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
243 template <typename PointT, typename NormalT> void
245 {
246  normals_ = norm;
247 }
248 
249 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
250 template <typename PointT, typename NormalT> void
251 pcl::RegionGrowing<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
252 {
253  clusters_.clear ();
254  clusters.clear ();
255  point_neighbours_.clear ();
256  point_labels_.clear ();
257  num_pts_in_segment_.clear ();
258  number_of_segments_ = 0;
259 
260  bool segmentation_is_possible = initCompute ();
261  if ( !segmentation_is_possible )
262  {
263  deinitCompute ();
264  return;
265  }
266 
267  segmentation_is_possible = prepareForSegmentation ();
268  if ( !segmentation_is_possible )
269  {
270  deinitCompute ();
271  return;
272  }
273 
274  findPointNeighbours ();
275  applySmoothRegionGrowingAlgorithm ();
276  assembleRegions ();
277 
278  clusters.resize (clusters_.size ());
279  std::vector<pcl::PointIndices>::iterator cluster_iter_input = clusters.begin ();
280  for (std::vector<pcl::PointIndices>::const_iterator cluster_iter = clusters_.begin (); cluster_iter != clusters_.end (); ++cluster_iter)
281  {
282  if ((static_cast<int> (cluster_iter->indices.size ()) >= min_pts_per_cluster_) &&
283  (static_cast<int> (cluster_iter->indices.size ()) <= max_pts_per_cluster_))
284  {
285  *cluster_iter_input = *cluster_iter;
286  ++cluster_iter_input;
287  }
288  }
289 
290  clusters_ = std::vector<pcl::PointIndices> (clusters.begin (), cluster_iter_input);
291  clusters.resize(clusters_.size());
292 
293  deinitCompute ();
294 }
295 
296 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
297 template <typename PointT, typename NormalT> bool
299 {
300  // if user forgot to pass point cloud or if it is empty
301  if ( input_->points.empty () )
302  return (false);
303 
304  // if user forgot to pass normals or the sizes of point and normal cloud are different
305  if ( !normals_ || input_->size () != normals_->size () )
306  return (false);
307 
308  // if residual test is on then we need to check if all needed parameters were correctly initialized
309  if (residual_flag_)
310  {
311  if (residual_threshold_ <= 0.0f)
312  return (false);
313  }
314 
315  // if curvature test is on ...
316  // if (curvature_flag_)
317  // {
318  // in this case we do not need to check anything that related to it
319  // so we simply commented it
320  // }
321 
322  // from here we check those parameters that are always valuable
323  if (neighbour_number_ == 0)
324  return (false);
325 
326  // if user didn't set search method
327  if (!search_)
328  search_.reset (new pcl::search::KdTree<PointT>);
329 
330  if (indices_)
331  {
332  if (indices_->empty ())
333  PCL_ERROR ("[pcl::RegionGrowing::prepareForSegmentation] Empty given indices!\n");
334  search_->setInputCloud (input_, indices_);
335  }
336  else
337  search_->setInputCloud (input_);
338 
339  return (true);
340 }
341 
342 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
343 template <typename PointT, typename NormalT> void
345 {
346  int point_number = static_cast<int> (indices_->size ());
347  std::vector<int> neighbours;
348  std::vector<float> distances;
349 
350  point_neighbours_.resize (input_->size (), neighbours);
351  if (input_->is_dense)
352  {
353  for (int i_point = 0; i_point < point_number; i_point++)
354  {
355  int point_index = (*indices_)[i_point];
356  neighbours.clear ();
357  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
358  point_neighbours_[point_index].swap (neighbours);
359  }
360  }
361  else
362  {
363  for (int i_point = 0; i_point < point_number; i_point++)
364  {
365  neighbours.clear ();
366  int point_index = (*indices_)[i_point];
367  if (!pcl::isFinite ((*input_)[point_index]))
368  continue;
369  search_->nearestKSearch (i_point, neighbour_number_, neighbours, distances);
370  point_neighbours_[point_index].swap (neighbours);
371  }
372  }
373 }
374 
375 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
376 template <typename PointT, typename NormalT> void
378 {
379  int num_of_pts = static_cast<int> (indices_->size ());
380  point_labels_.resize (input_->size (), -1);
381 
382  std::vector< std::pair<float, int> > point_residual;
383  std::pair<float, int> pair;
384  point_residual.resize (num_of_pts, pair);
385 
386  if (normal_flag_ == true)
387  {
388  for (int i_point = 0; i_point < num_of_pts; i_point++)
389  {
390  int point_index = (*indices_)[i_point];
391  point_residual[i_point].first = (*normals_)[point_index].curvature;
392  point_residual[i_point].second = point_index;
393  }
394  std::sort (point_residual.begin (), point_residual.end (), comparePair);
395  }
396  else
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 = 0;
402  point_residual[i_point].second = point_index;
403  }
404  }
405  int seed_counter = 0;
406  int seed = point_residual[seed_counter].second;
407 
408  int segmented_pts_num = 0;
409  int number_of_segments = 0;
410  while (segmented_pts_num < num_of_pts)
411  {
412  int pts_in_segment;
413  pts_in_segment = growRegion (seed, number_of_segments);
414  segmented_pts_num += pts_in_segment;
415  num_pts_in_segment_.push_back (pts_in_segment);
416  number_of_segments++;
417 
418  //find next point that is not segmented yet
419  for (int i_seed = seed_counter + 1; i_seed < num_of_pts; i_seed++)
420  {
421  int index = point_residual[i_seed].second;
422  if (point_labels_[index] == -1)
423  {
424  seed = index;
425  seed_counter = i_seed;
426  break;
427  }
428  }
429  }
430 }
431 
432 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
433 template <typename PointT, typename NormalT> int
434 pcl::RegionGrowing<PointT, NormalT>::growRegion (int initial_seed, int segment_number)
435 {
436  std::queue<int> seeds;
437  seeds.push (initial_seed);
438  point_labels_[initial_seed] = segment_number;
439 
440  int num_pts_in_segment = 1;
441 
442  while (!seeds.empty ())
443  {
444  int curr_seed;
445  curr_seed = seeds.front ();
446  seeds.pop ();
447 
448  std::size_t i_nghbr = 0;
449  while ( i_nghbr < neighbour_number_ && i_nghbr < point_neighbours_[curr_seed].size () )
450  {
451  int index = point_neighbours_[curr_seed][i_nghbr];
452  if (point_labels_[index] != -1)
453  {
454  i_nghbr++;
455  continue;
456  }
457 
458  bool is_a_seed = false;
459  bool belongs_to_segment = validatePoint (initial_seed, curr_seed, index, is_a_seed);
460 
461  if (!belongs_to_segment)
462  {
463  i_nghbr++;
464  continue;
465  }
466 
467  point_labels_[index] = segment_number;
468  num_pts_in_segment++;
469 
470  if (is_a_seed)
471  {
472  seeds.push (index);
473  }
474 
475  i_nghbr++;
476  }// next neighbour
477  }// next seed
478 
479  return (num_pts_in_segment);
480 }
481 
482 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
483 template <typename PointT, typename NormalT> bool
484 pcl::RegionGrowing<PointT, NormalT>::validatePoint (int initial_seed, int point, int nghbr, bool& is_a_seed) const
485 {
486  is_a_seed = true;
487 
488  float cosine_threshold = std::cos (theta_threshold_);
489  float data[4];
490 
491  data[0] = (*input_)[point].data[0];
492  data[1] = (*input_)[point].data[1];
493  data[2] = (*input_)[point].data[2];
494  data[3] = (*input_)[point].data[3];
495  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
496  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
497 
498  //check the angle between normals
499  if (smooth_mode_flag_ == true)
500  {
501  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
502  float dot_product = std::abs (nghbr_normal.dot (initial_normal));
503  if (dot_product < cosine_threshold)
504  {
505  return (false);
506  }
507  }
508  else
509  {
510  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
511  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> ((*normals_)[initial_seed].normal));
512  float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
513  if (dot_product < cosine_threshold)
514  return (false);
515  }
516 
517  // check the curvature if needed
518  if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
519  {
520  is_a_seed = false;
521  }
522 
523  // check the residual if needed
524  float data_1[4];
525 
526  data_1[0] = (*input_)[nghbr].data[0];
527  data_1[1] = (*input_)[nghbr].data[1];
528  data_1[2] = (*input_)[nghbr].data[2];
529  data_1[3] = (*input_)[nghbr].data[3];
530  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_1));
531  float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
532  if (residual_flag_ && residual > residual_threshold_)
533  is_a_seed = false;
534 
535  return (true);
536 }
537 
538 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
539 template <typename PointT, typename NormalT> void
541 {
542  const auto number_of_segments = num_pts_in_segment_.size ();
543  const auto number_of_points = input_->size ();
544 
545  pcl::PointIndices segment;
546  clusters_.resize (number_of_segments, segment);
547 
548  for (std::size_t i_seg = 0; i_seg < number_of_segments; i_seg++)
549  {
550  clusters_[i_seg].indices.resize ( num_pts_in_segment_[i_seg], 0);
551  }
552 
553  std::vector<int> counter(number_of_segments, 0);
554 
555  for (std::size_t i_point = 0; i_point < number_of_points; i_point++)
556  {
557  const auto segment_index = point_labels_[i_point];
558  if (segment_index != -1)
559  {
560  const auto point_index = counter[segment_index];
561  clusters_[segment_index].indices[point_index] = i_point;
562  counter[segment_index] = point_index + 1;
563  }
564  }
565 
566  number_of_segments_ = number_of_segments;
567 }
568 
569 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
570 template <typename PointT, typename NormalT> void
572 {
573  cluster.indices.clear ();
574 
575  bool segmentation_is_possible = initCompute ();
576  if ( !segmentation_is_possible )
577  {
578  deinitCompute ();
579  return;
580  }
581 
582  // first of all we need to find out if this point belongs to cloud
583  bool point_was_found = false;
584  int number_of_points = static_cast <int> (indices_->size ());
585  for (int point = 0; point < number_of_points; point++)
586  if ( (*indices_)[point] == index)
587  {
588  point_was_found = true;
589  break;
590  }
591 
592  if (point_was_found)
593  {
594  if (clusters_.empty ())
595  {
596  point_neighbours_.clear ();
597  point_labels_.clear ();
598  num_pts_in_segment_.clear ();
599  number_of_segments_ = 0;
600 
601  segmentation_is_possible = prepareForSegmentation ();
602  if ( !segmentation_is_possible )
603  {
604  deinitCompute ();
605  return;
606  }
607 
608  findPointNeighbours ();
609  applySmoothRegionGrowingAlgorithm ();
610  assembleRegions ();
611  }
612  // if we have already made the segmentation, then find the segment
613  // to which this point belongs
614  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
615  {
616  bool segment_was_found = false;
617  for (std::size_t i_point = 0; i_point < i_segment->indices.size (); i_point++)
618  {
619  if (i_segment->indices[i_point] == index)
620  {
621  segment_was_found = true;
622  cluster.indices.clear ();
623  cluster.indices.reserve (i_segment->indices.size ());
624  std::copy (i_segment->indices.begin (), i_segment->indices.end (), std::back_inserter (cluster.indices));
625  break;
626  }
627  }
628  if (segment_was_found)
629  {
630  break;
631  }
632  }// next segment
633  }// end if point was found
634 
635  deinitCompute ();
636 }
637 
638 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
639 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
641 {
643 
644  if (!clusters_.empty ())
645  {
646  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared ();
647 
648  srand (static_cast<unsigned int> (time (nullptr)));
649  std::vector<unsigned char> colors;
650  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
651  {
652  colors.push_back (static_cast<unsigned char> (rand () % 256));
653  colors.push_back (static_cast<unsigned char> (rand () % 256));
654  colors.push_back (static_cast<unsigned char> (rand () % 256));
655  }
656 
657  colored_cloud->width = input_->width;
658  colored_cloud->height = input_->height;
659  colored_cloud->is_dense = input_->is_dense;
660  for (const auto& i_point: *input_)
661  {
662  pcl::PointXYZRGB point;
663  point.x = *(i_point.data);
664  point.y = *(i_point.data + 1);
665  point.z = *(i_point.data + 2);
666  point.r = 255;
667  point.g = 0;
668  point.b = 0;
669  colored_cloud->points.push_back (point);
670  }
671 
672  int next_color = 0;
673  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
674  {
675  for (auto i_point = i_segment->indices.cbegin (); i_point != i_segment->indices.cend (); i_point++)
676  {
677  int index;
678  index = *i_point;
679  (*colored_cloud)[index].r = colors[3 * next_color];
680  (*colored_cloud)[index].g = colors[3 * next_color + 1];
681  (*colored_cloud)[index].b = colors[3 * next_color + 2];
682  }
683  next_color++;
684  }
685  }
686 
687  return (colored_cloud);
688 }
689 
690 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
691 template <typename PointT, typename NormalT> pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
693 {
695 
696  if (!clusters_.empty ())
697  {
698  colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGBA>)->makeShared ();
699 
700  srand (static_cast<unsigned int> (time (nullptr)));
701  std::vector<unsigned char> colors;
702  for (std::size_t i_segment = 0; i_segment < clusters_.size (); i_segment++)
703  {
704  colors.push_back (static_cast<unsigned char> (rand () % 256));
705  colors.push_back (static_cast<unsigned char> (rand () % 256));
706  colors.push_back (static_cast<unsigned char> (rand () % 256));
707  }
708 
709  colored_cloud->width = input_->width;
710  colored_cloud->height = input_->height;
711  colored_cloud->is_dense = input_->is_dense;
712  for (const auto& i_point: *input_)
713  {
714  pcl::PointXYZRGBA point;
715  point.x = *(i_point.data);
716  point.y = *(i_point.data + 1);
717  point.z = *(i_point.data + 2);
718  point.r = 255;
719  point.g = 0;
720  point.b = 0;
721  point.a = 0;
722  colored_cloud->points.push_back (point);
723  }
724 
725  int next_color = 0;
726  for (auto i_segment = clusters_.cbegin (); i_segment != clusters_.cend (); i_segment++)
727  {
728  for (auto i_point = i_segment->indices.cbegin (); i_point != i_segment->indices.cend (); i_point++)
729  {
730  int index = *i_point;
731  (*colored_cloud)[index].r = colors[3 * next_color];
732  (*colored_cloud)[index].g = colors[3 * next_color + 1];
733  (*colored_cloud)[index].b = colors[3 * next_color + 2];
734  }
735  next_color++;
736  }
737  }
738 
739  return (colored_cloud);
740 }
741 
742 #define PCL_INSTANTIATE_RegionGrowing(T) template class pcl::RegionGrowing<T, pcl::Normal>;
743 
pcl::RegionGrowing::getNumberOfNeighbours
unsigned int getNumberOfNeighbours() const
Returns the number of nearest neighbours used for KNN.
Definition: region_growing.hpp:209
pcl::RegionGrowing::getMaxClusterSize
int getMaxClusterSize()
Get the maximum number of points that a cluster needs to contain in order to be considered valid.
Definition: region_growing.hpp:105
point_types.h
pcl::RegionGrowing::KdTreePtr
typename KdTree::Ptr KdTreePtr
Definition: region_growing.h:67
pcl::PointCloud::height
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:415
pcl::PointCloud::points
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
pcl::isFinite
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:55
pcl::RegionGrowing::setCurvatureTestFlag
virtual void setCurvatureTestFlag(bool value)
Allows to turn on/off the curvature test.
Definition: region_growing.hpp:140
pcl::RegionGrowing::extract
virtual void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
Definition: region_growing.hpp:251
pcl::PointIndices::indices
Indices indices
Definition: PointIndices.h:21
pcl::RegionGrowing::applySmoothRegionGrowingAlgorithm
void applySmoothRegionGrowingAlgorithm()
This function implements the algorithm described in the article "Segmentation of point clouds using s...
Definition: region_growing.hpp:377
pcl::RegionGrowing::setResidualThreshold
void setResidualThreshold(float residual)
Allows to set residual threshold used for testing the points.
Definition: region_growing.hpp:188
pcl::RegionGrowing::setNumberOfNeighbours
void setNumberOfNeighbours(unsigned int neighbour_number)
Allows to set the number of neighbours.
Definition: region_growing.hpp:216
pcl::RegionGrowing::prepareForSegmentation
virtual bool prepareForSegmentation()
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
Definition: region_growing.hpp:298
pcl::RegionGrowing::setSmoothnessThreshold
void setSmoothnessThreshold(float theta)
Allows to set smoothness threshold used for testing the points.
Definition: region_growing.hpp:174
pcl::PointCloud< pcl::PointXYZRGB >
pcl::PointXYZRGB
A point structure representing Euclidean xyz coordinates, and the RGB color.
Definition: point_types.hpp:628
pcl::RegionGrowing::~RegionGrowing
~RegionGrowing()
This destructor destroys the cloud, normals and search method used for finding KNN.
Definition: region_growing.hpp:81
pcl::RegionGrowing::growRegion
int growRegion(int initial_seed, int segment_number)
This method grows a segment for the given seed point.
Definition: region_growing.hpp:434
pcl::RegionGrowing::getColoredCloud
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
If the cloud was successfully segmented, then function returns colored cloud.
Definition: region_growing.hpp:640
pcl::RegionGrowing::NormalPtr
typename Normal::Ptr NormalPtr
Definition: region_growing.h:69
pcl::RegionGrowing::getCurvatureThreshold
float getCurvatureThreshold() const
Returns curvature threshold.
Definition: region_growing.hpp:195
pcl::PointCloud::width
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:413
pcl::PointXYZRGBA
A point structure representing Euclidean xyz coordinates, and the RGBA color.
Definition: point_types.hpp:553
pcl::RegionGrowing::setResidualTestFlag
virtual void setResidualTestFlag(bool value)
Allows to turn on/off the residual test.
Definition: region_growing.hpp:157
pcl::RegionGrowing::RegionGrowing
RegionGrowing()
Constructor that sets default values for member variables.
Definition: region_growing.hpp:58
pcl::RegionGrowing::getSearchMethod
KdTreePtr getSearchMethod() const
Returns the pointer to the search method that is used for KNN.
Definition: region_growing.hpp:223
pcl::RegionGrowing::getResidualThreshold
float getResidualThreshold() const
Returns residual threshold.
Definition: region_growing.hpp:181
pcl::comparePair
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
Definition: region_growing.h:342
pcl::RegionGrowing::setMaxClusterSize
void setMaxClusterSize(int max_cluster_size)
Set the maximum number of points that a cluster needs to contain in order to be considered valid.
Definition: region_growing.hpp:112
M_PI
#define M_PI
Definition: pcl_macros.h:201
pcl::search::KdTree< PointT >
pcl::RegionGrowing::assembleRegions
void assembleRegions()
This function simply assembles the regions from list of point labels.
Definition: region_growing.hpp:540
pcl::PointCloud::is_dense
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
pcl::PointIndices
Definition: PointIndices.h:11
pcl::RegionGrowing::getCurvatureTestFlag
bool getCurvatureTestFlag() const
Returns the flag that signalize if the curvature test is turned on/off.
Definition: region_growing.hpp:133
pcl::RegionGrowing::setInputNormals
void setInputNormals(const NormalPtr &norm)
This method sets the normals.
Definition: region_growing.hpp:244
pcl::RegionGrowing::getSmoothnessThreshold
float getSmoothnessThreshold() const
Returns smoothness threshold.
Definition: region_growing.hpp:167
pcl::RegionGrowing::setSmoothModeFlag
void setSmoothModeFlag(bool value)
This function allows to turn on/off the smoothness constraint.
Definition: region_growing.hpp:126
pcl::RegionGrowing::getInputNormals
NormalPtr getInputNormals() const
Returns normals.
Definition: region_growing.hpp:237
pcl::PointCloud::Ptr
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:428
pcl::RegionGrowing::validatePoint
virtual bool validatePoint(int initial_seed, int point, int nghbr, bool &is_a_seed) const
This function is checking if the point with index 'nghbr' belongs to the segment.
Definition: region_growing.hpp:484
pcl::RegionGrowing::findPointNeighbours
virtual void findPointNeighbours()
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
Definition: region_growing.hpp:344
pcl::RegionGrowing::setSearchMethod
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method that will be used for finding KNN.
Definition: region_growing.hpp:230
pcl::RegionGrowing::setCurvatureThreshold
void setCurvatureThreshold(float curvature)
Allows to set curvature threshold used for testing the points.
Definition: region_growing.hpp:202
pcl::RegionGrowing::getColoredCloudRGBA
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr getColoredCloudRGBA()
If the cloud was successfully segmented, then function returns colored cloud.
Definition: region_growing.hpp:692
pcl::RegionGrowing::getResidualTestFlag
bool getResidualTestFlag() const
Returns the flag that signalize if the residual test is turned on/off.
Definition: region_growing.hpp:150
pcl::RegionGrowing::getSmoothModeFlag
bool getSmoothModeFlag() const
Returns the flag value.
Definition: region_growing.hpp:119
pcl::RegionGrowing::setMinClusterSize
void setMinClusterSize(int min_cluster_size)
Set the minimum number of points that a cluster needs to contain in order to be considered valid.
Definition: region_growing.hpp:98
pcl::RegionGrowing::getSegmentFromPoint
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.
Definition: region_growing.hpp:571
pcl::RegionGrowing::getMinClusterSize
int getMinClusterSize()
Get the minimum number of points that a cluster needs to contain in order to be considered valid.
Definition: region_growing.hpp:91