Use CGAL::for_each in classify functions

This commit is contained in:
Simon Giraudot 2020-04-02 10:44:15 +02:00
parent 7b4c664403
commit d9b5f4f1e5
1 changed files with 145 additions and 360 deletions

View File

@ -17,9 +17,12 @@
#include <CGAL/internal/Surface_mesh_segmentation/Alpha_expansion_graph_cut.h> #include <CGAL/internal/Surface_mesh_segmentation/Alpha_expansion_graph_cut.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/for_each.h>
#include <CGAL/Classification/Label_set.h> #include <CGAL/Classification/Label_set.h>
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <boost/iterator/counting_iterator.hpp>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
@ -31,299 +34,6 @@ namespace CGAL {
namespace Classification { namespace Classification {
/// \cond SKIP_IN_MANUAL
namespace internal {
template <typename Classifier, typename LabelIndexRange>
class Classify_functor
{
const Label_set& m_labels;
const Classifier& m_classifier;
LabelIndexRange& m_out;
public:
Classify_functor (const Label_set& labels,
const Classifier& classifier,
LabelIndexRange& out)
: m_labels (labels), m_classifier (classifier), m_out (out)
{ }
#ifdef CGAL_LINKED_WITH_TBB
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
for (std::size_t s = r.begin(); s != r.end(); ++ s)
apply(s);
}
#endif // CGAL_LINKED_WITH_TBB
inline void apply (std::size_t s) const
{
std::size_t nb_class_best=0;
std::vector<float> values;
m_classifier (s, values);
float val_class_best = 0.f;
for(std::size_t k = 0; k < m_labels.size(); ++ k)
{
if(val_class_best < values[k])
{
val_class_best = values[k];
nb_class_best = k;
}
}
m_out[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
}
};
template <typename Classifier, typename LabelIndexRange, typename ProbabilitiesRanges>
class Classify_detailed_output_functor
{
const Label_set& m_labels;
const Classifier& m_classifier;
LabelIndexRange& m_out;
ProbabilitiesRanges& m_prob;
public:
Classify_detailed_output_functor (const Label_set& labels,
const Classifier& classifier,
LabelIndexRange& out,
ProbabilitiesRanges& prob)
: m_labels (labels), m_classifier (classifier), m_out (out), m_prob (prob)
{ }
#ifdef CGAL_LINKED_WITH_TBB
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
for (std::size_t s = r.begin(); s != r.end(); ++ s)
apply(s);
}
#endif // CGAL_LINKED_WITH_TBB
inline void apply (std::size_t s) const
{
std::size_t nb_class_best=0;
std::vector<float> values;
m_classifier (s, values);
float val_class_best = 0.f;
for(std::size_t k = 0; k < m_labels.size(); ++ k)
{
m_prob[k][s] = values[k];
if(val_class_best < values[k])
{
val_class_best = values[k];
nb_class_best = k;
}
}
m_out[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
}
};
template <typename Classifier>
class Classify_functor_local_smoothing_preprocessing
{
const Label_set& m_labels;
const Classifier& m_classifier;
std::vector<std::vector<float> >& m_values;
public:
Classify_functor_local_smoothing_preprocessing
(const Label_set& labels,
const Classifier& classifier,
std::vector<std::vector<float> >& values)
: m_labels (labels), m_classifier (classifier), m_values (values)
{ }
#ifdef CGAL_LINKED_WITH_TBB
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
for (std::size_t s = r.begin(); s != r.end(); ++ s)
apply (s);
}
#endif
inline void apply (std::size_t s) const
{
std::vector<float> values;
m_classifier(s, values);
for(std::size_t k = 0; k < m_labels.size(); ++ k)
m_values[k][s] = values[k];
}
};
template <typename ItemRange, typename ItemMap, typename NeighborQuery, typename LabelIndexRange>
class Classify_functor_local_smoothing
{
const ItemRange& m_input;
const ItemMap m_item_map;
const Label_set& m_labels;
const std::vector<std::vector<float> >& m_values;
const NeighborQuery& m_neighbor_query;
LabelIndexRange& m_out;
public:
Classify_functor_local_smoothing (const ItemRange& input,
ItemMap item_map,
const Label_set& labels,
const std::vector<std::vector<float> >& values,
const NeighborQuery& neighbor_query,
LabelIndexRange& out)
: m_input (input), m_item_map (item_map), m_labels (labels),
m_values(values),
m_neighbor_query (neighbor_query),
m_out (out)
{ }
#ifdef CGAL_LINKED_WITH_TBB
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
for (std::size_t s = r.begin(); s != r.end(); ++ s)
apply (s);
}
#endif
inline void apply (std::size_t s) const
{
std::vector<std::size_t> neighbors;
m_neighbor_query (get (m_item_map, *(m_input.begin()+s)), std::back_inserter (neighbors));
std::vector<float> mean (m_values.size(), 0.);
for (std::size_t n = 0; n < neighbors.size(); ++ n)
for (std::size_t j = 0; j < m_values.size(); ++ j)
mean[j] += m_values[j][neighbors[n]];
std::size_t nb_class_best=0;
float val_class_best = 0.f;
for(std::size_t k = 0; k < mean.size(); ++ k)
{
mean[k] /= neighbors.size();
if(val_class_best < mean[k])
{
val_class_best = mean[k];
nb_class_best = k;
}
}
m_out[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
}
};
template <typename ItemRange, typename ItemMap,
typename Classifier, typename NeighborQuery,
typename LabelIndexRange>
class Classify_functor_graphcut
{
const ItemRange& m_input;
ItemMap m_item_map;
const Label_set& m_labels;
const Classifier& m_classifier;
const NeighborQuery& m_neighbor_query;
float m_strength;
const std::vector<std::vector<std::size_t> >& m_indices;
const std::vector<std::pair<std::size_t, std::size_t> >& m_input_to_indices;
LabelIndexRange& m_out;
#ifdef CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE
typedef CGAL::internal::Alpha_expansion_graph_cut_boost Alpha_expansion;
#else
typedef CGAL::internal::Alpha_expansion_graph_cut_boykov_kolmogorov Alpha_expansion;
#endif
public:
Classify_functor_graphcut (const ItemRange& input,
ItemMap item_map,
const Label_set& labels,
const Classifier& classifier,
const NeighborQuery& neighbor_query,
float strength,
const std::vector<std::vector<std::size_t> >& indices,
const std::vector<std::pair<std::size_t, std::size_t> >& input_to_indices,
LabelIndexRange& out)
: m_input (input), m_item_map (item_map), m_labels (labels),
m_classifier (classifier), m_neighbor_query (neighbor_query),
m_strength (strength), m_indices (indices), m_input_to_indices (input_to_indices), m_out (out)
{ }
#ifdef CGAL_LINKED_WITH_TBB
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
for (std::size_t s = r.begin(); s != r.end(); ++ s)
apply(s);
}
#endif // CGAL_LINKED_WITH_TBB
inline void apply (std::size_t sub) const
{
if (m_indices[sub].empty())
return;
std::vector<std::pair<std::size_t, std::size_t> > edges;
std::vector<double> edge_weights;
std::vector<std::vector<double> > probability_matrix
(m_labels.size(), std::vector<double>(m_indices[sub].size(), 0.));
std::vector<std::size_t> assigned_label (m_indices[sub].size());
for (std::size_t j = 0; j < m_indices[sub].size(); ++ j)
{
std::size_t s = m_indices[sub][j];
std::vector<std::size_t> neighbors;
m_neighbor_query (get(m_item_map, *(m_input.begin()+s)), std::back_inserter (neighbors));
for (std::size_t i = 0; i < neighbors.size(); ++ i)
if (sub == m_input_to_indices[neighbors[i]].first
&& j != m_input_to_indices[neighbors[i]].second)
{
edges.push_back (std::make_pair (j, m_input_to_indices[neighbors[i]].second));
edge_weights.push_back (m_strength);
}
std::vector<float> values;
m_classifier(s, values);
std::size_t nb_class_best = 0;
float val_class_best = 0.f;
for(std::size_t k = 0; k < m_labels.size(); ++ k)
{
float value = values[k];
probability_matrix[k][j] = -std::log(value);
if(val_class_best < value)
{
val_class_best = value;
nb_class_best = k;
}
}
assigned_label[j] = nb_class_best;
}
Alpha_expansion graphcut;
graphcut(edges, edge_weights, probability_matrix, assigned_label);
for (std::size_t i = 0; i < assigned_label.size(); ++ i)
m_out[m_indices[sub][i]] = static_cast<typename LabelIndexRange::iterator::value_type>(assigned_label[i]);
}
};
} // namespace internal
/// \endcond
/*! /*!
\ingroup PkgClassificationMain \ingroup PkgClassificationMain
@ -362,24 +72,29 @@ namespace internal {
const Classifier& classifier, const Classifier& classifier,
LabelIndexRange& output) LabelIndexRange& output)
{ {
internal::Classify_functor<Classifier, LabelIndexRange> CGAL::for_each<ConcurrencyTag>
f (labels, classifier, output); (CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(input.size())),
[&](const std::size_t& s) -> bool
{
std::size_t nb_class_best=0;
std::vector<float> values;
classifier (s, values);
#ifndef CGAL_LINKED_WITH_TBB float val_class_best = 0.f;
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value), for(std::size_t k = 0; k < labels.size(); ++ k)
"Parallel_tag is enabled but TBB is unavailable.");
#else
if (std::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
tbb::parallel_for(tbb::blocked_range<size_t>(0, input.size ()), f); if(val_class_best < values[k])
}
else
#endif
{ {
for (std::size_t i = 0; i < input.size(); ++ i) val_class_best = values[k];
f.apply(i); nb_class_best = k;
} }
} }
output[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
return true;
});
}
/// \cond SKIP_IN_MANUAL /// \cond SKIP_IN_MANUAL
// variant to get a detailed output (not documented yet) // variant to get a detailed output (not documented yet)
@ -394,24 +109,31 @@ namespace internal {
LabelIndexRange& output, LabelIndexRange& output,
ProbabilitiesRanges& probabilities) ProbabilitiesRanges& probabilities)
{ {
internal::Classify_detailed_output_functor<Classifier, LabelIndexRange, ProbabilitiesRanges> CGAL::for_each<ConcurrencyTag>
f (labels, classifier, output, probabilities); (CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(input.size())),
[&](const std::size_t& s) -> bool
{
std::size_t nb_class_best=0;
std::vector<float> values;
classifier (s, values);
#ifndef CGAL_LINKED_WITH_TBB float val_class_best = 0.f;
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value), for(std::size_t k = 0; k < labels.size(); ++ k)
"Parallel_tag is enabled but TBB is unavailable.");
#else
if (std::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
tbb::parallel_for(tbb::blocked_range<size_t>(0, input.size ()), f); probabilities[k][s] = values[k];
} if(val_class_best < values[k])
else
#endif
{ {
for (std::size_t i = 0; i < input.size(); ++ i) val_class_best = values[k];
f.apply(i); nb_class_best = k;
} }
} }
output[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
return true;
});
}
/// \endcond /// \endcond
/*! /*!
@ -460,30 +182,51 @@ namespace internal {
{ {
std::vector<std::vector<float> > values std::vector<std::vector<float> > values
(labels.size(), std::vector<float> (input.size(), -1.)); (labels.size(), std::vector<float> (input.size(), -1.));
internal::Classify_functor_local_smoothing_preprocessing<Classifier>
f1 (labels, classifier, values);
internal::Classify_functor_local_smoothing<ItemRange, ItemMap, NeighborQuery, LabelIndexRange>
f2 (input, item_map, labels, values, neighbor_query, output);
#ifndef CGAL_LINKED_WITH_TBB CGAL::for_each<ConcurrencyTag>
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value), (CGAL::make_range (boost::counting_iterator<std::size_t>(0),
"Parallel_tag is enabled but TBB is unavailable."); boost::counting_iterator<std::size_t>(input.size())),
#else [&](const std::size_t& s) -> bool
if (std::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
tbb::parallel_for(tbb::blocked_range<size_t>(0, input.size ()), f1); std::vector<float> v;
tbb::parallel_for(tbb::blocked_range<size_t>(0, input.size ()), f2); classifier(s, v);
} for(std::size_t k = 0; k < labels.size(); ++ k)
else values[k][s] = v[k];
#endif
return true;
});
CGAL::for_each<ConcurrencyTag>
(CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(input.size())),
[&](const std::size_t& s) -> bool
{ {
for (std::size_t i = 0; i < input.size(); ++ i) std::vector<std::size_t> neighbors;
f1.apply(i); neighbor_query (get (item_map, *(input.begin()+s)), std::back_inserter (neighbors));
for (std::size_t i = 0; i < input.size(); ++ i)
f2.apply(i); std::vector<float> mean (values.size(), 0.);
for (std::size_t n = 0; n < neighbors.size(); ++ n)
for (std::size_t j = 0; j < values.size(); ++ j)
mean[j] += values[j][neighbors[n]];
std::size_t nb_class_best=0;
float val_class_best = 0.f;
for(std::size_t k = 0; k < mean.size(); ++ k)
{
mean[k] /= neighbors.size();
if(val_class_best < mean[k])
{
val_class_best = mean[k];
nb_class_best = k;
} }
} }
output[s] = static_cast<typename LabelIndexRange::iterator::value_type>(nb_class_best);
return true;
});
}
/*! /*!
\ingroup PkgClassificationMain \ingroup PkgClassificationMain
@ -594,23 +337,65 @@ namespace internal {
CGAL_assertion_msg (i != bboxes.size(), "Point was not assigned to any subdivision."); CGAL_assertion_msg (i != bboxes.size(), "Point was not assigned to any subdivision.");
} }
internal::Classify_functor_graphcut<ItemRange, ItemMap, Classifier, NeighborQuery, LabelIndexRange> CGAL::for_each<ConcurrencyTag>
f (input, item_map, labels, classifier, neighbor_query, strength, indices, input_to_indices, output); (CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(indices.size())),
[&](const std::size_t& sub) -> bool
{
if (indices[sub].empty())
return true;
#ifndef CGAL_LINKED_WITH_TBB std::vector<std::pair<std::size_t, std::size_t> > edges;
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value), std::vector<double> edge_weights;
"Parallel_tag is enabled but TBB is unavailable."); std::vector<std::vector<double> > probability_matrix
(labels.size(), std::vector<double>(indices[sub].size(), 0.));
std::vector<std::size_t> assigned_label (indices[sub].size());
for (std::size_t j = 0; j < indices[sub].size(); ++ j)
{
std::size_t s = indices[sub][j];
std::vector<std::size_t> neighbors;
neighbor_query (get(item_map, *(input.begin()+s)), std::back_inserter (neighbors));
for (std::size_t i = 0; i < neighbors.size(); ++ i)
if (sub == input_to_indices[neighbors[i]].first
&& j != input_to_indices[neighbors[i]].second)
{
edges.push_back (std::make_pair (j, input_to_indices[neighbors[i]].second));
edge_weights.push_back (strength);
}
std::vector<float> values;
classifier(s, values);
std::size_t nb_class_best = 0;
float val_class_best = 0.f;
for(std::size_t k = 0; k < labels.size(); ++ k)
{
float value = values[k];
probability_matrix[k][j] = -std::log(value);
if(val_class_best < value)
{
val_class_best = value;
nb_class_best = k;
}
}
assigned_label[j] = nb_class_best;
}
#ifdef CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE
CGAL::internal::Alpha_expansion_graph_cut_boost graphcut;
#else #else
if (std::is_convertible<ConcurrencyTag,Parallel_tag>::value) CGAL::internal::Alpha_expansion_graph_cut_boykov_kolmogorov graphcut;
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, indices.size ()), f);
}
else
#endif #endif
{ graphcut(edges, edge_weights, probability_matrix, assigned_label);
for (std::size_t sub = 0; sub < indices.size(); ++ sub)
f.apply (sub); for (std::size_t i = 0; i < assigned_label.size(); ++ i)
} output[indices[sub][i]] = static_cast<typename LabelIndexRange::iterator::value_type>(assigned_label[i]);
return true;
});
} }