-
Notifications
You must be signed in to change notification settings - Fork 31
/
GCO_README.TXT
394 lines (290 loc) · 20.5 KB
/
GCO_README.TXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
##############################################################################
# #
# GCoptimization - software for energy minimization with graph cuts #
# Version 3.0 #
# http://www.csd.uwo.ca/faculty/olga/software.html #
# #
# Copyright 2007-2010 Olga Veksler <[email protected]> #
# Andrew Delong <[email protected]> #
# #
##############################################################################
C++ requires at least Visual C++ 2005 (VC8) or GCC 4.03. Supports 32 or 64-bit.
See matlab/README.TXT for bundled MATLAB wrapper and its documentation.
IMPORTANT:
To use this software, YOU MUST CITE the following in any resulting publication:
[1] Efficient Approximate Energy Minimization via Graph Cuts.
Y. Boykov, O. Veksler, R.Zabih. IEEE TPAMI, 20(12):1222-1239, Nov 2001.
[2] What Energy Functions can be Minimized via Graph Cuts?
V. Kolmogorov, R.Zabih. IEEE TPAMI, 26(2):147-159, Feb 2004.
[3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms for
Energy Minimization in Vision. Y. Boykov, V. Kolmogorov.
IEEE TPAMI, 26(9):1124-1137, Sep 2004.
Furthermore, if you use the label cost feature (setLabelCost), you should cite
[4] Fast Approximate Energy Minimization with Label Costs.
A. Delong, A. Osokin, H. N. Isack, Y. Boykov. In CVPR, June 2010.
This software can be used only for research purposes. For commercial purposes,
be aware that there is a US patent on the main algorithm itself:
R. Zabih, Y. Boykov, O. Veksler,
"System and method for fast approximate energy minimization via graph cuts",
United Stated Patent 6,744,923, June 1, 2004
Together with this library implemented by O. Veksler, we provide, with the
permission of the V. Kolmogorov and Y. Boykov, the following two libraries:
1) energy.h
Developed by V. Kolmogorov, this implements the binary energy minimization
technique described in [2] above. We use this to implement the binary
energy minimization step for the alpha-expansion and swap algorithms.
The graph construction provided by "energy.h" is more efficient than
the original graph construction for alpha-expansion described in [1].
Again, this software can be used only for research purposes. IF YOU USE
THIS SOFTWARE (energy.h), YOU SHOULD CITE THE AFOREMENTIONED PAPER [2]
IN ANY RESULTING PUBLICATION.
2) maxflow.cpp, graph.cpp, graph.h, block.h
Developed by Y. Boykov and V. Kolmogorov while at Siemens Corporate Research,
algorithm [3] was later reimplemented by V. Kolmogorov based on open publications
and we use his implementation here with permission.
If you use either of these libraries for research purposes, you should cite
the aforementioned papers in any resulting publication.
##################################################################
2. License & disclaimer.
Copyright 2007-2010 Olga Veksler <[email protected]>
Andrew Delong <[email protected]>
This software and its modifications can be used and distributed for
research purposes only. Publications resulting from use of this code
must cite publications according to the rules given above. Only
Olga Veksler has the right to redistribute this code, unless expressed
permission is given otherwise. Commercial use of this code, any of
its parts, or its modifications is not permited. The copyright notices
must not be removed in case of any modifications. This Licence
commences on the date it is electronically or physically delivered
to you and continues in effect unless you fail to comply with any of
the terms of the License and fail to cure such breach within 30 days
of becoming aware of the breach, in which case the Licence automatically
terminates. This Licence is governed by the laws of Canada and all
disputes arising from or relating to this Licence must be brought
in Toronto, Ontario.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
##################################################################
3. Energy Minimization
This software is for minimizing sums of three types of terms:
E(labeling) = DataCosts(labeling) + SmoothCosts(labeling) + LabelCosts(labeling).
More specifically,
DataCosts(l) = sum_p D_p(l_p) where l_p is a potential label for site p,
and D_p is the cost of assigning l_p,
SmoothCosts(l) = sum_pq V_pq(l_p,l_q) where p and q are two distinct site, and
V_pq is the cost for assigning l_p, l_q, and
LabelCosts(l) = sum_L' h_L'(l) where L' is some subset of labels L, and h_L'
adds a cost iff at least one label from L'
appears in the labeling l.
Here we have a finite set of sites (or pixels) P and a finite set of labels L.
A labeling l is assignments of labels in L to pixels in P. The individual pixels
are referred to with small letters p and q, label of pixel p is denoted by l_p,
and the set of all label-pixel assignments is denoted by l, that is
l = {l_p | p in P}.
The first term in the energy function E(l) is typically called the data term, and
it consists of the sum over all pixels p of the penalty(or cost) D(p,l_p), what
should be the cost of assigning label l_p to pixel p. D(p,l_p) can be arbitrary.
The second term is a sum over all pairs of neighboring pixels {p,q}.
That is there is a neighborhood relation on the set of pixels (this relationship
is symmetric, that is if p is a neighbor of q then q is a neighbor of p).
Here we assume that the neighbor pairs are unordered. This means that if pixels p and q are
neighbors, then there is either Vpq(l_p,l_q) in the second sum of the energy,
or Vqp(l_q,l_p), but not both. This is not a restriction, since in practice, one can always go
from the ordered energy to the unordered one. This second term is typically called the smoothness
term.
The third term is a sum over all labels (or, more generally, all subsets of labels)
such that each label can have non-negative penalties associated with its use.
This "label cost" feature is used to encourage labelings that use as fewer unique labels
or, more generally, labels from as few unique subsets as possible.
The expansion algorithm for energy minimization can be used whenever for any 3 labels a,b,c
V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words, expansion algorithm can be used if
the binary energy for the expansion algorithm step is regular, using V. Kolmogorov's terminology.
The swap algorithm for energy minimization can be used whenever for any 2 labels a,b
V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap algorithm can be used if
the binary energy for the swap algorithm step is regular, using V. Kolmogorov's terminology.
##################################################################
4. Data Types
Inside the GCoptimization.h file you can customize the following typedefs:
typedef <numeric type> SiteID; // index of a site (pixel); default is int32
typedef <numeric type> LabelID; // index of a label; default is int32
typedef <numeric type> EnergyType; // total energy value; default is int64
typedef <numeric type> EnergyTermType; // individual energy term; default is int32
For efficiency it is best to use integral types when possible; be sure that they are
large enough to avoid integer overflow. By default, the library will warn if energy
terms are dangerously large (larger than GCO_MAX_ENERGYTERM=10000000). Even with float
types it's best to avoid extremely large energy terms, because it introduces rounding
errors, and the behaviour of the algorithm is undefined if Inf or NaN values appear
in the energy terms.
Keep in mind that float/double may cause expansion/swap to report small increase in energy,
due to arithmetic error during max-flow computation.
###########################################################################
5. Specifying the energy
Before optimizing the energy, one has to specify it, that is specify the number of
labels, number of pixels, neighborhood system, the data terms, and the smoothness terms.
There are 2 constructors to use, one in case of the grid graph, and another in case
of a general graph.
In all cases, it is assumed that the sites go between 0...num_sites-1,
and labels go between 0....num_labels-1.
For a grid (4-connected) graph, site at coordinates (x,y) is numbered with x+y*width, where width
is the width of the grid, that is the row-major ordering of arrays is assumed.
________________________________________________________________________________________________
Constructor A.
GCoptimizationGridGraph(int width, int height,int num_labels);
Use this constructor only for grid of size width by height. If you use this constructor,
4 connected grid neigbhorhood structure is assumed, so you don't need to specify neighborhood
structure separately (and indeed cannot do so).
_______________________________________________________________________________________________
Constructor B.
GCoptimizationGeneralGraph(int num_sites,int num_labels);
Use this constructor for general graphs. If you use this constructor, you must setup up
neighborhood system using function. You can either specify neighbors individually or all at once.
i) setNeighbors(SiteID s1, SiteID s2, EnergyTermType weight=1);
Specifies neighbors individually. You must call this function exactly once for any
pair of neighboring sites s1 and s2. That is if you call setNeighbors(s1,s2) then you should not call
setNeighbors(s2,s1). If Vpq(l_p,l_q) = V(l_p,l_q)*w_pq, where V(l_p,l_q) is some function that
depends only on the labels l_p,l_q, then specify w_pq by using: setNeighbors(p,q,w_pq).
ii) To pass in all neighbor information at once, use function:
void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights);
Here:
(a) numNeighbors is an array of size num_sites, and numNeighbors[i] is the number of neighbors for site i
(b) neighborIndexes is an array of size num_pixels which stores of pointers. Namely,
neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i
(c) neighborWeights is an array of size num_sites, and neighborWeighs[i] is a pointer to array
storing the weights between site i and its neighbors in the same order as neighborIndexes[i]
stores the indexes of neighbors. Example: if sites i and j are neighbors, then
for some k and m, neighborsIndexes[i][k] == j and neighborsIndexes[j][m] = i. Then
neighborWeights[i][k] = w_ij and neighborWeights[j][m] = w_ij, where w_ij is the weight
betwen neighbors i and j, that is V_ij = w_ij *V(l_i,l_j)
_______________________________________________________________________________________________
6. Setting the data costs, smooth costs, and label costs.
The following functions can be called any time before or after expansion.
------------------------Data Costs (unary terms)-----------------------
(a) void setDataCost(EnergyTermType *dataArray);
dataArray is an array s.t. the data cost for pixel p and label l is stored at
dataArray[pixel*num_labels+l]. If the current neighborhood system is a grid, then
the data term for label l and pixel with coordinates (x,y) is stored at
dataArray[(x+y*width)*num_labels + l]. Thus the size of array dataArray is num_pixels*num_labels.
Can call this function only one time.
(b) void setDataCost(DataCostFn fn);
DataCostFn is a pointer to a function f(Pixel p, Label l), s.t. the data cost for pixel p to have
label l is given by f(p,l). Can call this function only one time.
(c) void setDataCost(DataCostFnExtra fn,void *extraData);
DataCostFnExtra is a pointer to a function f(SiteID p, LabelID l,void *extraData), s.t. the data
cost for pixel p to have label l is given by f(p,l,extraData). Can call this function only one time.
(d) void setDataCost(SiteID s, LabelID l, EnergyTermType e);
sets up D(s,l) = 3; You must call this function for each pixel and each label.
(e) void setDataCostFunctor(DataCostFunctor* f);
Experienced C++ users can subclass our DataCostFunctor base class to achieve
a similar functionality as (b) or (c) above. By overriding the compute() method
of DataCostFunctor, your compute() method will be called by the GCoptimization
class each time a data penalty must be computed.
(f) struct SparseDataCost {
SiteID site;
EnergyTermType cost;
};
void setDataCost(LabelID l, SparseDataCost *costs, SiteID count);
For some applications, each label is feasible for only a small fraction
of the overall sites. One way to do this is to simply assign high cost to
any infeasible site. A much more efficient way is to specify exactly
which sites are feasible for each label. Do this by calling
setDataCost(label, costs_for_label, num_costs_for_label) once for each
label. The cost array will be copied internally, so your cost array
can be freed.
Note that giveDataEnergy() will add a huge constant for each site
that is assigned an infeasible label in the current labeling.
------------------------Smooth Costs (pairwise terms)-----------------------
(a) void setSmoothCost(EnergyTermType *V)
V is an array of smoothness costs, such that V_pq(label1,label2) is stored at V[label1+num_labels*label2]
If graph is a grid, then using this function only if the smooth costs are not spacially varying
that is the smoothness penalty V depends only on labels, but not on sites. If the graph is
not a grid, then you can specify spacially varying coefficients w_pq when you set up the
neighborhood system using setNeighbor(p,q,w_pq) function. In this case,
V_pq(label1,label2) = V[label1+num_labels*label2]*w_pq. This function can be called only one time.
(b) void setSmoothCost(SmoothCostFn fn);
fn is pointer to a function f(s1,s2,l1,l2) such that smoothness penalty for neigboring sites
s1 and s2 to have labels, respectively, l1 and l2 is f(s1,s2,l1,l2). This function can be
called only one time.
(c) void setSmoothCost(SmoothCostFnExtra fn,void *extraData);
Same as above, but can pass an extra pointer to the data needed for computation
(d) void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e)
sets up V(l1,l2) = e. Must call this function for each pair of labels (l1,l2). Notice
that for any l1 and l2, you must call this function on (l1,l2) AND (l2,l1).
V(l1,l2) has to be equal to V(l2,l1) in this case.
(e) void setSmoothCostVH(EnergyTermType *V, EnergyTermType *vCosts, EnergyTermType *hCosts);
This function should be used only if the graph is a grid (GCoptimizationGridGraph class).
Array V is the same as above, under (a).
Arrays hCosts and vCosts have the same size as the image (that is width*height), and are used to set
the spatially varying coefficients w_pq. If p = (x,y) and q = (x+1,y), then
w_pq = hCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x+1,y) to have labels
label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*hCosts[x+y*width]
If p = (x,y) and q = (x,y+q), then
w_pq = vCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x,y+1) to have labels
label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*vCosts[x+y*width]
This function can be only called one time.
(f) void setSmoothCostFunctor(SmoothCostFunctor* f);
Experienced C++ users can subclass our SmoothCostFunctor base class to achieve
a similar functionality as (b) or (c) above. By overriding the compute() method
of SmoothCostFunctor, your compute() method will be called by the GCoptimization
class each time a smoothness penalty must be computed.
------------------------Label Costs (global indicator potentials)--------------------
(a) void setLabelCost(EnergyTermType cost);
Penalize the appearance of all labels equally. Replaces all current label
costs, if any.
(b) void setLabelCost(EnergyTermType* costArray);
Set each individual label cost separately. The costArray must have one
entry for each possible label. Replaces all current label costs, if any.
The cost array will be copied intenally, so your array can be freed.
(c) void setLabelSubsetCost(LabelID* labels, LabelID numLabels, EnergyTermType cost);
Set cost for a specific subset of labels. The cost will be imposed iff the
current labeling contains at least one label from the 'labels' array.
The labels array will be copied internally, so your array can be freed.
##################################################################
6. Optimizing the energy
You can optimize the energy and get the resulting labeling using the following functions. Notice that they can
be called as many times as one wishes after the constructor has been called and the data/smoothness terms
(and the neighborhood system, if general graph) has beeen set. The initial labeling is set to consists of
all 0's. Use function setLabel(SiteID pixelP, LabelID labelL), described under heading (x) in this section
to initialize the labeling to anything else (but in the valid range, of course, labels must be between
0 and num_labels-1)
a) EnergyType expansion(int max_num_iterations=-1);
Runs the expansion algorithm until convergence (convergence is guaranteed)
or, if max_num_iterations > 0, until a certain number of cycles (iterations).
Returns the energy of the resulting labeling.
b) bool alpha_expansion(LabelID alpha_label);
Performs expansion on the label specified by alpha_label.
Returns true if the energy was decreased, false otherwise.
c) EnergyType swap(int max_num_iterations=-1);
Runs the alpha-beta swap algorithm until convergence (convergence is guaranteed)
or, if max_num_iterations > 0, until a certain number of cycles (iterations).
Returns the energy of the resulting labeling.
d) void alpha_beta_swap(LabelID alpha_label, LabelID beta_label);
Performs swap on a pair of labels, specified by the input parameters alpha_label, beta_label.
e) EnergyType compute_energy();
EnergyType giveDataEnergy();
EnergyType giveSmoothEnergy();
EnergyType giveLabelEnergy();
Returns respectively the total, data part, smooth part, and label part of the energy of the current labling.
f) LabelID whatLabel(SiteID site);
Returns the current label assigned to site. Can be called at any time after the constructor call.
g) void setLabel(SiteID s, LabelID l);
Sets the label of site s to the the input parameter l. Can be called at any time after
the constructor call. This is useful for initializing the labeling to something specific
before optimization starts.
h) void setLabelOrder(bool RANDOM_LABEL_ORDER);
By default, the labels for the swap and expansion algorithms are visited in not random order,
but random label visitation might give better results. To set the label order to
be not random, call setLabelOrder(false). To set it to be random, call setLabelOrder(true). Notice,
that by using functions under heading (iii) and (vii) you can completely and exactly specify the desired
order on labels.
##################################################################
7. Example usage.
See example.cpp for C++ example, or see matlab\README.TXT for MATLAB example.