39#ifndef PCL_SEGMENTATION_MIN_CUT_SEGMENTATION_HPP_
40#define PCL_SEGMENTATION_MIN_CUT_SEGMENTATION_HPP_
42#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
43#include <pcl/segmentation/min_cut_segmentation.h>
44#include <pcl/search/search.h>
45#include <pcl/search/kdtree.h>
49template <
typename Po
intT>
53template <
typename Po
intT>
64template <
typename Po
intT>
void
74template <
typename Po
intT>
double
81template <
typename Po
intT>
void
92template <
typename Po
intT>
double
99template <
typename Po
intT>
void
110template <
typename Po
intT>
double
117template <
typename Po
intT>
void
135template <
typename Po
intT>
void
142template <
typename Po
intT>
unsigned int
149template <
typename Po
intT>
void
162template <
typename Po
intT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
169template <
typename Po
intT>
void
180template <
typename Po
intT> std::vector<PointT, Eigen::aligned_allocator<PointT> >
187template <
typename Po
intT>
void
198template <
typename Po
intT>
void
204 if ( !segmentation_is_possible )
269template <
typename Po
intT>
double
283template <
typename Po
intT>
bool
286 const auto number_of_points =
input_->size ();
287 const auto number_of_indices =
indices_->size ();
305 vertices_.resize (number_of_points + 2, vertex_descriptor);
307 std::set<int> out_edges_marker;
309 edge_marker_.resize (number_of_points + 2, out_edges_marker);
311 for (std::size_t i_point = 0; i_point < number_of_points + 2; i_point++)
317 for (
const auto& point_index : (*
indices_))
319 double source_weight = 0.0;
320 double sink_weight = 0.0;
323 addEdge (point_index,
static_cast<int> (
sink_), sink_weight);
329 for (std::size_t i_point = 0; i_point < number_of_indices; i_point++)
331 index_t point_index = (*indices_)[i_point];
333 for (std::size_t i_nghbr = 1; i_nghbr < neighbours.size (); i_nghbr++)
336 addEdge (point_index, neighbours[i_nghbr], weight);
337 addEdge (neighbours[i_nghbr], point_index, weight);
347template <
typename Po
intT>
void
350 double min_dist_to_foreground = std::numeric_limits<double>::max ();
353 double initial_point[] = {0.0, 0.0};
355 initial_point[0] = (*input_)[point].x;
356 initial_point[1] = (*input_)[point].y;
361 dist += (fg_point.x - initial_point[0]) * (fg_point.x - initial_point[0]);
362 dist += (fg_point.y - initial_point[1]) * (fg_point.y - initial_point[1]);
363 if (min_dist_to_foreground > dist)
365 min_dist_to_foreground = dist;
369 sink_weight = pow (min_dist_to_foreground /
radius_, 0.5);
403template <
typename Po
intT>
bool
412 bool edge_was_added, reverse_edge_was_added;
415 boost::tie (reverse_edge, reverse_edge_was_added) = boost::add_edge (
vertices_[target],
vertices_[source], *
graph_ );
416 if ( !edge_was_added || !reverse_edge_was_added )
419 (*capacity_)[edge] = weight;
420 (*capacity_)[reverse_edge] = 0.0;
421 (*reverse_edges_)[edge] = reverse_edge;
422 (*reverse_edges_)[reverse_edge] = edge;
429template <
typename Po
intT>
double
433 double distance = 0.0;
434 distance += ((*input_)[source].x - (*input_)[target].x) * ((*
input_)[source].x - (*
input_)[target].x);
435 distance += ((*input_)[source].y - (*input_)[target].y) * ((*
input_)[source].y - (*
input_)[target].y);
436 distance += ((*input_)[source].z - (*input_)[target].z) * ((*
input_)[source].z - (*
input_)[target].z);
438 weight = std::exp (-distance);
444template <
typename Po
intT>
bool
449 std::pair<EdgeDescriptor, bool> sink_edge;
451 for (boost::tie (src_edge_iter, src_edge_end) = boost::out_edges (
source_, *
graph_); src_edge_iter != src_edge_end; ++src_edge_iter)
453 double source_weight = 0.0;
454 double sink_weight = 0.0;
455 sink_edge.second =
false;
457 sink_edge = boost::lookup_edge (boost::target (*src_edge_iter, *
graph_),
sink_, *
graph_);
458 if (!sink_edge.second)
461 (*capacity_)[*src_edge_iter] = source_weight;
462 (*capacity_)[sink_edge.first] = sink_weight;
469template <
typename Po
intT>
bool
477 std::vector< std::set<VertexDescriptor> > edge_marker;
478 std::set<VertexDescriptor> out_edges_marker;
479 edge_marker.clear ();
480 edge_marker.resize (
input_->size () + 2, out_edges_marker);
482 for (boost::tie (vertex_iter, vertex_end) = boost::vertices (*
graph_); vertex_iter != vertex_end; ++vertex_iter)
487 for (boost::tie (edge_iter, edge_end) = boost::out_edges (source_vertex, *
graph_); edge_iter != edge_end; ++edge_iter)
496 auto iter_out = edge_marker[
static_cast<int> (source_vertex)].find (target_vertex);
497 if ( iter_out != edge_marker[
static_cast<int> (source_vertex)].end () )
504 (*capacity_)[*edge_iter] = weight;
505 edge_marker[
static_cast<int> (source_vertex)].insert (target_vertex);
514template <
typename Po
intT>
void
517 std::vector<int> labels;
518 labels.resize (
input_->size (), 0);
519 for (
const auto& i_point : (*
indices_))
528 for ( boost::tie (edge_iter, edge_end) = boost::out_edges (
source_, *
graph_); edge_iter != edge_end; ++edge_iter )
530 if (labels[edge_iter->m_target] == 1)
532 if (residual_capacity[*edge_iter] >
epsilon_)
533 clusters_[1].indices.push_back (
static_cast<int> (edge_iter->m_target));
535 clusters_[0].indices.push_back (
static_cast<int> (edge_iter->m_target));
549 unsigned char foreground_color[3] = {255, 255, 255};
550 unsigned char background_color[3] = {255, 0, 0};
552 colored_cloud->
height = 1;
556 for (
const auto& point_index : (
clusters_[0].indices))
558 point.x = *((*input_)[point_index].data);
559 point.y = *((*input_)[point_index].data + 1);
560 point.z = *((*input_)[point_index].data + 2);
561 point.r = background_color[0];
562 point.g = background_color[1];
563 point.b = background_color[2];
564 colored_cloud->
points.push_back (point);
567 for (
const auto& point_index : (
clusters_[1].indices))
569 point.x = *((*input_)[point_index].data);
570 point.y = *((*input_)[point_index].data + 1);
571 point.z = *((*input_)[point_index].data + 2);
572 point.r = foreground_color[0];
573 point.g = foreground_color[1];
574 point.b = foreground_color[2];
575 colored_cloud->
points.push_back (point);
579 return (colored_cloud);
582#define PCL_INSTANTIATE_MinCutSegmentation(T) template class PCL_EXPORTS pcl::MinCutSegmentation<T>;
KdTreePtr getSearchMethod() const
Returns search method that is used for finding KNN.
std::shared_ptr< ReverseEdgeMap > reverse_edges_
Stores reverse edges for every edge in the graph.
double max_flow_
Stores the maximum flow value that was calculated during the segmentation.
double inverse_sigma_
Stores the sigma coefficient.
unsigned int number_of_neighbours_
Stores the number of neighbors to find.
double source_weight_
Stores the weight for every edge that comes from source point.
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.
std::vector< pcl::PointIndices > clusters_
After the segmentation it will contain the segments.
mGraphPtr graph_
Stores the graph for finding the maximum flow.
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 epsilon_
Used for comparison of the floating point numbers.
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.
std::vector< PointT, Eigen::aligned_allocator< PointT > > foreground_points_
Stores the points that are known to be in the foreground.
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
VertexDescriptor sink_
Stores the vertex that serves as sink.
bool unary_potentials_are_valid_
Signalizes if the unary potentials are valid.
KdTreePtr search_
Stores the search method that will be used for finding K nearest neighbors.
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
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.
std::shared_ptr< CapacityMap > capacity_
Stores the capacity of every edge in the graph.
boost::property_map< mGraph, boost::edge_capacity_t >::type CapacityMap
double getMaxFlow() const
Returns that flow value that was calculated during the segmentation.
VertexDescriptor source_
Stores the vertex that serves as source.
bool graph_is_valid_
Signalizes if the graph is valid.
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.
std::vector< VertexDescriptor > vertices_
Stores the vertices of the graph.
typename PointCloud::ConstPtr PointCloudConstPtr
boost::graph_traits< mGraph >::vertex_iterator VertexIterator
std::vector< PointT, Eigen::aligned_allocator< PointT > > background_points_
Stores the points that are known to be in the background.
std::vector< std::set< int > > edge_marker_
Stores the information about the edges that were added to the graph.
typename KdTree::Ptr KdTreePtr
std::vector< PointT, Eigen::aligned_allocator< PointT > > getForegroundPoints() const
Returns the points that must belong to foreground.
bool binary_potentials_are_valid_
Signalizes if the binary potentials are valid.
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.
double radius_
Stores the distance to the background.
PointCloudConstPtr input_
The input point cloud dataset.
IndicesPtr indices_
A pointer to the vector of point indices to use.
bool initCompute()
This method should get called before starting the actual computation.
bool deinitCompute()
This method should get called after finishing the actual computation.
PointCloud represents the base class in PCL for storing collections of 3D points.
const_iterator cbegin() const noexcept
const_iterator cend() const noexcept
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
std::uint32_t width
The point cloud width (if organized as an image-structure).
std::uint32_t height
The point cloud height (if organized as an image-structure).
shared_ptr< PointCloud< PointT > > Ptr
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
IndicesAllocator<> Indices
Type used for indices in PCL.
A point structure representing Euclidean xyz coordinates, and the RGB color.