Point Cloud Library (PCL)  1.9.1-dev
cpc_segmentation.h
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 #pragma once
39 
40 // common includes
41 #include <pcl/pcl_base.h>
42 #include <pcl/point_types.h>
43 #include <pcl/point_cloud.h>
44 
45 // segmentation and sample consensus includes
46 #include <pcl/segmentation/supervoxel_clustering.h>
47 #include <pcl/segmentation/lccp_segmentation.h>
48 #include <pcl/sample_consensus/sac.h>
49 
50 #include <pcl/sample_consensus/sac_model_plane.h>
51 #include <pcl/segmentation/extract_clusters.h>
52 
53 #define PCL_INSTANTIATE_CPCSegmentation(T) template class PCL_EXPORTS pcl::CPCSegmentation<T>;
54 
55 namespace pcl
56 {
57  /** \brief A segmentation algorithm partitioning a supervoxel graph. It uses planar cuts induced by local concavities for the recursive segmentation. Cuts are estimated using locally constrained directed RANSAC.
58  * \note If you use this in a scientific work please cite the following paper:
59  * M. Schoeler, J. Papon, F. Woergoetter
60  * Constrained Planar Cuts - Object Partitioning for Point Clouds
61  * In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR) 2015
62  * Inherits most of its functionality from \ref LCCPSegmentation
63  * \author Markus Schoeler (mschoeler@web.de)
64  * \ingroup segmentation
65  */
66  template <typename PointT>
67  class CPCSegmentation : public LCCPSegmentation<PointT>
68  {
71  // LCCP typedefs
72  using EdgeID = typename LCCP::EdgeID;
73  using EdgeIterator = typename LCCP::EdgeIterator;
74  // LCCP methods
77  using LCCP::doGrouping;
79  // LCCP variables
81  using LCCP::k_factor_;
88 
89  public:
90  CPCSegmentation ();
91 
93 
94  /** \brief Merge supervoxels using cuts through local convexities. The input parameters are generated by using the \ref SupervoxelClustering class. To retrieve the output use the \ref relabelCloud method.
95  * \note There are three ways to retrieve the segmentation afterwards (inherited from \ref LCCPSegmentation): \ref relabelCloud, \ref getSegmentSupervoxelMap and \ref getSupervoxelSegmentMap*/
96  void
97  segment ();
98 
99  /** \brief Determines if we want to use cutting planes
100  * \param[in] max_cuts Maximum number of cuts
101  * \param[in] cutting_min_segments Minimum segment size for cutting
102  * \param[in] cutting_min_score Minimum score a proposed cut has to achieve for being performed
103  * \param[in] locally_constrained Decide if we constrain our cuts locally
104  * \param[in] directed_cutting Decide if we prefer cuts perpendicular to the edge-direction
105  * \param[in] clean_cutting Decide if we cut only edges with supervoxels on opposite sides of the plane (clean) or all edges within the seed_resolution_ distance to the plane (not clean). The later was used in the paper.
106  */
107  inline void
108  setCutting (const std::uint32_t max_cuts = 20,
109  const std::uint32_t cutting_min_segments = 0,
110  const float cutting_min_score = 0.16,
111  const bool locally_constrained = true,
112  const bool directed_cutting = true,
113  const bool clean_cutting = false)
114  {
115  max_cuts_ = max_cuts;
116  min_segment_size_for_cutting_ = cutting_min_segments;
117  min_cut_score_ = cutting_min_score;
118  use_local_constrains_ = locally_constrained;
119  use_directed_weights_ = directed_cutting;
120  use_clean_cutting_ = clean_cutting;
121  }
122 
123  /** \brief Set the number of iterations for the weighted RANSAC step (best cut estimations)
124  * \param[in] ransac_iterations The number of iterations */
125  inline void
126  setRANSACIterations (const std::uint32_t ransac_iterations)
127  {
128  ransac_itrs_ = ransac_iterations;
129  }
130 
131  private:
132 
133  /** \brief Used in for CPC to find and fit cutting planes to the pointcloud.
134  * \note Is used recursively
135  * \param[in] depth_levels_left When first calling the function set this parameter to the maximum levels you want to cut down */
136  void
137  applyCuttingPlane (std::uint32_t depth_levels_left);
138 
139  /// *** Parameters *** ///
140 
141  /** \brief Maximum number of cuts */
142  std::uint32_t max_cuts_;
143 
144  /** \brief Minimum segment size for cutting */
145  std::uint32_t min_segment_size_for_cutting_;
146 
147  /** \brief Cut_score threshold */
148  float min_cut_score_;
149 
150  /** \brief Use local constrains for cutting */
151  bool use_local_constrains_;
152 
153  /** \brief Use directed weights for the cutting */
154  bool use_directed_weights_;
155 
156  /** \brief Use clean cutting */
157  bool use_clean_cutting_;
158 
159  /** \brief Iterations for RANSAC */
160  std::uint32_t ransac_itrs_;
161 
162 
163 /******************************************* Directional weighted RANSAC declarations ******************************************************************/
164  /** \brief @b WeightedRandomSampleConsensus represents an implementation of the Directionally Weighted RANSAC algorithm, as described in: "Constrained Planar Cuts - Part Segmentation for Point Clouds", CVPR 2015, M. Schoeler, J. Papon, F. Wörgötter.
165  * \note It only uses points with a weight > 0 for the model calculation, but uses all points for the evaluation (scoring of the model)
166  * Only use in conjunction with sac_model_plane
167  * If you use this in a scientific work please cite the following paper:
168  * M. Schoeler, J. Papon, F. Woergoetter
169  * Constrained Planar Cuts - Object Partitioning for Point Clouds
170  * In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR) 2015
171  * \author Markus Schoeler (mschoeler@web.de)
172  * \ingroup segmentation
173  */
174 
175  class WeightedRandomSampleConsensus : public SampleConsensus<WeightSACPointType>
176  {
177  using SampleConsensusModelPtr = SampleConsensusModel<WeightSACPointType>::Ptr;
178 
179  public:
180  using Ptr = boost::shared_ptr<WeightedRandomSampleConsensus>;
181  using ConstPtr = boost::shared_ptr<const WeightedRandomSampleConsensus>;
182 
183  /** \brief WeightedRandomSampleConsensus (Weighted RAndom SAmple Consensus) main constructor
184  * \param[in] model a Sample Consensus model
185  * \param[in] random if true set the random seed to the current time, else set to 12345 (default: false)
186  */
187  WeightedRandomSampleConsensus (const SampleConsensusModelPtr &model,
188  bool random = false)
189  : SampleConsensus<WeightSACPointType> (model, random)
190  {
191  initialize ();
192  }
193 
194  /** \brief WeightedRandomSampleConsensus (Weighted RAndom SAmple Consensus) main constructor
195  * \param[in] model a Sample Consensus model
196  * \param[in] threshold distance to model threshold
197  * \param[in] random if true set the random seed to the current time, else set to 12345 (default: false)
198  */
199  WeightedRandomSampleConsensus (const SampleConsensusModelPtr &model,
200  double threshold,
201  bool random = false)
202  : SampleConsensus<WeightSACPointType> (model, threshold, random)
203  {
204  initialize ();
205  }
206 
207  /** \brief Compute the actual model and find the inliers
208  * \param[in] debug_verbosity_level enable/disable on-screen debug information and set the verbosity level
209  */
210  bool
211  computeModel (int debug_verbosity_level = 0) override;
212 
213  /** \brief Set the weights for the input points
214  * \param[in] weights Weights for input samples. Negative weights are counted as penalty.
215  */
216  void
217  setWeights (const std::vector<double> &weights,
218  const bool directed_weights = false)
219  {
220  if (weights.size () != full_cloud_pt_indices_->size ())
221  {
222  PCL_ERROR ("[pcl::WeightedRandomSampleConsensus::setWeights] Cannot assign weights. Weight vector needs to have the same length as the input pointcloud\n");
223  return;
224  }
225  weights_ = weights;
226  model_pt_indices_->clear ();
227  for (size_t i = 0; i < weights.size (); ++i)
228  {
229  if (weights[i] > std::numeric_limits<double>::epsilon ())
230  model_pt_indices_->push_back (i);
231  }
232  use_directed_weights_ = directed_weights;
233  }
234 
235  /** \brief Get the best score
236  * \returns The best score found.
237  */
238  double
239  getBestScore () const
240  {
241  return (best_score_);
242  }
243 
244  protected:
245  /** \brief Initialize the model parameters. Called by the constructors. */
246  void
247  initialize ()
248  {
249  // Maximum number of trials before we give up.
250  max_iterations_ = 10000;
251  use_directed_weights_ = false;
252  model_pt_indices_.reset (new std::vector<int>);
253  full_cloud_pt_indices_.reset (new std::vector<int> (* (sac_model_->getIndices ())));
254  point_cloud_ptr_ = sac_model_->getInputCloud ();
255  }
256 
257  /** \brief weight each positive weight point by the inner product between the normal and the plane normal */
258  bool use_directed_weights_;
259 
260  /** \brief vector of weights assigned to points. Set by the setWeights-method */
261  std::vector<double> weights_;
262 
263  /** \brief The indices used for estimating the RANSAC model. Only those whose weight is > 0 */
264  pcl::IndicesPtr model_pt_indices_;
265 
266  /** \brief The complete list of indices used for the model evaluation */
267  pcl::IndicesPtr full_cloud_pt_indices_;
268 
269  /** \brief Pointer to the input PointCloud */
271 
272  /** \brief Highest score found so far */
273  double best_score_;
274  };
275 
276  };
277 }
278 
279 #ifdef PCL_NO_PRECOMPILE
280  #include <pcl/segmentation/impl/cpc_segmentation.hpp>
281 #elif defined(PCL_ONLY_CORE_POINT_TYPES)
282  //pcl::PointXYZINormal is not a core point type (so we cannot use the precompiled classes here)
283  #include <pcl/sample_consensus/impl/sac_model_plane.hpp>
284  #include <pcl/segmentation/impl/extract_clusters.hpp>
285 #endif // PCL_NO_PRECOMPILE / PCL_ONLY_CORE_POINT_TYPES
A simple segmentation algorithm partitioning a supervoxel graph into groups of locally convex connect...
void doGrouping()
Perform depth search on the graph and recursively group all supervoxels with convex connections...
void segment()
Merge supervoxels using cuts through local convexities.
This file defines compatibility wrappers for low level I/O functions.
Definition: convolution.h:45
A segmentation algorithm partitioning a supervoxel graph.
std::map< std::uint32_t, typename pcl::Supervoxel< PointT >::Ptr > sv_label_to_supervoxel_map_
map from the supervoxel labels to the supervoxel objects
void setCutting(const std::uint32_t max_cuts=20, const std::uint32_t cutting_min_segments=0, const float cutting_min_score=0.16, const bool locally_constrained=true, const bool directed_cutting=true, const bool clean_cutting=false)
Determines if we want to use cutting planes.
std::uint32_t k_factor_
Factor used for k-convexity.
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_iterator EdgeIterator
typename boost::graph_traits< SupervoxelAdjacencyList >::edge_descriptor EdgeID
SampleConsensusModel represents the base model class.
Definition: sac_model.h:67
float seed_resolution_
Seed resolution of the supervoxels (used only for smoothness check)
boost::shared_ptr< Indices > IndicesPtr
Definition: pcl_base.h:61
Defines all the PCL implemented PointT point type structures.
A point structure representing Euclidean xyz coordinates, intensity, together with normal coordinates...
std::map< std::uint32_t, std::uint32_t > sv_label_to_seg_label_map_
Storing relation between original SuperVoxel Labels and new segmantion labels.
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.
boost::shared_ptr< const PointCloud< PointT > > ConstPtr
Definition: point_cloud.h:445
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...
void setRANSACIterations(const std::uint32_t ransac_iterations)
Set the number of iterations for the weighted RANSAC step (best cut estimations)
SampleConsensus represents the base class.
Definition: sac.h:57
SupervoxelAdjacencyList sv_adjacency_list_
Adjacency graph with the supervoxel labels as nodes and edges between adjacent supervoxels.