Point Cloud Library (PCL)  1.12.1-dev
min_cut_segmentation.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the copyright holder(s) nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * $Id:$
36  *
37  */
38 
39 #ifndef PCL_SEGMENTATION_MIN_CUT_SEGMENTATION_HPP_
40 #define PCL_SEGMENTATION_MIN_CUT_SEGMENTATION_HPP_
41 
42 #include <boost/graph/boykov_kolmogorov_max_flow.hpp> // for boykov_kolmogorov_max_flow
43 #include <pcl/segmentation/min_cut_segmentation.h>
44 #include <pcl/search/search.h>
45 #include <pcl/search/kdtree.h>
46 #include <cmath>
47 
48 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
49 template <typename PointT>
51  inverse_sigma_ (16.0),
52  binary_potentials_are_valid_ (false),
53  epsilon_ (0.0001),
54  radius_ (16.0),
55  unary_potentials_are_valid_ (false),
56  source_weight_ (0.8),
57  search_ (),
58  number_of_neighbours_ (14),
59  graph_is_valid_ (false),
60  foreground_points_ (0),
61  background_points_ (0),
62  clusters_ (0),
63  vertices_ (0),
64  edge_marker_ (0),
65  source_ (),/////////////////////////////////
66  sink_ (),///////////////////////////////////
67  max_flow_ (0.0)
68 {
69 }
70 
71 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
72 template <typename PointT>
74 {
75  foreground_points_.clear ();
76  background_points_.clear ();
77  clusters_.clear ();
78  vertices_.clear ();
79  edge_marker_.clear ();
80 }
81 
82 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
83 template <typename PointT> void
85 {
86  input_ = cloud;
87  graph_is_valid_ = false;
88  unary_potentials_are_valid_ = false;
89  binary_potentials_are_valid_ = false;
90 }
91 
92 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93 template <typename PointT> double
95 {
96  return (pow (1.0 / inverse_sigma_, 0.5));
97 }
98 
99 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100 template <typename PointT> void
102 {
103  if (sigma > epsilon_)
104  {
105  inverse_sigma_ = 1.0 / (sigma * sigma);
106  binary_potentials_are_valid_ = false;
107  }
108 }
109 
110 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111 template <typename PointT> double
113 {
114  return (pow (radius_, 0.5));
115 }
116 
117 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
118 template <typename PointT> void
120 {
121  if (radius > epsilon_)
122  {
123  radius_ = radius * radius;
124  unary_potentials_are_valid_ = false;
125  }
126 }
127 
128 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129 template <typename PointT> double
131 {
132  return (source_weight_);
133 }
134 
135 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136 template <typename PointT> void
138 {
139  if (weight > epsilon_)
140  {
141  source_weight_ = weight;
142  unary_potentials_are_valid_ = false;
143  }
144 }
145 
146 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
147 template <typename PointT> typename pcl::MinCutSegmentation<PointT>::KdTreePtr
149 {
150  return (search_);
151 }
152 
153 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154 template <typename PointT> void
156 {
157  search_ = tree;
158 }
159 
160 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
161 template <typename PointT> unsigned int
163 {
164  return (number_of_neighbours_);
165 }
166 
167 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
168 template <typename PointT> void
170 {
171  if (number_of_neighbours_ != neighbour_number && neighbour_number != 0)
172  {
173  number_of_neighbours_ = neighbour_number;
174  graph_is_valid_ = false;
175  unary_potentials_are_valid_ = false;
176  binary_potentials_are_valid_ = false;
177  }
178 }
179 
180 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
181 template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
183 {
184  return (foreground_points_);
185 }
186 
187 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
188 template <typename PointT> void
190 {
191  foreground_points_.clear ();
192  foreground_points_.insert(
193  foreground_points_.end(), foreground_points->cbegin(), foreground_points->cend());
194 
195  unary_potentials_are_valid_ = false;
196 }
197 
198 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199 template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
201 {
202  return (background_points_);
203 }
204 
205 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
206 template <typename PointT> void
208 {
209  background_points_.clear ();
210  background_points_.insert(
211  background_points_.end(), background_points->cbegin(), background_points->cend());
212 
213  unary_potentials_are_valid_ = false;
214 }
215 
216 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
217 template <typename PointT> void
218 pcl::MinCutSegmentation<PointT>::extract (std::vector <pcl::PointIndices>& clusters)
219 {
220  clusters.clear ();
221 
222  bool segmentation_is_possible = initCompute ();
223  if ( !segmentation_is_possible )
224  {
225  deinitCompute ();
226  return;
227  }
228 
229  if ( graph_is_valid_ && unary_potentials_are_valid_ && binary_potentials_are_valid_ )
230  {
231  clusters.reserve (clusters_.size ());
232  std::copy (clusters_.begin (), clusters_.end (), std::back_inserter (clusters));
233  deinitCompute ();
234  return;
235  }
236 
237  clusters_.clear ();
238 
239  if ( !graph_is_valid_ )
240  {
241  bool success = buildGraph ();
242  if (!success)
243  {
244  deinitCompute ();
245  return;
246  }
247  graph_is_valid_ = true;
248  unary_potentials_are_valid_ = true;
249  binary_potentials_are_valid_ = true;
250  }
251 
252  if ( !unary_potentials_are_valid_ )
253  {
254  bool success = recalculateUnaryPotentials ();
255  if (!success)
256  {
257  deinitCompute ();
258  return;
259  }
260  unary_potentials_are_valid_ = true;
261  }
262 
263  if ( !binary_potentials_are_valid_ )
264  {
265  bool success = recalculateBinaryPotentials ();
266  if (!success)
267  {
268  deinitCompute ();
269  return;
270  }
271  binary_potentials_are_valid_ = true;
272  }
273 
274  //IndexMap index_map = boost::get (boost::vertex_index, *graph_);
275  ResidualCapacityMap residual_capacity = boost::get (boost::edge_residual_capacity, *graph_);
276 
277  max_flow_ = boost::boykov_kolmogorov_max_flow (*graph_, source_, sink_);
278 
279  assembleLabels (residual_capacity);
280 
281  clusters.reserve (clusters_.size ());
282  std::copy (clusters_.begin (), clusters_.end (), std::back_inserter (clusters));
283 
284  deinitCompute ();
285 }
286 
287 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
288 template <typename PointT> double
290 {
291  return (max_flow_);
292 }
293 
294 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
295 template <typename PointT> typename pcl::MinCutSegmentation<PointT>::mGraphPtr
297 {
298  return (graph_);
299 }
300 
301 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302 template <typename PointT> bool
304 {
305  const auto number_of_points = input_->size ();
306  const auto number_of_indices = indices_->size ();
307 
308  if (input_->points.empty () || number_of_points == 0 || foreground_points_.empty () == true )
309  return (false);
310 
311  if (!search_)
312  search_.reset (new pcl::search::KdTree<PointT>);
313 
314  graph_.reset (new mGraph);
315 
316  capacity_.reset (new CapacityMap);
317  *capacity_ = boost::get (boost::edge_capacity, *graph_);
318 
319  reverse_edges_.reset (new ReverseEdgeMap);
320  *reverse_edges_ = boost::get (boost::edge_reverse, *graph_);
321 
322  VertexDescriptor vertex_descriptor(0);
323  vertices_.clear ();
324  vertices_.resize (number_of_points + 2, vertex_descriptor);
325 
326  std::set<int> out_edges_marker;
327  edge_marker_.clear ();
328  edge_marker_.resize (number_of_points + 2, out_edges_marker);
329 
330  for (std::size_t i_point = 0; i_point < number_of_points + 2; i_point++)
331  vertices_[i_point] = boost::add_vertex (*graph_);
332 
333  source_ = vertices_[number_of_points];
334  sink_ = vertices_[number_of_points + 1];
335 
336  for (const auto& point_index : (*indices_))
337  {
338  double source_weight = 0.0;
339  double sink_weight = 0.0;
340  calculateUnaryPotential (point_index, source_weight, sink_weight);
341  addEdge (static_cast<int> (source_), point_index, source_weight);
342  addEdge (point_index, static_cast<int> (sink_), sink_weight);
343  }
344 
345  pcl::Indices neighbours;
346  std::vector<float> distances;
347  search_->setInputCloud (input_, indices_);
348  for (std::size_t i_point = 0; i_point < number_of_indices; i_point++)
349  {
350  index_t point_index = (*indices_)[i_point];
351  search_->nearestKSearch (i_point, number_of_neighbours_, neighbours, distances);
352  for (std::size_t i_nghbr = 1; i_nghbr < neighbours.size (); i_nghbr++)
353  {
354  double weight = calculateBinaryPotential (point_index, neighbours[i_nghbr]);
355  addEdge (point_index, neighbours[i_nghbr], weight);
356  addEdge (neighbours[i_nghbr], point_index, weight);
357  }
358  neighbours.clear ();
359  distances.clear ();
360  }
361 
362  return (true);
363 }
364 
365 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366 template <typename PointT> void
367 pcl::MinCutSegmentation<PointT>::calculateUnaryPotential (int point, double& source_weight, double& sink_weight) const
368 {
369  double min_dist_to_foreground = std::numeric_limits<double>::max ();
370  //double min_dist_to_background = std::numeric_limits<double>::max ();
371  //double closest_background_point[] = {0.0, 0.0};
372  double initial_point[] = {0.0, 0.0};
373 
374  initial_point[0] = (*input_)[point].x;
375  initial_point[1] = (*input_)[point].y;
376 
377  for (const auto& fg_point : foreground_points_)
378  {
379  double dist = 0.0;
380  dist += (fg_point.x - initial_point[0]) * (fg_point.x - initial_point[0]);
381  dist += (fg_point.y - initial_point[1]) * (fg_point.y - initial_point[1]);
382  if (min_dist_to_foreground > dist)
383  {
384  min_dist_to_foreground = dist;
385  }
386  }
387 
388  sink_weight = pow (min_dist_to_foreground / radius_, 0.5);
389 
390  source_weight = source_weight_;
391  return;
392 /*
393  if (background_points_.size () == 0)
394  return;
395 
396  for (const auto& bg_point : background_points_)
397  {
398  double dist = 0.0;
399  dist += (bg_point.x - initial_point[0]) * (bg_point.x - initial_point[0]);
400  dist += (bg_point.y - initial_point[1]) * (bg_point.y - initial_point[1]);
401  if (min_dist_to_background > dist)
402  {
403  min_dist_to_background = dist;
404  closest_background_point[0] = bg_point.x;
405  closest_background_point[1] = bg_point.y;
406  }
407  }
408 
409  if (min_dist_to_background <= epsilon_)
410  {
411  source_weight = 0.0;
412  sink_weight = 1.0;
413  return;
414  }
415 
416  source_weight = 1.0 / (1.0 + pow (min_dist_to_background / min_dist_to_foreground, 0.5));
417  sink_weight = 1 - source_weight;
418 */
419 }
420 
421 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
422 template <typename PointT> bool
423 pcl::MinCutSegmentation<PointT>::addEdge (int source, int target, double weight)
424 {
425  std::set<int>::iterator iter_out = edge_marker_[source].find (target);
426  if ( iter_out != edge_marker_[source].end () )
427  return (false);
428 
429  EdgeDescriptor edge;
430  EdgeDescriptor reverse_edge;
431  bool edge_was_added, reverse_edge_was_added;
432 
433  boost::tie (edge, edge_was_added) = boost::add_edge ( vertices_[source], vertices_[target], *graph_ );
434  boost::tie (reverse_edge, reverse_edge_was_added) = boost::add_edge ( vertices_[target], vertices_[source], *graph_ );
435  if ( !edge_was_added || !reverse_edge_was_added )
436  return (false);
437 
438  (*capacity_)[edge] = weight;
439  (*capacity_)[reverse_edge] = 0.0;
440  (*reverse_edges_)[edge] = reverse_edge;
441  (*reverse_edges_)[reverse_edge] = edge;
442  edge_marker_[source].insert (target);
443 
444  return (true);
445 }
446 
447 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
448 template <typename PointT> double
450 {
451  double weight = 0.0;
452  double distance = 0.0;
453  distance += ((*input_)[source].x - (*input_)[target].x) * ((*input_)[source].x - (*input_)[target].x);
454  distance += ((*input_)[source].y - (*input_)[target].y) * ((*input_)[source].y - (*input_)[target].y);
455  distance += ((*input_)[source].z - (*input_)[target].z) * ((*input_)[source].z - (*input_)[target].z);
456  distance *= inverse_sigma_;
457  weight = std::exp (-distance);
458 
459  return (weight);
460 }
461 
462 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463 template <typename PointT> bool
465 {
466  OutEdgeIterator src_edge_iter;
467  OutEdgeIterator src_edge_end;
468  std::pair<EdgeDescriptor, bool> sink_edge;
469 
470  for (boost::tie (src_edge_iter, src_edge_end) = boost::out_edges (source_, *graph_); src_edge_iter != src_edge_end; src_edge_iter++)
471  {
472  double source_weight = 0.0;
473  double sink_weight = 0.0;
474  sink_edge.second = false;
475  calculateUnaryPotential (static_cast<int> (boost::target (*src_edge_iter, *graph_)), source_weight, sink_weight);
476  sink_edge = boost::lookup_edge (boost::target (*src_edge_iter, *graph_), sink_, *graph_);
477  if (!sink_edge.second)
478  return (false);
479 
480  (*capacity_)[*src_edge_iter] = source_weight;
481  (*capacity_)[sink_edge.first] = sink_weight;
482  }
483 
484  return (true);
485 }
486 
487 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
488 template <typename PointT> bool
490 {
491  VertexIterator vertex_iter;
492  VertexIterator vertex_end;
493  OutEdgeIterator edge_iter;
494  OutEdgeIterator edge_end;
495 
496  std::vector< std::set<VertexDescriptor> > edge_marker;
497  std::set<VertexDescriptor> out_edges_marker;
498  edge_marker.clear ();
499  edge_marker.resize (indices_->size () + 2, out_edges_marker);
500 
501  for (boost::tie (vertex_iter, vertex_end) = boost::vertices (*graph_); vertex_iter != vertex_end; vertex_iter++)
502  {
503  VertexDescriptor source_vertex = *vertex_iter;
504  if (source_vertex == source_ || source_vertex == sink_)
505  continue;
506  for (boost::tie (edge_iter, edge_end) = boost::out_edges (source_vertex, *graph_); edge_iter != edge_end; edge_iter++)
507  {
508  //If this is not the edge of the graph, but the reverse fictitious edge that is needed for the algorithm then continue
509  EdgeDescriptor reverse_edge = (*reverse_edges_)[*edge_iter];
510  if ((*capacity_)[reverse_edge] != 0.0)
511  continue;
512 
513  //If we already changed weight for this edge then continue
514  VertexDescriptor target_vertex = boost::target (*edge_iter, *graph_);
515  std::set<VertexDescriptor>::iterator iter_out = edge_marker[static_cast<int> (source_vertex)].find (target_vertex);
516  if ( iter_out != edge_marker[static_cast<int> (source_vertex)].end () )
517  continue;
518 
519  if (target_vertex != source_ && target_vertex != sink_)
520  {
521  //Change weight and remember that this edges were updated
522  double weight = calculateBinaryPotential (static_cast<int> (target_vertex), static_cast<int> (source_vertex));
523  (*capacity_)[*edge_iter] = weight;
524  edge_marker[static_cast<int> (source_vertex)].insert (target_vertex);
525  }
526  }
527  }
528 
529  return (true);
530 }
531 
532 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
533 template <typename PointT> void
535 {
536  std::vector<int> labels;
537  labels.resize (input_->size (), 0);
538  for (const auto& i_point : (*indices_))
539  labels[i_point] = 1;
540 
541  clusters_.clear ();
542 
543  pcl::PointIndices segment;
544  clusters_.resize (2, segment);
545 
546  OutEdgeIterator edge_iter, edge_end;
547  for ( boost::tie (edge_iter, edge_end) = boost::out_edges (source_, *graph_); edge_iter != edge_end; edge_iter++ )
548  {
549  if (labels[edge_iter->m_target] == 1)
550  {
551  if (residual_capacity[*edge_iter] > epsilon_)
552  clusters_[1].indices.push_back (static_cast<int> (edge_iter->m_target));
553  else
554  clusters_[0].indices.push_back (static_cast<int> (edge_iter->m_target));
555  }
556  }
557 }
558 
559 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
560 template <typename PointT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
562 {
564 
565  if (!clusters_.empty ())
566  {
567  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
568  unsigned char foreground_color[3] = {255, 255, 255};
569  unsigned char background_color[3] = {255, 0, 0};
570  colored_cloud->width = (clusters_[0].indices.size () + clusters_[1].indices.size ());
571  colored_cloud->height = 1;
572  colored_cloud->is_dense = input_->is_dense;
573 
574  pcl::PointXYZRGB point;
575  for (const auto& point_index : (clusters_[0].indices))
576  {
577  point.x = *((*input_)[point_index].data);
578  point.y = *((*input_)[point_index].data + 1);
579  point.z = *((*input_)[point_index].data + 2);
580  point.r = background_color[0];
581  point.g = background_color[1];
582  point.b = background_color[2];
583  colored_cloud->points.push_back (point);
584  }
585 
586  for (const auto& point_index : (clusters_[1].indices))
587  {
588  point.x = *((*input_)[point_index].data);
589  point.y = *((*input_)[point_index].data + 1);
590  point.z = *((*input_)[point_index].data + 2);
591  point.r = foreground_color[0];
592  point.g = foreground_color[1];
593  point.b = foreground_color[2];
594  colored_cloud->points.push_back (point);
595  }
596  }
597 
598  return (colored_cloud);
599 }
600 
601 #define PCL_INSTANTIATE_MinCutSegmentation(T) template class pcl::MinCutSegmentation<T>;
602 
603 #endif // PCL_SEGMENTATION_MIN_CUT_SEGMENTATION_HPP_
KdTreePtr getSearchMethod() const
Returns search method that is used for finding KNN.
void calculateUnaryPotential(int point, double &source_weight, double &sink_weight) const
Returns unary potential(data cost) for the given point index.
void setSigma(double sigma)
Allows to set the normalization value for the binary potentials as described in the article.
double getSigma() const
Returns normalization value for binary potentials.
MinCutSegmentation()
Constructor that sets default values for member variables.
void setRadius(double radius)
Allows to set the radius to the background.
void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
double getSourceWeight() const
Returns weight that every edge from the source point has.
mGraphPtr getGraph() const
Returns the graph that was build for finding the minimum cut.
void setInputCloud(const PointCloudConstPtr &cloud) override
This method simply sets the input point cloud.
void setSourceWeight(double weight)
Allows to set weight for source edges.
~MinCutSegmentation() override
Destructor that frees memory.
void setBackgroundPoints(typename pcl::PointCloud< PointT >::Ptr background_points)
Allows to specify points which are known to be the points of the background.
boost::graph_traits< mGraph >::out_edge_iterator OutEdgeIterator
unsigned int getNumberOfNeighbours() const
Returns the number of neighbours to find.
bool buildGraph()
This method simply builds the graph that will be used during the segmentation.
boost::property_map< mGraph, boost::edge_capacity_t >::type CapacityMap
double getMaxFlow() const
Returns that flow value that was calculated during the segmentation.
bool recalculateUnaryPotentials()
This method recalculates unary potentials(data cost) if some changes were made, instead of creating n...
boost::property_map< mGraph, boost::edge_reverse_t >::type ReverseEdgeMap
shared_ptr< mGraph > mGraphPtr
void setSearchMethod(const KdTreePtr &tree)
Allows to set search method for finding KNN.
double getRadius() const
Returns radius to the background.
double calculateBinaryPotential(int source, int target) const
Returns the binary potential(smooth cost) for the given indices of points.
bool recalculateBinaryPotentials()
This method recalculates binary potentials(smooth cost) if some changes were made,...
std::vector< PointT, Eigen::aligned_allocator< PointT > > getBackgroundPoints() const
Returns the points that must belong to background.
bool addEdge(int source, int target, double weight)
This method simply adds the edge from the source point to the target point with a given weight.
Traits::vertex_descriptor VertexDescriptor
void setNumberOfNeighbours(unsigned int neighbour_number)
Allows to set the number of neighbours to find.
boost::graph_traits< mGraph >::vertex_iterator VertexIterator
typename KdTree::Ptr KdTreePtr
std::vector< PointT, Eigen::aligned_allocator< PointT > > getForegroundPoints() const
Returns the points that must belong to foreground.
boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, boost::property< boost::vertex_name_t, std::string, boost::property< boost::vertex_index_t, long, boost::property< boost::vertex_color_t, boost::default_color_type, boost::property< boost::vertex_distance_t, long, boost::property< boost::vertex_predecessor_t, Traits::edge_descriptor > > > > >, boost::property< boost::edge_capacity_t, double, boost::property< boost::edge_residual_capacity_t, double, boost::property< boost::edge_reverse_t, Traits::edge_descriptor > > > > mGraph
boost::graph_traits< mGraph >::edge_descriptor EdgeDescriptor
boost::property_map< mGraph, boost::edge_residual_capacity_t >::type ResidualCapacityMap
void setForegroundPoints(typename pcl::PointCloud< PointT >::Ptr foreground_points)
Allows to specify points which are known to be the points of the object.
pcl::PointCloud< pcl::PointXYZRGB >::Ptr getColoredCloud()
Returns the colored cloud.
void assembleLabels(ResidualCapacityMap &residual_capacity)
This method analyzes the residual network and assigns a label to every point in the cloud.
typename PointCloud::ConstPtr PointCloudConstPtr
Definition: pcl_base.h:74
const_iterator cbegin() const noexcept
Definition: point_cloud.h:433
const_iterator cend() const noexcept
Definition: point_cloud.h:434
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
Definition: point_cloud.h:403
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:398
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:400
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:413
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:395
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
Definition: kdtree.h:62
float distance(const PointT &p1, const PointT &p2)
Definition: geometry.h:60
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition: types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition: types.h:133
A point structure representing Euclidean xyz coordinates, and the RGB color.