Point Cloud Library (PCL)  1.13.1-dev
region_growing_rgb.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_RGB_HPP_
41 #define PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
42 
43 #include <pcl/console/print.h> // for PCL_ERROR
44 #include <pcl/segmentation/region_growing_rgb.h>
45 #include <pcl/search/search.h>
46 #include <pcl/search/kdtree.h>
47 
48 #include <queue>
49 
50 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
51 template <typename PointT, typename NormalT>
53  color_p2p_threshold_ (1225.0f),
54  color_r2r_threshold_ (10.0f),
55  distance_threshold_ (0.05f),
56  region_neighbour_number_ (100),
57  point_distances_ (0),
58  segment_neighbours_ (0),
59  segment_distances_ (0),
60  segment_labels_ (0)
61 {
62  normal_flag_ = false;
63  curvature_flag_ = false;
64  residual_flag_ = false;
66 }
67 
68 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
69 template <typename PointT, typename NormalT>
71 {
72  point_distances_.clear ();
73  segment_neighbours_.clear ();
74  segment_distances_.clear ();
75  segment_labels_.clear ();
76 }
77 
78 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
79 template <typename PointT, typename NormalT> float
81 {
82  return (powf (color_p2p_threshold_, 0.5f));
83 }
84 
85 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
86 template <typename PointT, typename NormalT> void
88 {
89  color_p2p_threshold_ = thresh * thresh;
90 }
91 
92 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93 template <typename PointT, typename NormalT> float
95 {
96  return (powf (color_r2r_threshold_, 0.5f));
97 }
98 
99 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100 template <typename PointT, typename NormalT> void
102 {
103  color_r2r_threshold_ = thresh * thresh;
104 }
105 
106 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
107 template <typename PointT, typename NormalT> float
109 {
110  return (powf (distance_threshold_, 0.5f));
111 }
112 
113 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
114 template <typename PointT, typename NormalT> void
116 {
117  distance_threshold_ = thresh * thresh;
118 }
119 
120 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
121 template <typename PointT, typename NormalT> unsigned int
123 {
124  return (region_neighbour_number_);
125 }
126 
127 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
128 template <typename PointT, typename NormalT> void
130 {
131  region_neighbour_number_ = nghbr_number;
132 }
133 
134 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
135 template <typename PointT, typename NormalT> bool
137 {
138  return (normal_flag_);
139 }
140 
141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 template <typename PointT, typename NormalT> void
144 {
145  normal_flag_ = value;
146 }
147 
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 template <typename PointT, typename NormalT> void
151 {
152  curvature_flag_ = value;
153 }
154 
155 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
156 template <typename PointT, typename NormalT> void
158 {
159  residual_flag_ = value;
160 }
161 
162 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
163 template <typename PointT, typename NormalT> void
164 pcl::RegionGrowingRGB<PointT, NormalT>::extract (std::vector <pcl::PointIndices>& clusters)
165 {
166  clusters_.clear ();
167  clusters.clear ();
168  point_neighbours_.clear ();
169  point_labels_.clear ();
170  num_pts_in_segment_.clear ();
171  point_distances_.clear ();
172  segment_neighbours_.clear ();
173  segment_distances_.clear ();
174  segment_labels_.clear ();
175  number_of_segments_ = 0;
176 
177  bool segmentation_is_possible = initCompute ();
178  if ( !segmentation_is_possible )
179  {
180  deinitCompute ();
181  return;
182  }
183 
184  segmentation_is_possible = prepareForSegmentation ();
185  if ( !segmentation_is_possible )
186  {
187  deinitCompute ();
188  return;
189  }
190 
191  findPointNeighbours ();
192  applySmoothRegionGrowingAlgorithm ();
194 
195  findSegmentNeighbours ();
196  applyRegionMergingAlgorithm ();
197 
198  auto cluster_iter = clusters_.begin ();
199  while (cluster_iter != clusters_.end ())
200  {
201  if (cluster_iter->indices.size () < min_pts_per_cluster_ ||
202  cluster_iter->indices.size () > max_pts_per_cluster_)
203  {
204  cluster_iter = clusters_.erase (cluster_iter);
205  }
206  else
207  ++cluster_iter;
208  }
209 
210  clusters.reserve (clusters_.size ());
211  std::copy (clusters_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
212 
213  deinitCompute ();
214 }
215 
216 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
217 template <typename PointT, typename NormalT> bool
219 {
220  // if user forgot to pass point cloud or if it is empty
221  if ( input_->points.empty () )
222  return (false);
223 
224  // if normal/smoothness test is on then we need to check if all needed variables and parameters
225  // were correctly initialized
226  if (normal_flag_)
227  {
228  // if user forgot to pass normals or the sizes of point and normal cloud are different
229  if ( !normals_ || input_->size () != normals_->size () )
230  return (false);
231  }
232 
233  // if residual test is on then we need to check if all needed parameters were correctly initialized
234  if (residual_flag_)
235  {
236  if (residual_threshold_ <= 0.0f)
237  return (false);
238  }
239 
240  // if curvature test is on ...
241  // if (curvature_flag_)
242  // {
243  // in this case we do not need to check anything that related to it
244  // so we simply commented it
245  // }
246 
247  // here we check the parameters related to color-based segmentation
248  if ( region_neighbour_number_ == 0 || color_p2p_threshold_ < 0.0f || color_r2r_threshold_ < 0.0f || distance_threshold_ < 0.0f )
249  return (false);
250 
251  // from here we check those parameters that are always valuable
252  if (neighbour_number_ == 0)
253  return (false);
254 
255  // if user didn't set search method
256  if (!search_)
257  search_.reset (new pcl::search::KdTree<PointT>);
258 
259  if (indices_)
260  {
261  if (indices_->empty ())
262  PCL_ERROR ("[pcl::RegionGrowingRGB::prepareForSegmentation] Empty given indices!\n");
263  search_->setInputCloud (input_, indices_);
264  }
265  else
266  search_->setInputCloud (input_);
267 
268  return (true);
269 }
270 
271 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272 template <typename PointT, typename NormalT> void
274 {
275  pcl::Indices neighbours;
276  std::vector<float> distances;
277 
278  point_neighbours_.resize (input_->size (), neighbours);
279  point_distances_.resize (input_->size (), distances);
280 
281  for (const auto& point_index: (*indices_))
282  {
283  neighbours.clear ();
284  distances.clear ();
285  search_->nearestKSearch (point_index, region_neighbour_number_, neighbours, distances);
286  point_neighbours_[point_index].swap (neighbours);
287  point_distances_[point_index].swap (distances);
288  }
289 }
290 
291 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
292 template <typename PointT, typename NormalT> void
294 {
295  pcl::Indices neighbours;
296  std::vector<float> distances;
297  segment_neighbours_.resize (number_of_segments_, neighbours);
298  segment_distances_.resize (number_of_segments_, distances);
299 
300  for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
301  {
302  pcl::Indices nghbrs;
303  std::vector<float> dist;
304  findRegionsKNN (i_seg, region_neighbour_number_, nghbrs, dist);
305  segment_neighbours_[i_seg].swap (nghbrs);
306  segment_distances_[i_seg].swap (dist);
307  }
308 }
309 
310 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
311 template <typename PointT,typename NormalT> void
313 {
314  std::vector<float> distances;
315  float max_dist = std::numeric_limits<float>::max ();
316  distances.resize (clusters_.size (), max_dist);
317 
318  const auto number_of_points = num_pts_in_segment_[index];
319  //loop through every point in this segment and check neighbours
320  for (pcl::uindex_t i_point = 0; i_point < number_of_points; i_point++)
321  {
322  const auto point_index = clusters_[index].indices[i_point];
323  const auto number_of_neighbours = point_neighbours_[point_index].size ();
324  //loop through every neighbour of the current point, find out to which segment it belongs
325  //and if it belongs to neighbouring segment and is close enough then remember segment and its distance
326  for (std::size_t i_nghbr = 0; i_nghbr < number_of_neighbours; i_nghbr++)
327  {
328  // find segment
329  const pcl::index_t segment_index = point_labels_[ point_neighbours_[point_index][i_nghbr] ];
330 
331  if ( segment_index != index )
332  {
333  // try to push it to the queue
334  if (distances[segment_index] > point_distances_[point_index][i_nghbr])
335  distances[segment_index] = point_distances_[point_index][i_nghbr];
336  }
337  }
338  }// next point
339 
340  std::priority_queue<std::pair<float, int> > segment_neighbours;
341  for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
342  {
343  if (distances[i_seg] < max_dist)
344  {
345  segment_neighbours.push (std::make_pair (distances[i_seg], i_seg) );
346  if (segment_neighbours.size () > nghbr_number)
347  segment_neighbours.pop ();
348  }
349  }
350 
351  const std::size_t size = std::min<std::size_t> (segment_neighbours.size (), static_cast<std::size_t>(nghbr_number));
352  nghbrs.resize (size, 0);
353  dist.resize (size, 0);
354  pcl::uindex_t counter = 0;
355  while ( !segment_neighbours.empty () && counter < nghbr_number )
356  {
357  dist[counter] = segment_neighbours.top ().first;
358  nghbrs[counter] = segment_neighbours.top ().second;
359  segment_neighbours.pop ();
360  counter++;
361  }
362 }
363 
364 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
365 template <typename PointT, typename NormalT> void
367 {
368  // calculate color of each segment
369  std::vector< std::vector<unsigned int> > segment_color;
370  std::vector<unsigned int> color;
371  color.resize (3, 0);
372  segment_color.resize (number_of_segments_, color);
373 
374  for (const auto& point_index : (*indices_))
375  {
376  int segment_index = point_labels_[point_index];
377  segment_color[segment_index][0] += (*input_)[point_index].r;
378  segment_color[segment_index][1] += (*input_)[point_index].g;
379  segment_color[segment_index][2] += (*input_)[point_index].b;
380  }
381  for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
382  {
383  segment_color[i_seg][0] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][0]) / static_cast<float> (num_pts_in_segment_[i_seg]));
384  segment_color[i_seg][1] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][1]) / static_cast<float> (num_pts_in_segment_[i_seg]));
385  segment_color[i_seg][2] = static_cast<unsigned int> (static_cast<float> (segment_color[i_seg][2]) / static_cast<float> (num_pts_in_segment_[i_seg]));
386  }
387 
388  // now it is time to find out if there are segments with a similar color
389  // and merge them together
390  std::vector<unsigned int> num_pts_in_homogeneous_region;
391  std::vector<int> num_seg_in_homogeneous_region;
392 
393  segment_labels_.resize (number_of_segments_, -1);
394 
395  float dist_thresh = distance_threshold_;
396  int homogeneous_region_number = 0;
397  for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
398  {
399  int curr_homogeneous_region = 0;
400  if (segment_labels_[i_seg] == -1)
401  {
402  segment_labels_[i_seg] = homogeneous_region_number;
403  curr_homogeneous_region = homogeneous_region_number;
404  num_pts_in_homogeneous_region.push_back (num_pts_in_segment_[i_seg]);
405  num_seg_in_homogeneous_region.push_back (1);
406  homogeneous_region_number++;
407  }
408  else
409  curr_homogeneous_region = segment_labels_[i_seg];
410 
411  unsigned int i_nghbr = 0;
412  while ( i_nghbr < region_neighbour_number_ && i_nghbr < segment_neighbours_[i_seg].size () )
413  {
414  int index = segment_neighbours_[i_seg][i_nghbr];
415  if (segment_distances_[i_seg][i_nghbr] > dist_thresh)
416  {
417  i_nghbr++;
418  continue;
419  }
420  if ( segment_labels_[index] == -1 )
421  {
422  float difference = calculateColorimetricalDifference (segment_color[i_seg], segment_color[index]);
423  if (difference < color_r2r_threshold_)
424  {
425  segment_labels_[index] = curr_homogeneous_region;
426  num_pts_in_homogeneous_region[curr_homogeneous_region] += num_pts_in_segment_[index];
427  num_seg_in_homogeneous_region[curr_homogeneous_region] += 1;
428  }
429  }
430  i_nghbr++;
431  }// next neighbour
432  }// next segment
433 
434  segment_color.clear ();
435  color.clear ();
436 
437  std::vector< std::vector<int> > final_segments;
438  std::vector<int> region;
439  final_segments.resize (homogeneous_region_number, region);
440  for (int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
441  {
442  final_segments[i_reg].resize (num_seg_in_homogeneous_region[i_reg], 0);
443  }
444 
445  std::vector<int> counter;
446  counter.resize (homogeneous_region_number, 0);
447  for (int i_seg = 0; i_seg < number_of_segments_; i_seg++)
448  {
449  int index = segment_labels_[i_seg];
450  final_segments[ index ][ counter[index] ] = i_seg;
451  counter[index] += 1;
452  }
453 
454  std::vector< std::vector< std::pair<float, pcl::index_t> > > region_neighbours;
455  findRegionNeighbours (region_neighbours, final_segments);
456 
457  int final_segment_number = homogeneous_region_number;
458  for (int i_reg = 0; i_reg < homogeneous_region_number; i_reg++)
459  {
460  if (num_pts_in_homogeneous_region[i_reg] < min_pts_per_cluster_)
461  {
462  if ( region_neighbours[i_reg].empty () )
463  continue;
464  int nearest_neighbour = region_neighbours[i_reg][0].second;
465  if ( region_neighbours[i_reg][0].first == std::numeric_limits<float>::max () )
466  continue;
467  int reg_index = segment_labels_[nearest_neighbour];
468  int num_seg_in_reg = num_seg_in_homogeneous_region[i_reg];
469  for (int i_seg = 0; i_seg < num_seg_in_reg; i_seg++)
470  {
471  int segment_index = final_segments[i_reg][i_seg];
472  final_segments[reg_index].push_back (segment_index);
473  segment_labels_[segment_index] = reg_index;
474  }
475  final_segments[i_reg].clear ();
476  num_pts_in_homogeneous_region[reg_index] += num_pts_in_homogeneous_region[i_reg];
477  num_pts_in_homogeneous_region[i_reg] = 0;
478  num_seg_in_homogeneous_region[reg_index] += num_seg_in_homogeneous_region[i_reg];
479  num_seg_in_homogeneous_region[i_reg] = 0;
480  final_segment_number -= 1;
481 
482  for (auto& nghbr : region_neighbours[reg_index])
483  {
484  if ( segment_labels_[ nghbr.second ] == reg_index )
485  {
486  nghbr.first = std::numeric_limits<float>::max ();
487  nghbr.second = 0;
488  }
489  }
490  for (const auto& nghbr : region_neighbours[i_reg])
491  {
492  if ( segment_labels_[ nghbr.second ] != reg_index )
493  {
494  region_neighbours[reg_index].push_back (nghbr);
495  }
496  }
497  region_neighbours[i_reg].clear ();
498  std::sort (region_neighbours[reg_index].begin (), region_neighbours[reg_index].end (), comparePair);
499  }
500  }
501 
502  assembleRegions (num_pts_in_homogeneous_region, static_cast<int> (num_pts_in_homogeneous_region.size ()));
503 
504  number_of_segments_ = final_segment_number;
505 }
506 
507 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
508 template <typename PointT, typename NormalT> float
509 pcl::RegionGrowingRGB<PointT, NormalT>::calculateColorimetricalDifference (std::vector<unsigned int>& first_color, std::vector<unsigned int>& second_color) const
510 {
511  float difference = 0.0f;
512  difference += static_cast<float>((first_color[0] - second_color[0]) * (first_color[0] - second_color[0]));
513  difference += static_cast<float>((first_color[1] - second_color[1]) * (first_color[1] - second_color[1]));
514  difference += static_cast<float>((first_color[2] - second_color[2]) * (first_color[2] - second_color[2]));
515  return (difference);
516 }
517 
518 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
519 template <typename PointT, typename NormalT> void
520 pcl::RegionGrowingRGB<PointT, NormalT>::findRegionNeighbours (std::vector< std::vector< std::pair<float, pcl::index_t> > >& neighbours_out, std::vector< std::vector<int> >& regions_in)
521 {
522  int region_number = static_cast<int> (regions_in.size ());
523  neighbours_out.clear ();
524  neighbours_out.resize (region_number);
525 
526  for (int i_reg = 0; i_reg < region_number; i_reg++)
527  {
528  neighbours_out[i_reg].reserve (regions_in[i_reg].size () * region_neighbour_number_);
529  for (const auto& curr_segment : regions_in[i_reg])
530  {
531  const std::size_t nghbr_number = segment_neighbours_[curr_segment].size ();
532  std::pair<float, pcl::index_t> pair;
533  for (std::size_t i_nghbr = 0; i_nghbr < nghbr_number; i_nghbr++)
534  {
535  const auto segment_index = segment_neighbours_[curr_segment][i_nghbr];
536  if ( segment_distances_[curr_segment][i_nghbr] == std::numeric_limits<float>::max () )
537  continue;
538  if (segment_labels_[segment_index] != i_reg)
539  {
540  pair.first = segment_distances_[curr_segment][i_nghbr];
541  pair.second = segment_index;
542  neighbours_out[i_reg].push_back (pair);
543  }
544  }// next neighbour
545  }// next segment
546  std::sort (neighbours_out[i_reg].begin (), neighbours_out[i_reg].end (), comparePair);
547  }// next homogeneous region
548 }
549 
550 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
551 template <typename PointT, typename NormalT> void
552 pcl::RegionGrowingRGB<PointT, NormalT>::assembleRegions (std::vector<unsigned int>& num_pts_in_region, int num_regions)
553 {
554  clusters_.clear ();
555  pcl::PointIndices segment;
556  clusters_.resize (num_regions, segment);
557  for (int i_seg = 0; i_seg < num_regions; i_seg++)
558  {
559  clusters_[i_seg].indices.resize (num_pts_in_region[i_seg]);
560  }
561 
562  std::vector<int> counter;
563  counter.resize (num_regions, 0);
564  for (const auto& point_index : (*indices_))
565  {
566  int index = point_labels_[point_index];
567  index = segment_labels_[index];
568  clusters_[index].indices[ counter[index] ] = point_index;
569  counter[index] += 1;
570  }
571 
572  // now we need to erase empty regions
573  if (clusters_.empty ())
574  return;
575 
576  std::vector<pcl::PointIndices>::iterator itr1, itr2;
577  itr1 = clusters_.begin ();
578  itr2 = clusters_.end () - 1;
579 
580  while (itr1 < itr2)
581  {
582  while (!(itr1->indices.empty ()) && itr1 < itr2)
583  ++itr1;
584  while ( itr2->indices.empty () && itr1 < itr2)
585  --itr2;
586 
587  if (itr1 != itr2)
588  itr1->indices.swap (itr2->indices);
589  }
590 
591  if (itr2->indices.empty ())
592  clusters_.erase (itr2, clusters_.end ());
593 }
594 
595 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
596 template <typename PointT, typename NormalT> bool
598 {
599  is_a_seed = true;
600 
601  // check the color difference
602  std::vector<unsigned int> point_color;
603  point_color.resize (3, 0);
604  std::vector<unsigned int> nghbr_color;
605  nghbr_color.resize (3, 0);
606  point_color[0] = (*input_)[point].r;
607  point_color[1] = (*input_)[point].g;
608  point_color[2] = (*input_)[point].b;
609  nghbr_color[0] = (*input_)[nghbr].r;
610  nghbr_color[1] = (*input_)[nghbr].g;
611  nghbr_color[2] = (*input_)[nghbr].b;
612  float difference = calculateColorimetricalDifference (point_color, nghbr_color);
613  if (difference > color_p2p_threshold_)
614  return (false);
615 
616  float cosine_threshold = std::cos (theta_threshold_);
617 
618  // check the angle between normals if needed
619  if (normal_flag_)
620  {
621  float data[4];
622  data[0] = (*input_)[point].data[0];
623  data[1] = (*input_)[point].data[1];
624  data[2] = (*input_)[point].data[2];
625  data[3] = (*input_)[point].data[3];
626 
627  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data));
628  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
629  if (smooth_mode_flag_ == true)
630  {
631  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
632  float dot_product = std::abs (nghbr_normal.dot (initial_normal));
633  if (dot_product < cosine_threshold)
634  return (false);
635  }
636  else
637  {
638  Eigen::Map<Eigen::Vector3f> nghbr_normal (static_cast<float*> ((*normals_)[nghbr].normal));
639  Eigen::Map<Eigen::Vector3f> initial_seed_normal (static_cast<float*> ((*normals_)[initial_seed].normal));
640  float dot_product = std::abs (nghbr_normal.dot (initial_seed_normal));
641  if (dot_product < cosine_threshold)
642  return (false);
643  }
644  }
645 
646  // check the curvature if needed
647  if (curvature_flag_ && (*normals_)[nghbr].curvature > curvature_threshold_)
648  is_a_seed = false;
649 
650  // check the residual if needed
651  if (residual_flag_)
652  {
653  float data_p[4];
654  data_p[0] = (*input_)[point].data[0];
655  data_p[1] = (*input_)[point].data[1];
656  data_p[2] = (*input_)[point].data[2];
657  data_p[3] = (*input_)[point].data[3];
658  float data_n[4];
659  data_n[0] = (*input_)[nghbr].data[0];
660  data_n[1] = (*input_)[nghbr].data[1];
661  data_n[2] = (*input_)[nghbr].data[2];
662  data_n[3] = (*input_)[nghbr].data[3];
663  Eigen::Map<Eigen::Vector3f> nghbr_point (static_cast<float*> (data_n));
664  Eigen::Map<Eigen::Vector3f> initial_point (static_cast<float*> (data_p));
665  Eigen::Map<Eigen::Vector3f> initial_normal (static_cast<float*> ((*normals_)[point].normal));
666  float residual = std::abs (initial_normal.dot (initial_point - nghbr_point));
667  if (residual > residual_threshold_)
668  is_a_seed = false;
669  }
670 
671  return (true);
672 }
673 
674 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
675 template <typename PointT, typename NormalT> void
677 {
678  cluster.indices.clear ();
679 
680  bool segmentation_is_possible = initCompute ();
681  if ( !segmentation_is_possible )
682  {
683  deinitCompute ();
684  return;
685  }
686 
687  // first of all we need to find out if this point belongs to cloud
688  bool point_was_found = false;
689  for (const auto& point : (*indices_))
690  if (point == index)
691  {
692  point_was_found = true;
693  break;
694  }
695 
696  if (point_was_found)
697  {
698  if (clusters_.empty ())
699  {
700  clusters_.clear ();
701  point_neighbours_.clear ();
702  point_labels_.clear ();
703  num_pts_in_segment_.clear ();
704  point_distances_.clear ();
705  segment_neighbours_.clear ();
706  segment_distances_.clear ();
707  segment_labels_.clear ();
708  number_of_segments_ = 0;
709 
710  segmentation_is_possible = prepareForSegmentation ();
711  if ( !segmentation_is_possible )
712  {
713  deinitCompute ();
714  return;
715  }
716 
717  findPointNeighbours ();
718  applySmoothRegionGrowingAlgorithm ();
720 
721  findSegmentNeighbours ();
722  applyRegionMergingAlgorithm ();
723  }
724  // if we have already made the segmentation, then find the segment
725  // to which this point belongs
726  for (const auto& i_segment : clusters_)
727  {
728  const auto it = std::find (i_segment.indices.cbegin (), i_segment.indices.cend (), index);
729  if (it != i_segment.indices.cend())
730  {
731  // if segment was found
732  cluster.indices.clear ();
733  cluster.indices.reserve (i_segment.indices.size ());
734  std::copy (i_segment.indices.begin (), i_segment.indices.end (), std::back_inserter (cluster.indices));
735  break;
736  }
737  }// next segment
738  }// end if point was found
739 
740  deinitCompute ();
741 }
742 
743 #endif // PCL_SEGMENTATION_REGION_GROWING_RGB_HPP_
bool curvature_flag_
If set to true then curvature test will be done during segmentation.
bool normal_flag_
If set to true then normal/smoothness test will be done during segmentation.
bool residual_flag_
If set to true then residual test will be done during segmentation.
pcl::uindex_t min_pts_per_cluster_
Stores the minimum number of points that a cluster needs to contain in order to be considered valid.
void assembleRegions()
This function simply assembles the regions from list of point labels.
void getSegmentFromPoint(index_t index, pcl::PointIndices &cluster) override
For a given point this function builds a segment to which it belongs and returns this segment.
void setDistanceThreshold(float thresh)
Allows to set distance threshold.
void setRegionColorThreshold(float thresh)
This method specifies the threshold value for color test between the regions.
float getPointColorThreshold() const
Returns the color threshold value used for testing if points belong to the same region.
bool prepareForSegmentation() override
This method simply checks if it is possible to execute the segmentation algorithm with the current se...
void findRegionNeighbours(std::vector< std::vector< std::pair< float, pcl::index_t > > > &neighbours_out, std::vector< std::vector< int > > &regions_in)
This method assembles the array containing neighbours of each homogeneous region.
void applyRegionMergingAlgorithm()
This function implements the merging algorithm described in the article "Color-based segmentation of ...
unsigned int getNumberOfRegionNeighbours() const
Returns the number of nearest neighbours used for searching K nearest segments.
void setCurvatureTestFlag(bool value) override
Allows to turn on/off the curvature test.
void extract(std::vector< pcl::PointIndices > &clusters) override
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
void setNormalTestFlag(bool value)
Allows to turn on/off the smoothness test.
void setNumberOfRegionNeighbours(unsigned int nghbr_number)
This method allows to set the number of neighbours that is used for finding neighbouring segments.
float calculateColorimetricalDifference(std::vector< unsigned int > &first_color, std::vector< unsigned int > &second_color) const
This method calculates the colorimetrical difference between two points.
float getDistanceThreshold() const
Returns the distance threshold.
bool getNormalTestFlag() const
Returns the flag that signalize if the smoothness test is turned on/off.
void findRegionsKNN(pcl::index_t index, pcl::uindex_t nghbr_number, Indices &nghbrs, std::vector< float > &dist)
This method finds K nearest neighbours of the given segment.
RegionGrowingRGB()
Constructor that sets default values for member variables.
void setResidualTestFlag(bool value) override
Allows to turn on/off the residual test.
~RegionGrowingRGB() override
Destructor that frees memory.
void findPointNeighbours() override
This method finds KNN for each point and saves them to the array because the algorithm needs to find ...
float getRegionColorThreshold() const
Returns the color threshold value used for testing if regions can be merged.
void findSegmentNeighbours()
This method simply calls the findRegionsKNN for each segment and saves the results for later use.
void setPointColorThreshold(float thresh)
This method specifies the threshold value for color test between the points.
bool validatePoint(index_t initial_seed, index_t point, index_t nghbr, bool &is_a_seed) const override
This function is checking if the point with index 'nghbr' belongs to the segment.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
Definition: kdtree.h:62
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
Definition: types.h:120
bool comparePair(std::pair< float, int > i, std::pair< float, int > j)
This function is used as a comparator for sorting.
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition: types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition: types.h:133