Use BGL API in regularize_selection

This commit is contained in:
Simon Giraudot 2019-07-18 15:48:53 +02:00
parent 6b79764dbb
commit 461bb19e2d
2 changed files with 228 additions and 58 deletions

View File

@ -16,6 +16,10 @@
#include <CGAL/boost/graph/iterator.h> #include <CGAL/boost/graph/iterator.h>
#include <boost/unordered_set.hpp> #include <boost/unordered_set.hpp>
#include <CGAL/boost/graph/Dual.h>
#include <boost/graph/filtered_graph.hpp>
#include <boost/iterator/filter_iterator.hpp>
#define CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE #define CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE
#include <CGAL/internal/Surface_mesh_segmentation/Alpha_expansion_graph_cut.h> #include <CGAL/internal/Surface_mesh_segmentation/Alpha_expansion_graph_cut.h>
@ -59,6 +63,200 @@ extract_selection_boundary(
return out; return out;
} }
template <typename FaceGraph,
typename IsSelectedMap,
typename FaceIndexMap,
typename VertexPointMap>
struct Regularization_graph
{
typedef boost::graph_traits<FaceGraph> GT;
typedef typename GT::face_descriptor fg_face_descriptor;
typedef typename GT::face_iterator fg_face_iterator;
typedef typename GT::halfedge_descriptor fg_halfedge_descriptor;
typedef typename GT::edge_descriptor fg_edge_descriptor;
typedef typename GT::edge_iterator fg_edge_iterator;
typedef typename GT::vertex_descriptor fg_vertex_descriptor;
typedef fg_face_descriptor vertex_descriptor;
typedef fg_face_iterator vertex_iterator;
typedef fg_edge_descriptor edge_descriptor;
typedef boost::undirected_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::edge_list_graph_tag traversal_category;
struct Filter_border_edges
{
FaceGraph* fg;
Filter_border_edges (FaceGraph& fg) : fg (&fg) { }
bool operator() (const fg_edge_descriptor ed) const
{
return !is_border (ed, *fg);
}
};
typedef boost::filter_iterator<Filter_border_edges, fg_edge_iterator> edge_iterator;
struct Vertex_label_map
{
typedef vertex_descriptor key_type;
typedef std::size_t value_type;
typedef std::size_t& reference;
typedef boost::lvalue_property_map_tag category;
std::vector<std::size_t>* labels;
FaceIndexMap face_index_map;
Vertex_label_map (std::vector<std::size_t>& labels, FaceIndexMap face_index_map)
: labels (&labels), face_index_map (face_index_map) { }
friend reference get (const Vertex_label_map& map, key_type k)
{
return (*map.labels)[get(map.face_index_map,k)];
}
friend void put (const Vertex_label_map& map, key_type k, const value_type& v)
{
(*map.labels)[get(map.face_index_map,k)] = v;
}
};
struct Vertex_label_probability_map
{
typedef vertex_descriptor key_type;
typedef std::vector<double> value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
IsSelectedMap is_selected_map;
bool prevent_deselection;
Vertex_label_probability_map (IsSelectedMap is_selected_map,
bool prevent_deselection)
: is_selected_map (is_selected_map)
, prevent_deselection (prevent_deselection)
{ }
friend reference get (const Vertex_label_probability_map& pmap, key_type fd)
{
std::vector<double> out(2);
if (get(pmap.is_selected_map, fd))
{
if (pmap.prevent_deselection)
out[0] = std::numeric_limits<double>::max();
else
out[0] = 1.;
out[1] = 0.;
}
else
{
out[0] = 0.;
out[1] = 1.;
}
return out;
}
};
struct Edge_weight_map
{
typedef edge_descriptor key_type;
typedef double value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
const FaceGraph* fg;
VertexPointMap vertex_point_map;
double normalization_factor;
Edge_weight_map (const FaceGraph& fg, VertexPointMap vertex_point_map,
double normalization_factor)
: fg (&fg), vertex_point_map (vertex_point_map),
normalization_factor (normalization_factor) { }
friend reference get (const Edge_weight_map& pmap, key_type ed)
{
fg_vertex_descriptor esource = source(ed, *pmap.fg);
fg_vertex_descriptor etarget = target(ed, *pmap.fg);
// Weight
double edge_length = std::sqrt(CGAL::squared_distance (get (pmap.vertex_point_map, esource),
get (pmap.vertex_point_map, etarget)));
return pmap.normalization_factor * edge_length;
}
};
FaceGraph& fg;
IsSelectedMap is_selected_map;
FaceIndexMap face_index_map;
VertexPointMap vertex_point_map;
double normalization_factor;
bool prevent_deselection;
std::vector<std::size_t> labels;
Regularization_graph (FaceGraph& fg,
IsSelectedMap is_selected_map,
FaceIndexMap face_index_map,
VertexPointMap vertex_point_map,
double normalization_factor,
bool prevent_deselection)
: fg (fg),
is_selected_map (is_selected_map),
face_index_map (face_index_map),
vertex_point_map (vertex_point_map),
normalization_factor (normalization_factor),
prevent_deselection (prevent_deselection)
{
labels.reserve(num_faces(fg));
std::size_t nb_selected = 0;
for (fg_face_descriptor fd : faces(fg))
{
if (get(is_selected_map,fd))
{
labels.push_back(1);
++ nb_selected;
}
else
labels.push_back(0);
}
std::cerr << nb_selected << " selected face(s)" << std::endl;
}
friend CGAL::Iterator_range<vertex_iterator>
vertices (const Regularization_graph& graph)
{
return faces (graph.fg);
}
friend std::size_t num_vertices (const Regularization_graph& graph) { return num_faces(graph.fg); }
friend CGAL::Iterator_range<edge_iterator>
edges (const Regularization_graph& graph)
{
return CGAL::make_range (boost::make_filter_iterator
(Filter_border_edges(graph.fg),
begin(edges(graph.fg)), end(edges(graph.fg))),
boost::make_filter_iterator
(Filter_border_edges(graph.fg),
end(edges(graph.fg)), end(edges(graph.fg))));
}
friend vertex_descriptor source (edge_descriptor ed, const Regularization_graph& graph)
{
return face (halfedge (ed, graph.fg), graph.fg);
}
friend vertex_descriptor target (edge_descriptor ed, const Regularization_graph& graph)
{
return face (opposite(halfedge (ed, graph.fg), graph.fg), graph.fg);
}
Vertex_label_map vertex_label_map() { return Vertex_label_map(labels, face_index_map); }
Vertex_label_probability_map vertex_label_probability_map() const
{ return Vertex_label_probability_map(is_selected_map, prevent_deselection); }
Edge_weight_map edge_weight_map() const
{ return Edge_weight_map(fg, vertex_point_map, normalization_factor); }
};
} //end of namespace internal } //end of namespace internal
@ -207,11 +405,12 @@ reduce_face_selection(
} }
// TODO: document me // TODO: document me
template <class FaceGraph, class IsFaceSelectedPMap, class VertexPointMap> template <class FaceGraph, class IsSelectedMap, class FaceIndexMap, class VertexPointMap>
void void
regularize_face_selection_borders( regularize_face_selection_borders(
FaceGraph& fg, FaceGraph& fg,
IsFaceSelectedPMap is_selected, IsSelectedMap is_selected,
FaceIndexMap face_index_map,
VertexPointMap vertex_point_map, VertexPointMap vertex_point_map,
double weight = 0.5, double weight = 0.5,
bool prevent_deselection = true, bool prevent_deselection = true,
@ -227,76 +426,44 @@ regularize_face_selection_borders(
if (global_regularization) // Use graphcut if (global_regularization) // Use graphcut
{ {
std::vector<std::pair<std::size_t, std::size_t> > gedges; // Compute normalization factor
std::vector<double> edge_weights;
std::vector<std::vector<double> > probability_matrix;
probability_matrix.resize(2);
std::vector<std::size_t> labels;
std::map<fg_face_descriptor, std::size_t> map_f2i;
std::size_t idx = 0;
std::size_t nb_selected = 0;
for(fg_face_descriptor fd : faces(fg))
{
if (get(is_selected,fd))
{
if (prevent_deselection)
probability_matrix[0].push_back(std::numeric_limits<double>::max());
else
probability_matrix[0].push_back(1.);
probability_matrix[1].push_back(0.);
labels.push_back(1);
++ nb_selected;
}
else
{
probability_matrix[0].push_back(0.0);
probability_matrix[1].push_back(1.0);
labels.push_back(0);
}
map_f2i.insert (std::make_pair (fd, idx ++));
}
double normalization_factor = 0.; double normalization_factor = 0.;
std::size_t nb_edges = 0;
for (fg_edge_descriptor ed : edges(fg)) for (fg_edge_descriptor ed : edges(fg))
{ {
if (is_border (ed, fg)) if (is_border (ed, fg))
continue; continue;
fg_vertex_descriptor esource = source(ed, fg); fg_vertex_descriptor esource = source(ed, fg);
fg_vertex_descriptor etarget = target(ed, fg); fg_vertex_descriptor etarget = target(ed, fg);
fg_face_descriptor f0 = face (halfedge (ed, fg), fg);
fg_face_descriptor f1 = face (opposite(halfedge (ed, fg), fg), fg);
std::size_t i0 = map_f2i[f0];
std::size_t i1 = map_f2i[f1];
// Weight
double edge_length = std::sqrt(CGAL::squared_distance (get (vertex_point_map, esource), double edge_length = std::sqrt(CGAL::squared_distance (get (vertex_point_map, esource),
get (vertex_point_map, etarget))); get (vertex_point_map, etarget)));
normalization_factor += edge_length; normalization_factor += edge_length;
++ nb_edges;
gedges.push_back (std::make_pair (i0, i1));
edge_weights.push_back (edge_length);
} }
weight = -10. * std::log(1.0 - weight); // Internal cooking so that weight = -10. * std::log(1.0 - weight); // Internal cooking so that
// API weights are in [0:1[ // API weights are in [0:1[
normalization_factor = weight * nb_edges / normalization_factor;
normalization_factor = weight * edge_weights.size() / normalization_factor;
for (double& w : edge_weights)
w *= normalization_factor;
internal::Alpha_expansion_graph_cut_boost alpha_expansion; internal::Regularization_graph<FaceGraph, IsSelectedMap, FaceIndexMap,
alpha_expansion (gedges, edge_weights, probability_matrix, labels); VertexPointMap>
graph (fg, is_selected,
face_index_map,
vertex_point_map,
normalization_factor,
prevent_deselection);
for (const auto& p : map_f2i) internal::Alpha_expansion_graph_cut_boost alpha_expansion;
put(is_selected, p.first, (labels[p.second] == 1)); alpha_expansion (graph,
graph.edge_weight_map(),
face_index_map,
graph.vertex_label_map(),
graph.vertex_label_probability_map());
for (fg_face_descriptor fd : faces(fg))
put(is_selected, fd, graph.labels[get(face_index_map,fd)]);
} }
else // No graphcut, use direct solve else // No graphcut, use direct solve
{ {

View File

@ -387,8 +387,10 @@ public Q_SLOTS:
if (!ok) if (!ok)
return; return;
boost::unordered_map<fg_face_descriptor, bool> is_selected_map; boost::unordered_map<fg_face_descriptor, bool> is_selected_map;
int index = 0; boost::unordered_map<fg_face_descriptor, std::size_t> face_index_map;
std::size_t index = 0;
for(fg_face_descriptor fh : faces(*selection_item->polyhedron())) for(fg_face_descriptor fh : faces(*selection_item->polyhedron()))
{ {
if(selection_item->selected_facets.find(fh) if(selection_item->selected_facets.find(fh)
@ -398,7 +400,7 @@ public Q_SLOTS:
{ {
is_selected_map[fh]=true; is_selected_map[fh]=true;
} }
++index; face_index_map[fh] = index ++;
} }
auto border_length = auto border_length =
@ -433,6 +435,7 @@ public Q_SLOTS:
CGAL::regularize_face_selection_borders (*selection_item->polyhedron(), CGAL::regularize_face_selection_borders (*selection_item->polyhedron(),
boost::make_assoc_property_map(is_selected_map), boost::make_assoc_property_map(is_selected_map),
boost::make_assoc_property_map(face_index_map),
get(CGAL::vertex_point,*selection_item->polyhedron()), get(CGAL::vertex_point,*selection_item->polyhedron()),
weight, true, (weight != 1.0)); weight, true, (weight != 1.0));