Point Cloud Library (PCL) 1.13.0
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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
49template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
72template <typename PointT>
74{
75 foreground_points_.clear ();
76 background_points_.clear ();
77 clusters_.clear ();
78 vertices_.clear ();
79 edge_marker_.clear ();
80}
81
82//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
83template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93template <typename PointT> double
95{
96 return (pow (1.0 / inverse_sigma_, 0.5));
97}
98
99//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111template <typename PointT> double
113{
114 return (pow (radius_, 0.5));
115}
116
117//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
118template <typename PointT> void
120{
121 if (radius > epsilon_)
122 {
123 radius_ = radius * radius;
124 unary_potentials_are_valid_ = false;
125 }
126}
127
128//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129template <typename PointT> double
131{
132 return (source_weight_);
133}
134
135//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
136template <typename PointT> void
138{
139 if (weight > epsilon_)
140 {
141 source_weight_ = weight;
142 unary_potentials_are_valid_ = false;
143 }
144}
145
146//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
147template <typename PointT> typename pcl::MinCutSegmentation<PointT>::KdTreePtr
149{
150 return (search_);
151}
152
153//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154template <typename PointT> void
156{
157 search_ = tree;
158}
159
160//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
161template <typename PointT> unsigned int
163{
164 return (number_of_neighbours_);
165}
166
167//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
168template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
181template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
183{
184 return (foreground_points_);
185}
186
187//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
188template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199template <typename PointT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
201{
202 return (background_points_);
203}
204
205//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
206template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
217template <typename PointT> void
218pcl::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_.cbegin (), clusters_.cend (), 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_.cbegin (), clusters_.cend (), std::back_inserter (clusters));
283
284 deinitCompute ();
285}
286
287//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
288template <typename PointT> double
290{
291 return (max_flow_);
292}
293
294//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
295template <typename PointT> typename pcl::MinCutSegmentation<PointT>::mGraphPtr
297{
298 return (graph_);
299}
300
301//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366template <typename PointT> void
367pcl::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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
422template <typename PointT> bool
423pcl::MinCutSegmentation<PointT>::addEdge (int source, int target, double weight)
424{
425 auto 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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
448template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
488template <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 auto 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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
533template <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//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
560template <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.