Point Cloud Library (PCL)  1.8.0
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 
43 
44 //////////////////////////////////////////////////////////
45 //////////////////////////////////////////////////////////
46 /////////////////// Public Functions /////////////////////
47 //////////////////////////////////////////////////////////
48 //////////////////////////////////////////////////////////
49 
50 
51 
52 template <typename PointT>
54  concavity_tolerance_threshold_ (10),
55  grouping_data_valid_ (false),
56  supervoxels_set_ (false),
57  use_smoothness_check_ (false),
58  smoothness_threshold_ (0.1),
59  use_sanity_check_ (false),
60  seed_resolution_ (0),
61  voxel_resolution_ (0),
62  k_factor_ (0),
63  min_segment_size_ (0)
64 {
65 }
66 
67 template <typename PointT>
69 {
70 }
71 
72 template <typename PointT> void
74 {
75  sv_adjacency_list_.clear ();
76  processed_.clear ();
81  grouping_data_valid_ = false;
82  supervoxels_set_ = false;
83 }
84 
85 template <typename PointT> void
87 {
88  if (supervoxels_set_)
89  {
90  // Calculate for every Edge if the connection is convex or invalid
91  // This effectively performs the segmentation.
93 
94  // Correct edge relations using extended convexity definition if k>0
96 
97  // group supervoxels
98  doGrouping ();
99 
100  grouping_data_valid_ = true;
101 
102  // merge small segments
104  }
105  else
106  PCL_WARN ("[pcl::LCCPSegmentation::segment] WARNING: Call function setInputSupervoxels first. Nothing has been done. \n");
107 }
108 
109 
110 template <typename PointT> void
112 {
114  {
115  // Relabel all Points in cloud with new labels
116  typename pcl::PointCloud<pcl::PointXYZL>::iterator voxel_itr = labeled_cloud_arg.begin ();
117  for (; voxel_itr != labeled_cloud_arg.end (); ++voxel_itr)
118  {
119  voxel_itr->label = sv_label_to_seg_label_map_[voxel_itr->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  uint32_t current_segLabel;
146  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 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 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<uint32_t> filteredSegLabels;
178 
179  uint32_t largest_neigh_size = 0;
180  uint32_t largest_neigh_seg_label = 0;
181  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 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 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  std::set<uint32_t>::const_iterator neighbors_itr = seg_label_to_neighbor_set_map_[current_seg_label].begin ();
212  for (; neighbors_itr != seg_label_to_neighbor_set_map_[current_seg_label].end (); ++neighbors_itr)
213  {
214  if (seg_label_to_sv_list_map_[*neighbors_itr].size () >= largest_neigh_size)
215  {
216  largest_neigh_seg_label = *neighbors_itr;
217  largest_neigh_size = seg_label_to_sv_list_map_[*neighbors_itr].size ();
218  }
219  }
220 
221  // Add to largest neighbor
222  if (largest_neigh_seg_label != current_seg_label)
223  {
224  if (filteredSegLabels.count (largest_neigh_seg_label) > 0)
225  continue; // If neighbor was already assigned to someone else
226 
227  sv_label_to_seg_label_map_[sv_label] = largest_neigh_seg_label;
228  filteredSegLabels.insert (current_seg_label);
229 
230  // Assign supervoxel labels of filtered segment to new owner
231  std::set<uint32_t>::iterator sv_ID_itr = seg_label_to_sv_list_map_[current_seg_label].begin ();
232  sv_ID_itr = seg_label_to_sv_list_map_[current_seg_label].begin ();
233  for (; sv_ID_itr != seg_label_to_sv_list_map_[current_seg_label].end (); ++sv_ID_itr)
234  {
235  seg_label_to_sv_list_map_[largest_neigh_seg_label].insert (*sv_ID_itr);
236  }
237  }
238  }
239  }
240 
241  // Erase filtered Segments from segment map
242  std::set<uint32_t>::iterator filtered_ID_itr = filteredSegLabels.begin ();
243  for (; filtered_ID_itr != filteredSegLabels.end (); ++filtered_ID_itr)
244  {
245  seg_label_to_sv_list_map_.erase (*filtered_ID_itr);
246  }
247 
248  // After filtered Segments are deleted, compute completely new adjacency map
249  // NOTE Recomputing the adjacency of every segment in every iteration is an easy but inefficient solution.
250  // Because the number of segments in an average scene is usually well below 1000, the time spend for noise filtering is still neglible in most cases
252  } // End while (Filtering)
253 }
254 
255 template <typename PointT> void
256 pcl::LCCPSegmentation<PointT>::prepareSegmentation (const std::map<uint32_t, typename pcl::Supervoxel<PointT>::Ptr>& supervoxel_clusters_arg,
257  const std::multimap<uint32_t, uint32_t>& label_adjaceny_arg)
258 {
259  // Clear internal data
260  reset ();
261 
262  // Copy map with supervoxel pointers
263  sv_label_to_supervoxel_map_ = supervoxel_clusters_arg;
264 
265  // Build a boost adjacency list from the adjacency multimap
266  std::map<uint32_t, VertexID> label_ID_map;
267 
268  // Add all supervoxel labels as vertices
269  for (typename std::map<uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
270  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
271  {
272  const uint32_t& sv_label = svlabel_itr->first;
273  VertexID node_id = boost::add_vertex (sv_adjacency_list_);
274  sv_adjacency_list_[node_id] = sv_label;
275  label_ID_map[sv_label] = node_id;
276  }
277 
278  // Add all edges
279  for (std::multimap<uint32_t, uint32_t>::const_iterator sv_neighbors_itr = label_adjaceny_arg.begin (); sv_neighbors_itr != label_adjaceny_arg.end ();
280  ++sv_neighbors_itr)
281  {
282  const uint32_t& sv_label = sv_neighbors_itr->first;
283  const uint32_t& neighbor_label = sv_neighbors_itr->second;
284 
285  VertexID u = label_ID_map[sv_label];
286  VertexID v = label_ID_map[neighbor_label];
287 
288  boost::add_edge (u, v, sv_adjacency_list_);
289  }
290 
291  // Initialization
292  // clear the processed_ map
293  seg_label_to_sv_list_map_.clear ();
294  for (typename std::map<uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
295  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
296  {
297  const uint32_t& sv_label = svlabel_itr->first;
298  processed_[sv_label] = false;
299  sv_label_to_seg_label_map_[sv_label] = 0;
300  }
301 }
302 
303 
304 
305 
306 template <typename PointT> void
308 {
309  // clear the processed_ map
310  seg_label_to_sv_list_map_.clear ();
311  for (typename std::map<uint32_t, typename pcl::Supervoxel<PointT>::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin ();
312  svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
313  {
314  const uint32_t& sv_label = svlabel_itr->first;
315  processed_[sv_label] = false;
316  sv_label_to_seg_label_map_[sv_label] = 0;
317  }
318 
319  // Perform depth search on the graph and recursively group all supervoxels with convex connections
320  //The vertices in the supervoxel adjacency list are the supervoxel centroids
321  std::pair< VertexIterator, VertexIterator> vertex_iterator_range;
322  vertex_iterator_range = boost::vertices (sv_adjacency_list_);
323 
324  // Note: *sv_itr is of type " boost::graph_traits<VoxelAdjacencyList>::vertex_descriptor " which it nothing but a typedef of size_t..
325  unsigned int segment_label = 1; // This starts at 1, because 0 is reserved for errors
326  for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all supervoxels
327  {
328  const VertexID sv_vertex_id = *sv_itr;
329  const uint32_t& sv_label = sv_adjacency_list_[sv_vertex_id];
330  if (!processed_[sv_label])
331  {
332  // Add neighbors (and their neighbors etc.) to group if similarity constraint is met
333  recursiveSegmentGrowing (sv_vertex_id, segment_label);
334  ++segment_label; // After recursive grouping ended (no more neighbors to consider) -> go to next group
335  }
336  }
337 }
338 
339 template <typename PointT> void
341  const unsigned int segment_label)
342 {
343  const uint32_t& sv_label = sv_adjacency_list_[query_point_id];
344 
345  processed_[sv_label] = true;
346 
347  // The next two lines add the supervoxel to the segment
348  sv_label_to_seg_label_map_[sv_label] = segment_label;
349  seg_label_to_sv_list_map_[segment_label].insert (sv_label);
350 
351  // Iterate through all neighbors of this supervoxel and check wether they should be merged with the current supervoxel
352  std::pair<OutEdgeIterator, OutEdgeIterator> out_edge_iterator_range;
353  out_edge_iterator_range = boost::out_edges (query_point_id, sv_adjacency_list_); // adjacent vertices to node (*itr) in graph sv_adjacency_list_
354  for (OutEdgeIterator out_Edge_itr = out_edge_iterator_range.first; out_Edge_itr != out_edge_iterator_range.second; ++out_Edge_itr)
355  {
356  const VertexID neighbor_ID = boost::target (*out_Edge_itr, sv_adjacency_list_);
357  const uint32_t& neighbor_label = sv_adjacency_list_[neighbor_ID];
358 
359  if (!processed_[neighbor_label]) // If neighbor was not already processed
360  {
361  if (sv_adjacency_list_[*out_Edge_itr].is_valid)
362  {
363  recursiveSegmentGrowing (neighbor_ID, segment_label);
364  }
365  }
366  } // End neighbor loop
367 }
368 
369 template <typename PointT> void
371 {
372  if (k_arg == 0)
373  return;
374 
375  bool is_convex;
376  unsigned int kcount = 0;
377 
378  EdgeIterator edge_itr, edge_itr_end, next_edge;
379  boost::tie (edge_itr, edge_itr_end) = boost::edges (sv_adjacency_list_);
380 
381  std::pair<OutEdgeIterator, OutEdgeIterator> source_neighbors_range;
382  std::pair<OutEdgeIterator, OutEdgeIterator> target_neighbors_range;
383 
384  // Check all edges in the graph for k-convexity
385  for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
386  {
387  next_edge++; // next_edge iterator is neccessary, because removing an edge invalidates the iterator to the current edge
388 
389  is_convex = sv_adjacency_list_[*edge_itr].is_convex;
390 
391  if (is_convex) // If edge is (0-)convex
392  {
393  kcount = 0;
394 
395  const VertexID source = boost::source (*edge_itr, sv_adjacency_list_);
396  const VertexID target = boost::target (*edge_itr, sv_adjacency_list_);
397 
398  source_neighbors_range = boost::out_edges (source, sv_adjacency_list_);
399  target_neighbors_range = boost::out_edges (target, sv_adjacency_list_);
400 
401  // Find common neighbors, check their connection
402  for (OutEdgeIterator source_neighbors_itr = source_neighbors_range.first; source_neighbors_itr != source_neighbors_range.second; ++source_neighbors_itr) // For all supervoxels
403  {
404  VertexID source_neighbor_ID = boost::target (*source_neighbors_itr, sv_adjacency_list_);
405 
406  for (OutEdgeIterator target_neighbors_itr = target_neighbors_range.first; target_neighbors_itr != target_neighbors_range.second; ++target_neighbors_itr) // For all supervoxels
407  {
408  VertexID target_neighbor_ID = boost::target (*target_neighbors_itr, sv_adjacency_list_);
409  if (source_neighbor_ID == target_neighbor_ID) // Common neighbor
410  {
411  EdgeID src_edge = boost::edge (source, source_neighbor_ID, sv_adjacency_list_).first;
412  EdgeID tar_edge = boost::edge (target, source_neighbor_ID, sv_adjacency_list_).first;
413 
414  bool src_is_convex = (sv_adjacency_list_)[src_edge].is_convex;
415  bool tar_is_convex = (sv_adjacency_list_)[tar_edge].is_convex;
416 
417  if (src_is_convex && tar_is_convex)
418  ++kcount;
419 
420  break;
421  }
422  }
423 
424  if (kcount >= k_arg) // Connection is k-convex, stop search
425  break;
426  }
427 
428  // Check k convexity
429  if (kcount < k_arg)
430  (sv_adjacency_list_)[*edge_itr].is_valid = false;
431  }
432  }
433 }
434 
435 template <typename PointT> void
437 {
438  bool is_convex;
439 
440  EdgeIterator edge_itr, edge_itr_end, next_edge;
441  boost::tie (edge_itr, edge_itr_end) = boost::edges (adjacency_list_arg);
442 
443  for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
444  {
445  next_edge++; // next_edge iterator is neccessary, because removing an edge invalidates the iterator to the current edge
446 
447  uint32_t source_sv_label = adjacency_list_arg[boost::source (*edge_itr, adjacency_list_arg)];
448  uint32_t target_sv_label = adjacency_list_arg[boost::target (*edge_itr, adjacency_list_arg)];
449 
450  float normal_difference;
451  is_convex = connIsConvex (source_sv_label, target_sv_label, normal_difference);
452  adjacency_list_arg[*edge_itr].is_convex = is_convex;
453  adjacency_list_arg[*edge_itr].is_valid = is_convex;
454  adjacency_list_arg[*edge_itr].normal_difference = normal_difference;
455  }
456 }
457 
458 template <typename PointT> bool
459 pcl::LCCPSegmentation<PointT>::connIsConvex (const uint32_t source_label_arg,
460  const uint32_t target_label_arg,
461  float &normal_angle)
462 {
463  typename pcl::Supervoxel<PointT>::Ptr& sv_source = sv_label_to_supervoxel_map_[source_label_arg];
464  typename pcl::Supervoxel<PointT>::Ptr& sv_target = sv_label_to_supervoxel_map_[target_label_arg];
465 
466  const Eigen::Vector3f& source_centroid = sv_source->centroid_.getVector3fMap ();
467  const Eigen::Vector3f& target_centroid = sv_target->centroid_.getVector3fMap ();
468 
469  const Eigen::Vector3f& source_normal = sv_source->normal_.getNormalVector3fMap (). normalized ();
470  const Eigen::Vector3f& target_normal = sv_target->normal_.getNormalVector3fMap (). normalized ();
471 
472  //NOTE For angles below 0 nothing will be merged
474  {
475  return (false);
476  }
477 
478  bool is_convex = true;
479  bool is_smooth = true;
480 
481  normal_angle = getAngle3D (source_normal, target_normal, true);
482  // Geometric comparisons
483  Eigen::Vector3f vec_t_to_s, vec_s_to_t;
484 
485  vec_t_to_s = source_centroid - target_centroid;
486  vec_s_to_t = -vec_t_to_s;
487 
488  Eigen::Vector3f ncross;
489  ncross = source_normal.cross (target_normal);
490 
491  // Smoothness Check: Check if there is a step between adjacent patches
493  {
494  float expected_distance = ncross.norm () * seed_resolution_;
495  float dot_p_1 = vec_t_to_s.dot (source_normal);
496  float dot_p_2 = vec_s_to_t.dot (target_normal);
497  float point_dist = (std::fabs (dot_p_1) < std::fabs (dot_p_2)) ? std::fabs (dot_p_1) : std::fabs (dot_p_2);
498  const float dist_smoothing = smoothness_threshold_ * voxel_resolution_; // This is a slacking variable especially important for patches with very similar normals
499 
500  if (point_dist > (expected_distance + dist_smoothing))
501  {
502  is_smooth &= false;
503  }
504  }
505  // ----------------
506 
507  // Sanity Criterion: Check if definition convexity/concavity makes sense for connection of given patches
508  float intersection_angle = getAngle3D (ncross, vec_t_to_s, true);
509  float min_intersect_angle = (intersection_angle < 90.) ? intersection_angle : 180. - intersection_angle;
510 
511  float intersect_thresh = 60. * 1. / (1. + exp (-0.25 * (normal_angle - 25.)));
512  if (min_intersect_angle < intersect_thresh && use_sanity_check_)
513  {
514  // std::cout << "Concave/Convex not defined for given case!" << std::endl;
515  is_convex &= false;
516  }
517 
518 
519  // vec_t_to_s is the reference direction for angle measurements
520  // Convexity Criterion: Check if connection of patches is convex. If this is the case the two supervoxels should be merged.
521  if ((getAngle3D (vec_t_to_s, source_normal) - getAngle3D (vec_t_to_s, target_normal)) <= 0)
522  {
523  is_convex &= true; // connection convex
524  }
525  else
526  {
527  is_convex &= (normal_angle < concavity_tolerance_threshold_); // concave connections will be accepted if difference of normals is small
528  }
529  return (is_convex && is_smooth);
530 }
531 
532 #endif // PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
std::map< uint32_t, bool > processed_
Stores which supervoxel labels were already visited during recursive grouping.
bool use_smoothness_check_
Determines if the smoothness check is used during segmentation.
std::map< uint32_t, std::set< uint32_t > > seg_label_to_neighbor_set_map_
map < SegmentID, std::set< Neighboring segment labels> >
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...
boost::graph_traits< SupervoxelAdjacencyList >::vertex_iterator VertexIterator
pcl::PointXYZRGBA centroid_
The centroid of the supervoxel - average voxel.
iterator end()
Definition: point_cloud.h:435
pcl::Normal normal_
The normal calculated for the voxels contained in the supervoxel.
float voxel_resolution_
Voxel resolution used to build the supervoxels (used only for smoothness check)
uint32_t min_segment_size_
Minimum segment size.
VectorType::iterator iterator
Definition: point_cloud.h:432
uint32_t k_factor_
Factor used for k-convexity.
std::map< uint32_t, std::set< uint32_t > > seg_label_to_sv_list_map_
map <Segment Label, std::set <SuperVoxel labels>=""> >
std::map< uint32_t, typename pcl::Supervoxel< PointT >::Ptr > sv_label_to_supervoxel_map_
map from the supervoxel labels to the supervoxel objects
void prepareSegmentation(const std::map< uint32_t, typename pcl::Supervoxel< PointT >::Ptr > &supervoxel_clusters_arg, const std::multimap< uint32_t, uint32_t > &label_adjacency_arg)
Is called within setInputSupervoxels mainly to reserve required memory.
float seed_resolution_
Seed resolution of the supervoxels (used only for smoothness check)
boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, uint32_t, EdgeProperties > SupervoxelAdjacencyList
boost::graph_traits< SupervoxelAdjacencyList >::edge_iterator EdgeIterator
float smoothness_threshold_
Two supervoxels are unsmooth if their plane-to-plane distance DIST > (expected_distance + smoothness_...
void reset()
Reset internal memory.
boost::graph_traits< SupervoxelAdjacencyList >::adjacency_iterator AdjacencyIterator
bool supervoxels_set_
Marks if supervoxels have been set by calling setInputSupervoxels.
boost::graph_traits< SupervoxelAdjacencyList >::vertex_descriptor VertexID
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. ...
boost::graph_traits< SupervoxelAdjacencyList >::edge_descriptor EdgeID
void segment()
Merge supervoxels using local convexity.
void recursiveSegmentGrowing(const VertexID &queryPointID, const unsigned int group_label)
Assigns neighbors of the query point to the same group as the query point.
iterator begin()
Definition: point_cloud.h:434
boost::graph_traits< SupervoxelAdjacencyList >::out_edge_iterator OutEdgeIterator
std::map< uint32_t, uint32_t > sv_label_to_seg_label_map_
Storing relation between original SuperVoxel Labels and new segmantion labels.
boost::shared_ptr< Supervoxel< PointT > > Ptr
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 avaiable...
SupervoxelAdjacencyList sv_adjacency_list_
Adjacency graph with the supervoxel labels as nodes and edges between adjacent supervoxels.
bool connIsConvex(const uint32_t source_label_arg, const uint32_t target_label_arg, float &normal_angle)
Returns true if the connection between source and target is convex.