Update with reviews

This commit is contained in:
Simon Giraudot 2020-01-15 12:46:53 +01:00
parent 0bc24a42b7
commit 1b900e8b86
4 changed files with 178 additions and 12 deletions

View File

@ -654,10 +654,10 @@ can be done directly using `Face_filtered_graph`.
Using \ref BGLNamedParameters some of the many options of METIS can be customized, Using \ref BGLNamedParameters some of the many options of METIS can be customized,
as shown in \ref BGL_polyhedron_3/polyhedron_partition.cpp "this example". as shown in \ref BGL_polyhedron_3/polyhedron_partition.cpp "this example".
\section BGLGraphcut Graphcut \section BGLGraphcut Graph Cut
Optimal partition from a set of labels can be computed through a An optimal partition from a set of labels can be computed through a
graphcut approach called Alpha Expansion graph cut approach called Alpha Expansion
\cgalCite{boykov2001fastapproximate}. \cgal provides \cgalCite{boykov2001fastapproximate}. \cgal provides
`CGAL::alpha_expansion_graphcut()` which, or a graph \f$(V,E)\f$, this `CGAL::alpha_expansion_graphcut()` which, or a graph \f$(V,E)\f$, this
function seeks for the partioning `f` that minimizes the following function seeks for the partioning `f` that minimizes the following
@ -695,6 +695,33 @@ Comparison of time and memory consumed by the different Alpha
Expansion implementation. Expansion implementation.
\cgalFigureEnd \cgalFigureEnd
The following example shows how to apply the Alpha Expansion algorithm
to a `boost::adjacency_list` describing a 2D array with 3 labels "X",
" " and "O":
\cgalExample{BGL_graphcut/alpha_expansion_example.cpp}
The output of this program shows how the initial 2D array is
regularized spatially:
```
Input:
XOX
XX X O
OX OO
X OOX
OXOO
Alpha expansion...
Output:
XXX
XX O
XX OO
X OOO
OOOO
```
*/ */
} /* namespace CGAL */ } /* namespace CGAL */

View File

@ -0,0 +1,42 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
cmake_minimum_required(VERSION 3.1...3.15)
project( BGL_graphcut )
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
# include for local package
# Creating entries for all C++ files with "main" routine
# ##########################################################
create_single_source_cgal_program( "alpha_expansion_example.cpp" )

View File

@ -0,0 +1,95 @@
#include <CGAL/boost/graph/alpha_expansion_graphcut.h>
#include <boost/graph/adjacency_list.hpp>
struct Vertex_property
{
int label;
std::vector<double> cost;
};
struct Edge_property
{
double weight;
};
using Graph = boost::adjacency_list <boost::setS,
boost::vecS,
boost::undirectedS,
Vertex_property,
Edge_property>;
using GT = boost::graph_traits<Graph>;
using vertex_descriptor = GT::vertex_descriptor;
using edge_descriptor = GT::edge_descriptor;
int main()
{
std::array<char, 3> labels = { 'X', ' ', 'O' };
std::array<std::array<int, 6>, 5> input
= { { { 0, 2, 0, 1, 1, 1 },
{ 0, 0, 1, 0, 1, 2 },
{ 2, 0, 1, 1, 2, 2 },
{ 0, 1, 1, 2, 2, 0 },
{ 1, 1, 2, 0, 2, 2 } } };
std::array<std::array<vertex_descriptor, 6>, 5> vertices;
// Init vertices from values
Graph g;
for (std::size_t i = 0; i < input.size(); ++ i)
for (std::size_t j = 0; j < input[i].size(); ++ j)
{
vertices[i][j] = boost::add_vertex(g);
g[vertices[i][j]].label = input[i][j];
// Cost of assigning this vertex to any label is positive except
// for current label which is 0 (favor init solution)
g[vertices[i][j]].cost.resize(3, 1);
g[vertices[i][j]].cost[std::size_t(input[i][j])] = 0;
}
// Display input values
std::cerr << "Input:" << std::endl;
for (std::size_t i = 0; i < vertices.size(); ++ i)
{
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
std::cerr << labels[std::size_t(g[vertices[i][j]].label)];
std::cerr << std::endl;
}
// Init adjacency
double weight = 0.5;
for (std::size_t i = 0; i < vertices.size(); ++ i)
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
{
// Neighbor vertices are connected
if (i < vertices.size() - 1)
{
edge_descriptor ed = boost::add_edge (vertices[i][j], vertices[i+1][j], g).first;
g[ed].weight = weight;
}
if (j < vertices[i].size() - 1)
{
edge_descriptor ed = boost::add_edge (vertices[i][j], vertices[i][j+1], g).first;
g[ed].weight = weight;
}
}
std::cerr << std::endl << "Alpha expansion..." << std::endl << std::endl;
CGAL::alpha_expansion_graphcut (g,
get (&Edge_property::weight, g),
get (boost::vertex_index, g),
get (&Vertex_property::cost, g),
get (&Vertex_property::label, g));
// Display output graph
std::cerr << "Output:" << std::endl;
for (std::size_t i = 0; i < vertices.size(); ++ i)
{
for (std::size_t j = 0; j < vertices[i].size(); ++ j)
std::cerr << labels[std::size_t(g[vertices[i][j]].label)];
std::cerr << std::endl;
}
return 0;
}

