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