energy.h 9.3 KB

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