energy.h
Go to the documentation of this file.
00001 /* energy.h */
00002 /* Vladimir Kolmogorov (vnk@cs.cornell.edu), 2003. */
00003 
00004 /*
00005         This software implements an energy minimization technique described in
00006 
00007         What Energy Functions can be Minimized via Graph Cuts?
00008         Vladimir Kolmogorov and Ramin Zabih. 
00009         To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI). 
00010         Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002. 
00011 
00012         More specifically, it computes the global minimum of a function E of binary
00013         variables x_1, ..., x_n which can be written as a sum of terms involving
00014         at most three variables at a time:
00015 
00016                 E(x_1, ..., x_n) = \sum_{i}     E^{i}    (x_i)
00017                                  + \sum_{i,j}   E^{i,j}  (x_i, x_j)
00018                                  + \sum_{i,j,k} E^{i,j,k}(x_i, x_j, x_k)
00019 
00020         The method works only if each term is "regular". Definitions of regularity
00021         for terms E^{i}, E^{i,j}, E^{i,j,k} are given below as comments to functions
00022         add_term1(), add_term2(), add_term3(). 
00023 
00024         This software can be used only for research purposes. IF YOU USE THIS SOFTWARE,
00025         YOU SHOULD CITE THE AFOREMENTIONED PAPER IN ANY RESULTING PUBLICATION.
00026 
00027         In order to use it, you will also need a MAXFLOW software which can be
00028         obtained from http://www.cs.cornell.edu/People/vnk/software.html
00029 
00030 
00031         Example usage
00032         (Minimizes the following function of 3 binary variables:
00033         E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|):
00034 
00036 
00037         #include <stdio.h>
00038         #include "energy.h"
00039 
00040         void main()
00041         {
00042                 // Minimize the following function of 3 binary variables:
00043                 // E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|
00044                    
00045                 Energy::Var varx, vary, varz;
00046                 Energy *e = new Energy();
00047 
00048                 varx = e -> add_variable();
00049                 vary = e -> add_variable();
00050                 varz = e -> add_variable();
00051 
00052                 e -> add_term1(varx, 0, 1);  // add term x 
00053                 e -> add_term1(vary, 0, -2); // add term -2*y
00054                 e -> add_term1(varz, 3, 0);  // add term 3*(1-z)
00055 
00056                 e -> add_term2(x, y, 0, 0, 0, -4); // add term -4*x*y
00057                 e -> add_term2(y, z, 0, 5, 5, 0); // add term 5*|y-z|
00058 
00059                 Energy::TotalValue Emin = e -> minimize();
00060                 
00061                 printf("Minimum = %d\n", Emin);
00062                 printf("Optimal solution:\n");
00063                 printf("x = %d\n", e->get_var(varx));
00064                 printf("y = %d\n", e->get_var(vary));
00065                 printf("z = %d\n", e->get_var(varz));
00066 
00067                 delete e;
00068         }
00069 
00071 */
00072 
00073 #ifndef __ENERGY_H__
00074 #define __ENERGY_H__
00075 
00076 #include <assert.h>
00077 #include "graph.h"
00078 
00079 template <typename captype, typename tcaptype, typename flowtype> class Energy: public Graph<captype,tcaptype,flowtype>
00080 {
00081         typedef Graph<captype,tcaptype,flowtype> GraphT;
00082 public:
00083         typedef typename GraphT::node_id Var;
00084 
00085         /* Types of energy values.
00086            Value is a type of a value in a single term
00087            TotalValue is a type of a value of the total energy.
00088            By default Value = short, TotalValue = int.
00089            To change it, change the corresponding types in graph.h */
00090         typedef captype Value;
00091         typedef flowtype TotalValue;
00092 
00093         /* interface functions */
00094 
00095         /* Constructor. Optional argument is the pointer to the
00096            function which will be called if an error occurs;
00097            an error message is passed to this function. If this
00098            argument is omitted, exit(1) will be called. */
00099         Energy(int var_num_max, int edge_num_max, void (*err_function)(char *) = NULL);
00100 
00101         /* Destructor */
00102         ~Energy();
00103 
00104         /* Adds a new binary variable */
00105         Var add_variable(int num=1);
00106 
00107         /* Adds a constant E to the energy function */
00108         void add_constant(Value E);
00109 
00110         /* Adds a new term E(x) of one binary variable
00111            to the energy function, where
00112                E(0) = E0, E(1) = E1
00113            E0 and E1 can be arbitrary */
00114         void add_term1(Var x,
00115                        Value E0, Value E1);
00116 
00117         /* Adds a new term E(x,y) of two binary variables
00118            to the energy function, where
00119                E(0,0) = E00, E(0,1) = E01
00120                E(1,0) = E10, E(1,1) = E11
00121            The term must be regular, i.e. E00 + E11 <= E01 + E10 */
00122         void add_term2(Var x, Var y,
00123                        Value E00, Value E01,
00124                        Value E10, Value E11);
00125 
00126         /* Adds a new term E(x,y,z) of three binary variables
00127            to the energy function, where
00128                E(0,0,0) = E000, E(0,0,1) = E001
00129                E(0,1,0) = E010, E(0,1,1) = E011
00130                E(1,0,0) = E100, E(1,0,1) = E101
00131                E(1,1,0) = E110, E(1,1,1) = E111
00132            The term must be regular. It means that if one
00133            of the variables is fixed (for example, y=1), then
00134            the resulting function of two variables must be regular.
00135            Since there are 6 ways to fix one variable
00136            (3 variables times 2 binary values - 0 and 1),
00137            this is equivalent to 6 inequalities */
00138         void add_term3(Var x, Var y, Var z,
00139                        Value E000, Value E001,
00140                        Value E010, Value E011,
00141                        Value E100, Value E101,
00142                        Value E110, Value E111);
00143 
00144         /* After the energy function has been constructed,
00145            call this function to minimize it.
00146            Returns the minimum of the function */
00147         TotalValue minimize();
00148 
00149         /* After 'minimize' has been called, this function
00150            can be used to determine the value of variable 'x'
00151            in the optimal solution.
00152            Returns either 0 or 1 */
00153         int get_var(Var x);
00154 
00155 /***********************************************************************/
00156 /***********************************************************************/
00157 /***********************************************************************/
00158 
00159 private:
00160         /* internal variables and functions */
00161 
00162         TotalValue      Econst;
00163         void            (*error_function)(char *);      /* this function is called if a error occurs,
00164                                                                                         with a corresponding error message
00165                                                                                         (or exit(1) is called if it's NULL) */
00166 };
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 /***********************************************************************/
00183 /************************  Implementation ******************************/
00184 /***********************************************************************/
00185 
00186 template <typename captype, typename tcaptype, typename flowtype> 
00187 inline Energy<captype,tcaptype,flowtype>::Energy(int var_num_max, int edge_num_max, void (*err_function)(char *)) : Graph<captype,tcaptype,flowtype>(var_num_max, edge_num_max, err_function)
00188 {
00189         Econst = 0;
00190         error_function = err_function;
00191 }
00192 
00193 template <typename captype, typename tcaptype, typename flowtype> 
00194 inline Energy<captype,tcaptype,flowtype>::~Energy() {}
00195 
00196 template <typename captype, typename tcaptype, typename flowtype> 
00197 inline typename Energy<captype,tcaptype,flowtype>::Var Energy<captype,tcaptype,flowtype>::add_variable(int num) 
00198 {       return GraphT::add_node(num); }
00199 
00200 template <typename captype, typename tcaptype, typename flowtype> 
00201 inline void Energy<captype,tcaptype,flowtype>::add_constant(Value A) { Econst += A; }
00202 
00203 template <typename captype, typename tcaptype, typename flowtype> 
00204 inline void Energy<captype,tcaptype,flowtype>::add_term1(Var x,
00205                               Value A, Value B)
00206 {
00207         add_tweights(x, B, A);
00208 }
00209 
00210 template <typename captype, typename tcaptype, typename flowtype> 
00211 inline void Energy<captype,tcaptype,flowtype>::add_term2(Var x, Var y,
00212                               Value A, Value B,
00213                               Value C, Value D)
00214 {
00215         /* 
00216            E = A A  +  0   B-A
00217                D D     C-D 0
00218            Add edges for the first term
00219         */
00220         add_tweights(x, D, A);
00221         B -= A; C -= D;
00222 
00223         /* now need to represent
00224            0 B
00225            C 0
00226         */
00227 
00228         assert(B + C >= 0); /* check regularity */
00229         if (B < 0)
00230         {
00231                 /* Write it as
00232                    B B  +  -B 0  +  0   0
00233                    0 0     -B 0     B+C 0
00234                 */
00235                 add_tweights(x, 0, B); /* first term */
00236                 add_tweights(y, 0, -B); /* second term */
00237                 add_edge(x, y, 0, B+C); /* third term */
00238         }
00239         else if (C < 0)
00240         {
00241                 /* Write it as
00242                    -C -C  +  C 0  +  0 B+C
00243                     0  0     C 0     0 0
00244                 */
00245                 add_tweights(x, 0, -C); /* first term */
00246                 add_tweights(y, 0, C); /* second term */
00247                 add_edge(x, y, B+C, 0); /* third term */
00248         }
00249         else /* B >= 0, C >= 0 */
00250         {
00251                 add_edge(x, y, B, C);
00252         }
00253 }
00254 
00255 template <typename captype, typename tcaptype, typename flowtype> 
00256 inline void Energy<captype,tcaptype,flowtype>::add_term3(Var x, Var y, Var z,
00257                               Value E000, Value E001,
00258                               Value E010, Value E011,
00259                               Value E100, Value E101,
00260                               Value E110, Value E111)
00261 {
00262         register Value pi = (E000 + E011 + E101 + E110) - (E100 + E010 + E001 + E111);
00263         register Value delta;
00264         register Var u;
00265 
00266         if (pi >= 0)
00267         {
00268                 Econst += E111 - (E011 + E101 + E110);
00269 
00270                 add_tweights(x, E101, E001);
00271                 add_tweights(y, E110, E100);
00272                 add_tweights(z, E011, E010);
00273 
00274                 delta = (E010 + E001) - (E000 + E011); /* -pi(E[x=0]) */
00275                 assert(delta >= 0); /* check regularity */
00276                 add_edge(y, z, delta, 0);
00277 
00278                 delta = (E100 + E001) - (E000 + E101); /* -pi(E[y=0]) */
00279                 assert(delta >= 0); /* check regularity */
00280                 add_edge(z, x, delta, 0);
00281 
00282                 delta = (E100 + E010) - (E000 + E110); /* -pi(E[z=0]) */
00283                 assert(delta >= 0); /* check regularity */
00284                 add_edge(x, y, delta, 0);
00285 
00286                 if (pi > 0)
00287                 {
00288                         u = add_variable();
00289                         add_edge(x, u, pi, 0);
00290                         add_edge(y, u, pi, 0);
00291                         add_edge(z, u, pi, 0);
00292                         add_tweights(u, 0, pi);
00293                 }
00294         }
00295         else
00296         {
00297                 Econst += E000 - (E100 + E010 + E001);
00298 
00299                 add_tweights(x, E110, E010);
00300                 add_tweights(y, E011, E001);
00301                 add_tweights(z, E101, E100);
00302 
00303                 delta = (E110 + E101) - (E100 + E111); /* -pi(E[x=1]) */
00304                 assert(delta >= 0); /* check regularity */
00305                 add_edge(z, y, delta, 0);
00306 
00307                 delta = (E110 + E011) - (E010 + E111); /* -pi(E[y=1]) */
00308                 assert(delta >= 0); /* check regularity */
00309                 add_edge(x, z, delta, 0);
00310 
00311                 delta = (E101 + E011) - (E001 + E111); /* -pi(E[z=1]) */
00312                 assert(delta >= 0); /* check regularity */
00313                 add_edge(y, x, delta, 0);
00314 
00315                 u = add_variable();
00316                 add_edge(u, x, -pi, 0);
00317                 add_edge(u, y, -pi, 0);
00318                 add_edge(u, z, -pi, 0);
00319                 add_tweights(u, -pi, 0);
00320         }
00321 }
00322 
00323 template <typename captype, typename tcaptype, typename flowtype> 
00324 inline typename Energy<captype,tcaptype,flowtype>::TotalValue Energy<captype,tcaptype,flowtype>::minimize() { 
00325 return Econst + GraphT::maxflow(); }
00326 
00327 template <typename captype, typename tcaptype, typename flowtype> 
00328 inline int Energy<captype,tcaptype,flowtype>::get_var(Var x) { return (int) what_segment(x); }
00329 
00330 #endif


tabletop_pushing
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:59:44