Make Boost Alpha Expansion use BGL API

This commit is contained in:
Simon Giraudot 2019-07-18 11:07:03 +02:00
parent 0dd30b1a68
commit 5ca8fcf47b
1 changed files with 143 additions and 26 deletions

View File

@ -75,6 +75,84 @@ namespace CGAL
namespace internal namespace internal
{ {
struct Alpha_expansion_old_API_wrapper_graph
{
typedef std::size_t vertex_descriptor;
typedef std::size_t edge_descriptor;
typedef boost::directed_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::edge_list_graph_tag traversal_category;
typedef boost::counting_iterator<std::size_t> counting_iterator;
typedef CGAL::Iterator_range<counting_iterator> counting_range;
typedef CGAL::Identity_property_map<std::size_t> Vertex_index_map;
typedef CGAL::Pointer_property_map<std::size_t>::type Vertex_label_map;
struct Vertex_label_probability_map
{
typedef std::size_t key_type;
typedef std::vector<double> value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
const std::vector<std::vector<double> >* probability_matrix;
Vertex_label_probability_map (const std::vector<std::vector<double> >* probability_matrix)
: probability_matrix (probability_matrix)
{ }
friend reference get (const Vertex_label_probability_map& pmap, key_type idx)
{
std::vector<double> out;
out.reserve (pmap.probability_matrix->size());
for (std::size_t i = 0; i < pmap.probability_matrix->size(); ++ i)
out.push_back ((*pmap.probability_matrix)[i][idx]);
return out;
}
};
typedef CGAL::Pointer_property_map<double>::const_type Edge_weight_map;
const std::vector<std::pair<std::size_t, std::size_t> >& edges;
const std::vector<double>& edge_weights;
const std::vector<std::vector<double> >& probability_matrix;
std::vector<std::size_t>& labels;
Alpha_expansion_old_API_wrapper_graph (const std::vector<std::pair<std::size_t, std::size_t> >& edges,
const std::vector<double>& edge_weights,
const std::vector<std::vector<double> >& probability_matrix,
std::vector<std::size_t>& labels)
: edges (edges), edge_weights (edge_weights), probability_matrix (probability_matrix), labels (labels)
{ }
friend counting_range vertices (const Alpha_expansion_old_API_wrapper_graph& graph)
{
return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(graph.labels.size()));
}
friend std::size_t num_vertices (const Alpha_expansion_old_API_wrapper_graph& graph) { return graph.labels.size(); }
friend counting_range edges (const Alpha_expansion_old_API_wrapper_graph& graph)
{
return CGAL::make_range (boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(graph.edges.size()));
}
friend vertex_descriptor source (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
{ return graph.edges[ed].first; }
friend vertex_descriptor target (edge_descriptor ed, const Alpha_expansion_old_API_wrapper_graph& graph)
{ return graph.edges[ed].second; }
Vertex_index_map vertex_index_map() const { return Vertex_index_map(); }
Vertex_label_map vertex_label_map() { return CGAL::make_property_map(labels); }
Vertex_label_probability_map vertex_label_probability_map() const
{ return Vertex_label_probability_map(&probability_matrix); }
Edge_weight_map edge_weight_map() const { return CGAL::make_property_map(edge_weights); }
};
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// Comments about performance: // Comments about performance:
// //
@ -182,6 +260,8 @@ private:
return boost::make_tuple(v1_v2, v2_v1); return boost::make_tuple(v1_v2, v2_v1);
} }
public: public:
/** /**
* Applies alpha-expansion graph-cut for energy minimization. * Applies alpha-expansion graph-cut for energy minimization.
@ -196,7 +276,33 @@ public:
edges, edges,
const std::vector<double>& edge_weights, const std::vector<double>& edge_weights,
const std::vector<std::vector<double> >& probability_matrix, const std::vector<std::vector<double> >& probability_matrix,
std::vector<std::size_t>& labels) const { std::vector<std::size_t>& labels) const
{
Alpha_expansion_old_API_wrapper_graph graph (edges, edge_weights, probability_matrix, labels);
return (*this)(graph,
graph.edge_weight_map(),
graph.vertex_index_map(),
graph.vertex_label_map(),
graph.vertex_label_probability_map());
}
template <typename InputGraph,
typename Edge_weight_map,
typename Vertex_index_map,
typename Vertex_label_map,
typename Vertex_label_probability_map>
double operator()(const InputGraph& input_graph,
Edge_weight_map edge_weight_map,
Vertex_index_map vertex_index_map,
Vertex_label_map vertex_label_map,
Vertex_label_probability_map vertex_label_probability_map) const
{
typedef boost::graph_traits<InputGraph> GT;
typedef typename GT::edge_descriptor input_edge_descriptor;
typedef typename GT::vertex_descriptor input_vertex_descriptor;
// TODO: check this hardcoded parameter
const double tolerance = 1e-10; const double tolerance = 1e-10;
double min_cut = (std::numeric_limits<double>::max)(); double min_cut = (std::numeric_limits<double>::max)();
@ -207,18 +313,18 @@ public:
#endif #endif
std::vector<Vertex_descriptor> inserted_vertices; std::vector<Vertex_descriptor> inserted_vertices;
inserted_vertices.resize(labels.size()); inserted_vertices.resize(num_vertices (input_graph));
std::size_t number_of_labels = get(vertex_label_probability_map, *std::begin(vertices(input_graph))).size();
Graph graph; Graph graph;
bool success; bool success;
do { do {
success = false; success = false;
std::size_t alpha = 0;
for(std::vector<std::vector<double> >::const_iterator it = for (std::size_t alpha = 0; alpha < number_of_labels; ++ alpha)
probability_matrix.begin(); {
it != probability_matrix.end(); ++it, ++alpha) {
graph.clear(); graph.clear();
Vertex_descriptor cluster_source = boost::add_vertex(graph); Vertex_descriptor cluster_source = boost::add_vertex(graph);
@ -230,16 +336,18 @@ public:
#endif #endif
// For E-Data // For E-Data
// add every facet as a vertex to the graph, put edges to source & sink vertices // add every input vertex as a vertex to the graph, put edges to source & sink vertices
for(std::size_t vertex_i = 0; vertex_i < labels.size(); ++vertex_i) { for (input_vertex_descriptor vd : vertices(input_graph))
{
std::size_t vertex_i = get(vertex_index_map, vd);
Vertex_descriptor new_vertex = boost::add_vertex(graph); Vertex_descriptor new_vertex = boost::add_vertex(graph);
inserted_vertices[vertex_i] = new_vertex; inserted_vertices[vertex_i] = new_vertex;
double source_weight = probability_matrix[alpha][vertex_i]; double source_weight = get(vertex_label_probability_map, vd)[alpha];
// since it is expansion move, current alpha labeled vertices will be assigned to alpha again, // since it is expansion move, current alpha labeled vertices will be assigned to alpha again,
// making sink_weight 'infinity' guarantee this. // making sink_weight 'infinity' guarantee this.
double sink_weight = (labels[vertex_i] == alpha) ? double sink_weight = (get(vertex_label_map, vd) == alpha ?
(std::numeric_limits<double>::max)() (std::numeric_limits<double>::max)()
: probability_matrix[labels[vertex_i]][vertex_i]; : get(vertex_label_probability_map, vd)[get(vertex_label_map, vd)]);
add_edge_and_reverse(cluster_source, new_vertex, source_weight, 0.0, graph); add_edge_and_reverse(cluster_source, new_vertex, source_weight, 0.0, graph);
add_edge_and_reverse(new_vertex, cluster_sink, sink_weight, 0.0, graph); add_edge_and_reverse(new_vertex, cluster_sink, sink_weight, 0.0, graph);
@ -251,25 +359,32 @@ public:
// For E-Smooth // For E-Smooth
// add edge between every vertex, // add edge between every vertex,
std::vector<double>::const_iterator weight_it = edge_weights.begin(); for (input_edge_descriptor ed : edges(input_graph))
for(std::vector<std::pair<std::size_t, std::size_t> >::const_iterator edge_it = {
edges.begin(); edge_it != edges.end(); input_vertex_descriptor vd1 = source(ed, input_graph);
++edge_it, ++weight_it) { input_vertex_descriptor vd2 = target(ed, input_graph);
Vertex_descriptor v1 = inserted_vertices[edge_it->first], std::size_t idx1 = get (vertex_index_map, vd1);
v2 = inserted_vertices[edge_it->second]; std::size_t idx2 = get (vertex_index_map, vd2);
std::size_t label_1 = labels[edge_it->first], label_2 = labels[edge_it->second];
double weight = get (edge_weight_map, ed);
Vertex_descriptor v1 = inserted_vertices[idx1],
v2 = inserted_vertices[idx2];
std::size_t label_1 = get (vertex_label_map, vd1);
std::size_t label_2 = get (vertex_label_map, vd2);
if(label_1 == label_2) { if(label_1 == label_2) {
if(label_1 != alpha) { if(label_1 != alpha) {
add_edge_and_reverse(v1, v2, *weight_it, *weight_it, graph); add_edge_and_reverse(v1, v2, weight, weight, graph);
} }
} else { } else {
Vertex_descriptor inbetween = boost::add_vertex(graph); Vertex_descriptor inbetween = boost::add_vertex(graph);
double w1 = (label_1 == alpha) ? 0 : *weight_it; double w1 = (label_1 == alpha) ? 0 : weight;
double w2 = (label_2 == alpha) ? 0 : *weight_it; double w2 = (label_2 == alpha) ? 0 : weight;
add_edge_and_reverse(inbetween, v1, w1, w1, graph); add_edge_and_reverse(inbetween, v1, w1, w1, graph);
add_edge_and_reverse(inbetween, v2, w2, w2, graph); add_edge_and_reverse(inbetween, v2, w2, w2, graph);
add_edge_and_reverse(inbetween, cluster_sink, *weight_it, 0.0, graph); add_edge_and_reverse(inbetween, cluster_sink, weight, 0.0, graph);
} }
} }
#ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT #ifdef CGAL_SEGMENTATION_BENCH_GRAPHCUT
@ -302,12 +417,14 @@ public:
min_cut = flow; min_cut = flow;
success = true; success = true;
//update labeling //update labeling
for(std::size_t vertex_i = 0; vertex_i < inserted_vertices.size(); ++vertex_i) { for (input_vertex_descriptor vd : vertices (input_graph))
{
std::size_t vertex_i = get (vertex_index_map, vd);
boost::default_color_type color = boost::get(boost::vertex_color, graph, boost::default_color_type color = boost::get(boost::vertex_color, graph,
inserted_vertices[vertex_i]); inserted_vertices[vertex_i]);
if(labels[vertex_i] != alpha if(get (vertex_label_map, vd) != alpha
&& color == ColorTraits::white()) { //new comers (expansion occurs) && color == ColorTraits::white()) { //new comers (expansion occurs)
labels[vertex_i] = alpha; put (vertex_label_map, vd, alpha);
} }
} }
} }