diff --git a/BGL/doc/BGL/BGL.txt b/BGL/doc/BGL/BGL.txt index 34b833b28b8..e404294a878 100644 --- a/BGL/doc/BGL/BGL.txt +++ b/BGL/doc/BGL/BGL.txt @@ -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, 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 -graphcut approach called Alpha Expansion +An optimal partition from a set of labels can be computed through a +graph cut approach called Alpha Expansion \cgalCite{boykov2001fastapproximate}. \cgal provides `CGAL::alpha_expansion_graphcut()` which, or a graph \f$(V,E)\f$, this 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. \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 */ diff --git a/BGL/examples/BGL_graphcut/CMakeLists.txt b/BGL/examples/BGL_graphcut/CMakeLists.txt new file mode 100644 index 00000000000..36663654a74 --- /dev/null +++ b/BGL/examples/BGL_graphcut/CMakeLists.txt @@ -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" ) + + diff --git a/BGL/examples/BGL_graphcut/alpha_expansion_example.cpp b/BGL/examples/BGL_graphcut/alpha_expansion_example.cpp new file mode 100644 index 00000000000..e70914d52c1 --- /dev/null +++ b/BGL/examples/BGL_graphcut/alpha_expansion_example.cpp @@ -0,0 +1,95 @@ +#include +#include + +struct Vertex_property +{ + int label; + std::vector cost; +}; + +struct Edge_property +{ + double weight; +}; + +using Graph = boost::adjacency_list ; +using GT = boost::graph_traits; +using vertex_descriptor = GT::vertex_descriptor; +using edge_descriptor = GT::edge_descriptor; + +int main() +{ + std::array labels = { 'X', ' ', 'O' }; + + std::array, 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, 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; +} diff --git a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h index d86fb9162ea..ff45252929b 100644 --- a/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h +++ b/BGL/include/CGAL/boost/graph/alpha_expansion_graphcut.h @@ -473,7 +473,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, /** \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}. 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 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 `boost::graph_traits::%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 vertex, an `std::vector` containing the cost of this vertex to - belong to each label. For example, - `get(vertex_label_cost_map, vd)[label_idx]` returns the cost - of vertex `vd` to belong to the label `label_idx`. + belong to each label. Each `std::vector` should have the same size + `n` (which is the number of labels), each label being indexed from + `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 inserted_vertices; 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; do { @@ -588,7 +590,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, // For E-Data // 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); Vertex_descriptor new_vertex = alpha_expansion.add_vertex(); @@ -609,7 +611,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, // For E-Smooth // 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 vd2 = target(ed, input_graph); @@ -659,7 +661,7 @@ double alpha_expansion_graphcut (const InputGraph& input_graph, min_cut = flow; success = true; //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); alpha_expansion.update(vertex_label_map, inserted_vertices, vd, vertex_i, alpha);