Alpha Expansion Library
C++ library for the Alpha-Expansion graph-cut algorithm with Python bindings
Loading...
Searching...
No Matches
AlphaExpansion.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <memory>
6#include <functional>
7#include <type_traits>
8
19template <typename T>
21public:
25 using SolverFactory = std::function<std::unique_ptr<MaxFlowSolver<T>>(int num_vars, int num_edges)>;
26
31 : model_(model), solver_factory_(std::move(solver_factory)) {
32 }
33
38 void set_on_iteration(std::function<void()> cb) { on_iteration_ = std::move(cb); }
39
47 [[nodiscard]] bool perform_expansion_move(const int alpha_label) const {
48 on_iteration_();
49 const std::vector<int> active_nodes = model_.get_active_nodes(alpha_label);
50 if (active_nodes.empty()) return false;
51
52 std::vector<typename MaxFlowSolver<T>::Var> node_var_ids;
53 T old_subgraph_energy = 0;
54 const auto solver = build_expansion_graph(alpha_label, active_nodes, node_var_ids, old_subgraph_energy);
55
56 const T new_subgraph_energy = solver->minimize();
57
58 bool improved;
59 if constexpr (std::is_floating_point_v<T>) {
60 improved = (old_subgraph_energy - new_subgraph_energy > static_cast<T>(1e-5));
61 } else {
62 improved = (new_subgraph_energy < old_subgraph_energy);
63 }
64 if (!improved) return false;
65
66 bool changed = false;
67 for (const int node: active_nodes) {
68 if (const typename MaxFlowSolver<T>::Var var = node_var_ids[node]; solver->get_var(var) == 0) {
69 model_.set_label(node, alpha_label);
70 changed = true;
71 }
72 }
73 return changed;
74 }
75
76private:
80 std::unique_ptr<MaxFlowSolver<T>> build_expansion_graph(const int alpha_label, const std::vector<int> &active_nodes,
81 std::vector<typename MaxFlowSolver<T>::Var> &node_var_ids,
82 T &old_subgraph_energy) const {
83 const int num_active = active_nodes.size();
84 if (num_active == 0) return nullptr;
85
86 const int estimated_edges = num_active * 4;
87 auto solver = solver_factory_(num_active, estimated_edges);
88
89 node_var_ids.assign(model_.num_nodes(), -1);
90
91 for (int i = 0; i < num_active; ++i) {
92 int node = active_nodes[i];
93 node_var_ids[node] = solver->add_variable();
94 }
95
96 T old_energy = 0;
97
98 for (const int node: active_nodes) {
99 const typename MaxFlowSolver<T>::Var var = node_var_ids[node];
100 const int current_label = model_.get_label(node);
101 const T e0 = model_.get_unary_cost(node, alpha_label);
102 const T e1 = model_.get_unary_cost(node, current_label);
103 solver->add_term1(var, e0, e1);
104 old_energy += e1;
105 }
106
107 for (const int node_i: active_nodes) {
108 const int current_label_i = model_.get_label(node_i);
109 const typename MaxFlowSolver<T>::Var var_i = node_var_ids[node_i];
110
111 for (const int node_j: model_.get_neighbors_range(node_i)) {
112 if (node_var_ids[node_j] != -1) {
113 if (node_i < node_j) {
114 const typename MaxFlowSolver<T>::Var var_j = node_var_ids[node_j];
115 const int current_label_j = model_.get_label(node_j);
116 const T e00 = model_.get_pairwise_cost(node_i, node_j, alpha_label, alpha_label);
117 const T e01 = model_.get_pairwise_cost(node_i, node_j, alpha_label, current_label_j);
118 const T e10 = model_.get_pairwise_cost(node_i, node_j, current_label_i, alpha_label);
119 const T e11 = model_.get_pairwise_cost(node_i, node_j, current_label_i, current_label_j);
120 solver->add_term2(var_i, var_j, e00, e01, e10, e11);
121 old_energy += e11;
122 }
123 } else {
124 const int current_label_j = model_.get_label(node_j);
125 const T e0 = model_.get_pairwise_cost(node_i, node_j, alpha_label, current_label_j);
126 const T e1 = model_.get_pairwise_cost(node_i, node_j, current_label_i, current_label_j);
127 solver->add_term1(var_i, e0, e1);
128 old_energy += e1;
129 }
130 }
131 }
132
133 old_subgraph_energy = old_energy;
134 return solver;
135 }
136
137 EnergyModel<T> &model_;
138 SolverFactory solver_factory_;
139 std::function<void()> on_iteration_ = []{};
140};
Performs alpha-expansion moves on an EnergyModel using a pluggable max-flow solver.
Definition AlphaExpansion.hpp:20
bool perform_expansion_move(const int alpha_label) const
Attempts a single alpha-expansion move for alpha_label.
Definition AlphaExpansion.hpp:47
void set_on_iteration(std::function< void()> cb)
Installs a callback invoked at the start of every perform_expansion_move.
Definition AlphaExpansion.hpp:38
std::function< std::unique_ptr< MaxFlowSolver< T > >(int num_vars, int num_edges)> SolverFactory
Definition AlphaExpansion.hpp:25
AlphaExpansion(EnergyModel< T > &model, SolverFactory solver_factory)
Constructs the optimizer.
Definition AlphaExpansion.hpp:30
Stores the graph and energy costs for the Alpha-Expansion algorithm.
Definition EnergyModel.hpp:17
int Var
Integer handle identifying a binary variable.
Definition MaxFlowSolver.hpp:20