38 #ifndef PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
39 #define PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
41 #include <pcl/segmentation/lccp_segmentation.h>
52 template <
typename Po
intT>
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),
61 voxel_resolution_ (0),
67 template <
typename Po
intT>
72 template <
typename Po
intT>
void
75 sv_adjacency_list_.clear ();
77 sv_label_to_supervoxel_map_.clear ();
78 sv_label_to_seg_label_map_.clear ();
79 seg_label_to_sv_list_map_.clear ();
80 seg_label_to_neighbor_set_map_.clear ();
81 grouping_data_valid_ =
false;
82 supervoxels_set_ =
false;
85 template <
typename Po
intT>
void
92 calculateConvexConnections (sv_adjacency_list_);
95 applyKconvexity (k_factor_);
100 grouping_data_valid_ =
true;
103 mergeSmallSegments ();
106 PCL_WARN (
"[pcl::LCCPSegmentation::segment] WARNING: Call function setInputSupervoxels first. Nothing has been done. \n");
110 template <
typename Po
intT>
void
113 if (grouping_data_valid_)
117 for (; voxel_itr != labeled_cloud_arg.
end (); ++voxel_itr)
119 voxel_itr->label = sv_label_to_seg_label_map_[voxel_itr->label];
124 PCL_WARN (
"[pcl::LCCPSegmentation::relabelCloud] WARNING: Call function segment first. Nothing has been done. \n");
136 template <
typename Po
intT>
void
139 seg_label_to_neighbor_set_map_.clear ();
142 std::pair<VertexIterator, VertexIterator> vertex_iterator_range;
143 vertex_iterator_range = boost::vertices (sv_adjacency_list_);
145 uint32_t current_segLabel;
146 uint32_t neigh_segLabel;
149 for (
VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr)
151 const uint32_t& sv_label = sv_adjacency_list_[*sv_itr];
152 current_segLabel = sv_label_to_seg_label_map_[sv_label];
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)
158 const uint32_t& neigh_label = sv_adjacency_list_[*itr_neighbor];
159 neigh_segLabel = sv_label_to_seg_label_map_[neigh_label];
161 if (current_segLabel != neigh_segLabel)
163 seg_label_to_neighbor_set_map_[current_segLabel].insert (neigh_segLabel);
169 template <
typename Po
intT>
void
172 if (min_segment_size_ == 0)
175 computeSegmentAdjacency ();
177 std::set<uint32_t> filteredSegLabels;
179 uint32_t largest_neigh_size = 0;
180 uint32_t largest_neigh_seg_label = 0;
181 uint32_t current_seg_label;
183 std::pair<VertexIterator, VertexIterator> vertex_iterator_range;
184 vertex_iterator_range = boost::vertices (sv_adjacency_list_);
186 bool continue_filtering =
true;
188 while (continue_filtering)
190 continue_filtering =
false;
191 unsigned int nr_filtered = 0;
194 for (
VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr)
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 ();
201 const uint32_t& nr_neighbors = seg_label_to_neighbor_set_map_[current_seg_label].size ();
202 if (nr_neighbors == 0)
205 if (seg_label_to_sv_list_map_[current_seg_label].size () <= min_segment_size_)
207 continue_filtering =
true;
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)
214 if (seg_label_to_sv_list_map_[*neighbors_itr].size () >= largest_neigh_size)
216 largest_neigh_seg_label = *neighbors_itr;
217 largest_neigh_size = seg_label_to_sv_list_map_[*neighbors_itr].size ();
222 if (largest_neigh_seg_label != current_seg_label)
224 if (filteredSegLabels.count (largest_neigh_seg_label) > 0)
227 sv_label_to_seg_label_map_[sv_label] = largest_neigh_seg_label;
228 filteredSegLabels.insert (current_seg_label);
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)
235 seg_label_to_sv_list_map_[largest_neigh_seg_label].insert (*sv_ID_itr);
242 std::set<uint32_t>::iterator filtered_ID_itr = filteredSegLabels.begin ();
243 for (; filtered_ID_itr != filteredSegLabels.end (); ++filtered_ID_itr)
245 seg_label_to_sv_list_map_.erase (*filtered_ID_itr);
251 computeSegmentAdjacency ();
255 template <
typename Po
intT>
void
257 const std::multimap<uint32_t, uint32_t>& label_adjaceny_arg)
263 sv_label_to_supervoxel_map_ = supervoxel_clusters_arg;
266 std::map<uint32_t, VertexID> label_ID_map;
270 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
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;
279 for (std::multimap<uint32_t, uint32_t>::const_iterator sv_neighbors_itr = label_adjaceny_arg.begin (); sv_neighbors_itr != label_adjaceny_arg.end ();
282 const uint32_t& sv_label = sv_neighbors_itr->first;
283 const uint32_t& neighbor_label = sv_neighbors_itr->second;
285 VertexID u = label_ID_map[sv_label];
286 VertexID v = label_ID_map[neighbor_label];
288 boost::add_edge (u, v, sv_adjacency_list_);
293 seg_label_to_sv_list_map_.clear ();
295 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
297 const uint32_t& sv_label = svlabel_itr->first;
298 processed_[sv_label] =
false;
299 sv_label_to_seg_label_map_[sv_label] = 0;
306 template <
typename Po
intT>
void
310 seg_label_to_sv_list_map_.clear ();
312 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
314 const uint32_t& sv_label = svlabel_itr->first;
315 processed_[sv_label] =
false;
316 sv_label_to_seg_label_map_[sv_label] = 0;
321 std::pair< VertexIterator, VertexIterator> vertex_iterator_range;
322 vertex_iterator_range = boost::vertices (sv_adjacency_list_);
325 unsigned int segment_label = 1;
326 for (
VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr)
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])
333 recursiveSegmentGrowing (sv_vertex_id, segment_label);
339 template <
typename Po
intT>
void
341 const unsigned int segment_label)
343 const uint32_t& sv_label = sv_adjacency_list_[query_point_id];
345 processed_[sv_label] =
true;
348 sv_label_to_seg_label_map_[sv_label] = segment_label;
349 seg_label_to_sv_list_map_[segment_label].insert (sv_label);
352 std::pair<OutEdgeIterator, OutEdgeIterator> out_edge_iterator_range;
353 out_edge_iterator_range = boost::out_edges (query_point_id, 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)
356 const VertexID neighbor_ID = boost::target (*out_Edge_itr, sv_adjacency_list_);
357 const uint32_t& neighbor_label = sv_adjacency_list_[neighbor_ID];
359 if (!processed_[neighbor_label])
361 if (sv_adjacency_list_[*out_Edge_itr].is_valid)
363 recursiveSegmentGrowing (neighbor_ID, segment_label);
369 template <
typename Po
intT>
void
376 unsigned int kcount = 0;
379 boost::tie (edge_itr, edge_itr_end) = boost::edges (sv_adjacency_list_);
381 std::pair<OutEdgeIterator, OutEdgeIterator> source_neighbors_range;
382 std::pair<OutEdgeIterator, OutEdgeIterator> target_neighbors_range;
385 for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
389 is_convex = sv_adjacency_list_[*edge_itr].is_convex;
395 const VertexID source = boost::source (*edge_itr, sv_adjacency_list_);
396 const VertexID target = boost::target (*edge_itr, sv_adjacency_list_);
398 source_neighbors_range = boost::out_edges (source, sv_adjacency_list_);
399 target_neighbors_range = boost::out_edges (target, sv_adjacency_list_);
402 for (
OutEdgeIterator source_neighbors_itr = source_neighbors_range.first; source_neighbors_itr != source_neighbors_range.second; ++source_neighbors_itr)
404 VertexID source_neighbor_ID = boost::target (*source_neighbors_itr, sv_adjacency_list_);
406 for (
OutEdgeIterator target_neighbors_itr = target_neighbors_range.first; target_neighbors_itr != target_neighbors_range.second; ++target_neighbors_itr)
408 VertexID target_neighbor_ID = boost::target (*target_neighbors_itr, sv_adjacency_list_);
409 if (source_neighbor_ID == target_neighbor_ID)
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;
414 bool src_is_convex = (sv_adjacency_list_)[src_edge].is_convex;
415 bool tar_is_convex = (sv_adjacency_list_)[tar_edge].is_convex;
417 if (src_is_convex && tar_is_convex)
430 (sv_adjacency_list_)[*edge_itr].is_valid =
false;
435 template <
typename Po
intT>
void
441 boost::tie (edge_itr, edge_itr_end) = boost::edges (adjacency_list_arg);
443 for (next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
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)];
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;
458 template <
typename Po
intT>
bool
460 const uint32_t target_label_arg,
466 const Eigen::Vector3f& source_centroid = sv_source->
centroid_.getVector3fMap ();
467 const Eigen::Vector3f& target_centroid = sv_target->
centroid_.getVector3fMap ();
469 const Eigen::Vector3f& source_normal = sv_source->
normal_.getNormalVector3fMap (). normalized ();
470 const Eigen::Vector3f& target_normal = sv_target->
normal_.getNormalVector3fMap (). normalized ();
473 if (concavity_tolerance_threshold_ < 0)
478 bool is_convex =
true;
479 bool is_smooth =
true;
481 normal_angle =
getAngle3D (source_normal, target_normal,
true);
483 Eigen::Vector3f vec_t_to_s, vec_s_to_t;
485 vec_t_to_s = source_centroid - target_centroid;
486 vec_s_to_t = -vec_t_to_s;
488 Eigen::Vector3f ncross;
489 ncross = source_normal.cross (target_normal);
492 if (use_smoothness_check_)
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_;
500 if (point_dist > (expected_distance + dist_smoothing))
508 float intersection_angle =
getAngle3D (ncross, vec_t_to_s,
true);
509 float min_intersect_angle = (intersection_angle < 90.) ? intersection_angle : 180. - intersection_angle;
511 float intersect_thresh = 60. * 1. / (1. + exp (-0.25 * (normal_angle - 25.)));
512 if (min_intersect_angle < intersect_thresh && use_sanity_check_)
527 is_convex &= (normal_angle < concavity_tolerance_threshold_);
529 return (is_convex && is_smooth);
532 #endif // PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
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. ...
boost::graph_traits< SupervoxelAdjacencyList >::vertex_iterator VertexIterator
pcl::PointXYZRGBA centroid_
The centroid of the supervoxel - average voxel.
pcl::Normal normal_
The normal calculated for the voxels contained in the supervoxel.
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.
virtual ~LCCPSegmentation()
boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, uint32_t, EdgeProperties > SupervoxelAdjacencyList
boost::graph_traits< SupervoxelAdjacencyList >::edge_iterator EdgeIterator
void reset()
Reset internal memory.
boost::graph_traits< SupervoxelAdjacencyList >::adjacency_iterator AdjacencyIterator
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.
boost::graph_traits< SupervoxelAdjacencyList >::out_edge_iterator OutEdgeIterator
boost::shared_ptr< Supervoxel< PointT > > Ptr
VectorType::iterator iterator
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 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.