Point Cloud Library (PCL)  1.9.1-dev
lccp_segmentation.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2014-, Open Perception, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the copyright holder(s) nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
39 #define PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
40 
41 #include <pcl/segmentation/lccp_segmentation.h>
42 #include <pcl/common/common.h>
43 
44 
45 //////////////////////////////////////////////////////////
46 //////////////////////////////////////////////////////////
47 /////////////////// Public Functions /////////////////////
48 //////////////////////////////////////////////////////////
49 //////////////////////////////////////////////////////////
50 
51 
52 
53 template <typename PointT>
55  concavity_tolerance_threshold_ (10),
56  grouping_data_valid_ (false),
57  supervoxels_set_ (false),
58  use_smoothness_check_ (false),
59  smoothness_threshold_ (0.1),
60  use_sanity_check_ (false),
61  seed_resolution_ (0),
62  voxel_resolution_ (0),
63  k_factor_ (0),
64  min_segment_size_ (0)
65 {
66 }
67 
68 template <typename PointT>
70 {
71 }
72 
73 template <typename PointT> void
75 {
76  sv_adjacency_list_.clear ();
77  processed_.clear ();
82  grouping_data_valid_ = false;
83  supervoxels_set_ = false;
84 }
85 
86 template <typename PointT> void
88 {
89  if (supervoxels_set_)
90  {
91  // Calculate for every Edge if the connection is convex or invalid
92  // This effectively performs the segmentation.
94 
95  // Correct edge relations using extended convexity definition if k>0
97 
98  // group supervoxels
99  doGrouping ();
100 
101  grouping_data_valid_ = true;
102 
103  // merge small segments
105  }
106  else
107  PCL_WARN ("[pcl::LCCPSegmentation::segment] WARNING: Call function setInputSupervoxels first. Nothing has been done. \n");
108 }
109 
110 
111 template <typename PointT> void
113 {
115  {
116  // Relabel all Points in cloud with new labels
117  for (auto &voxel : labeled_cloud_arg)
118  {
119  voxel.label = sv_label_to_seg_label_map_[voxel.label];
120  }
121  }
122  else
123  {
124  PCL_WARN ("[pcl::LCCPSegmentation::relabelCloud] WARNING: Call function segment first. Nothing has been done. \n");
125  }
126 }
127 
128 
129 
130 //////////////////////////////////////////////////////////
131 //////////////////////////////////////////////////////////
132 /////////////////// Protected Functions //////////////////
133 //////////////////////////////////////////////////////////
134 //////////////////////////////////////////////////////////
135 
136 template <typename PointT> void
138 {
140 
141  //The vertices in the supervoxel adjacency list are the supervoxel centroids
142  std::pair<VertexIterator, VertexIterator> vertex_iterator_range;
143  vertex_iterator_range = boost::vertices (sv_adjacency_list_);
144 
145  std::uint32_t current_segLabel;
146  std::uint32_t neigh_segLabel;
147 
148  // For every Supervoxel..
149  for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all supervoxels
150  {
151  const std::uint32_t& sv_label = sv_adjacency_list_[*sv_itr];
152  current_segLabel = sv_label_to_seg_label_map_[sv_label];
153 
154  // ..look at all neighbors and insert their labels into the neighbor set
155  std::pair<AdjacencyIterator, AdjacencyIterator> neighbors = boost::adjacent_vertices (*sv_itr, sv_adjacency_list_);
156  for (AdjacencyIterator itr_neighbor = neighbors.first; itr_neighbor != neighbors.second; ++itr_neighbor)
157  {
158  const std::uint32_t& neigh_label = sv_adjacency_list_[*itr_neighbor];
159  neigh_segLabel = sv_label_to_seg_label_map_[neigh_label];
160 
161  if (current_segLabel != neigh_segLabel)
162  {
163  seg_label_to_neighbor_set_map_[current_segLabel].insert (neigh_segLabel);
164  }
165  }
166  }
167 }
168 
169 template <typename PointT> void
171 {
172  if (min_segment_size_ == 0)
173  return;
174 
176 
177  std::set<std::uint32_t> filteredSegLabels;
178 
179  std::uint32_t largest_neigh_size = 0;
180  std::uint32_t largest_neigh_seg_label = 0;
181  std::uint32_t current_seg_label;
182 
183  std::pair<VertexIterator, VertexIterator> vertex_iterator_range;
184  vertex_iterator_range = boost::vertices (sv_adjacency_list_);
185 
186  bool continue_filtering = true;
187 
188  while (continue_filtering)
189  {
190  continue_filtering = false;
191  unsigned int nr_filtered = 0;
192 
193  // Iterate through all supervoxels, check if they are in a "small" segment -> change label to largest neighborID
194  for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all supervoxels
195  {
196  const std::uint32_t& sv_label = sv_adjacency_list_[*sv_itr];
197  current_seg_label = sv_label_to_seg_label_map_[sv_label];
198  largest_neigh_seg_label = current_seg_label;
199  largest_neigh_size = seg_label_to_sv_list_map_[current_seg_label].size ();
200 
201  const std::uint32_t& nr_neighbors = seg_label_to_neighbor_set_map_[current_seg_label].size ();
202  if (nr_neighbors == 0)
203  continue;
204 
205  if (seg_label_to_sv_list_map_[current_seg_label].size () <= min_segment_size_)
206  {
207  continue_filtering = true;
208  nr_filtered++;
209 
210  // Find largest neighbor
211  for (auto neighbors_itr = seg_label_to_neighbor_set_map_[current_seg_label].cbegin (); neighbors_itr != seg_label_to_neighbor_set_map_[current_seg_label].cend (); ++neighbors_itr)
212  {
213  if (seg_label_to_sv_list_map_[*neighbors_itr].size () >= largest_neigh_size)
214  {
215  largest_neigh_seg_label = *neighbors_itr;
216  largest_neigh_size = seg_label_to_sv_list_map_[*neighbors_itr].size ();
217  }
218  }
219 
220  // Add to largest neighbor
221  if (largest_neigh_seg_label != current_seg_label)
222  {
223  if (filteredSegLabels.count (largest_neigh_seg_label) > 0)
224  continue; // If neighbor was already assigned to someone else
225 
226  sv_label_to_seg_label_map_[sv_label] = largest_neigh_seg_label;
227  filteredSegLabels.insert (current_seg_label);
228 
229  // Assign supervoxel labels of filtered segment to new owner
230  for (auto sv_ID_itr = seg_label_to_sv_list_map_[current_seg_label].cbegin (); sv_ID_itr != seg_label_to_sv_list_map_[current_seg_label].cend (); ++sv_ID_itr)
231  {
232  seg_label_to_sv_list_map_[largest_neigh_seg_label].insert (*sv_ID_itr);
233  }
234  }
235  }
236  }
237 
238  // Erase filtered Segments from segment map
239  for (const unsigned int &filteredSegLabel : filteredSegLabels)
240  {
241  seg_label_to_sv_list_map_.erase (filteredSegLabel);
242  }
243 
244  // After filtered Segments are deleted, compute completely new adjacency map
245  // NOTE Recomputing the adjacency of every segment in every iteration is an easy but inefficient solution.
246  // Because the number of segments in an average scene is usually well below 1000, the time spend for noise filtering is still negligible in most cases
248  } // End while (Filtering)
249 }
250 
251 template <typename PointT> void
252 pcl::LCCPSegmentation<PointT>::prepareSegmentation (const std::map<std::uint32_t, typename pcl::Supervoxel<PointT>::Ptr>& supervoxel_clusters_arg,
253  const std::multimap<std::uint32_t, std::uint32_t>& label_adjaceny_arg)
254 {
255  // Clear internal data
256  reset ();
257 
258  // Copy map with supervoxel pointers
259  sv_label_to_supervoxel_map_ = supervoxel_clusters_arg;
260 
261  // Build a boost adjacency list from the adjacency multimap
262  std::map<std::uint32_t, VertexID> label_ID_map;
263 
264  // Add all supervoxel labels as vertices
265  for (typename std::map<std::uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
266  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
267  {
268  const std::uint32_t& sv_label = svlabel_itr->first;
269  VertexID node_id = boost::add_vertex (sv_adjacency_list_);
270  sv_adjacency_list_[node_id] = sv_label;
271  label_ID_map[sv_label] = node_id;
272  }
273 
274  // Add all edges
275  for (const auto &sv_neighbors_itr : label_adjaceny_arg)
276  {
277  const std::uint32_t& sv_label = sv_neighbors_itr.first;
278  const std::uint32_t& neighbor_label = sv_neighbors_itr.second;
279 
280  VertexID u = label_ID_map[sv_label];
281  VertexID v = label_ID_map[neighbor_label];
282 
283  boost::add_edge (u, v, sv_adjacency_list_);
284  }
285 
286  // Initialization
287  // clear the processed_ map
288  seg_label_to_sv_list_map_.clear ();
289  for (typename std::map<std::uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
290  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
291  {
292  const std::uint32_t& sv_label = svlabel_itr->first;
293  processed_[sv_label] = false;
294  sv_label_to_seg_label_map_[sv_label] = 0;
295  }
296 }
297 
298 
299 
300 
301 template <typename PointT> void
303 {
304  // clear the processed_ map
305  seg_label_to_sv_list_map_.clear ();
306  for (typename std::map<std::uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
307  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
308  {
309  const std::uint32_t& sv_label = svlabel_itr->first;
310  processed_[sv_label] = false;
311  sv_label_to_seg_label_map_[sv_label] = 0;
312  }
313 
314  // Perform depth search on the graph and recursively group all supervoxels with convex connections
315  //The vertices in the supervoxel adjacency list are the supervoxel centroids
316  std::pair< VertexIterator, VertexIterator> vertex_iterator_range;
317  vertex_iterator_range = boost::vertices (sv_adjacency_list_);
318 
319  // Note: *sv_itr is of type " boost::graph_traits<VoxelAdjacencyList>::vertex_descriptor " which it nothing but a typedef of size_t..
320  unsigned int segment_label = 1; // This starts at 1, because 0 is reserved for errors
321  for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all supervoxels
322  {
323  const VertexID sv_vertex_id = *sv_itr;
324  const std::uint32_t& sv_label = sv_adjacency_list_[sv_vertex_id];
325  if (!processed_[sv_label])
326  {
327  // Add neighbors (and their neighbors etc.) to group if similarity constraint is met
328  recursiveSegmentGrowing (sv_vertex_id, segment_label);
329  ++segment_label; // After recursive grouping ended (no more neighbors to consider) -> go to next group
330  }
331  }
332 }
333 
334 template <typename PointT> void
336  const unsigned int segment_label)
337 {
338  const std::uint32_t& sv_label = sv_adjacency_list_[query_point_id];
339 
340  processed_[sv_label] = true;
341 
342  // The next two lines add the supervoxel to the segment
343  sv_label_to_seg_label_map_[sv_label] = segment_label;
344  seg_label_to_sv_list_map_[segment_label].insert (sv_label);
345 
346  // Iterate through all neighbors of this supervoxel and check whether they should be merged with the current supervoxel
347  std::pair<OutEdgeIterator, OutEdgeIterator> out_edge_iterator_range;
348  out_edge_iterator_range = boost::out_edges (query_point_id, sv_adjacency_list_); // adjacent vertices to node (*itr) in graph sv_adjacency_list_
349  for (OutEdgeIterator out_Edge_itr = out_edge_iterator_range.first; out_Edge_itr != out_edge_iterator_range.second; ++out_Edge_itr)
350  {
351  const VertexID neighbor_ID = boost::target (*out_Edge_itr, sv_adjacency_list_);
352  const std::uint32_t& neighbor_label = sv_adjacency_list_[neighbor_ID];
353 
354  if (!processed_[neighbor_label]) // If neighbor was not already processed
355  {
356  if (sv_adjacency_list_[*out_Edge_itr].is_valid)
357  {
358  recursiveSegmentGrowing (neighbor_ID, segment_label);
359  }
360  }
361  } // End neighbor loop
362 }
363 
364 template <typename PointT> void
366 {
367  if (k_arg == 0)
368  return;
369 
370  bool is_convex;
371  unsigned int kcount = 0;
372 
373  EdgeIterator edge_itr, edge_itr_end, next_edge;
374  boost::tie (edge_itr, edge_itr_end) = boost::edges (sv_adjacency_list_);
375 
376  std::pair<OutEdgeIterator, OutEdgeIterator> source_neighbors_range;
377  std::pair<OutEdgeIterator, OutEdgeIterator> target_neighbors_range;
378 
379  // Check all edges in the graph for k-convexity
380  for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
381  {
382  next_edge++; // next_edge iterator is necessary, because removing an edge invalidates the iterator to the current edge
383 
384  is_convex = sv_adjacency_list_[*edge_itr].is_convex;
385 
386  if (is_convex) // If edge is (0-)convex
387  {
388  kcount = 0;
389 
390  const VertexID source = boost::source (*edge_itr, sv_adjacency_list_);
391  const VertexID target = boost::target (*edge_itr, sv_adjacency_list_);
392 
393  source_neighbors_range = boost::out_edges (source, sv_adjacency_list_);
394  target_neighbors_range = boost::out_edges (target, sv_adjacency_list_);
395 
396  // Find common neighbors, check their connection
397  for (OutEdgeIterator source_neighbors_itr = source_neighbors_range.first; source_neighbors_itr != source_neighbors_range.second; ++source_neighbors_itr) // For all supervoxels
398  {
399  VertexID source_neighbor_ID = boost::target (*source_neighbors_itr, sv_adjacency_list_);
400 
401  for (OutEdgeIterator target_neighbors_itr = target_neighbors_range.first; target_neighbors_itr != target_neighbors_range.second; ++target_neighbors_itr) // For all supervoxels
402  {
403  VertexID target_neighbor_ID = boost::target (*target_neighbors_itr, sv_adjacency_list_);
404  if (source_neighbor_ID == target_neighbor_ID) // Common neighbor
405  {
406  EdgeID src_edge = boost::edge (source, source_neighbor_ID, sv_adjacency_list_).first;
407  EdgeID tar_edge = boost::edge (target, source_neighbor_ID, sv_adjacency_list_).first;
408 
409  bool src_is_convex = (sv_adjacency_list_)[src_edge].is_convex;
410  bool tar_is_convex = (sv_adjacency_list_)[tar_edge].is_convex;
411 
412  if (src_is_convex && tar_is_convex)
413  ++kcount;
414 
415  break;
416  }
417  }
418 
419  if (kcount >= k_arg) // Connection is k-convex, stop search
420  break;
421  }
422 
423  // Check k convexity
424  if (kcount < k_arg)
425  (sv_adjacency_list_)[*edge_itr].is_valid = false;
426  }
427  }
428 }
429 
430 template <typename PointT> void
432 {
433  bool is_convex;
434 
435  EdgeIterator edge_itr, edge_itr_end, next_edge;
436  boost::tie (edge_itr, edge_itr_end) = boost::edges (adjacency_list_arg);
437 
438  for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
439  {
440  next_edge++; // next_edge iterator is necessary, because removing an edge invalidates the iterator to the current edge
441 
442  std::uint32_t source_sv_label = adjacency_list_arg[boost::source (*edge_itr, adjacency_list_arg)];
443  std::uint32_t target_sv_label = adjacency_list_arg[boost::target (*edge_itr, adjacency_list_arg)];
444 
445  float normal_difference;
446  is_convex = connIsConvex (source_sv_label, target_sv_label, normal_difference);
447  adjacency_list_arg[*edge_itr].is_convex = is_convex;
448  adjacency_list_arg[*edge_itr].is_valid = is_convex;
449  adjacency_list_arg[*edge_itr].normal_difference = normal_difference;
450  }
451 }
452 
453 template <typename PointT> bool
454 pcl::LCCPSegmentation<PointT>::connIsConvex (const std::uint32_t source_label_arg,
455  const std::uint32_t target_label_arg,
456  float &normal_angle)
457 {
458  typename pcl::Supervoxel<PointT>::Ptr& sv_source = sv_label_to_supervoxel_map_[source_label_arg];
459  typename pcl::Supervoxel<PointT>::Ptr& sv_target = sv_label_to_supervoxel_map_[target_label_arg];
460 
461  const Eigen::Vector3f& source_centroid = sv_source->centroid_.getVector3fMap ();
462  const Eigen::Vector3f& target_centroid = sv_target->centroid_.getVector3fMap ();
463 
464  const Eigen::Vector3f& source_normal = sv_source->normal_.getNormalVector3fMap (). normalized ();
465  const Eigen::Vector3f& target_normal = sv_target->normal_.getNormalVector3fMap (). normalized ();
466 
467  //NOTE For angles below 0 nothing will be merged
469  {
470  return (false);
471  }
472 
473  bool is_convex = true;
474  bool is_smooth = true;
475 
476  normal_angle = getAngle3D (source_normal, target_normal, true);
477  // Geometric comparisons
478  Eigen::Vector3f vec_t_to_s, vec_s_to_t;
479 
480  vec_t_to_s = source_centroid - target_centroid;
481  vec_s_to_t = -vec_t_to_s;
482 
483  Eigen::Vector3f ncross;
484  ncross = source_normal.cross (target_normal);
485 
486  // Smoothness Check: Check if there is a step between adjacent patches
488  {
489  float expected_distance = ncross.norm () * seed_resolution_;
490  float dot_p_1 = vec_t_to_s.dot (source_normal);
491  float dot_p_2 = vec_s_to_t.dot (target_normal);
492  float point_dist = (std::fabs (dot_p_1) < std::fabs (dot_p_2)) ? std::fabs (dot_p_1) : std::fabs (dot_p_2);
493  const float dist_smoothing = smoothness_threshold_ * voxel_resolution_; // This is a slacking variable especially important for patches with very similar normals
494 
495  if (point_dist > (expected_distance + dist_smoothing))
496  {
497  is_smooth &= false;
498  }
499  }
500  // ----------------
501 
502  // Sanity Criterion: Check if definition convexity/concavity makes sense for connection of given patches
503  float intersection_angle = getAngle3D (ncross, vec_t_to_s, true);
504  float min_intersect_angle = (intersection_angle < 90.) ? intersection_angle : 180. - intersection_angle;
505 
506  float intersect_thresh = 60. * 1. / (1. + std::exp (-0.25 * (normal_angle - 25.)));
507  if (min_intersect_angle < intersect_thresh && use_sanity_check_)
508  {
509  // std::cout << "Concave/Convex not defined for given case!" << std::endl;
510  is_convex &= false;
511  }
512 
513 
514  // vec_t_to_s is the reference direction for angle measurements
515  // Convexity Criterion: Check if connection of patches is convex. If this is the case the two supervoxels should be merged.
516  if ((getAngle3D (vec_t_to_s, source_normal) - getAngle3D (vec_t_to_s, target_normal)) <= 0)
517  {
518  is_convex &= true; // connection convex
519  }
520  else
521  {
522  is_convex &= (normal_angle < concavity_tolerance_threshold_); // concave connections will be accepted if difference of normals is small
523  }
524  return (is_convex && is_smooth);
525 }
526 
527 #endif // PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
typename boost::graph_traits< SupervoxelAdjacencyList >::out_edge_iterator OutEdgeIterator
bool use_smoothness_check_
Determines if the smoothness check is used during segmentation.
void doGrouping()
Perform depth search on the graph and recursively group all supervoxels with convex connections...
void computeSegmentAdjacency()
Compute the adjacency of the segments.
void relabelCloud(pcl::PointCloud< pcl::PointXYZL > &labeled_cloud_arg)
Relabels cloud with supervoxel labels with the computed segment labels.
double getAngle3D(const Eigen::Vector4f &v1, const Eigen::Vector4f &v2, const bool in_degree=false)
Compute the smallest angle between two 3D vectors in radians (default) or degree. ...
Definition: common.hpp:46
bool use_sanity_check_
Determines if we use the sanity check which tries to find and invalidate singular connected patches...
pcl::PointXYZRGBA centroid_
The centroid of the supervoxel - average voxel.
pcl::Normal normal_
The normal calculated for the voxels contained in the supervoxel.
std::map< std::uint32_t, typename pcl::Supervoxel< PointT >::Ptr > sv_label_to_supervoxel_map_
map from the supervoxel labels to the supervoxel objects
std::map< std::uint32_t, bool > processed_
Stores which supervoxel labels were already visited during recursive grouping.
float voxel_resolution_
Voxel resolution used to build the supervoxels (used only for smoothness check)
void prepareSegmentation(const std::map< std::uint32_t, typename pcl::Supervoxel< PointT >::Ptr > &supervoxel_clusters_arg, const std::multimap< std::uint32_t, std::uint32_t > &label_adjacency_arg)
Is called within setInputSupervoxels mainly to reserve required memory.
std::uint32_t k_factor_
Factor used for k-convexity.
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_iterator EdgeIterator
bool connIsConvex(const std::uint32_t source_label_arg, const std::uint32_t target_label_arg, float &normal_angle)
Returns true if the connection between source and target is convex.
Define standard C methods and C++ classes that are common to all methods.
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_descriptor EdgeID
boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, std::uint32_t, EdgeProperties > SupervoxelAdjacencyList
float seed_resolution_
Seed resolution of the supervoxels (used only for smoothness check)
std::map< std::uint32_t, std::uint32_t > sv_label_to_seg_label_map_
Storing relation between original SuperVoxel Labels and new segmantion labels.
float smoothness_threshold_
Two supervoxels are unsmooth if their plane-to-plane distance DIST > (expected_distance + smoothness_...
std::uint32_t min_segment_size_
Minimum segment size.
boost::shared_ptr< Supervoxel< PointT > > Ptr
void reset()
Reset internal memory.
typename boost::graph_traits< SupervoxelAdjacencyList >::vertex_descriptor VertexID
typename boost::graph_traits< SupervoxelAdjacencyList >::vertex_iterator VertexIterator
bool supervoxels_set_
Marks if supervoxels have been set by calling setInputSupervoxels.
void mergeSmallSegments()
Segments smaller than min_segment_size_ are merged to the label of largest neighbor.
PointCloud represents the base class in PCL for storing collections of 3D points. ...
void segment()
Merge supervoxels using local convexity.
std::map< std::uint32_t, std::set< std::uint32_t > > seg_label_to_neighbor_set_map_
map < SegmentID, std::set< Neighboring segment labels> >
std::map< std::uint32_t, std::set< std::uint32_t > > seg_label_to_sv_list_map_
map <Segment Label, std::set <SuperVoxel labels>=""> >
void recursiveSegmentGrowing(const VertexID &queryPointID, const unsigned int group_label)
Assigns neighbors of the query point to the same group as the query point.
float concavity_tolerance_threshold_
*** Parameters *** ///
void calculateConvexConnections(SupervoxelAdjacencyList &adjacency_list_arg)
Calculates convexity of edges and saves this to the adjacency graph.
void applyKconvexity(const unsigned int k_arg)
Connections are only convex if this is true for at least k_arg common neighbors of the two patches...
bool grouping_data_valid_
Marks if valid grouping data (sv_adjacency_list_, sv_label_to_seg_label_map_, processed_) is availabl...
SupervoxelAdjacencyList sv_adjacency_list_
Adjacency graph with the supervoxel labels as nodes and edges between adjacent supervoxels.
typename boost::graph_traits< SupervoxelAdjacencyList >::adjacency_iterator AdjacencyIterator