38 #ifndef PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
39 #define PCL_SEGMENTATION_IMPL_LCCP_SEGMENTATION_HPP_
41 #include <pcl/segmentation/lccp_segmentation.h>
53 template <
typename Po
intT>
56 template <
typename Po
intT>
59 template <
typename Po
intT>
void
62 sv_adjacency_list_.clear ();
64 sv_label_to_supervoxel_map_.clear ();
65 sv_label_to_seg_label_map_.clear ();
66 seg_label_to_sv_list_map_.clear ();
67 seg_label_to_neighbor_set_map_.clear ();
68 grouping_data_valid_ =
false;
69 supervoxels_set_ =
false;
72 template <
typename Po
intT>
void
79 calculateConvexConnections (sv_adjacency_list_);
82 applyKconvexity (k_factor_);
87 grouping_data_valid_ =
true;
90 mergeSmallSegments ();
93 PCL_WARN (
"[pcl::LCCPSegmentation::segment] WARNING: Call function setInputSupervoxels first. Nothing has been done. \n");
97 template <
typename Po
intT>
void
100 if (grouping_data_valid_)
103 for (
auto &voxel : labeled_cloud_arg)
105 voxel.label = sv_label_to_seg_label_map_[voxel.label];
110 PCL_WARN (
"[pcl::LCCPSegmentation::relabelCloud] WARNING: Call function segment first. Nothing has been done. \n");
122 template <
typename Po
intT>
void
125 seg_label_to_neighbor_set_map_.clear ();
127 std::uint32_t current_segLabel;
128 std::uint32_t neigh_segLabel;
133 for(std::tie(sv_itr, sv_itr_end) = boost::vertices(sv_adjacency_list_); sv_itr != sv_itr_end; ++sv_itr)
135 const std::uint32_t& sv_label = sv_adjacency_list_[*sv_itr];
136 current_segLabel = sv_label_to_seg_label_map_[sv_label];
140 for (std::tie(itr_neighbor, itr_neighbor_end) = boost::adjacent_vertices (*sv_itr, sv_adjacency_list_); itr_neighbor != itr_neighbor_end; ++itr_neighbor)
142 const std::uint32_t& neigh_label = sv_adjacency_list_[*itr_neighbor];
143 neigh_segLabel = sv_label_to_seg_label_map_[neigh_label];
145 if (current_segLabel != neigh_segLabel)
147 seg_label_to_neighbor_set_map_[current_segLabel].insert (neigh_segLabel);
153 template <
typename Po
intT>
void
156 if (min_segment_size_ == 0)
159 computeSegmentAdjacency ();
161 std::set<std::uint32_t> filteredSegLabels;
163 bool continue_filtering =
true;
165 while (continue_filtering)
167 continue_filtering =
false;
171 for (std::tie(sv_itr, sv_itr_end) = boost::vertices (sv_adjacency_list_); sv_itr != sv_itr_end; ++sv_itr)
173 const std::uint32_t& sv_label = sv_adjacency_list_[*sv_itr];
174 std::uint32_t current_seg_label = sv_label_to_seg_label_map_[sv_label];
175 std::uint32_t largest_neigh_seg_label = current_seg_label;
176 std::uint32_t largest_neigh_size = seg_label_to_sv_list_map_[current_seg_label].size ();
178 const std::uint32_t& nr_neighbors = seg_label_to_neighbor_set_map_[current_seg_label].size ();
179 if (nr_neighbors == 0)
182 if (seg_label_to_sv_list_map_[current_seg_label].size () <= min_segment_size_)
184 continue_filtering =
true;
187 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)
189 if (seg_label_to_sv_list_map_[*neighbors_itr].size () >= largest_neigh_size)
191 largest_neigh_seg_label = *neighbors_itr;
192 largest_neigh_size = seg_label_to_sv_list_map_[*neighbors_itr].size ();
197 if (largest_neigh_seg_label != current_seg_label)
199 if (filteredSegLabels.count (largest_neigh_seg_label) > 0)
202 sv_label_to_seg_label_map_[sv_label] = largest_neigh_seg_label;
203 filteredSegLabels.insert (current_seg_label);
206 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)
208 seg_label_to_sv_list_map_[largest_neigh_seg_label].insert (*sv_ID_itr);
215 for (
const unsigned int &filteredSegLabel : filteredSegLabels)
217 seg_label_to_sv_list_map_.erase (filteredSegLabel);
223 computeSegmentAdjacency ();
227 template <
typename Po
intT>
void
229 const std::multimap<std::uint32_t, std::uint32_t>& label_adjaceny_arg)
235 sv_label_to_supervoxel_map_ = supervoxel_clusters_arg;
238 std::map<std::uint32_t, VertexID> label_ID_map;
241 for (
auto svlabel_itr = sv_label_to_supervoxel_map_.begin ();
242 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
244 const std::uint32_t& sv_label = svlabel_itr->first;
245 VertexID node_id = boost::add_vertex (sv_adjacency_list_);
246 sv_adjacency_list_[node_id] = sv_label;
247 label_ID_map[sv_label] = node_id;
251 for (
const auto &sv_neighbors_itr : label_adjaceny_arg)
253 const std::uint32_t& sv_label = sv_neighbors_itr.first;
254 const std::uint32_t& neighbor_label = sv_neighbors_itr.second;
256 VertexID u = label_ID_map[sv_label];
257 VertexID v = label_ID_map[neighbor_label];
259 boost::add_edge (u, v, sv_adjacency_list_);
264 seg_label_to_sv_list_map_.clear ();
265 for (
auto svlabel_itr = sv_label_to_supervoxel_map_.begin ();
266 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
268 const std::uint32_t& sv_label = svlabel_itr->first;
269 processed_[sv_label] =
false;
270 sv_label_to_seg_label_map_[sv_label] = 0;
277 template <
typename Po
intT>
void
281 seg_label_to_sv_list_map_.clear ();
282 for (
auto svlabel_itr = sv_label_to_supervoxel_map_.begin ();
283 svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr)
285 const std::uint32_t& sv_label = svlabel_itr->first;
286 processed_[sv_label] =
false;
287 sv_label_to_seg_label_map_[sv_label] = 0;
294 unsigned int segment_label = 1;
295 for (std::tie(sv_itr, sv_itr_end) = boost::vertices (sv_adjacency_list_); sv_itr != sv_itr_end; ++sv_itr)
297 const VertexID sv_vertex_id = *sv_itr;
298 const std::uint32_t& sv_label = sv_adjacency_list_[sv_vertex_id];
299 if (!processed_[sv_label])
302 recursiveSegmentGrowing (sv_vertex_id, segment_label);
308 template <
typename Po
intT>
void
310 const unsigned int segment_label)
312 const std::uint32_t& sv_label = sv_adjacency_list_[query_point_id];
314 processed_[sv_label] =
true;
317 sv_label_to_seg_label_map_[sv_label] = segment_label;
318 seg_label_to_sv_list_map_[segment_label].insert (sv_label);
323 for (std::tie(out_Edge_itr, out_Edge_itr_end) = boost::out_edges (query_point_id, sv_adjacency_list_); out_Edge_itr != out_Edge_itr_end; ++out_Edge_itr)
325 const VertexID neighbor_ID = boost::target (*out_Edge_itr, sv_adjacency_list_);
326 const std::uint32_t& neighbor_label = sv_adjacency_list_[neighbor_ID];
328 if (!processed_[neighbor_label])
330 if (sv_adjacency_list_[*out_Edge_itr].is_valid)
332 recursiveSegmentGrowing (neighbor_ID, segment_label);
338 template <
typename Po
intT>
void
346 for (std::tie (edge_itr, edge_itr_end) = boost::edges (sv_adjacency_list_), next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
350 bool is_convex = sv_adjacency_list_[*edge_itr].is_convex;
354 unsigned int kcount = 0;
356 const VertexID source = boost::source (*edge_itr, sv_adjacency_list_);
357 const VertexID target = boost::target (*edge_itr, sv_adjacency_list_);
361 for (std::tie(source_neighbors_itr, source_neighbors_itr_end) = boost::out_edges (source, sv_adjacency_list_); source_neighbors_itr != source_neighbors_itr_end; ++source_neighbors_itr)
363 VertexID source_neighbor_ID = boost::target (*source_neighbors_itr, sv_adjacency_list_);
366 for (std::tie(target_neighbors_itr, target_neighbors_itr_end) = boost::out_edges (target, sv_adjacency_list_); target_neighbors_itr != target_neighbors_itr_end; ++target_neighbors_itr)
368 VertexID target_neighbor_ID = boost::target (*target_neighbors_itr, sv_adjacency_list_);
369 if (source_neighbor_ID == target_neighbor_ID)
371 EdgeID src_edge = boost::edge (source, source_neighbor_ID, sv_adjacency_list_).first;
372 EdgeID tar_edge = boost::edge (target, source_neighbor_ID, sv_adjacency_list_).first;
374 bool src_is_convex = (sv_adjacency_list_)[src_edge].is_convex;
375 bool tar_is_convex = (sv_adjacency_list_)[tar_edge].is_convex;
377 if (src_is_convex && tar_is_convex)
390 (sv_adjacency_list_)[*edge_itr].is_valid =
false;
395 template <
typename Po
intT>
void
400 for (std::tie(edge_itr, edge_itr_end) = boost::edges (adjacency_list_arg), next_edge = edge_itr; edge_itr != edge_itr_end; edge_itr = next_edge)
404 std::uint32_t source_sv_label = adjacency_list_arg[boost::source (*edge_itr, adjacency_list_arg)];
405 std::uint32_t target_sv_label = adjacency_list_arg[boost::target (*edge_itr, adjacency_list_arg)];
407 float normal_difference;
408 bool is_convex = connIsConvex (source_sv_label, target_sv_label, normal_difference);
409 adjacency_list_arg[*edge_itr].is_convex = is_convex;
410 adjacency_list_arg[*edge_itr].is_valid = is_convex;
411 adjacency_list_arg[*edge_itr].normal_difference = normal_difference;
415 template <
typename Po
intT>
bool
417 const std::uint32_t target_label_arg,
423 const Eigen::Vector3f& source_centroid = sv_source->
centroid_.getVector3fMap ();
424 const Eigen::Vector3f& target_centroid = sv_target->
centroid_.getVector3fMap ();
426 const Eigen::Vector3f& source_normal = sv_source->
normal_.getNormalVector3fMap (). normalized ();
427 const Eigen::Vector3f& target_normal = sv_target->
normal_.getNormalVector3fMap (). normalized ();
430 if (concavity_tolerance_threshold_ < 0)
435 bool is_convex =
true;
436 bool is_smooth =
true;
438 normal_angle =
getAngle3D (source_normal, target_normal,
true);
440 Eigen::Vector3f vec_t_to_s, vec_s_to_t;
442 vec_t_to_s = source_centroid - target_centroid;
443 vec_s_to_t = -vec_t_to_s;
445 Eigen::Vector3f ncross;
446 ncross = source_normal.cross (target_normal);
449 if (use_smoothness_check_)
451 float expected_distance = ncross.norm () * seed_resolution_;
452 float dot_p_1 = vec_t_to_s.dot (source_normal);
453 float dot_p_2 = vec_s_to_t.dot (target_normal);
454 float point_dist = (std::fabs (dot_p_1) < std::fabs (dot_p_2)) ? std::fabs (dot_p_1) : std::fabs (dot_p_2);
455 const float dist_smoothing = smoothness_threshold_ * voxel_resolution_;
457 if (point_dist > (expected_distance + dist_smoothing))
465 float intersection_angle =
getAngle3D (ncross, vec_t_to_s,
true);
466 float min_intersect_angle = (intersection_angle < 90.) ? intersection_angle : 180. - intersection_angle;
468 float intersect_thresh = 60. * 1. / (1. + std::exp (-0.25 * (normal_angle - 25.)));
469 if (min_intersect_angle < intersect_thresh && use_sanity_check_)
484 is_convex &= (normal_angle < concavity_tolerance_threshold_);
486 return (is_convex && is_smooth);
virtual ~LCCPSegmentation()
typename boost::graph_traits< SupervoxelAdjacencyList >::vertex_iterator VertexIterator
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_iterator EdgeIterator
boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, std::uint32_t, EdgeProperties > SupervoxelAdjacencyList
void recursiveSegmentGrowing(const VertexID &queryPointID, const unsigned int group_label)
Assigns neighbors of the query point to the same group as the query point.
void calculateConvexConnections(SupervoxelAdjacencyList &adjacency_list_arg)
Calculates convexity of edges and saves this to the adjacency graph.
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.
void mergeSmallSegments()
Segments smaller than min_segment_size_ are merged to the label of largest neighbor.
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.
void segment()
Merge supervoxels using local convexity.
typename boost::graph_traits< SupervoxelAdjacencyList >::out_edge_iterator OutEdgeIterator
typename boost::graph_traits< SupervoxelAdjacencyList >::adjacency_iterator AdjacencyIterator
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.
void doGrouping()
Perform depth search on the graph and recursively group all supervoxels with convex connections.
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.
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_descriptor EdgeID
typename boost::graph_traits< SupervoxelAdjacencyList >::vertex_descriptor VertexID
void reset()
Reset internal memory.
PointCloud represents the base class in PCL for storing collections of 3D points.
pcl::PointXYZRGBA centroid_
The centroid of the supervoxel - average voxel.
shared_ptr< Supervoxel< PointT > > Ptr
pcl::Normal normal_
The normal calculated for the voxels contained in the supervoxel.
Define standard C methods and C++ classes that are common to all methods.
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.