Point Cloud Library (PCL)  1.15.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/auto.h>
46 #include <cmath>
47 
48 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
49 template <typename PointT>
51 
52 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
53 template <typename PointT>
55 {
56  foreground_points_.clear ();
57  background_points_.clear ();
58  clusters_.clear ();
59  vertices_.clear ();
60  edge_marker_.clear ();
61 }
62 
63 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64 template <typename PointT> void
66 {
67  input_ = cloud;
68  graph_is_valid_ = false;
69  unary_potentials_are_valid_ = false;
70  binary_potentials_are_valid_ = false;
71 }
72 
73 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
74 template <typename PointT> double
76 {
77  return (pow (1.0 / inverse_sigma_, 0.5));
78 }
79 
80 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
81 template <typename PointT> void
83 {
84  if (sigma > epsilon_)
85  {
86  inverse_sigma_ = 1.0 / (sigma * sigma);
87  binary_potentials_are_valid_ = false;
88  }
89 }
90 
91 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
92 template <typename PointT> double
94 {
95  return (pow (radius_, 0.5));
96 }
97 
98 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
99 template <typename PointT> void
101 {
102  if (radius > epsilon_)
103  {
104  radius_ = radius * radius;
105  unary_potentials_are_valid_ = false;
106  }
107 }
108 
109 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110 template <typename PointT> double
112 {
113  return (source_weight_);
114 }
115 
116 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117 template <typename PointT> void
119 {
120  if (weight > epsilon_)
121  {
122  source_weight_ = weight;
123  unary_potentials_are_valid_ = false;
124  }
125 }
126 
127 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
128 template <typename PointT> typename pcl::MinCutSegmentation<PointT>::KdTreePtr
130 {
131  return (search_);
132 }
133 
134 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
135 template <typename PointT> void
137 {
138  search_ = tree;
139 }
140 
141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 template <typename PointT> unsigned int
144 {
145  return (number_of_neighbours_);
146 }
147 
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 template <typename PointT> void
151 {
152  if (number_of_neighbours_ != neighbour_number && neighbour_number != 0)
153  {
154  number_of_neighbours_ = neighbour_number;
155  graph_is_valid_ = false;
156  unary_potentials_are_valid_ = false;
157  binary_potentials_are_valid_ = false;
158  }
159 }
160 
161 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
162 template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
164 {
165  return (foreground_points_);
166 }
167 
168 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169 template <typename PointT> void
171 {
172  foreground_points_.clear ();
173  foreground_points_.insert(
174  foreground_points_.end(), foreground_points->cbegin(), foreground_points->cend());
175 
176  unary_potentials_are_valid_ = false;
177 }
178 
179 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
180 template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
182 {
183  return (background_points_);
184 }
185 
186 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
187 template <typename PointT> void
189 {
190  background_points_.clear ();
191  background_points_.insert(
192  background_points_.end(), background_points->cbegin(), background_points->cend());
193 
194  unary_potentials_are_valid_ = false;
195 }
196 
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198 template <typename PointT> void
199 pcl::MinCutSegmentation<PointT>::extract (std::vector <pcl::PointIndices>& clusters)
200 {
201  clusters.clear ();
202 
203  bool segmentation_is_possible = initCompute ();
204  if ( !segmentation_is_possible )
205  {
206  deinitCompute ();
207  return;
208  }
209 
210  if ( graph_is_valid_ && unary_potentials_are_valid_ && binary_potentials_are_valid_ )
211  {
212  clusters.reserve (clusters_.size ());
213  std::copy (clusters_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
214  deinitCompute ();
215  return;
216  }
217 
218  clusters_.clear ();
219 
220  if ( !graph_is_valid_ )
221  {
222  bool success = buildGraph ();
223  if (!success)
224  {
225  deinitCompute ();
226  return;
227  }
228  graph_is_valid_ = true;
229  unary_potentials_are_valid_ = true;
230  binary_potentials_are_valid_ = true;
231  }
232 
233  if ( !unary_potentials_are_valid_ )
234  {
235  bool success = recalculateUnaryPotentials ();
236  if (!success)
237  {
238  deinitCompute ();
239  return;
240  }
241  unary_potentials_are_valid_ = true;
242  }
243 
244  if ( !binary_potentials_are_valid_ )
245  {
246  bool success = recalculateBinaryPotentials ();
247  if (!success)
248  {
249  deinitCompute ();
250  return;
251  }
252  binary_potentials_are_valid_ = true;
253  }
254 
255  //IndexMap index_map = boost::get (boost::vertex_index, *graph_);
256  ResidualCapacityMap residual_capacity = boost::get (boost::edge_residual_capacity, *graph_);
257 
258  max_flow_ = boost::boykov_kolmogorov_max_flow (*graph_, source_, sink_);
259 
260  assembleLabels (residual_capacity);
261 
262  clusters.reserve (clusters_.size ());
263  std::copy (clusters_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
264 
265  deinitCompute ();
266 }
267 
268 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
269 template <typename PointT> double
271 {
272  return (max_flow_);
273 }
274 
275 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276 template <typename PointT> typename pcl::MinCutSegmentation<PointT>::mGraphPtr
278 {
279  return (graph_);
280 }
281 
282 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
283 template <typename PointT> bool
285 {
286  const auto number_of_points = input_->size ();
287  const auto number_of_indices = indices_->size ();
288 
289  if (input_->points.empty () || number_of_points == 0 || foreground_points_.empty () == true )
290  return (false);
291 
292  if (!search_)
293  {
294  search_.reset (pcl::search::autoSelectMethod<PointT>(input_, indices_, true, pcl::search::Purpose::many_knn_search));
295  }
296  else
297  {
298  search_->setInputCloud (input_, indices_);
299  }
300 
301  graph_.reset (new mGraph);
302 
303  capacity_.reset (new CapacityMap);
304  *capacity_ = boost::get (boost::edge_capacity, *graph_);
305 
306  reverse_edges_.reset (new ReverseEdgeMap);
307  *reverse_edges_ = boost::get (boost::edge_reverse, *graph_);
308 
309  VertexDescriptor vertex_descriptor(0);
310  vertices_.clear ();
311  vertices_.resize (number_of_points + 2, vertex_descriptor);
312 
313  std::set<int> out_edges_marker;
314  edge_marker_.clear ();
315  edge_marker_.resize (number_of_points + 2, out_edges_marker);
316 
317  for (std::size_t i_point = 0; i_point < number_of_points + 2; i_point++)
318  vertices_[i_point] = boost::add_vertex (*graph_);
319 
320  source_ = vertices_[number_of_points];
321  sink_ = vertices_[number_of_points + 1];
322 
323  for (const auto& point_index : (*indices_))
324  {
325  double source_weight = 0.0;
326  double sink_weight = 0.0;
327  calculateUnaryPotential (point_index, source_weight, sink_weight);
328  addEdge (static_cast<int> (source_), point_index, source_weight);
329  addEdge (point_index, static_cast<int> (sink_), sink_weight);
330  }
331 
332  pcl::Indices neighbours;
333  std::vector<float> distances;
334  for (std::size_t i_point = 0; i_point < number_of_indices; i_point++)
335  {
336  index_t point_index = (*indices_)[i_point];
337  search_->nearestKSearch (i_point, number_of_neighbours_, neighbours, distances);
338  for (std::size_t i_nghbr = 1; i_nghbr < neighbours.size (); i_nghbr++)
339  {
340  double weight = calculateBinaryPotential (point_index, neighbours[i_nghbr]);
341  addEdge (point_index, neighbours[i_nghbr], weight);
342  addEdge (neighbours[i_nghbr], point_index, weight);
343  }
344  neighbours.clear ();
345  distances.clear ();
346  }
347 
348  return (true);
349 }
350 
351 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
352 template <typename PointT> void
353 pcl::MinCutSegmentation<PointT>::calculateUnaryPotential (int point, double& source_weight, double& sink_weight) const
354 {
355  double min_dist_to_foreground = std::numeric_limits<double>::max ();
356  //double min_dist_to_background = std::numeric_limits<double>::max ();
357  //double closest_background_point[] = {0.0, 0.0};
358  double initial_point[] = {0.0, 0.0};
359 
360  initial_point[0] = (*input_)[point].x;
361  initial_point[1] = (*input_)[point].y;
362 
363  for (const auto& fg_point : foreground_points_)
364  {
365  double dist = 0.0;
366  dist += (fg_point.x - initial_point[0]) * (fg_point.x - initial_point[0]);
367  dist += (fg_point.y - initial_point[1]) * (fg_point.y - initial_point[1]);
368  if (min_dist_to_foreground > dist)
369  {
370  min_dist_to_foreground = dist;
371  }
372  }
373 
374  sink_weight = pow (min_dist_to_foreground / radius_, 0.5);
375 
376  source_weight = source_weight_;
377  return;
378 /*
379  if (background_points_.size () == 0)
380  return;
381 
382  for (const auto& bg_point : background_points_)
383  {
384  double dist = 0.0;
385  dist += (bg_point.x - initial_point[0]) * (bg_point.x - initial_point[0]);
386  dist += (bg_point.y - initial_point[1]) * (bg_point.y - initial_point[1]);
387  if (min_dist_to_background > dist)
388  {
389  min_dist_to_background = dist;
390  closest_background_point[0] = bg_point.x;
391  closest_background_point[1] = bg_point.y;
392  }
393  }
394 
395  if (min_dist_to_background <= epsilon_)
396  {
397  source_weight = 0.0;
398  sink_weight = 1.0;
399  return;
400  }
401 
402  source_weight = 1.0 / (1.0 + pow (min_dist_to_background / min_dist_to_foreground, 0.5));
403  sink_weight = 1 - source_weight;
404 */
405 }
406 
407 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
408 template <typename PointT> bool
409 pcl::MinCutSegmentation<PointT>::addEdge (int source, int target, double weight)
410 {
411  auto iter_out = edge_marker_[source].find (target);
412  if ( iter_out != edge_marker_[source].end () )
413  return (false);
414 
415  EdgeDescriptor edge;
416  EdgeDescriptor reverse_edge;
417  bool edge_was_added, reverse_edge_was_added;
418 
419  boost::tie (edge, edge_was_added) = boost::add_edge ( vertices_[source], vertices_[target], *graph_ );
420  boost::tie (reverse_edge, reverse_edge_was_added) = boost::add_edge ( vertices_[target], vertices_[source], *graph_ );
421  if ( !edge_was_added || !reverse_edge_was_added )
422  return (false);
423 
424  (*capacity_)[edge] = weight;
425  (*capacity_)[reverse_edge] = 0.0;
426  (*reverse_edges_)[edge] = reverse_edge;
427  (*reverse_edges_)[reverse_edge] = edge;
428  edge_marker_[source].insert (target);
429 
430  return (true);
431 }
432 
433 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
434 template <typename PointT> double
436 {
437  double weight = 0.0;
438  double distance = 0.0;
439  distance += ((*input_)[source].x - (*input_)[target].x) * ((*input_)[source].x - (*input_)[target].x);
440  distance += ((*input_)[source].y - (*input_)[target].y) * ((*input_)[source].y - (*input_)[target].y);
441  distance += ((*input_)[source].z - (*input_)[target].z) * ((*input_)[source].z - (*input_)[target].z);
442  distance *= inverse_sigma_;
443  weight = std::exp (-distance);
444 
445  return (weight);
446 }
447 
448 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
449 template <typename PointT> bool
451 {
452  OutEdgeIterator src_edge_iter;
453  OutEdgeIterator src_edge_end;
454  std::pair<EdgeDescriptor, bool> sink_edge;
455 
456  for (boost::tie (src_edge_iter, src_edge_end) = boost::out_edges (source_, *graph_); src_edge_iter != src_edge_end; ++src_edge_iter)
457  {
458  double source_weight = 0.0;
459  double sink_weight = 0.0;
460  sink_edge.second = false;
461  calculateUnaryPotential (static_cast<int> (boost::target (*src_edge_iter, *graph_)), source_weight, sink_weight);
462  sink_edge = boost::lookup_edge (boost::target (*src_edge_iter, *graph_), sink_, *graph_);
463  if (!sink_edge.second)
464  return (false);
465 
466  (*capacity_)[*src_edge_iter] = source_weight;
467  (*capacity_)[sink_edge.first] = sink_weight;
468  }
469 
470  return (true);
471 }
472 
473 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
474 template <typename PointT> bool
476 {
477  VertexIterator vertex_iter;
478  VertexIterator vertex_end;
479  OutEdgeIterator edge_iter;
480  OutEdgeIterator edge_end;
481 
482  std::vector< std::set<VertexDescriptor> > edge_marker;
483  std::set<VertexDescriptor> out_edges_marker;
484  edge_marker.clear ();
485  edge_marker.resize (input_->size () + 2, out_edges_marker);
486 
487  for (boost::tie (vertex_iter, vertex_end) = boost::vertices (*graph_); vertex_iter != vertex_end; ++vertex_iter)
488  {
489  VertexDescriptor source_vertex = *vertex_iter;
490  if (source_vertex == source_ || source_vertex == sink_)
491  continue;
492  for (boost::tie (edge_iter, edge_end) = boost::out_edges (source_vertex, *graph_); edge_iter != edge_end; ++edge_iter)
493  {
494  //If this is not the edge of the graph, but the reverse fictitious edge that is needed for the algorithm then continue
495  EdgeDescriptor reverse_edge = (*reverse_edges_)[*edge_iter];
496  if ((*capacity_)[reverse_edge] != 0.0)
497  continue;
498 
499  //If we already changed weight for this edge then continue
500  VertexDescriptor target_vertex = boost::target (*edge_iter, *graph_);
501  auto iter_out = edge_marker[static_cast<int> (source_vertex)].find (target_vertex);
502  if ( iter_out != edge_marker[static_cast<int> (source_vertex)].end () )
503  continue;
504 
505  if (target_vertex != source_ && target_vertex != sink_)
506  {
507  //Change weight and remember that this edges were updated
508  double weight = calculateBinaryPotential (static_cast<int> (target_vertex), static_cast<int> (source_vertex));
509  (*capacity_)[*edge_iter] = weight;
510  edge_marker[static_cast<int> (source_vertex)].insert (target_vertex);
511  }
512  }
513  }
514 
515  return (true);
516 }
517 
518 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
519 template <typename PointT> void
521 {
522  std::vector<int> labels;
523  labels.resize (input_->size (), 0);
524  for (const auto& i_point : (*indices_))
525  labels[i_point] = 1;
526 
527  clusters_.clear ();
528 
529  pcl::PointIndices segment;
530  clusters_.resize (2, segment);
531 
532  OutEdgeIterator edge_iter, edge_end;
533  for ( boost::tie (edge_iter, edge_end) = boost::out_edges (source_, *graph_); edge_iter != edge_end; ++edge_iter )
534  {
535  if (labels[edge_iter->m_target] == 1)
536  {
537  if (residual_capacity[*edge_iter] > epsilon_)
538  clusters_[1].indices.push_back (static_cast<int> (edge_iter->m_target));
539  else
540  clusters_[0].indices.push_back (static_cast<int> (edge_iter->m_target));
541  }
542  }
543 }
544 
545 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
546 template <typename PointT> pcl::PointCloud<pcl::PointXYZRGB>::Ptr
548 {
550 
551  if (!clusters_.empty ())
552  {
553  colored_cloud.reset(new pcl::PointCloud<pcl::PointXYZRGB>);
554  unsigned char foreground_color[3] = {255, 255, 255};
555  unsigned char background_color[3] = {255, 0, 0};
556  colored_cloud->width = (clusters_[0].indices.size () + clusters_[1].indices.size ());
557  colored_cloud->height = 1;
558  colored_cloud->is_dense = input_->is_dense;
559 
560  pcl::PointXYZRGB point;
561  for (const auto& point_index : (clusters_[0].indices))
562  {
563  point.x = *((*input_)[point_index].data);
564  point.y = *((*input_)[point_index].data + 1);
565  point.z = *((*input_)[point_index].data + 2);
566  point.r = background_color[0];
567  point.g = background_color[1];
568  point.b = background_color[2];
569  colored_cloud->points.push_back (point);
570  }
571 
572  for (const auto& point_index : (clusters_[1].indices))
573  {
574  point.x = *((*input_)[point_index].data);
575  point.y = *((*input_)[point_index].data + 1);
576  point.z = *((*input_)[point_index].data + 2);
577  point.r = foreground_color[0];
578  point.g = foreground_color[1];
579  point.b = foreground_color[2];
580  colored_cloud->points.push_back (point);
581  }
582  }
583 
584  return (colored_cloud);
585 }
586 
587 #define PCL_INSTANTIATE_MinCutSegmentation(T) template class PCL_EXPORTS pcl::MinCutSegmentation<T>;
588 
589 #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:434
const_iterator cend() const noexcept
Definition: point_cloud.h:435
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:404
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:399
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:401
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:414
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:396
float distance(const PointT &p1, const PointT &p2)
Definition: geometry.h:60
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
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.