41 #include <pcl/common/io.h>
42 #include <pcl/common/point_tests.h>
43 #include <pcl/search/auto.h>
53 return ((c1.
r-c2.
r)*(c1.
r-c2.
r)+(c1.
g-c2.
g)*(c1.
g-c2.
g)+(c1.
b-c2.
b)*(c1.
b-c2.
b));
56 namespace segmentation
59 template <
typename Po
intT>
62 r =
static_cast<float> (p.r) / 255.0;
63 g =
static_cast<float> (p.g) / 255.0;
64 b =
static_cast<float> (p.b) / 255.0;
67 template <
typename Po
intT>
68 grabcut::Color::operator
PointT ()
const
71 p.r =
static_cast<std::uint32_t
> (r * 255);
72 p.g =
static_cast<std::uint32_t
> (g * 255);
73 p.b =
static_cast<std::uint32_t
> (b * 255);
79 template <
typename Po
intT>
void
85 template <
typename Po
intT>
bool
91 PCL_ERROR (
"[pcl::GrabCut::initCompute ()] Init failed!\n");
95 std::vector<pcl::PCLPointField> in_fields_;
96 if ((pcl::getFieldIndex<PointT> (
"rgb", in_fields_) == -1) &&
97 (pcl::getFieldIndex<PointT> (
"rgba", in_fields_) == -1))
99 PCL_ERROR (
"[pcl::GrabCut::initCompute ()] No RGB data available, aborting!\n");
104 image_.reset (
new Image (input_->width, input_->height));
105 for (std::size_t i = 0; i < input_->size (); ++i)
107 (*image_) [i] =
Color ((*input_)[i]);
109 width_ = image_->width;
110 height_ = image_->height;
113 if (!tree_ && !input_->isOrganized ())
116 const std::size_t indices_size = indices_->size ();
117 trimap_ = std::vector<segmentation::grabcut::TrimapValue> (indices_size,
TrimapUnknown);
118 hard_segmentation_ = std::vector<segmentation::grabcut::SegmentationValue> (indices_size,
120 GMM_component_.resize (indices_size);
121 n_links_.resize (indices_size);
124 foreground_GMM_.resize (K_);
125 background_GMM_.resize (K_);
130 if (image_->isOrganized ())
132 computeBetaOrganized ();
133 computeNLinksOrganized ();
137 computeBetaNonOrganized ();
138 computeNLinksNonOrganized ();
141 initialized_ =
false;
145 template <
typename Po
intT>
void
148 graph_.addEdge (v1, v2, capacity, rev_capacity);
151 template <
typename Po
intT>
void
154 graph_.addSourceEdge (v, source_capacity);
155 graph_.addTargetEdge (v, sink_capacity);
158 template <
typename Po
intT>
void
167 for (
const auto &index : indices->indices)
180 template <
typename Po
intT>
void
184 buildGMMs (*image_, *indices_, hard_segmentation_, GMM_component_, background_GMM_, foreground_GMM_);
190 template <
typename Po
intT>
int
194 learnGMMs (*image_, *indices_, hard_segmentation_, GMM_component_, background_GMM_, foreground_GMM_);
199 float flow = graph_.solve ();
201 int changed = updateHardSegmentation ();
202 PCL_INFO (
"%d pixels changed segmentation (max flow = %f)\n", changed, flow);
207 template <
typename Po
intT>
void
210 std::size_t changed = indices_->size ();
213 changed = refineOnce ();
216 template <
typename Po
intT>
int
223 const int number_of_indices =
static_cast<int> (indices_->size ());
224 for (
int i_point = 0; i_point < number_of_indices; ++i_point)
235 if (isSource (graph_nodes_[i_point]))
241 if (old_value != hard_segmentation_ [i_point])
247 template <
typename Po
intT>
void
251 for (
const auto &index : indices->indices)
256 for (
const auto &index : indices->indices)
260 for (
const auto &index : indices->indices)
264 template <
typename Po
intT>
void
268 const int number_of_indices =
static_cast<int> (indices_->size ());
271 graph_nodes_.clear ();
272 graph_nodes_.resize (indices_->size ());
273 int start = graph_.addNodes (indices_->size ());
274 for (std::size_t idx = 0; idx < indices_->size (); ++idx)
276 graph_nodes_[idx] = start;
281 for (
int i_point = 0; i_point < number_of_indices; ++i_point)
283 int point_index = (*indices_) [i_point];
286 switch (trimap_[point_index])
290 fore =
static_cast<float> (-std::log (background_GMM_.probabilityDensity ((*image_)[point_index])));
291 back =
static_cast<float> (-std::log (foreground_GMM_.probabilityDensity ((*image_)[point_index])));
307 setTerminalWeights (graph_nodes_[i_point], fore, back);
311 for (
int i_point = 0; i_point < number_of_indices; ++i_point)
313 const NLinks &n_link = n_links_[i_point];
316 const auto point_index = (*indices_) [i_point];
317 auto weights_it = n_link.
weights.begin ();
318 for (
auto indices_it = n_link.
indices.cbegin (); indices_it != n_link.
indices.cend (); ++indices_it, ++weights_it)
320 if ((*indices_it != point_index) && (*indices_it !=
UNAVAILABLE))
322 addEdge (graph_nodes_[i_point], graph_nodes_[*indices_it], *weights_it, *weights_it);
329 template <
typename Po
intT>
void
332 const int number_of_indices =
static_cast<int> (indices_->size ());
333 for (
int i_point = 0; i_point < number_of_indices; ++i_point)
335 NLinks &n_link = n_links_[i_point];
338 const auto point_index = (*indices_) [i_point];
339 auto dists_it = n_link.
dists.cbegin ();
340 auto weights_it = n_link.
weights.begin ();
341 for (
auto indices_it = n_link.
indices.cbegin (); indices_it != n_link.
indices.cend (); ++indices_it, ++dists_it, ++weights_it)
343 if (*indices_it != point_index)
346 float color_distance = *weights_it;
348 *weights_it =
static_cast<float> (lambda_ * std::exp (-beta_ * color_distance) / sqrt (*dists_it));
355 template <
typename Po
intT>
void
358 for(
unsigned int y = 0; y < image_->height; ++y )
360 for(
unsigned int x = 0; x < image_->width; ++x )
364 std::size_t point_index = y * input_->width + x;
365 NLinks &links = n_links_[point_index];
367 if( x > 0 && y < image_->height-1 )
370 if( y < image_->height-1 )
373 if( x < image_->width-1 && y < image_->height-1 )
376 if( x < image_->width-1 )
382 template <
typename Po
intT>
void
386 std::size_t edges = 0;
388 const int number_of_indices =
static_cast<int> (indices_->size ());
390 for (
int i_point = 0; i_point < number_of_indices; i_point++)
392 const auto point_index = (*indices_)[i_point];
393 const PointT& point = input_->points [point_index];
396 NLinks &links = n_links_[i_point];
397 int found = tree_->nearestKSearch (point, nb_neighbours_, links.
indices, links.
dists);
402 for (
const auto& nn_index : links.
indices)
404 if (nn_index != point_index)
407 links.
weights.push_back (color_distance);
408 result+= color_distance;
418 beta_ = 1e5 / (2*result / edges);
421 template <
typename Po
intT>
void
425 std::size_t edges = 0;
427 for (
unsigned int y = 0; y < input_->height; ++y)
429 for (
unsigned int x = 0; x < input_->width; ++x)
431 std::size_t point_index = y * input_->width + x;
432 NLinks &links = n_links_[point_index];
438 if (x > 0 && y < input_->height-1)
440 std::size_t upleft = (y+1) * input_->width + x - 1;
442 links.
dists[0] = std::sqrt (2.f);
450 if (y < input_->height-1)
452 std::size_t up = (y+1) * input_->width + x;
462 if (x < input_->width-1 && y < input_->height-1)
464 std::size_t upright = (y+1) * input_->width + x + 1;
466 links.
dists[2] = std::sqrt (2.f);
468 image_->points [upright]);
474 if (x < input_->width-1)
476 std::size_t right = y * input_->width + x + 1;
488 beta_ = 1e5 / (2*result / edges);
491 template <
typename Po
intT>
void
497 template <
typename Po
intT>
void
503 clusters[0].indices.reserve (indices_->size ());
504 clusters[1].indices.reserve (indices_->size ());
506 assert (hard_segmentation_.size () == indices_->size ());
507 const int indices_size =
static_cast<int> (indices_->size ());
508 for (
int i = 0; i < indices_size; ++i)
510 clusters[1].indices.push_back (i);
512 clusters[0].indices.push_back (i);
void computeL()
Compute L parameter from given lambda.
void addEdge(vertex_descriptor v1, vertex_descriptor v2, float capacity, float rev_capacity)
Add an edge to the graph, graph must be oriented so we add the edge and its reverse.
virtual void fitGMMs()
Fit Gaussian Multi Models.
int updateHardSegmentation()
void computeNLinksNonOrganized()
Compute NLinks from cloud.
virtual void refine()
Run Grabcut refinement on the hard segmentation.
void setTrimap(const PointIndicesConstPtr &indices, segmentation::grabcut::TrimapValue t)
Edit Trimap.
pcl::segmentation::grabcut::BoykovKolmogorov::vertex_descriptor vertex_descriptor
void extract(std::vector< pcl::PointIndices > &clusters)
This method launches the segmentation algorithm and returns the clusters that were obtained during th...
void initGraph()
Build the graph for GraphCut.
void computeBetaOrganized()
Compute beta from image.
void computeNLinksOrganized()
Compute NLinks from image.
void setTerminalWeights(vertex_descriptor v, float source_capacity, float sink_capacity)
Set the weights of SOURCE --> v and v --> SINK.
void setBackgroundPointsIndices(int x1, int y1, int x2, int y2)
Set background indices, foreground indices = indices \ background indices.
void setInputCloud(const PointCloudConstPtr &cloud) override
Provide a pointer to the input dataset.
void computeBetaNonOrganized()
Compute beta from cloud.
typename PointCloud::ConstPtr PointCloudConstPtr
PointIndices::ConstPtr PointIndicesConstPtr
PointCloud represents the base class in PCL for storing collections of 3D points.
Define standard C methods to do distance calculations.
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
TrimapValue
User supplied Trimap values.
PCL_EXPORTS void buildGMMs(const Image &image, const Indices &indices, const std::vector< SegmentationValue > &hardSegmentation, std::vector< std::size_t > &components, GMM &background_GMM, GMM &foreground_GMM)
Build the initial GMMs using the Orchard and Bouman color clustering algorithm.
SegmentationValue
Grabcut derived hard segmentation values.
PCL_EXPORTS void learnGMMs(const Image &image, const Indices &indices, const std::vector< SegmentationValue > &hard_segmentation, std::vector< std::size_t > &components, GMM &background_GMM, GMM &foreground_GMM)
Iteratively learn GMMs using GrabCut updating algorithm.
float squaredEuclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the squared euclidean distance between the two given points.
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested return true if f...
static constexpr index_t UNAVAILABLE
std::vector< float > weights
std::vector< float > dists
A point structure representing Euclidean xyz coordinates, and the RGB color.
Structure to save RGB colors into floats.