From a8077942fb0a8ebf4f0911d4e789950bc53aed4f Mon Sep 17 00:00:00 2001 From: Markus Schoeler Date: Wed, 29 Jul 2015 10:26:56 +0200 Subject: [PATCH] Changes to LCCP algorithm to prepare it as a base for CPC. Small corrections to existing code, too. --- .../example_lccp_segmentation.cpp | 14 ++--- .../segmentation/impl/lccp_segmentation.hpp | 63 ++++++++++++------- .../pcl/segmentation/lccp_segmentation.h | 33 +++++++--- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/examples/segmentation/example_lccp_segmentation.cpp b/examples/segmentation/example_lccp_segmentation.cpp index 5856b5a0b02..985118d6e84 100644 --- a/examples/segmentation/example_lccp_segmentation.cpp +++ b/examples/segmentation/example_lccp_segmentation.cpp @@ -167,7 +167,7 @@ LCCPSegmentation Parameters: \n\ -st - Invalidate steps. Value from the interval [0,1], where 0 is the strictest and 1 equals 'no smoothness check' \n\ -ec - Use extended (less local) convexity check\n\ -sc - Use sanity criterion to invalidate singular connected patches\n\ - -smooth - Remove small segments which have fewer points than minimal segment size\n\ + -smooth - Merge small segments which have fewer points than minimal segment size\n\ \n", argv[0]); return (1); @@ -391,14 +391,14 @@ LCCPSegmentation Parameters: \n\ /// Create a cloud of the voxelcenters and map: VertexID in adjacency graph -> Point index in cloud - vtkSmartPointer points = vtkSmartPointer::New (); - vtkSmartPointer cells = vtkSmartPointer::New (); + vtkSmartPointer points = vtkSmartPointer::New (); + vtkSmartPointer cells = vtkSmartPointer::New (); vtkSmartPointer colors = vtkSmartPointer::New (); colors->SetNumberOfComponents (3); colors->SetName ("Colors"); // Create a polydata to store everything in - vtkSmartPointer polyData = vtkSmartPointer::New (); + vtkSmartPointer polyData = vtkSmartPointer::New (); for (VertexIterator itr = vertex_iterator_range.first; itr != vertex_iterator_range.second; ++itr) { const uint32_t sv_label = sv_adjacency_list[*itr]; @@ -417,7 +417,7 @@ LCCPSegmentation Parameters: \n\ colors->InsertNextTupleValue (color); pcl::Supervoxel::Ptr supervoxel = supervoxel_clusters.at (sv_label); - pcl::PointXYZRGBA vert_curr = supervoxel->centroid_; + pcl::PointXYZRGBA vert_curr = supervoxel->centroid_; const uint32_t sv_neighbor_label = sv_adjacency_list[*itr_neighbor]; @@ -434,10 +434,10 @@ LCCPSegmentation Parameters: \n\ polyLine->GetPointIds ()->SetId (1, points->GetNumberOfPoints ()-1); cells->InsertNextCell (polyLine); } - } + } polyData->SetPoints (points); // Add the lines to the dataset - polyData->SetLines (cells); + polyData->SetLines (cells); polyData->GetPointData ()->SetScalars (colors); diff --git a/segmentation/include/pcl/segmentation/impl/lccp_segmentation.hpp b/segmentation/include/pcl/segmentation/impl/lccp_segmentation.hpp index 3eb217eeca5..167fb43564a 100644 --- a/segmentation/include/pcl/segmentation/impl/lccp_segmentation.hpp +++ b/segmentation/include/pcl/segmentation/impl/lccp_segmentation.hpp @@ -106,14 +106,14 @@ pcl::LCCPSegmentation::computeSegmentAdjacency () // For every Supervoxel.. for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all SuperVoxels { - const uint32_t sv_label = sv_adjacency_list_[*sv_itr]; + const uint32_t& sv_label = sv_adjacency_list_[*sv_itr]; current_segLabel = sv_label_to_seg_label_map_[sv_label]; // ..look at all neighbors and insert their labels into the neighbor set std::pair neighbors = boost::adjacent_vertices (*sv_itr, sv_adjacency_list_); for (AdjacencyIterator itr_neighbor = neighbors.first; itr_neighbor != neighbors.second; ++itr_neighbor) { - const uint32_t neigh_label = sv_adjacency_list_[*itr_neighbor]; + const uint32_t& neigh_label = sv_adjacency_list_[*itr_neighbor]; neigh_segLabel = sv_label_to_seg_label_map_[neigh_label]; if (current_segLabel != neigh_segLabel) @@ -159,12 +159,12 @@ pcl::LCCPSegmentation::mergeSmallSegments (uint32_t min_segment_size_arg // Iterate through all supervoxels, check if they are in a "small" segment -> change label to largest neighborID for (VertexIterator sv_itr = vertex_iterator_range.first; sv_itr != vertex_iterator_range.second; ++sv_itr) // For all SuperVoxels { - const uint32_t sv_label = sv_adjacency_list_[*sv_itr]; + const uint32_t& sv_label = sv_adjacency_list_[*sv_itr]; current_seg_label = sv_label_to_seg_label_map_[sv_label]; largest_neigh_seg_label = current_seg_label; largest_neigh_size = seg_label_to_sv_list_map_[current_seg_label].size (); - const uint32_t nr_neighbors = seg_label_to_neighbor_set_map_[current_seg_label].size (); + const uint32_t& nr_neighbors = seg_label_to_neighbor_set_map_[current_seg_label].size (); if (nr_neighbors == 0) continue; @@ -240,7 +240,7 @@ pcl::LCCPSegmentation::prepareSegmentation (const std::map::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin (); svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr) { - const uint32_t sv_label = svlabel_itr->first; + const uint32_t& sv_label = svlabel_itr->first; VertexID node_id = boost::add_vertex (sv_adjacency_list_); sv_adjacency_list_[node_id] = sv_label; label_ID_map[sv_label] = node_id; @@ -250,8 +250,8 @@ pcl::LCCPSegmentation::prepareSegmentation (const std::map::const_iterator sv_neighbors_itr = label_adjaceny_arg.begin (); sv_neighbors_itr != label_adjaceny_arg.end (); ++sv_neighbors_itr) { - const uint32_t sv_label = sv_neighbors_itr->first; - const uint32_t neighbor_label = sv_neighbors_itr->second; + const uint32_t& sv_label = sv_neighbors_itr->first; + const uint32_t& neighbor_label = sv_neighbors_itr->second; VertexID u = label_ID_map[sv_label]; VertexID v = label_ID_map[neighbor_label]; @@ -265,7 +265,7 @@ pcl::LCCPSegmentation::prepareSegmentation (const std::map::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin (); svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr) { - const uint32_t sv_label = svlabel_itr->first; + const uint32_t& sv_label = svlabel_itr->first; processed_[sv_label] = false; sv_label_to_seg_label_map_[sv_label] = 0; } @@ -285,6 +285,24 @@ pcl::LCCPSegmentation::segment (std::map0 applyKconvexity (k_factor_); + // Determine wether to use cutting planes + doGrouping (); + grouping_data_valid_ = true; +} + +template void +pcl::LCCPSegmentation::doGrouping () +{ + // clear the processed_ map + seg_label_to_sv_list_map_.clear (); + for (typename std::map::Ptr>::iterator svlabel_itr = sv_label_to_supervoxel_map_.begin (); + svlabel_itr != sv_label_to_supervoxel_map_.end (); ++svlabel_itr) + { + const uint32_t& sv_label = svlabel_itr->first; + processed_[sv_label] = false; + sv_label_to_seg_label_map_[sv_label] = 0; + } + // Perform depth search on the graph and recursively group all supervoxels with convex connections //The vertices in the supervoxel adjacency list are the supervoxel centroids std::pair< VertexIterator, VertexIterator> vertex_iterator_range; @@ -295,22 +313,21 @@ pcl::LCCPSegmentation::segment (std::map go to next group } } - grouping_data_valid_ = true; } template void -pcl::LCCPSegmentation::recursiveGrouping (VertexID const &query_point_id, - unsigned int const segment_label) +pcl::LCCPSegmentation::recursiveSegmentGrowing (VertexID const &query_point_id, + unsigned int const segment_label) { - const uint32_t sv_label = sv_adjacency_list_[query_point_id]; + const uint32_t& sv_label = sv_adjacency_list_[query_point_id]; processed_[sv_label] = true; @@ -324,13 +341,13 @@ pcl::LCCPSegmentation::recursiveGrouping (VertexID const &query_point_id for (OutEdgeIterator out_Edge_itr = out_edge_iterator_range.first; out_Edge_itr != out_edge_iterator_range.second; ++out_Edge_itr) { const VertexID neighbor_ID = boost::target (*out_Edge_itr, sv_adjacency_list_); - const uint32_t neighbor_label = sv_adjacency_list_[neighbor_ID]; + const uint32_t& neighbor_label = sv_adjacency_list_[neighbor_ID]; if (!processed_[neighbor_label]) // If neighbor was not already processed { - if (sv_adjacency_list_[*out_Edge_itr].is_convex) + if (sv_adjacency_list_[*out_Edge_itr].is_valid) { - recursiveGrouping (neighbor_ID, segment_label); + recursiveSegmentGrowing (neighbor_ID, segment_label); } } } // End neighbor loop @@ -397,7 +414,7 @@ pcl::LCCPSegmentation::applyKconvexity (unsigned int k_arg) // Check k convexity if (kcount < k_arg) - (sv_adjacency_list_)[*edge_itr].is_convex = false; + (sv_adjacency_list_)[*edge_itr].is_valid = false; } } } @@ -417,14 +434,18 @@ pcl::LCCPSegmentation::calculateConvexConnections (SupervoxelAdjacencyLi uint32_t source_sv_label = adjacency_list_arg[boost::source (*edge_itr, adjacency_list_arg)]; uint32_t target_sv_label = adjacency_list_arg[boost::target (*edge_itr, adjacency_list_arg)]; - is_convex = connIsConvex (source_sv_label, target_sv_label); + float normal_difference; + is_convex = connIsConvex (source_sv_label, target_sv_label, normal_difference); adjacency_list_arg[*edge_itr].is_convex = is_convex; + adjacency_list_arg[*edge_itr].is_valid = is_convex; + adjacency_list_arg[*edge_itr].normal_difference = normal_difference; } } template bool pcl::LCCPSegmentation::connIsConvex (uint32_t source_label_arg, - uint32_t target_label_arg) + uint32_t target_label_arg, + float &normal_angle) { typename pcl::Supervoxel::Ptr& sv_source = sv_label_to_supervoxel_map_[source_label_arg]; typename pcl::Supervoxel::Ptr& sv_target = sv_label_to_supervoxel_map_[target_label_arg]; @@ -444,7 +465,7 @@ pcl::LCCPSegmentation::connIsConvex (uint32_t source_label_arg, bool is_convex = true; bool is_smooth = true; - float normal_angle = getAngle3D (source_normal, target_normal, true); + normal_angle = getAngle3D (source_normal, target_normal, true); // Geometric comparisons Eigen::Vector3f vec_t_to_s, vec_s_to_t; diff --git a/segmentation/include/pcl/segmentation/lccp_segmentation.h b/segmentation/include/pcl/segmentation/lccp_segmentation.h index a1d9589d7f9..183f4798366 100644 --- a/segmentation/include/pcl/segmentation/lccp_segmentation.h +++ b/segmentation/include/pcl/segmentation/lccp_segmentation.h @@ -61,9 +61,20 @@ namespace pcl /** \brief Edge Properties stored in the adjacency graph.*/ struct EdgeProperties { + /** \brief Desribes the difference of normals of the two supervoxels being connected*/ + float normal_difference; + + /** \brief Desribes if a connection is convex or concave*/ bool is_convex; + + /** \brief Describes if a connection is valid for the segment growing. Usually convex connections are and concave connection are not. Due to k-concavity a convex connection can be invalidated*/ + bool is_valid; + + /** \brief Additional member used for the CPC algorithm. If edge has already induced a cut, it should be ignored for further cutting.*/ + bool used_for_cutting; + EdgeProperties () : - is_convex (false) + normal_difference (0), is_convex (false), is_valid (false), used_for_cutting (false) { } }; @@ -204,7 +215,7 @@ namespace pcl k_factor_ = k; } - private: + protected: /** \brief Compute the adjacency of the segments */ void @@ -217,12 +228,18 @@ namespace pcl prepareSegmentation (const std::map::Ptr> &supervoxel_clusters_arg, const std::multimap &label_adjacency_arg); + + /** Perform depth search on the graph and recursively group all supervoxels with convex connections + * \note The vertices in the supervoxel adjacency list are the supervoxel centroids */ + void + doGrouping (); + /** \brief Assigns neighbors of the query point to the same group as the query point. Recursive part of groupSupervoxels (..). Grouping is done by a depth-search of nodes in the adjacency-graph. * \param[in] queryPointID ID of point whose neighbors will be considered for grouping * \param[in] group_label ID of the group/segment the queried point belongs to */ void - recursiveGrouping (VertexID const &queryPointID, - unsigned int const group_label); + recursiveSegmentGrowing (VertexID const &queryPointID, + unsigned int const group_label); /** \brief Calculates convexity of edges and saves this to the adjacency graph. * \param[in] adjacency_list_arg The supervoxel adjacency list*/ @@ -237,10 +254,12 @@ namespace pcl /** \brief Returns true if the connection between source and target is convex. * \param[in] source_label_arg Label of one Supervoxel connected to the edge that should be checked * \param[in] target_label_arg Label of the other Supervoxel connected to the edge that should be checked + * \param[out] normal_angle The angle between source and target * \return True if connection is convex */ bool connIsConvex (uint32_t source_label_arg, - uint32_t target_label_arg); + uint32_t target_label_arg, + float &normal_angle); /// *** Parameters *** /// @@ -266,7 +285,7 @@ namespace pcl float voxel_resolution_; /** \brief Factor used for k-convexity */ - unsigned int k_factor_; + uint32_t k_factor_; /** \brief Stores which SuperVoxel labels were already visited during recursive grouping. processed_[sv_Label] = false (default)/true (already processed) */ std::map processed_; @@ -283,7 +302,7 @@ namespace pcl /** \brief map > */ std::map > seg_label_to_sv_list_map_; - /** \brief map > */ + /** \brief map < SegmentID, std::set< Neighboring segment labels> > */ std::map > seg_label_to_neighbor_set_map_; };