ReadFramework
energy.h
Go to the documentation of this file.
1 /* energy.h */
2 /* Vladimir Kolmogorov (vnk@cs.cornell.edu), 2003. */
3 
4 /*
5  This software implements an energy minimization technique described in
6 
7  What Energy Functions can be Minimized via Graph Cuts?
8  Vladimir Kolmogorov and Ramin Zabih.
9  To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI).
10  Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002.
11 
12  More specifically, it computes the global minimum of a function E of binary
13  variables x_1, ..., x_n which can be written as a sum of terms involving
14  at most three variables at a time:
15 
16  E(x_1, ..., x_n) = \sum_{i} E^{i} (x_i)
17  + \sum_{i,j} E^{i,j} (x_i, x_j)
18  + \sum_{i,j,k} E^{i,j,k}(x_i, x_j, x_k)
19 
20  The method works only if each term is "regular". Definitions of regularity
21  for terms E^{i}, E^{i,j}, E^{i,j,k} are given below as comments to functions
22  add_term1(), add_term2(), add_term3().
23 
24  This software can be used only for research purposes. IF YOU USE THIS SOFTWARE,
25  YOU SHOULD CITE THE AFOREMENTIONED PAPER IN ANY RESULTING PUBLICATION.
26 
27  In order to use it, you will also need a MAXFLOW software which can be
28  obtained from http://www.cs.cornell.edu/People/vnk/software.html
29 
30 
31  Example usage
32  (Minimizes the following function of 3 binary variables:
33  E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|):
34 
36 
37  #include <stdio.h>
38  #include "energy.h"
39 
40  void main()
41  {
42  // Minimize the following function of 3 binary variables:
43  // E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|
44 
45  Energy::Var varx, vary, varz;
46  Energy *e = new Energy();
47 
48  varx = e -> add_variable();
49  vary = e -> add_variable();
50  varz = e -> add_variable();
51 
52  e -> add_term1(varx, 0, 1); // add term x
53  e -> add_term1(vary, 0, -2); // add term -2*y
54  e -> add_term1(varz, 3, 0); // add term 3*(1-z)
55 
56  e -> add_term2(x, y, 0, 0, 0, -4); // add term -4*x*y
57  e -> add_term2(y, z, 0, 5, 5, 0); // add term 5*|y-z|
58 
59  Energy::TotalValue Emin = e -> minimize();
60 
61  printf("Minimum = %d\n", Emin);
62  printf("Optimal solution:\n");
63  printf("x = %d\n", e->get_var(varx));
64  printf("y = %d\n", e->get_var(vary));
65  printf("z = %d\n", e->get_var(varz));
66 
67  delete e;
68  }
69 
71 */
72 
73 #ifndef __ENERGY_H__
74 #define __ENERGY_H__
75 
76 #include <assert.h>
77 #include "graph.h"
78 
79 template <typename captype, typename tcaptype, typename flowtype> class Energy: public Graph<captype,tcaptype,flowtype>
80 {
82 public:
83  typedef typename GraphT::node_id Var;
84 
85  /* Types of energy values.
86  Value is a type of a value in a single term
87  TotalValue is a type of a value of the total energy.
88  By default Value = short, TotalValue = int.
89  To change it, change the corresponding types in graph.h */
90  typedef captype Value;
91  typedef flowtype TotalValue;
92 
93  /* interface functions */
94 
95  /* Constructor. Optional argument is the pointer to the
96  function which will be called if an error occurs;
97  an error message is passed to this function. If this
98  argument is omitted, exit(1) will be called. */
99  Energy(int var_num_max, int edge_num_max, void (*err_function)(const char *) = NULL);
100 
101  /* Destructor */
102  ~Energy();
103 
104  /* Adds a new binary variable */
105  Var add_variable(int num=1);
106 
107  /* Adds a constant E to the energy function */
108  void add_constant(Value E);
109 
110  /* Adds a new term E(x) of one binary variable
111  to the energy function, where
112  E(0) = E0, E(1) = E1
113  E0 and E1 can be arbitrary */
114  void add_term1(Var x,
115  Value E0, Value E1);
116 
117  /* Adds a new term E(x,y) of two binary variables
118  to the energy function, where
119  E(0,0) = E00, E(0,1) = E01
120  E(1,0) = E10, E(1,1) = E11
121  The term must be regular, i.e. E00 + E11 <= E01 + E10 */
122  void add_term2(Var x, Var y,
123  Value E00, Value E01,
124  Value E10, Value E11);
125 
126  /* Adds a new term E(x,y,z) of three binary variables
127  to the energy function, where
128  E(0,0,0) = E000, E(0,0,1) = E001
129  E(0,1,0) = E010, E(0,1,1) = E011
130  E(1,0,0) = E100, E(1,0,1) = E101
131  E(1,1,0) = E110, E(1,1,1) = E111
132  The term must be regular. It means that if one
133  of the variables is fixed (for example, y=1), then
134  the resulting function of two variables must be regular.
135  Since there are 6 ways to fix one variable
136  (3 variables times 2 binary values - 0 and 1),
137  this is equivalent to 6 inequalities */
138  void add_term3(Var x, Var y, Var z,
139  Value E000, Value E001,
140  Value E010, Value E011,
141  Value E100, Value E101,
142  Value E110, Value E111);
143 
144  /* After the energy function has been constructed,
145  call this function to minimize it.
146  Returns the minimum of the function */
147  TotalValue minimize();
148 
149  /* After 'minimize' has been called, this function
150  can be used to determine the value of variable 'x'
151  in the optimal solution.
152  Returns either 0 or 1 */
153  int get_var(Var x);
154 
155 /***********************************************************************/
156 /***********************************************************************/
157 /***********************************************************************/
158 
159 private:
160  /* internal variables and functions */
161 
162  TotalValue Econst;
163  void (*error_function)(const char *); /* this function is called if a error occurs,
164  with a corresponding error message
165  (or exit(1) is called if it's NULL) */
166 };
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 /***********************************************************************/
183 /************************ Implementation ******************************/
184 /***********************************************************************/
185 
186 template <typename captype, typename tcaptype, typename flowtype>
187 inline Energy<captype,tcaptype,flowtype>::Energy(int var_num_max, int edge_num_max, void (*err_function)(const char *)) : Graph<captype,tcaptype,flowtype>(var_num_max, edge_num_max, err_function)
188 {
189  Econst = 0;
190  error_function = err_function;
191 }
192 
193 template <typename captype, typename tcaptype, typename flowtype>
195 
196 template <typename captype, typename tcaptype, typename flowtype>
198 { return GraphT::add_node(num); }
199 
200 template <typename captype, typename tcaptype, typename flowtype>
201 inline void Energy<captype,tcaptype,flowtype>::add_constant(Value A) { Econst += A; }
202 
203 template <typename captype, typename tcaptype, typename flowtype>
205  Value A, Value B)
206 {
207  this->add_tweights(x, B, A);
208 }
209 
210 template <typename captype, typename tcaptype, typename flowtype>
212  Value A, Value B,
213  Value C, Value D)
214 {
215  /*
216  E = A A + 0 B-A
217  D D C-D 0
218  Add edges for the first term
219  */
220  this->add_tweights(x, D, A);
221  B -= A; C -= D;
222 
223  /* now need to represent
224  0 B
225  C 0
226  */
227 
228  assert(B + C >= 0); /* check regularity */
229  if (B < 0)
230  {
231  /* Write it as
232  B B + -B 0 + 0 0
233  0 0 -B 0 B+C 0
234  */
235  this->add_tweights(x, 0, B); /* first term */
236  this->add_tweights(y, 0, -B); /* second term */
237  this->add_edge(x, y, 0, B+C); /* third term */
238  }
239  else if (C < 0)
240  {
241  /* Write it as
242  -C -C + C 0 + 0 B+C
243  0 0 C 0 0 0
244  */
245  this->add_tweights(x, 0, -C); /* first term */
246  this->add_tweights(y, 0, C); /* second term */
247  this->add_edge(x, y, B+C, 0); /* third term */
248  }
249  else /* B >= 0, C >= 0 */
250  {
251  this->add_edge(x, y, B, C);
252  }
253 }
254 
255 template <typename captype, typename tcaptype, typename flowtype>
256 inline void Energy<captype,tcaptype,flowtype>::add_term3(Var x, Var y, Var z,
257  Value E000, Value E001,
258  Value E010, Value E011,
259  Value E100, Value E101,
260  Value E110, Value E111)
261 {
262  register Value pi = (E000 + E011 + E101 + E110) - (E100 + E010 + E001 + E111);
263  register Value delta;
264  register Var u;
265 
266  if (pi >= 0)
267  {
268  Econst += E111 - (E011 + E101 + E110);
269 
270  add_tweights(x, E101, E001);
271  add_tweights(y, E110, E100);
272  add_tweights(z, E011, E010);
273 
274  delta = (E010 + E001) - (E000 + E011); /* -pi(E[x=0]) */
275  assert(delta >= 0); /* check regularity */
276  add_edge(y, z, delta, 0);
277 
278  delta = (E100 + E001) - (E000 + E101); /* -pi(E[y=0]) */
279  assert(delta >= 0); /* check regularity */
280  add_edge(z, x, delta, 0);
281 
282  delta = (E100 + E010) - (E000 + E110); /* -pi(E[z=0]) */
283  assert(delta >= 0); /* check regularity */
284  add_edge(x, y, delta, 0);
285 
286  if (pi > 0)
287  {
288  u = add_variable();
289  add_edge(x, u, pi, 0);
290  add_edge(y, u, pi, 0);
291  add_edge(z, u, pi, 0);
292  add_tweights(u, 0, pi);
293  }
294  }
295  else
296  {
297  Econst += E000 - (E100 + E010 + E001);
298 
299  add_tweights(x, E110, E010);
300  add_tweights(y, E011, E001);
301  add_tweights(z, E101, E100);
302 
303  delta = (E110 + E101) - (E100 + E111); /* -pi(E[x=1]) */
304  assert(delta >= 0); /* check regularity */
305  add_edge(z, y, delta, 0);
306 
307  delta = (E110 + E011) - (E010 + E111); /* -pi(E[y=1]) */
308  assert(delta >= 0); /* check regularity */
309  add_edge(x, z, delta, 0);
310 
311  delta = (E101 + E011) - (E001 + E111); /* -pi(E[z=1]) */
312  assert(delta >= 0); /* check regularity */
313  add_edge(y, x, delta, 0);
314 
315  u = add_variable();
316  add_edge(u, x, -pi, 0);
317  add_edge(u, y, -pi, 0);
318  add_edge(u, z, -pi, 0);
319  this->add_tweights(u, -pi, 0);
320  }
321 }
322 
323 template <typename captype, typename tcaptype, typename flowtype>
325 return Econst + GraphT::maxflow(); }
326 
327 template <typename captype, typename tcaptype, typename flowtype>
328 inline int Energy<captype,tcaptype,flowtype>::get_var(Var x) { return (int) this->what_segment(x); }
329 
330 #endif
void add_term2(Var x, Var y, Value E00, Value E01, Value E10, Value E11)
Definition: energy.h:211
void add_constant(Value E)
Definition: energy.h:201
void add_edge(node_id i, node_id j, captype cap, captype rev_cap)
Definition: graph.h:400
node_id add_node(int num=1)
Definition: graph.h:360
void add_term3(Var x, Var y, Var z, Value E000, Value E001, Value E010, Value E011, Value E100, Value E101, Value E110, Value E111)
Definition: energy.h:256
int node_id
Definition: graph.h:63
Definition: graph.h:55
void add_term1(Var x, Value E0, Value E1)
Definition: energy.h:204
void add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink)
Definition: graph.h:388
GraphT::node_id Var
Definition: energy.h:83
flowtype TotalValue
Definition: energy.h:91
flowtype maxflow(bool reuse_trees=false, Block< node_id > *changed_list=NULL)
Definition: maxflow.cpp:475
Energy(int var_num_max, int edge_num_max, void(*err_function)(const char *)=NULL)
Definition: energy.h:187
Definition: energy.h:79
captype Value
Definition: energy.h:90
TotalValue minimize()
Definition: energy.h:324
termtype what_segment(node_id i, termtype default_segm=SOURCE)
Definition: graph.h:478
Var add_variable(int num=1)
Definition: energy.h:197
int get_var(Var x)
Definition: energy.h:328
~Energy()
Definition: energy.h:194