ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
graph_cut.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <boost/graph/adjacency_list.hpp>
11 #include <boost/graph/boykov_kolmogorov_max_flow.hpp>
12 #include <boost/graph/graph_traits.hpp>
13 #include <boost/graph/one_bit_color_map.hpp>
14 #include <unordered_map>
15 #include <vector>
16 
17 #include "util/logging.h"
18 
19 namespace colmap {
20 
21 // Compute the min-cut of a undirected graph using the Stoer Wagner algorithm.
23  const std::vector<std::pair<int, int>>& edges,
24  const std::vector<int>& weights,
25  int* cut_weight,
26  std::vector<char>* cut_labels);
27 
28 // Compute the normalized min-cut of an undirected graph using Graclus.
29 // Partitions the graph into clusters and returns the cluster labels per vertex.
30 std::unordered_map<int, int> ComputeNormalizedMinGraphCut(
31  const std::vector<std::pair<int, int>>& edges,
32  const std::vector<int>& weights,
33  const int num_parts);
34 
35 // Compute the minimum graph cut of a directed S-T graph using the
36 // Boykov-Kolmogorov max-flow min-cut algorithm, as descibed in:
37 // "An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy
38 // Minimization in Vision". Yuri Boykov and Vladimir Kolmogorov. PAMI, 2004.
39 template <typename node_t, typename value_t>
41 public:
42  typedef boost::
43  adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS>
45  typedef graph_traits_t::edge_descriptor edge_descriptor_t;
46  typedef graph_traits_t::vertices_size_type vertices_size_t;
47 
48  struct Edge {
49  value_t capacity;
50  value_t residual;
52  };
53 
54  typedef boost::adjacency_list<boost::vecS,
55  boost::vecS,
56  boost::directedS,
57  size_t,
58  Edge>
60 
61  MinSTGraphCut(const size_t num_nodes);
62 
63  // Count the number of nodes and edges in the graph.
64  size_t NumNodes() const;
65  size_t NumEdges() const;
66 
67  // Add node to the graph.
68  void AddNode(const node_t node_idx,
69  const value_t source_capacity,
70  const value_t sink_capacity);
71 
72  // Add edge to the graph.
73  void AddEdge(const node_t node_idx1,
74  const node_t node_idx2,
75  const value_t capacity,
76  const value_t reverse_capacity);
77 
78  // Compute the min-cut using the max-flow algorithm. Returns the flow.
79  value_t Compute();
80 
81  // Check whether node is connected to source or sink after computing the
82  // cut.
83  bool IsConnectedToSource(const node_t node_idx) const;
84  bool IsConnectedToSink(const node_t node_idx) const;
85 
86 private:
87  const node_t S_node_;
88  const node_t T_node_;
89  graph_t graph_;
90  std::vector<boost::default_color_type> colors_;
91 };
92 
94 // Implementation
96 
97 template <typename node_t, typename value_t>
99  : S_node_(num_nodes), T_node_(num_nodes + 1), graph_(num_nodes + 2) {}
100 
101 template <typename node_t, typename value_t>
103  return boost::num_vertices(graph_) - 2;
104 }
105 
106 template <typename node_t, typename value_t>
108  return boost::num_edges(graph_);
109 }
110 
111 template <typename node_t, typename value_t>
112 void MinSTGraphCut<node_t, value_t>::AddNode(const node_t node_idx,
113  const value_t source_capacity,
114  const value_t sink_capacity) {
115  CHECK_GE(node_idx, 0);
116  CHECK_LE(node_idx, boost::num_vertices(graph_));
117  CHECK_GE(source_capacity, 0);
118  CHECK_GE(sink_capacity, 0);
119 
120  if (source_capacity > 0) {
121  const edge_descriptor_t edge =
122  boost::add_edge(S_node_, node_idx, graph_).first;
123  const edge_descriptor_t edge_reverse =
124  boost::add_edge(node_idx, S_node_, graph_).first;
125  graph_[edge].capacity = source_capacity;
126  graph_[edge].reverse = edge_reverse;
127  graph_[edge_reverse].reverse = edge;
128  }
129 
130  if (sink_capacity > 0) {
131  const edge_descriptor_t edge =
132  boost::add_edge(node_idx, T_node_, graph_).first;
133  const edge_descriptor_t edge_reverse =
134  boost::add_edge(T_node_, node_idx, graph_).first;
135  graph_[edge].capacity = sink_capacity;
136  graph_[edge].reverse = edge_reverse;
137  graph_[edge_reverse].reverse = edge;
138  }
139 }
140 
141 template <typename node_t, typename value_t>
142 void MinSTGraphCut<node_t, value_t>::AddEdge(const node_t node_idx1,
143  const node_t node_idx2,
144  const value_t capacity,
145  const value_t reverse_capacity) {
146  CHECK_GE(node_idx1, 0);
147  CHECK_LE(node_idx1, boost::num_vertices(graph_));
148  CHECK_GE(node_idx2, 0);
149  CHECK_LE(node_idx2, boost::num_vertices(graph_));
150  CHECK_GE(capacity, 0);
151  CHECK_GE(reverse_capacity, 0);
152 
153  const edge_descriptor_t edge =
154  boost::add_edge(node_idx1, node_idx2, graph_).first;
155  const edge_descriptor_t edge_reverse =
156  boost::add_edge(node_idx2, node_idx1, graph_).first;
157  graph_[edge].capacity = capacity;
158  graph_[edge_reverse].capacity = reverse_capacity;
159  graph_[edge].reverse = edge_reverse;
160  graph_[edge_reverse].reverse = edge;
161 }
162 
163 template <typename node_t, typename value_t>
165  const vertices_size_t num_vertices = boost::num_vertices(graph_);
166 
167  colors_.resize(num_vertices);
168  std::vector<edge_descriptor_t> predecessors(num_vertices);
169  std::vector<vertices_size_t> distances(num_vertices);
170 
171  return boost::boykov_kolmogorov_max_flow(
172  graph_, boost::get(&Edge::capacity, graph_),
173  boost::get(&Edge::residual, graph_),
174  boost::get(&Edge::reverse, graph_), predecessors.data(),
175  colors_.data(), distances.data(),
176  boost::get(boost::vertex_index, graph_), S_node_, T_node_);
177 }
178 
179 template <typename node_t, typename value_t>
181  const node_t node_idx) const {
182  return colors_.at(node_idx) != boost::white_color;
183 }
184 
185 template <typename node_t, typename value_t>
187  const node_t node_idx) const {
188  return colors_.at(node_idx) == boost::white_color;
189 }
190 
191 } // namespace colmap
long vertex_index
graph_traits_t::vertices_size_type vertices_size_t
Definition: graph_cut.h:46
bool IsConnectedToSource(const node_t node_idx) const
Definition: graph_cut.h:180
void AddNode(const node_t node_idx, const value_t source_capacity, const value_t sink_capacity)
Definition: graph_cut.h:112
graph_traits_t::edge_descriptor edge_descriptor_t
Definition: graph_cut.h:45
size_t NumNodes() const
Definition: graph_cut.h:102
boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, size_t, Edge > graph_t
Definition: graph_cut.h:59
size_t NumEdges() const
Definition: graph_cut.h:107
boost::adjacency_list_traits< boost::vecS, boost::vecS, boost::directedS > graph_traits_t
Definition: graph_cut.h:44
MinSTGraphCut(const size_t num_nodes)
Definition: graph_cut.h:98
bool IsConnectedToSink(const node_t node_idx) const
Definition: graph_cut.h:186
void AddEdge(const node_t node_idx1, const node_t node_idx2, const value_t capacity, const value_t reverse_capacity)
Definition: graph_cut.h:142
std::unordered_map< int, int > ComputeNormalizedMinGraphCut(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, const int num_parts)
Definition: graph_cut.cc:186
void ComputeMinGraphCutStoerWagner(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, int *cut_weight, std::vector< char > *cut_labels)
Definition: graph_cut.cc:150
edge_descriptor_t reverse
Definition: graph_cut.h:51