View File

@ -473,7 +473,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
/** /**
\ingroup PkgBGLPartition \ingroup PkgBGLPartition
Regularizes a partition of a graph into `n` labels using the Alpha regularizes a partition of a graph into `n` labels using the Alpha
Expansion algorithm \cgalCite{Boykov2001FastApproximate}. Expansion algorithm \cgalCite{Boykov2001FastApproximate}.
For a graph \f$(V,E)\f$, this function seeks for the partioning `f` For a graph \f$(V,E)\f$, this function seeks for the partioning `f`
@ -487,7 +487,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
\f$\{v0,v1\}\f$ and \f$C(f_v)\f$ is the cost of assigning the \f$\{v0,v1\}\f$ and \f$C(f_v)\f$ is the cost of assigning the
vertex \f$v\f$ to the labeling \f$f\f$. vertex \f$v\f$ to the labeling \f$f\f$.
\tparam InputGraph a model of `Graph` \tparam InputGraph a model of `VertexAndEdgeListGraph`
\tparam EdgeWeightMap a model of `ReadablePropertyMap` with \tparam EdgeWeightMap a model of `ReadablePropertyMap` with
`boost::graph_traits<InputGraph>::%edge_descriptor` as key and `double` `boost::graph_traits<InputGraph>::%edge_descriptor` as key and `double`
@ -532,9 +532,11 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
\param vertex_label_cost_map a property map providing, for each \param vertex_label_cost_map a property map providing, for each
vertex, an `std::vector` containing the cost of this vertex to vertex, an `std::vector` containing the cost of this vertex to
belong to each label. For example, belong to each label. Each `std::vector` should have the same size
`get(vertex_label_cost_map, vd)[label_idx]` returns the cost `n` (which is the number of labels), each label being indexed from
of vertex `vd` to belong to the label `label_idx`. `0` to `n-1`. For example, `get(vertex_label_cost_map,
vd)[label_idx]` returns the cost of vertex `vd` to belong to the
label `label_idx`.
*/ */
template <typename InputGraph, template <typename InputGraph,
typename EdgeWeightMap, typename EdgeWeightMap,
@ -571,7 +573,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
std::vector<Vertex_descriptor> inserted_vertices; std::vector<Vertex_descriptor> inserted_vertices;
inserted_vertices.resize(num_vertices (input_graph)); inserted_vertices.resize(num_vertices (input_graph));
std::size_t number_of_labels = get(vertex_label_cost_map, *std::begin(vertices(input_graph))).size(); std::size_t number_of_labels = get(vertex_label_cost_map, *(vertices(input_graph).first)).size();
bool success; bool success;
do { do {
@ -588,7 +590,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
// For E-Data // For E-Data
// add every input vertex 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 (input_vertex_descriptor vd : vertices(input_graph)) for (input_vertex_descriptor vd : CGAL::make_range(vertices(input_graph)))
{ {
std::size_t vertex_i = get(vertex_index_map, vd); std::size_t vertex_i = get(vertex_index_map, vd);
Vertex_descriptor new_vertex = alpha_expansion.add_vertex(); Vertex_descriptor new_vertex = alpha_expansion.add_vertex();
@ -609,7 +611,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
// For E-Smooth // For E-Smooth
// add edge between every vertex, // add edge between every vertex,
for (input_edge_descriptor ed : edges(input_graph)) for (input_edge_descriptor ed : CGAL::make_range(edges(input_graph)))
{ {
input_vertex_descriptor vd1 = source(ed, input_graph); input_vertex_descriptor vd1 = source(ed, input_graph);
input_vertex_descriptor vd2 = target(ed, input_graph); input_vertex_descriptor vd2 = target(ed, input_graph);
@ -659,7 +661,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph,
min_cut = flow; min_cut = flow;
success = true; success = true;
//update labeling //update labeling
for (input_vertex_descriptor vd : vertices (input_graph)) for (input_vertex_descriptor vd : CGAL::make_range(vertices (input_graph)))
{ {
std::size_t vertex_i = get (vertex_index_map, vd); std::size_t vertex_i = get (vertex_index_map, vd);
alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha); alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha);