├── Output
├── graphCut-man.jpg
├── graphCut4.jpg
├── lableMap-man.jpg
├── lableMap4.jpg
├── result-man.jpg
└── result4.jpg
├── Project1
├── Project1.vcxproj
├── Project1.vcxproj.filters
├── Project1.vcxproj.user
└── src
│ ├── PoissonBlending.cpp
│ ├── PoissonBlending.h
│ ├── gco
│ ├── GCO_README.TXT
│ ├── GCoptimization.cpp
│ ├── GCoptimization.h
│ ├── LinkedBlockList.cpp
│ ├── LinkedBlockList.h
│ ├── block.h
│ ├── energy.h
│ ├── example.cpp
│ ├── graph.cpp
│ ├── graph.h
│ └── maxflow.cpp
│ ├── inpainter.cpp
│ ├── inpainter.h
│ ├── main.cpp
│ ├── pm_minimal.cpp
│ ├── utils.cpp
│ └── utils.h
├── ReadMe.md
├── inpainting.sln
├── pami14completion.pdf
└── testsImage
├── image1.jpg
├── image2.jpg
├── image3.jpg
├── image4.jpg
├── man-mask.png
├── man.png
├── mask1.jpg
├── mask2.jpg
├── mask3.jpg
├── mask4.jpg
├── result1.jpg
├── result2.jpg
└── result3.jpg
/Output/graphCut-man.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/graphCut-man.jpg
--------------------------------------------------------------------------------
/Output/graphCut4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/graphCut4.jpg
--------------------------------------------------------------------------------
/Output/lableMap-man.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/lableMap-man.jpg
--------------------------------------------------------------------------------
/Output/lableMap4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/lableMap4.jpg
--------------------------------------------------------------------------------
/Output/result-man.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/result-man.jpg
--------------------------------------------------------------------------------
/Output/result4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Output/result4.jpg
--------------------------------------------------------------------------------
/Project1/Project1.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | 15.0
43 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}
44 | Project1
45 | 10.0.17763.0
46 | inpainting
47 |
48 |
49 |
50 | Application
51 | true
52 | v141
53 | MultiByte
54 |
55 |
56 | Application
57 | false
58 | v141
59 | true
60 | MultiByte
61 |
62 |
63 | Application
64 | true
65 | v141
66 | MultiByte
67 |
68 |
69 | Application
70 | false
71 | v141
72 | true
73 | MultiByte
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | .\Project1\src\gco;$(IncludePath)
97 |
98 |
99 | $(IncludePath)
100 |
101 |
102 |
103 | Level3
104 | Disabled
105 | true
106 | true
107 |
108 |
109 |
110 |
111 | Level3
112 | Disabled
113 | true
114 | true
115 |
116 |
117 |
118 |
119 | Level3
120 | MaxSpeed
121 | true
122 | true
123 | true
124 | true
125 |
126 |
127 | true
128 | true
129 |
130 |
131 |
132 |
133 | Level3
134 | MaxSpeed
135 | true
136 | true
137 | true
138 | true
139 |
140 |
141 | true
142 | true
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/Project1/Project1.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {81b1a976-3afe-42c5-a99f-aa8370fe1fc5}
18 |
19 |
20 |
21 |
22 | 源文件
23 |
24 |
25 | 源文件
26 |
27 |
28 | 源文件
29 |
30 |
31 | 源文件\GCO
32 |
33 |
34 | 源文件\GCO
35 |
36 |
37 | 源文件\GCO
38 |
39 |
40 | 源文件\GCO
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 |
--------------------------------------------------------------------------------
/Project1/Project1.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Project1/src/PoissonBlending.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "PoissonBlending.h"
3 |
4 | using namespace Eigen;
5 |
6 |
7 | void Blending::BuildLookUpTable()
8 | {
9 | int Num = 0;
10 | for (int i = 0; i < srcImage.rows; i++)
11 | {
12 | for (int j = 0; j < srcImage.cols; j++)
13 | {
14 |
15 | if (mask.at(i, j)) //
16 | {
17 | maskPointToNodeIdx[make_pair(j, i)] = Num++;
18 | }
19 | else
20 | {
21 | maskPointToNodeIdx[make_pair(j, i)] = -1;
22 | }
23 | }
24 | }
25 |
26 | nUnknowns = Num;
27 | }
28 |
29 | Blending::Blending(Mat inputImage, Mat forgroundMask, Mat Guidance)
30 | {
31 | srcImage = inputImage;
32 | srcImage.convertTo(boundaryValues, CV_32FC3);
33 | mask = forgroundMask;
34 |
35 | F = Guidance;
36 | srcImage.convertTo(Result, CV_32FC3);
37 |
38 | BuildLookUpTable();
39 | }
40 |
41 |
42 |
43 |
44 |
45 | void Blending::Compute()
46 | {
47 | const cv::Rect bounds(0, 0, srcImage.cols, srcImage.rows);
48 |
49 | // Directional indices
50 | const int center = 0;
51 | const int north = 1;
52 | const int east = 2;
53 | const int south = 3;
54 | const int west = 4;
55 |
56 | // Neighbor offsets in all directions
57 | const int offsets[5][2] = { { 0, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
58 |
59 | // Directional opposite
60 | const int opposite[5] = { center, south, west, north, east };
61 | // blending
62 |
63 | std::vector< Eigen::Triplet > lhsTriplets;
64 | lhsTriplets.reserve(nUnknowns * 5);
65 |
66 | int channels = srcImage.channels();
67 | Eigen::MatrixXf rhs(nUnknowns, channels);
68 | rhs.setZero();
69 |
70 | for (int y =0; y < srcImage.rows; y++)
71 | {
72 | for (int x = 0; x < srcImage.cols; x++)
73 | {
74 | int pid = maskPointToNodeIdx[make_pair(x, y)];
75 | //
76 | if (pid == -1)
77 | {
78 | continue;
79 | }
80 |
81 | float lhs[] = { -4.f, 1.f, 1.f, 1.f, 1.f };
82 |
83 | for (int n = 1; n < 5; ++n)
84 | {
85 | const cv::Point q(x + offsets[n][0], y + offsets[n][1]);
86 |
87 | const bool hasNeighbor = bounds.contains(q);
88 | const bool isNeighborDirichlet = hasNeighbor && (mask.at(q) == 0);
89 |
90 | if (!hasNeighbor)
91 | {
92 | lhs[center] += lhs[n];
93 | lhs[n] = 0.f;
94 | }
95 | else if (isNeighborDirichlet)
96 | {
97 |
98 | // Implementation note:
99 | //
100 | // Dirichlet boundary conditions (DB) turn neighbor unknowns into knowns (data) and
101 | // are therefore moved to the right hand side. Alternatively, we could add more
102 | // equations for these pixels setting the lhs 1 and rhs to the Dirichlet value, but
103 | // that would unnecessarily blow up the equation system.
104 |
105 | rhs.row(pid) -= lhs[n] * Eigen::Map(boundaryValues.ptr(q.y, q.x), channels);
106 | lhs[n] = 0.f;
107 | }
108 | }
109 |
110 |
111 | // Add f to rhs.
112 | rhs.row(pid) += Eigen::Map(F.ptr(y, x), channels);
113 |
114 | // Build triplets for row
115 | for (int n = 0; n < 5; ++n)
116 | {
117 | if (lhs[n] != 0.f)
118 | {
119 | int qId = maskPointToNodeIdx[make_pair(x + offsets[n][0], y + offsets[n][1])];
120 |
121 | lhsTriplets.push_back(Eigen::Triplet(pid, qId, lhs[n]));
122 | }
123 | }
124 | }
125 | }
126 |
127 |
128 | // Solve the sparse linear system of equations
129 | Eigen::SparseMatrix A(nUnknowns, nUnknowns);
130 | A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());
131 |
132 | Eigen::SparseLU< Eigen::SparseMatrix > solver;
133 | solver.analyzePattern(A);
134 | solver.factorize(A);
135 |
136 | Eigen::MatrixXf result(nUnknowns, channels);
137 | for (int c = 0; c < channels; ++c)
138 | result.col(c) = solver.solve(rhs.col(c));
139 |
140 |
141 | // Copy results back
142 | for (int y = 0; y < srcImage.rows; ++y)
143 | {
144 | for (int x = 0; x < srcImage.cols; ++x)
145 | {
146 | const int pid = maskPointToNodeIdx[make_pair(x , y )];
147 |
148 | if (pid > -1)
149 | {
150 | Eigen::Map(Result.ptr(y, x), channels) = result.row(pid);
151 | }
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/Project1/src/PoissonBlending.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Project1/src/PoissonBlending.h
--------------------------------------------------------------------------------
/Project1/src/gco/GCO_README.TXT:
--------------------------------------------------------------------------------
1 | ##############################################################################
2 | # #
3 | # GCoptimization - software for energy minimization with graph cuts #
4 | # Version 3.0 #
5 | # http://www.csd.uwo.ca/faculty/olga/software.html #
6 | # #
7 | # Copyright 2007-2010 Olga Veksler #
8 | # Andrew Delong #
9 | # #
10 | ##############################################################################
11 |
12 | C++ requires at least Visual C++ 2005 (VC8) or GCC 4.03. Supports 32 or 64-bit.
13 | See matlab/README.TXT for bundled MATLAB wrapper and its documentation.
14 |
15 | IMPORTANT:
16 | To use this software, YOU MUST CITE the following in any resulting publication:
17 |
18 | [1] Efficient Approximate Energy Minimization via Graph Cuts.
19 | Y. Boykov, O. Veksler, R.Zabih. IEEE TPAMI, 20(12):1222-1239, Nov 2001.
20 |
21 | [2] What Energy Functions can be Minimized via Graph Cuts?
22 | V. Kolmogorov, R.Zabih. IEEE TPAMI, 26(2):147-159, Feb 2004.
23 |
24 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms for
25 | Energy Minimization in Vision. Y. Boykov, V. Kolmogorov.
26 | IEEE TPAMI, 26(9):1124-1137, Sep 2004.
27 |
28 | Furthermore, if you use the label cost feature (setLabelCost), you should cite
29 |
30 | [4] Fast Approximate Energy Minimization with Label Costs.
31 | A. Delong, A. Osokin, H. N. Isack, Y. Boykov. In CVPR, June 2010.
32 |
33 | This software can be used only for research purposes. For commercial purposes,
34 | be aware that there is a US patent on the main algorithm itself:
35 |
36 | R. Zabih, Y. Boykov, O. Veksler,
37 | "System and method for fast approximate energy minimization via graph cuts",
38 | United Stated Patent 6,744,923, June 1, 2004
39 |
40 | Together with this library implemented by O. Veksler, we provide, with the
41 | permission of the V. Kolmogorov and Y. Boykov, the following two libraries:
42 |
43 | 1) energy.h
44 | Developed by V. Kolmogorov, this implements the binary energy minimization
45 | technique described in [2] above. We use this to implement the binary
46 | energy minimization step for the alpha-expansion and swap algorithms.
47 | The graph construction provided by "energy.h" is more efficient than
48 | the original graph construction for alpha-expansion described in [1].
49 |
50 | Again, this software can be used only for research purposes. IF YOU USE
51 | THIS SOFTWARE (energy.h), YOU SHOULD CITE THE AFOREMENTIONED PAPER [2]
52 | IN ANY RESULTING PUBLICATION.
53 |
54 | 2) maxflow.cpp, graph.cpp, graph.h, block.h
55 | Developed by Y. Boykov and V. Kolmogorov while at Siemens Corporate Research,
56 | algorithm [3] was later reimplemented by V. Kolmogorov based on open publications
57 | and we use his implementation here with permission.
58 |
59 | If you use either of these libraries for research purposes, you should cite
60 | the aforementioned papers in any resulting publication.
61 |
62 | ##################################################################
63 |
64 | 2. License & disclaimer.
65 |
66 | Copyright 2007-2010 Olga Veksler
67 | Andrew Delong
68 |
69 | This software and its modifications can be used and distributed for
70 | research purposes only. Publications resulting from use of this code
71 | must cite publications according to the rules given above. Only
72 | Olga Veksler has the right to redistribute this code, unless expressed
73 | permission is given otherwise. Commercial use of this code, any of
74 | its parts, or its modifications is not permited. The copyright notices
75 | must not be removed in case of any modifications. This Licence
76 | commences on the date it is electronically or physically delivered
77 | to you and continues in effect unless you fail to comply with any of
78 | the terms of the License and fail to cure such breach within 30 days
79 | of becoming aware of the breach, in which case the Licence automatically
80 | terminates. This Licence is governed by the laws of Canada and all
81 | disputes arising from or relating to this Licence must be brought
82 | in Toronto, Ontario.
83 |
84 |
85 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
86 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
87 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
88 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
89 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
90 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
91 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
92 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
93 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
94 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
95 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
96 |
97 | ##################################################################
98 |
99 |
100 | 3. Energy Minimization
101 |
102 | This software is for minimizing sums of three types of terms:
103 |
104 | E(labeling) = DataCosts(labeling) + SmoothCosts(labeling) + LabelCosts(labeling).
105 |
106 | More specifically,
107 |
108 | DataCosts(l) = sum_p D_p(l_p) where l_p is a potential label for site p,
109 | and D_p is the cost of assigning l_p,
110 |
111 | SmoothCosts(l) = sum_pq V_pq(l_p,l_q) where p and q are two distinct site, and
112 | V_pq is the cost for assigning l_p, l_q, and
113 |
114 | LabelCosts(l) = sum_L' h_L'(l) where L' is some subset of labels L, and h_L'
115 | adds a cost iff at least one label from L'
116 | appears in the labeling l.
117 |
118 | Here we have a finite set of sites (or pixels) P and a finite set of labels L.
119 | A labeling l is assignments of labels in L to pixels in P. The individual pixels
120 | are referred to with small letters p and q, label of pixel p is denoted by l_p,
121 | and the set of all label-pixel assignments is denoted by l, that is
122 | l = {l_p | p in P}.
123 |
124 | The first term in the energy function E(l) is typically called the data term, and
125 | it consists of the sum over all pixels p of the penalty(or cost) D(p,l_p), what
126 | should be the cost of assigning label l_p to pixel p. D(p,l_p) can be arbitrary.
127 |
128 | The second term is a sum over all pairs of neighboring pixels {p,q}.
129 | That is there is a neighborhood relation on the set of pixels (this relationship
130 | is symmetric, that is if p is a neighbor of q then q is a neighbor of p).
131 | Here we assume that the neighbor pairs are unordered. This means that if pixels p and q are
132 | neighbors, then there is either Vpq(l_p,l_q) in the second sum of the energy,
133 | or Vqp(l_q,l_p), but not both. This is not a restriction, since in practice, one can always go
134 | from the ordered energy to the unordered one. This second term is typically called the smoothness
135 | term.
136 |
137 | The third term is a sum over all labels (or, more generally, all subsets of labels)
138 | such that each label can have non-negative penalties associated with its use.
139 | This "label cost" feature is used to encourage labelings that use as fewer unique labels
140 | or, more generally, labels from as few unique subsets as possible.
141 |
142 | The expansion algorithm for energy minimization can be used whenever for any 3 labels a,b,c
143 | V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words, expansion algorithm can be used if
144 | the binary energy for the expansion algorithm step is regular, using V. Kolmogorov's terminology.
145 |
146 | The swap algorithm for energy minimization can be used whenever for any 2 labels a,b
147 | V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap algorithm can be used if
148 | the binary energy for the swap algorithm step is regular, using V. Kolmogorov's terminology.
149 |
150 | ##################################################################
151 |
152 | 4. Data Types
153 |
154 | Inside the GCoptimization.h file you can customize the following typedefs:
155 |
156 | typedef SiteID; // index of a site (pixel); default is int32
157 | typedef LabelID; // index of a label; default is int32
158 | typedef EnergyType; // total energy value; default is int64
159 | typedef EnergyTermType; // individual energy term; default is int32
160 |
161 | For efficiency it is best to use integral types when possible; be sure that they are
162 | large enough to avoid integer overflow. By default, the library will warn if energy
163 | terms are dangerously large (larger than GCO_MAX_ENERGYTERM=10000000). Even with float
164 | types it's best to avoid extremely large energy terms, because it introduces rounding
165 | errors, and the behaviour of the algorithm is undefined if Inf or NaN values appear
166 | in the energy terms.
167 |
168 | Keep in mind that float/double may cause expansion/swap to report small increase in energy,
169 | due to arithmetic error during max-flow computation.
170 |
171 | ###########################################################################
172 |
173 | 5. Specifying the energy
174 |
175 | Before optimizing the energy, one has to specify it, that is specify the number of
176 | labels, number of pixels, neighborhood system, the data terms, and the smoothness terms.
177 | There are 2 constructors to use, one in case of the grid graph, and another in case
178 | of a general graph.
179 | In all cases, it is assumed that the sites go between 0...num_sites-1,
180 | and labels go between 0....num_labels-1.
181 | For a grid (4-connected) graph, site at coordinates (x,y) is numbered with x+y*width, where width
182 | is the width of the grid, that is the row-major ordering of arrays is assumed.
183 | ________________________________________________________________________________________________
184 |
185 | Constructor A.
186 |
187 | GCoptimizationGridGraph(int width, int height,int num_labels);
188 |
189 | Use this constructor only for grid of size width by height. If you use this constructor,
190 | 4 connected grid neigbhorhood structure is assumed, so you don't need to specify neighborhood
191 | structure separately (and indeed cannot do so).
192 | _______________________________________________________________________________________________
193 |
194 | Constructor B.
195 |
196 | GCoptimizationGeneralGraph(int num_sites,int num_labels);
197 |
198 |
199 | Use this constructor for general graphs. If you use this constructor, you must setup up
200 | neighborhood system using function. You can either specify neighbors individually or all at once.
201 |
202 | i) setNeighbors(SiteID s1, SiteID s2, EnergyTermType weight=1);
203 | Specifies neighbors individually. You must call this function exactly once for any
204 | pair of neighboring sites s1 and s2. That is if you call setNeighbors(s1,s2) then you should not call
205 | 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
206 | depends only on the labels l_p,l_q, then specify w_pq by using: setNeighbors(p,q,w_pq).
207 |
208 | ii) To pass in all neighbor information at once, use function:
209 |
210 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights);
211 | Here:
212 | (a) numNeighbors is an array of size num_sites, and numNeighbors[i] is the number of neighbors for site i
213 |
214 | (b) neighborIndexes is an array of size num_pixels which stores of pointers. Namely,
215 | neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i
216 |
217 | (c) neighborWeights is an array of size num_sites, and neighborWeighs[i] is a pointer to array
218 | storing the weights between site i and its neighbors in the same order as neighborIndexes[i]
219 | stores the indexes of neighbors. Example: if sites i and j are neighbors, then
220 | for some k and m, neighborsIndexes[i][k] == j and neighborsIndexes[j][m] = i. Then
221 | neighborWeights[i][k] = w_ij and neighborWeights[j][m] = w_ij, where w_ij is the weight
222 | betwen neighbors i and j, that is V_ij = w_ij *V(l_i,l_j)
223 |
224 |
225 | _______________________________________________________________________________________________
226 |
227 |
228 | 6. Setting the data costs, smooth costs, and label costs.
229 |
230 | The following functions can be called any time before or after expansion.
231 |
232 |
233 | ------------------------Data Costs (unary terms)-----------------------
234 |
235 | (a) void setDataCost(EnergyTermType *dataArray);
236 | dataArray is an array s.t. the data cost for pixel p and label l is stored at
237 | dataArray[pixel*num_labels+l]. If the current neighborhood system is a grid, then
238 | the data term for label l and pixel with coordinates (x,y) is stored at
239 | dataArray[(x+y*width)*num_labels + l]. Thus the size of array dataArray is num_pixels*num_labels.
240 | Can call this function only one time.
241 |
242 | (b) void setDataCost(DataCostFn fn);
243 | DataCostFn is a pointer to a function f(Pixel p, Label l), s.t. the data cost for pixel p to have
244 | label l is given by f(p,l). Can call this function only one time.
245 |
246 | (c) void setDataCost(DataCostFnExtra fn,void *extraData);
247 | DataCostFnExtra is a pointer to a function f(SiteID p, LabelID l,void *extraData), s.t. the data
248 | cost for pixel p to have label l is given by f(p,l,extraData). Can call this function only one time.
249 |
250 | (d) void setDataCost(SiteID s, LabelID l, EnergyTermType e);
251 | sets up D(s,l) = 3; You must call this function for each pixel and each label.
252 |
253 | (e) void setDataCostFunctor(DataCostFunctor* f);
254 | Experienced C++ users can subclass our DataCostFunctor base class to achieve
255 | a similar functionality as (b) or (c) above. By overriding the compute() method
256 | of DataCostFunctor, your compute() method will be called by the GCoptimization
257 | class each time a data penalty must be computed.
258 |
259 | (f) struct SparseDataCost {
260 | SiteID site;
261 | EnergyTermType cost;
262 | };
263 | void setDataCost(LabelID l, SparseDataCost *costs, SiteID count);
264 |
265 | For some applications, each label is feasible for only a small fraction
266 | of the overall sites. One way to do this is to simply assign high cost to
267 | any infeasible site. A much more efficient way is to specify exactly
268 | which sites are feasible for each label. Do this by calling
269 | setDataCost(label, costs_for_label, num_costs_for_label) once for each
270 | label. The cost array will be copied internally, so your cost array
271 | can be freed.
272 | Note that giveDataEnergy() will add a huge constant for each site
273 | that is assigned an infeasible label in the current labeling.
274 |
275 |
276 | ------------------------Smooth Costs (pairwise terms)-----------------------
277 |
278 | (a) void setSmoothCost(EnergyTermType *V)
279 |
280 | V is an array of smoothness costs, such that V_pq(label1,label2) is stored at V[label1+num_labels*label2]
281 | If graph is a grid, then using this function only if the smooth costs are not spacially varying
282 | that is the smoothness penalty V depends only on labels, but not on sites. If the graph is
283 | not a grid, then you can specify spacially varying coefficients w_pq when you set up the
284 | neighborhood system using setNeighbor(p,q,w_pq) function. In this case,
285 | V_pq(label1,label2) = V[label1+num_labels*label2]*w_pq. This function can be called only one time.
286 |
287 | (b) void setSmoothCost(SmoothCostFn fn);
288 |
289 | fn is pointer to a function f(s1,s2,l1,l2) such that smoothness penalty for neigboring sites
290 | s1 and s2 to have labels, respectively, l1 and l2 is f(s1,s2,l1,l2). This function can be
291 | called only one time.
292 |
293 | (c) void setSmoothCost(SmoothCostFnExtra fn,void *extraData);
294 |
295 | Same as above, but can pass an extra pointer to the data needed for computation
296 |
297 | (d) void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e)
298 |
299 | sets up V(l1,l2) = e. Must call this function for each pair of labels (l1,l2). Notice
300 | that for any l1 and l2, you must call this function on (l1,l2) AND (l2,l1).
301 | V(l1,l2) has to be equal to V(l2,l1) in this case.
302 |
303 | (e) void setSmoothCostVH(EnergyTermType *V, EnergyTermType *vCosts, EnergyTermType *hCosts);
304 |
305 | This function should be used only if the graph is a grid (GCoptimizationGridGraph class).
306 | Array V is the same as above, under (a).
307 | Arrays hCosts and vCosts have the same size as the image (that is width*height), and are used to set
308 | the spatially varying coefficients w_pq. If p = (x,y) and q = (x+1,y), then
309 | w_pq = hCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x+1,y) to have labels
310 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*hCosts[x+y*width]
311 | If p = (x,y) and q = (x,y+q), then
312 | w_pq = vCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x,y+1) to have labels
313 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*vCosts[x+y*width]
314 | This function can be only called one time.
315 |
316 | (f) void setSmoothCostFunctor(SmoothCostFunctor* f);
317 |
318 | Experienced C++ users can subclass our SmoothCostFunctor base class to achieve
319 | a similar functionality as (b) or (c) above. By overriding the compute() method
320 | of SmoothCostFunctor, your compute() method will be called by the GCoptimization
321 | class each time a smoothness penalty must be computed.
322 |
323 |
324 | ------------------------Label Costs (global indicator potentials)--------------------
325 |
326 | (a) void setLabelCost(EnergyTermType cost);
327 | Penalize the appearance of all labels equally. Replaces all current label
328 | costs, if any.
329 |
330 | (b) void setLabelCost(EnergyTermType* costArray);
331 | Set each individual label cost separately. The costArray must have one
332 | entry for each possible label. Replaces all current label costs, if any.
333 | The cost array will be copied intenally, so your array can be freed.
334 |
335 | (c) void setLabelSubsetCost(LabelID* labels, LabelID numLabels, EnergyTermType cost);
336 | Set cost for a specific subset of labels. The cost will be imposed iff the
337 | current labeling contains at least one label from the 'labels' array.
338 | The labels array will be copied internally, so your array can be freed.
339 |
340 | ##################################################################
341 |
342 | 6. Optimizing the energy
343 |
344 | You can optimize the energy and get the resulting labeling using the following functions. Notice that they can
345 | be called as many times as one wishes after the constructor has been called and the data/smoothness terms
346 | (and the neighborhood system, if general graph) has beeen set. The initial labeling is set to consists of
347 | all 0's. Use function setLabel(SiteID pixelP, LabelID labelL), described under heading (x) in this section
348 | to initialize the labeling to anything else (but in the valid range, of course, labels must be between
349 | 0 and num_labels-1)
350 |
351 | a) EnergyType expansion(int max_num_iterations=-1);
352 | Runs the expansion algorithm until convergence (convergence is guaranteed)
353 | or, if max_num_iterations > 0, until a certain number of cycles (iterations).
354 | Returns the energy of the resulting labeling.
355 |
356 | b) bool alpha_expansion(LabelID alpha_label);
357 | Performs expansion on the label specified by alpha_label.
358 | Returns true if the energy was decreased, false otherwise.
359 |
360 | c) EnergyType swap(int max_num_iterations=-1);
361 | Runs the alpha-beta swap algorithm until convergence (convergence is guaranteed)
362 | or, if max_num_iterations > 0, until a certain number of cycles (iterations).
363 | Returns the energy of the resulting labeling.
364 |
365 | d) void alpha_beta_swap(LabelID alpha_label, LabelID beta_label);
366 | Performs swap on a pair of labels, specified by the input parameters alpha_label, beta_label.
367 |
368 | e) EnergyType compute_energy();
369 | EnergyType giveDataEnergy();
370 | EnergyType giveSmoothEnergy();
371 | EnergyType giveLabelEnergy();
372 | Returns respectively the total, data part, smooth part, and label part of the energy of the current labling.
373 |
374 | f) LabelID whatLabel(SiteID site);
375 | Returns the current label assigned to site. Can be called at any time after the constructor call.
376 |
377 | g) void setLabel(SiteID s, LabelID l);
378 | Sets the label of site s to the the input parameter l. Can be called at any time after
379 | the constructor call. This is useful for initializing the labeling to something specific
380 | before optimization starts.
381 |
382 | h) void setLabelOrder(bool RANDOM_LABEL_ORDER);
383 | By default, the labels for the swap and expansion algorithms are visited in not random order,
384 | but random label visitation might give better results. To set the label order to
385 | be not random, call setLabelOrder(false). To set it to be random, call setLabelOrder(true). Notice,
386 | that by using functions under heading (iii) and (vii) you can completely and exactly specify the desired
387 | order on labels.
388 |
389 | ##################################################################
390 |
391 | 7. Example usage.
392 |
393 | See example.cpp for C++ example, or see matlab\README.TXT for MATLAB example.
394 |
395 |
--------------------------------------------------------------------------------
/Project1/src/gco/GCoptimization.h:
--------------------------------------------------------------------------------
1 | /*
2 | ##############################################################################
3 | # #
4 | # GCoptimization - software for energy minimization with graph cuts #
5 | # Version 3.0 #
6 | # http://www.csd.uwo.ca/faculty/olga/software.html #
7 | # #
8 | # Copyright 2007-2010 Olga Veksler (olga@csd.uwo.ca) #
9 | # Andrew Delong (andrew.delong@gmail.com) #
10 | # #
11 | ##############################################################################
12 |
13 | C++ requires at least Visual C++ 2005 (VC8) or GCC 4.03. Supports 32 or 64-bit.
14 | See matlab/README.TXT for bundled MATLAB wrapper and its documentation.
15 |
16 | IMPORTANT:
17 | To use this software, YOU MUST CITE the following in any resulting publication:
18 |
19 | [1] Efficient Approximate Energy Minimization via Graph Cuts.
20 | Y. Boykov, O. Veksler, R.Zabih. IEEE TPAMI, 20(12):1222-1239, Nov 2001.
21 |
22 | [2] What Energy Functions can be Minimized via Graph Cuts?
23 | V. Kolmogorov, R.Zabih. IEEE TPAMI, 26(2):147-159, Feb 2004.
24 |
25 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms for
26 | Energy Minimization in Vision. Y. Boykov, V. Kolmogorov.
27 | IEEE TPAMI, 26(9):1124-1137, Sep 2004.
28 |
29 | Furthermore, if you use the label cost feature (setLabelCost), you should cite
30 |
31 | [4] Fast Approximate Energy Minimization with Label Costs.
32 | A. Delong, A. Osokin, H. N. Isack, Y. Boykov. In CVPR, June 2010.
33 |
34 | This software can be used only for research purposes. For commercial purposes,
35 | be aware that there is a US patent on the main algorithm itself:
36 |
37 | R. Zabih, Y. Boykov, O. Veksler,
38 | "System and method for fast approximate energy minimization via graph cuts",
39 | United Stated Patent 6,744,923, June 1, 2004
40 |
41 | Together with this library implemented by O. Veksler, we provide, with the
42 | permission of the V. Kolmogorov and Y. Boykov, the following two libraries:
43 |
44 | 1) energy.h
45 | Developed by V. Kolmogorov, this implements the binary energy minimization
46 | technique described in [2] above. We use this to implement the binary
47 | energy minimization step for the alpha-expansion and swap algorithms.
48 | The graph construction provided by "energy.h" is more efficient than
49 | the original graph construction for alpha-expansion described in [1].
50 |
51 | Again, this software can be used only for research purposes. IF YOU USE
52 | THIS SOFTWARE (energy.h), YOU SHOULD CITE THE AFOREMENTIONED PAPER [2]
53 | IN ANY RESULTING PUBLICATION.
54 |
55 | 2) maxflow.cpp, graph.cpp, graph.h, block.h
56 | Developed by Y. Boykov and V. Kolmogorov while at Siemens Corporate Research,
57 | algorithm [3] was later reimplemented by V. Kolmogorov based on open publications
58 | and we use his implementation here with permission.
59 |
60 | If you use either of these libraries for research purposes, you should cite
61 | the aforementioned papers in any resulting publication.
62 |
63 | ##################################################################
64 |
65 | License & disclaimer.
66 |
67 | Copyright 2007-2010 Olga Veksler
68 | Andrew Delong
69 |
70 | This software and its modifications can be used and distributed for
71 | research purposes only. Publications resulting from use of this code
72 | must cite publications according to the rules given above. Only
73 | Olga Veksler has the right to redistribute this code, unless expressed
74 | permission is given otherwise. Commercial use of this code, any of
75 | its parts, or its modifications is not permited. The copyright notices
76 | must not be removed in case of any modifications. This Licence
77 | commences on the date it is electronically or physically delivered
78 | to you and continues in effect unless you fail to comply with any of
79 | the terms of the License and fail to cure such breach within 30 days
80 | of becoming aware of the breach, in which case the Licence automatically
81 | terminates. This Licence is governed by the laws of Canada and all
82 | disputes arising from or relating to this Licence must be brought
83 | in Toronto, Ontario.
84 |
85 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
86 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
87 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
88 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
89 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
90 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
91 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
92 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
93 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
94 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
95 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
96 |
97 | ##################################################################
98 | */
99 |
100 | #ifndef __GCOPTIMIZATION_H__
101 | #define __GCOPTIMIZATION_H__
102 | // Due to quiet bugs in function template specialization, it is not
103 | // safe to use earlier MS compilers.
104 | #if defined(_MSC_VER) && _MSC_VER < 1400
105 | #error Requires Visual C++ 2005 (VC8) compiler or later.
106 | #endif
107 |
108 | #include
109 | #include "energy.h"
110 | #include "graph.cpp"
111 | #include "maxflow.cpp"
112 |
113 | /////////////////////////////////////////////////////////////////////
114 | // Utility functions, classes, and macros
115 | /////////////////////////////////////////////////////////////////////
116 |
117 | class GCException {
118 | public:
119 | const char* message;
120 | GCException( const char* m ): message(m) { }
121 | void Report();
122 | };
123 |
124 | #ifdef _WIN32
125 | typedef __int64 gcoclock_t;
126 | #else
127 | #include
128 | typedef clock_t gcoclock_t;
129 | #endif
130 | extern "C" gcoclock_t gcoclock(); // fairly high-resolution timer... better than clock() when available
131 | extern "C" gcoclock_t GCO_CLOCKS_PER_SEC; // this variable will stay 0 until gcoclock() is called for the first time
132 |
133 | #ifdef _MSC_EXTENSIONS
134 | #define OLGA_INLINE __forceinline
135 | #else
136 | #define OLGA_INLINE inline
137 | #endif
138 |
139 | #ifndef GCO_MAX_ENERGYTERM
140 | #define GCO_MAX_ENERGYTERM 2147400000 // maximum safe coefficient to avoid integer overflow
141 | // if a data/smooth/label cost term is larger than this,
142 | // the library will raise an exception
143 | #endif
144 |
145 | #if defined(GCO_ENERGYTYPE) && !defined(GCO_ENERGYTERMTYPE)
146 | #define GCO_ENERGYTERMTYPE GCO_ENERGYTYPE
147 | #endif
148 | #if !defined(GCO_ENERGYTYPE) && defined(GCO_ENERGYTERMTYPE)
149 | #define GCO_ENERGYTYPE GCO_ENERGYTERMTYPE
150 | #endif
151 |
152 |
153 | /////////////////////////////////////////////////////////////////////
154 | // GCoptimization class
155 | /////////////////////////////////////////////////////////////////////
156 | class LinkedBlockList;
157 |
158 | class GCoptimization
159 | {
160 | public:
161 | #ifdef GCO_ENERGYTYPE
162 | typedef GCO_ENERGYTYPE EnergyType;
163 | typedef GCO_ENERGYTERMTYPE EnergyTermType;
164 | #else
165 | #ifdef GCO_ENERGYTYPE32
166 | typedef int EnergyType; // 32-bit energy total
167 | #else
168 | typedef double EnergyType; // 64-bit energy total
169 | #endif
170 | typedef double EnergyTermType; // 32-bit energy terms
171 | #endif
172 | typedef Energy EnergyT;
173 | typedef EnergyT::Var VarID;
174 | typedef int LabelID; // Type for labels
175 | typedef VarID SiteID; // Type for sites
176 | typedef EnergyTermType (*SmoothCostFn)(SiteID s1, SiteID s2, LabelID l1, LabelID l2);
177 | typedef EnergyTermType (*DataCostFn)(SiteID s, LabelID l);
178 | typedef EnergyTermType (*SmoothCostFnExtra)(SiteID s1, SiteID s2, LabelID l1, LabelID l2,void *);
179 | typedef EnergyTermType (*DataCostFnExtra)(SiteID s, LabelID l,void *);
180 |
181 | GCoptimization(SiteID num_sites, LabelID num_labels);
182 | virtual ~GCoptimization();
183 |
184 | // Peforms expansion algorithm. Runs the number of iterations specified by max_num_iterations
185 | // If no input specified,runs until convergence. Returns total energy of labeling.
186 | EnergyType expansion(int max_num_iterations=-1);
187 |
188 | // Peforms expansion on one label, specified by the input parameter alpha_label
189 | bool alpha_expansion(LabelID alpha_label);
190 |
191 | // Peforms swap algorithm. Runs it the specified number of iterations. If no
192 | // input is specified,runs until convergence
193 | EnergyType swap(int max_num_iterations=-1);
194 |
195 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label
196 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label);
197 |
198 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label
199 | // only on the sitess in the specified arrays, alphaSites and betaSitess, and the array sizes
200 | // are, respectively, alpha_size and beta_size
201 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label, SiteID *alphaSites,
202 | SiteID alpha_size, SiteID *betaSites, SiteID beta_size);
203 |
204 | struct DataCostFunctor; // use this class to pass a functor to setDataCost
205 | struct SmoothCostFunctor; // use this class to pass a functor to setSmoothCost
206 |
207 | // Set cost for all (SiteID,LabelID) pairs. Default data cost is all zeros.
208 | void setDataCost(DataCostFn fn);
209 | void setDataCost(DataCostFnExtra fn, void *extraData);
210 | void setDataCost(EnergyTermType *dataArray);
211 | void setDataCost(SiteID s, LabelID l, EnergyTermType e);
212 | void setDataCostFunctor(DataCostFunctor* f);
213 | struct DataCostFunctor {
214 | virtual EnergyTermType compute(SiteID s, LabelID l) = 0;
215 | };
216 | // Set cost of assigning 'l' to a specific subset of sites.
217 | // The sites are listed as (SiteID,cost) pairs.
218 | struct SparseDataCost {
219 | SiteID site;
220 | EnergyTermType cost;
221 | };
222 | void setDataCost(LabelID l, SparseDataCost *costs, SiteID count);
223 |
224 | // Set cost for all (LabelID,LabelID) pairs; the actual smooth cost is then weighted
225 | // at each pair of on neighbors. Defaults to Potts model (0 if l1==l2, 1 otherwise)
226 | void setSmoothCost(SmoothCostFn fn);
227 | void setSmoothCost(SmoothCostFnExtra fn, void *extraData);
228 | void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e);
229 | void setSmoothCost(EnergyTermType *smoothArray);
230 | void setSmoothCostFunctor(SmoothCostFunctor* f);
231 | struct SmoothCostFunctor {
232 | virtual EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) = 0;
233 | };
234 |
235 | // Sets the cost of using label in the solution.
236 | // Set either as uniform cost, or an individual per-label cost.
237 | void setLabelCost(EnergyTermType cost);
238 | void setLabelCost(EnergyTermType* costArray);
239 | void setLabelSubsetCost(LabelID* labels, LabelID numLabels, EnergyTermType cost);
240 |
241 | // Returns current label assigned to input site
242 | LabelID whatLabel(SiteID site);
243 | void whatLabel(SiteID start, SiteID count, LabelID* labeling);
244 |
245 | // This function can be used to change the label of any site at any time
246 | void setLabel(SiteID site, LabelID label);
247 |
248 | // setLabelOrder(false) sets the order to be not random; setLabelOrder(true)
249 | // sets the order to random. By default, the labels are visited in non-random order
250 | // for both the swap and alpha-expansion moves
251 | // Note that srand() must be initialized with an appropriate seed in order for
252 | // random order to take effect!
253 | void setLabelOrder(bool isRandom);
254 | void setLabelOrder(const LabelID* order, LabelID size);
255 |
256 | // Returns total energy for the current labeling
257 | EnergyType compute_energy();
258 |
259 | // Returns separate Data, Smooth, and Label energy of current labeling
260 | EnergyType giveDataEnergy();
261 | EnergyType giveSmoothEnergy();
262 | EnergyType giveLabelEnergy();
263 |
264 | // Returns number of sites/labels as specified in the constructor
265 | SiteID numSites() const;
266 | LabelID numLabels() const;
267 |
268 | // Prints output to stdout during exansion/swap execution.
269 | // 0 => no output
270 | // 1 => cycle-level output (cycle number, current energy)
271 | // 2 => expansion-/swap-level output (label(s), current energy)
272 | void setVerbosity(int level) { m_verbosity = level; }
273 |
274 | protected:
275 | struct LabelCost {
276 | ~LabelCost() { delete [] labels; }
277 | EnergyTermType cost;
278 | bool active; // flag indicates if this particular labelcost is in effect (i.e. wrt m_labeling)
279 | VarID aux;
280 | LabelCost* next; // global list of LabelSetCost records
281 | LabelID numLabels;
282 | LabelID* labels;
283 | };
284 |
285 | struct LabelCostIter {
286 | LabelCost* node;
287 | LabelCostIter* next; // local list of LabelSetCost records that contain this label
288 | };
289 |
290 | LabelID m_num_labels;
291 | SiteID m_num_sites;
292 | LabelID *m_labeling;
293 | SiteID *m_lookupSiteVar; // holds index of variable corresponding to site participating in a move,
294 | // -1 for nonparticipating site
295 | LabelID *m_labelTable; // to figure out label order in which to do expansion/swaps
296 | int m_stepsThisCycle;
297 | int m_stepsThisCycleTotal;
298 | int m_random_label_order;
299 | EnergyTermType* m_datacostIndividual;
300 | EnergyTermType* m_smoothcostIndividual;
301 | EnergyTermType* m_labelingDataCosts;
302 | SiteID* m_labelCounts;
303 | SiteID* m_activeLabelCounts;
304 | LabelCost* m_labelcostsAll;
305 | LabelCostIter** m_labelcostsByLabel;
306 | int m_labelcostCount;
307 | bool m_labelingInfoDirty;
308 | int m_verbosity;
309 |
310 | void* m_datacostFn;
311 | void* m_smoothcostFn;
312 | EnergyType m_beforeExpansionEnergy;
313 |
314 | SiteID *m_numNeighbors; // holds num of neighbors for each site
315 | SiteID m_numNeighborsTotal; // holds total num of neighbor relationships
316 |
317 | EnergyType (GCoptimization::*m_giveSmoothEnergyInternal)();
318 | SiteID (GCoptimization::*m_queryActiveSitesExpansion)(LabelID, SiteID*);
319 | void (GCoptimization::*m_setupDataCostsExpansion)(SiteID,LabelID,EnergyT*,SiteID*);
320 | void (GCoptimization::*m_setupSmoothCostsExpansion)(SiteID,LabelID,EnergyT*,SiteID*);
321 | void (GCoptimization::*m_setupDataCostsSwap)(SiteID,LabelID,LabelID,EnergyT*,SiteID*);
322 | void (GCoptimization::*m_setupSmoothCostsSwap)(SiteID,LabelID,LabelID,EnergyT*,SiteID*);
323 | void (GCoptimization::*m_applyNewLabeling)(EnergyT*,SiteID*,SiteID,LabelID);
324 | void (GCoptimization::*m_updateLabelingDataCosts)();
325 |
326 | void (*m_datacostFnDelete)(void* f);
327 | void (*m_smoothcostFnDelete)(void* f);
328 | bool (GCoptimization::*m_solveSpecialCases)(EnergyType&);
329 |
330 | // returns a pointer to the neighbors of a site and the weights
331 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights)=0;
332 | virtual void finalizeNeighbors() = 0;
333 |
334 | struct DataCostFnFromArray {
335 | DataCostFnFromArray(EnergyTermType* theArray, LabelID num_labels)
336 | : m_array(theArray), m_num_labels(num_labels){}
337 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_array[s*m_num_labels+l];}
338 | private:
339 | const EnergyTermType* const m_array;
340 | const LabelID m_num_labels;
341 | };
342 |
343 | struct DataCostFnFromFunction {
344 | DataCostFnFromFunction(DataCostFn fn): m_fn(fn){}
345 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l);}
346 | private:
347 | const DataCostFn m_fn;
348 | };
349 |
350 | struct DataCostFnFromFunctionExtra {
351 | DataCostFnFromFunctionExtra(DataCostFnExtra fn,void *extraData): m_fn(fn),m_extraData(extraData){}
352 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l,m_extraData);}
353 | private:
354 | const DataCostFnExtra m_fn;
355 | void *m_extraData;
356 | };
357 |
358 | struct SmoothCostFnFromArray {
359 | SmoothCostFnFromArray(EnergyTermType* theArray, LabelID num_labels)
360 | : m_array(theArray), m_num_labels(num_labels){}
361 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_array[l1*m_num_labels+l2];}
362 | private:
363 | const EnergyTermType* const m_array;
364 | const LabelID m_num_labels;
365 | };
366 |
367 | struct SmoothCostFnFromFunction {
368 | SmoothCostFnFromFunction(SmoothCostFn fn)
369 | : m_fn(fn){}
370 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2);}
371 | private:
372 | const SmoothCostFn m_fn;
373 | };
374 |
375 | struct SmoothCostFnFromFunctionExtra {
376 | SmoothCostFnFromFunctionExtra(SmoothCostFnExtra fn,void *extraData)
377 | : m_fn(fn),m_extraData(extraData){}
378 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2,m_extraData);}
379 | private:
380 | const SmoothCostFnExtra m_fn;
381 | void *m_extraData;
382 | };
383 |
384 | struct SmoothCostFnPotts {
385 | OLGA_INLINE EnergyTermType compute(SiteID, SiteID, LabelID l1, LabelID l2){return l1 != l2 ? (EnergyTermType)1 : (EnergyTermType)0;}
386 | };
387 |
388 | /////////////////////////////////////////////////////////////////////
389 | // DataCostFnSparse
390 | // This data cost functor maintains a simple sparse structure
391 | // to quickly find the cost associated with any (site,label) pair.
392 | /////////////////////////////////////////////////////////////////////
393 | class DataCostFnSparse {
394 | // cLogSitesPerBucket basically controls the compression ratio
395 | // of the sparse structure: 1 => a dense array, num_sites => a single sparse list.
396 | // The amount (cLogSitesPerBucket - cLinearSearchSize) determines the maximum
397 | // number of binary search steps taken for a cost lookup for specific (site,label).
398 | //
399 | static const int cLogSitesPerBucket = 9;
400 | static const int cSitesPerBucket = (1 << cLogSitesPerBucket);
401 | static const size_t cDataCostPtrMask = ~(sizeof(SparseDataCost)-1);
402 | static const ptrdiff_t cLinearSearchSize = 64/sizeof(SparseDataCost);
403 |
404 | struct DataCostBucket {
405 | const SparseDataCost* begin;
406 | const SparseDataCost* end; // one-past-the-last item in the range
407 | const SparseDataCost* predict; // predicts the next cost to be needed
408 | };
409 |
410 | public:
411 | DataCostFnSparse(SiteID num_sites, LabelID num_labels);
412 | DataCostFnSparse(const DataCostFnSparse& src);
413 | ~DataCostFnSparse();
414 |
415 | void set(LabelID l, const SparseDataCost* costs, SiteID count);
416 | EnergyTermType compute(SiteID s, LabelID l);
417 | SiteID queryActiveSitesExpansion(LabelID alpha_label, const LabelID* labeling, SiteID* activeSites);
418 |
419 | class iterator {
420 | public:
421 | OLGA_INLINE iterator(): m_ptr(0) { }
422 | OLGA_INLINE iterator& operator++() { m_ptr++; return *this; }
423 | OLGA_INLINE SiteID site() const { return m_ptr->site; }
424 | OLGA_INLINE EnergyTermType cost() const { return m_ptr->cost; }
425 | OLGA_INLINE bool operator==(const iterator& b) const { return m_ptr == b.m_ptr; }
426 | OLGA_INLINE bool operator!=(const iterator& b) const { return m_ptr != b.m_ptr; }
427 | OLGA_INLINE ptrdiff_t operator- (const iterator& b) const { return m_ptr - b.m_ptr; }
428 | private:
429 | OLGA_INLINE iterator(const SparseDataCost* ptr): m_ptr(ptr) { }
430 | const SparseDataCost* m_ptr;
431 | friend class DataCostFnSparse;
432 | };
433 |
434 | OLGA_INLINE iterator begin(LabelID label) const { return m_buckets[label*m_buckets_per_label].begin; }
435 | OLGA_INLINE iterator end(LabelID label) const { return m_buckets[label*m_buckets_per_label + m_buckets_per_label-1].end; }
436 |
437 | private:
438 | EnergyTermType search(DataCostBucket& b, SiteID s);
439 | const SiteID m_num_sites;
440 | const LabelID m_num_labels;
441 | const int m_buckets_per_label;
442 | mutable DataCostBucket* m_buckets;
443 | };
444 |
445 | template SiteID queryActiveSitesExpansion(LabelID alpha_label, SiteID* activeSites);
446 | template void setupDataCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites);
447 | template void setupDataCostsSwap(SiteID size,LabelID alpha_label,LabelID beta_label,EnergyT *e,SiteID *activeSites);
448 | template void setupSmoothCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites);
449 | template void setupSmoothCostsSwap(SiteID size,LabelID alpha_label,LabelID beta_label,EnergyT *e,SiteID *activeSites);
450 | template void applyNewLabeling(EnergyT *e,SiteID *activeSites,SiteID size,LabelID alpha_label);
451 | template void updateLabelingDataCosts();
452 | template void specializeDataCostFunctor(const UserFunctor f);
453 | template void specializeSmoothCostFunctor(const UserFunctor f);
454 |
455 | EnergyType setupLabelCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites);
456 | void updateLabelingInfo(bool updateCounts=true,bool updateActive=true,bool updateCosts=true);
457 |
458 | // Check for overflow and submodularity issues when setting up binary graph cut
459 | void addterm1_checked(EnergyT *e,VarID i,EnergyTermType e0,EnergyTermType e1);
460 | void addterm1_checked(EnergyT *e,VarID i,EnergyTermType e0,EnergyTermType e1,EnergyTermType w);
461 | void addterm2_checked(EnergyT *e,VarID i,VarID j,EnergyTermType e00,EnergyTermType e01,EnergyTermType e10,EnergyTermType e11,EnergyTermType w);
462 |
463 | // Returns Smooth Energy of current labeling
464 | template EnergyType giveSmoothEnergyInternal();
465 | template static void deleteFunctor(void* f) { delete reinterpret_cast(f); }
466 |
467 | static void handleError(const char *message);
468 | static void checkInterrupt();
469 |
470 | private:
471 | // Peforms one iteration (one pass over all pairs of labels) of expansion/swap algorithm
472 | EnergyType oneExpansionIteration();
473 | EnergyType oneSwapIteration();
474 | void printStatus1(const char* extraMsg=0);
475 | void printStatus1(int cycle, bool isSwap, gcoclock_t ticks0);
476 | void printStatus2(int alpha, int beta, int numVars, gcoclock_t ticks0);
477 |
478 | void permuteLabelTable();
479 |
480 | template bool solveSpecialCases(EnergyType& energy);
481 | template EnergyType solveGreedy();
482 |
483 | /////////////////////////////////////////////////////////////////////
484 | // GreedyIter
485 | // Lets solveGreedy efficiently traverse the datacosts when
486 | // searching for the next greedy move.
487 | /////////////////////////////////////////////////////////////////////
488 | template
489 | class GreedyIter {
490 | public:
491 | GreedyIter(DataCostT& dc, SiteID numSites)
492 | : m_dc(dc), m_site(0), m_numSites(numSites), m_label(0), m_lbegin(0), m_lend(0)
493 | { }
494 |
495 | OLGA_INLINE void start(const LabelID* labels, LabelID labelCount=1)
496 | {
497 | m_site = labelCount ? 0 : m_numSites;
498 | m_label = m_lbegin = labels;
499 | m_lend = labels + labelCount;
500 | }
501 | OLGA_INLINE SiteID site() const { return m_site; }
502 | OLGA_INLINE SiteID label() const { return *m_label; }
503 | OLGA_INLINE bool done() const { return m_site == m_numSites; }
504 | OLGA_INLINE GreedyIter& operator++()
505 | {
506 | // The inner loop is over labels, not sites, to improve memory locality.
507 | // When dc() is pulling datacosts from an array (the typical format), this can
508 | // improve performance by a factor of 2x, often more like 4x.
509 | if (++m_label >= m_lend) {
510 | m_label = m_lbegin;
511 | ++m_site;
512 | }
513 | return *this;
514 | }
515 | OLGA_INLINE EnergyTermType compute() const { return m_dc.compute(m_site,*m_label); }
516 | OLGA_INLINE SiteID feasibleSites() const { return m_numSites; }
517 |
518 | private:
519 | SiteID m_site;
520 | DataCostT& m_dc;
521 | const SiteID m_numSites;
522 | const LabelID* m_label;
523 | const LabelID* m_lbegin;
524 | const LabelID* m_lend;
525 | };
526 | };
527 |
528 |
529 | //////////////////////////////////////////////////////////////////////////////////////////////////
530 | // Use this derived class for grid graphs
531 | //////////////////////////////////////////////////////////////////////////////////////////////////
532 |
533 | class GCoptimizationGridGraph: public GCoptimization
534 | {
535 | public:
536 | GCoptimizationGridGraph(SiteID width,SiteID height,LabelID num_labels);
537 | virtual ~GCoptimizationGridGraph();
538 |
539 | void setSmoothCostVH(EnergyTermType *smoothArray, EnergyTermType *vCosts, EnergyTermType *hCosts);
540 |
541 | protected:
542 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights);
543 | virtual void finalizeNeighbors();
544 | EnergyTermType m_unityWeights[4];
545 | int m_weightedGraph; // true if spatially varying w_pq's are present. False otherwise.
546 |
547 | private:
548 | SiteID m_width;
549 | SiteID m_height;
550 | SiteID *m_neighbors; // holds neighbor indexes
551 | EnergyTermType *m_neighborsWeights; // holds neighbor weights
552 |
553 | void setupNeighbData(SiteID startY,SiteID endY,SiteID startX,SiteID endX,SiteID maxInd,SiteID *indexes);
554 | void computeNeighborWeights(EnergyTermType *vCosts,EnergyTermType *hCosts);
555 | };
556 |
557 | //////////////////////////////////////////////////////////////////////////////////////////////////
558 |
559 | class GCoptimizationGeneralGraph:public GCoptimization
560 | {
561 | public:
562 | // This is the constructor for non-grid graphs. Neighborhood structure must be specified by
563 | // setNeighbors() function
564 | GCoptimizationGeneralGraph(SiteID num_sites,LabelID num_labels);
565 | virtual ~GCoptimizationGeneralGraph();
566 |
567 | // Makes site1 and site2 neighbors of each other. Can be called only 1 time for each
568 | // unordered pair of sites. Parameter weight can be used to set spacially varying terms
569 | // If the desired penalty for neighboring sites site1 and site2 is
570 | // V(label1,label2) = weight*SmoothnessPenalty(label1,label2), then
571 | // member function setLabel should be called as: setLabel(site1,site2,weight)
572 | void setNeighbors(SiteID site1, SiteID site2, EnergyTermType weight=1);
573 |
574 | // passes pointers to arrays storing neighbor information
575 | // numNeighbors[i] is the number of neighbors for site i
576 | // neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i
577 | // neighborWeights[i] is a pointer to array storing the weights between site i and its neighbors
578 | // in the same order as neighborIndexes[i] stores the indexes
579 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights);
580 |
581 | protected:
582 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights);
583 | virtual void finalizeNeighbors();
584 |
585 | private:
586 |
587 | typedef struct NeighborStruct{
588 | SiteID to_node;
589 | EnergyTermType weight;
590 | } Neighbor;
591 |
592 | LinkedBlockList *m_neighbors;
593 | bool m_needToFinishSettingNeighbors;
594 | SiteID **m_neighborsIndexes;
595 | EnergyTermType **m_neighborsWeights;
596 | bool m_needTodeleteNeighbors;
597 | };
598 |
599 |
600 | ////////////////////////////////////////////////////////////////////
601 | // Methods
602 | ////////////////////////////////////////////////////////////////////
603 |
604 |
605 | OLGA_INLINE GCoptimization::SiteID GCoptimization::numSites() const
606 | {
607 | return m_num_sites;
608 | }
609 |
610 | OLGA_INLINE GCoptimization::LabelID GCoptimization::numLabels() const
611 | {
612 | return m_num_labels;
613 | }
614 |
615 | OLGA_INLINE void GCoptimization::setLabel(SiteID site, LabelID label)
616 | {
617 | assert(label >= 0 && label < m_num_labels && site >= 0 && site < m_num_sites);
618 | m_labeling[site] = label;
619 | m_labelingInfoDirty = true;
620 | }
621 |
622 | OLGA_INLINE GCoptimization::LabelID GCoptimization::whatLabel(SiteID site)
623 | {
624 | assert(site >= 0 && site < m_num_sites);
625 | return m_labeling[site];
626 | }
627 |
628 | #endif
629 |
--------------------------------------------------------------------------------
/Project1/src/gco/LinkedBlockList.cpp:
--------------------------------------------------------------------------------
1 | #include "LinkedBlockList.h"
2 | #include
3 | #include
4 |
5 | /*********************************************************************/
6 |
7 | void LinkedBlockList::addFront(ListType item) {
8 |
9 | if ( m_head_block_size == GCLL_BLOCK_SIZE )
10 | {
11 | LLBlock *tmp = (LLBlock *) new LLBlock;
12 | if ( !tmp ) {printf("\nOut of memory");exit(1);}
13 | tmp -> m_next = m_head;
14 | m_head = tmp;
15 | m_head_block_size = 0;
16 | }
17 |
18 | m_head ->m_item[m_head_block_size] = item;
19 | m_head_block_size++;
20 | }
21 |
22 | /*********************************************************************/
23 |
24 | ListType LinkedBlockList::next()
25 | {
26 | ListType toReturn = m_cursor -> m_item[m_cursor_ind];
27 |
28 | m_cursor_ind++;
29 |
30 | if ( m_cursor == m_head && m_cursor_ind >= m_head_block_size )
31 | {
32 | m_cursor = m_cursor ->m_next;
33 | m_cursor_ind = 0;
34 | }
35 | else if ( m_cursor_ind == GCLL_BLOCK_SIZE )
36 | {
37 | m_cursor = m_cursor ->m_next;
38 | m_cursor_ind = 0;
39 | }
40 | return(toReturn);
41 | }
42 |
43 | /*********************************************************************/
44 |
45 | bool LinkedBlockList::hasNext()
46 | {
47 | if ( m_cursor != 0 ) return (true);
48 | else return(false);
49 | }
50 |
51 |
52 | /*********************************************************************/
53 |
54 | LinkedBlockList::~LinkedBlockList()
55 | {
56 | LLBlock *tmp;
57 |
58 | while ( m_head != 0 )
59 | {
60 | tmp = m_head;
61 | m_head = m_head->m_next;
62 | delete tmp;
63 | }
64 | };
65 |
66 | /*********************************************************************/
67 |
68 |
--------------------------------------------------------------------------------
/Project1/src/gco/LinkedBlockList.h:
--------------------------------------------------------------------------------
1 | /* Singly Linked List of Blocks */
2 | // This data structure should be used only for the GCoptimization class implementation
3 | // because it lucks some important general functions for general list, like remove_item()
4 | // The head block may be not full
5 | // For regular 2D grids, it's better to set GCLL_BLOCK_SIZE to 2
6 | // For other graphs, it should be set to the average expected number of neighbors
7 | // Data in linked list for the neighborhood system is allocated in blocks of size GCLL_BLOCK_SIZE
8 |
9 | #ifndef __LINKEDBLOCKLIST_H__
10 | #define __LINKEDBLOCKLIST_H__
11 |
12 | #define GCLL_BLOCK_SIZE 4
13 | // GCLL_BLOCKSIZE should "fit" into the type BlockType. That is
14 | // if GCLL_BLOCKSIZE is larger than 255 but smaller than largest short integer
15 | // then BlockType should be set to short
16 | typedef char BlockType;
17 |
18 | //The type of data stored in the linked list
19 | typedef void * ListType;
20 |
21 | class LinkedBlockList{
22 |
23 | public:
24 | void addFront(ListType item);
25 | inline bool isEmpty(){if (m_head == 0) return(true); else return(false);};
26 | inline LinkedBlockList(){m_head = 0; m_head_block_size = GCLL_BLOCK_SIZE;};
27 | ~LinkedBlockList();
28 |
29 | // Next three functins are for the linked list traversal
30 | inline void setCursorFront(){m_cursor = m_head; m_cursor_ind = 0;};
31 | ListType next();
32 | bool hasNext();
33 |
34 | private:
35 | typedef struct LLBlockStruct{
36 | ListType m_item[GCLL_BLOCK_SIZE];
37 | struct LLBlockStruct *m_next;
38 | } LLBlock;
39 |
40 | LLBlock *m_head;
41 | // Remembers the number of elements in the head block, since it may not be full
42 | BlockType m_head_block_size;
43 | // For block traversal, points to current element in the current block
44 | BlockType m_cursor_ind;
45 | // For block traversal, points to current block in the linked list
46 | LLBlock *m_cursor;
47 | };
48 |
49 | #endif
50 |
51 |
--------------------------------------------------------------------------------
/Project1/src/gco/block.h:
--------------------------------------------------------------------------------
1 | /* block.h */
2 | /*
3 | Template classes Block and DBlock
4 | Implement adding and deleting items of the same type in blocks.
5 |
6 | If there there are many items then using Block or DBlock
7 | is more efficient than using 'new' and 'delete' both in terms
8 | of memory and time since
9 | (1) On some systems there is some minimum amount of memory
10 | that 'new' can allocate (e.g., 64), so if items are
11 | small that a lot of memory is wasted.
12 | (2) 'new' and 'delete' are designed for items of varying size.
13 | If all items has the same size, then an algorithm for
14 | adding and deleting can be made more efficient.
15 | (3) All Block and DBlock functions are inline, so there are
16 | no extra function calls.
17 |
18 | Differences between Block and DBlock:
19 | (1) DBlock allows both adding and deleting items,
20 | whereas Block allows only adding items.
21 | (2) Block has an additional operation of scanning
22 | items added so far (in the order in which they were added).
23 | (3) Block allows to allocate several consecutive
24 | items at a time, whereas DBlock can add only a single item.
25 |
26 | Note that no constructors or destructors are called for items.
27 |
28 | Example usage for items of type 'MyType':
29 |
30 | ///////////////////////////////////////////////////
31 | #include "block.h"
32 | #define BLOCK_SIZE 1024
33 | typedef struct { int a, b; } MyType;
34 | MyType *ptr, *array[10000];
35 |
36 | ...
37 |
38 | Block *block = new Block(BLOCK_SIZE);
39 |
40 | // adding items
41 | for (int i=0; i New();
44 | ptr -> a = ptr -> b = rand();
45 | }
46 |
47 | // reading items
48 | for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext())
49 | {
50 | printf("%d %d\n", ptr->a, ptr->b);
51 | }
52 |
53 | delete block;
54 |
55 | ...
56 |
57 | DBlock *dblock = new DBlock(BLOCK_SIZE);
58 |
59 | // adding items
60 | for (int i=0; i New();
63 | }
64 |
65 | // deleting items
66 | for (int i=0; i Delete(array[i]);
69 | }
70 |
71 | // adding items
72 | for (int i=0; i New();
75 | }
76 |
77 | delete dblock;
78 |
79 | ///////////////////////////////////////////////////
80 |
81 | Note that DBlock deletes items by marking them as
82 | empty (i.e., by adding them to the list of free items),
83 | so that this memory could be used for subsequently
84 | added items. Thus, at each moment the memory allocated
85 | is determined by the maximum number of items allocated
86 | simultaneously at earlier moments. All memory is
87 | deallocated only when the destructor is called.
88 | */
89 |
90 | #ifndef __BLOCK_H__
91 | #define __BLOCK_H__
92 |
93 | #include
94 |
95 | /***********************************************************************/
96 | /***********************************************************************/
97 | /***********************************************************************/
98 |
99 | template class Block
100 | {
101 | public:
102 | /* Constructor. Arguments are the block size and
103 | (optionally) the pointer to the function which
104 | will be called if allocation failed; the message
105 | passed to this function is "Not enough memory!" */
106 | Block(int size, void (*err_function)(const char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
107 |
108 | /* Destructor. Deallocates all items added so far */
109 | ~Block() { while (first) { block *next = first -> next; delete first; first = next; } }
110 |
111 | /* Allocates 'num' consecutive items; returns pointer
112 | to the first item. 'num' cannot be greater than the
113 | block size since items must fit in one block */
114 | Type *New(int num = 1)
115 | {
116 | Type *t;
117 |
118 | if (!last || last->current + num > last->last)
119 | {
120 | if (last && last->next) last = last -> next;
121 | else
122 | {
123 | block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)];
124 | if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
125 | if (last) last -> next = next;
126 | else first = next;
127 | last = next;
128 | last -> current = & ( last -> data[0] );
129 | last -> last = last -> current + block_size;
130 | last -> next = NULL;
131 | }
132 | }
133 |
134 | t = last -> current;
135 | last -> current += num;
136 | return t;
137 | }
138 |
139 | /* Returns the first item (or NULL, if no items were added) */
140 | Type *ScanFirst()
141 | {
142 | for (scan_current_block=first; scan_current_block; scan_current_block = scan_current_block->next)
143 | {
144 | scan_current_data = & ( scan_current_block -> data[0] );
145 | if (scan_current_data < scan_current_block -> current) return scan_current_data ++;
146 | }
147 | return NULL;
148 | }
149 |
150 | /* Returns the next item (or NULL, if all items have been read)
151 | Can be called only if previous ScanFirst() or ScanNext()
152 | call returned not NULL. */
153 | Type *ScanNext()
154 | {
155 | while (scan_current_data >= scan_current_block -> current)
156 | {
157 | scan_current_block = scan_current_block -> next;
158 | if (!scan_current_block) return NULL;
159 | scan_current_data = & ( scan_current_block -> data[0] );
160 | }
161 | return scan_current_data ++;
162 | }
163 |
164 | /* Marks all elements as empty */
165 | void Reset()
166 | {
167 | block *b;
168 | if (!first) return;
169 | for (b=first; ; b=b->next)
170 | {
171 | b -> current = & ( b -> data[0] );
172 | if (b == last) break;
173 | }
174 | last = first;
175 | }
176 |
177 | /***********************************************************************/
178 |
179 | private:
180 |
181 | typedef struct block_st
182 | {
183 | Type *current, *last;
184 | struct block_st *next;
185 | Type data[1];
186 | } block;
187 |
188 | int block_size;
189 | block *first;
190 | block *last;
191 |
192 | block *scan_current_block;
193 | Type *scan_current_data;
194 |
195 | void (*error_function)(const char *);
196 | };
197 |
198 | /***********************************************************************/
199 | /***********************************************************************/
200 | /***********************************************************************/
201 |
202 | template class DBlock
203 | {
204 | public:
205 | /* Constructor. Arguments are the block size and
206 | (optionally) the pointer to the function which
207 | will be called if allocation failed; the message
208 | passed to this function is "Not enough memory!" */
209 | DBlock(int size, void (*err_function)(const char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
210 |
211 | /* Destructor. Deallocates all items added so far */
212 | ~DBlock() { while (first) { block *next = first -> next; delete first; first = next; } }
213 |
214 | /* Allocates one item */
215 | Type *New()
216 | {
217 | block_item *item;
218 |
219 | if (!first_free)
220 | {
221 | block *next = first;
222 | first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)];
223 | if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
224 | first_free = & (first -> data[0] );
225 | for (item=first_free; item next_free = item + 1;
227 | item -> next_free = NULL;
228 | first -> next = next;
229 | }
230 |
231 | item = first_free;
232 | first_free = item -> next_free;
233 | return (Type *) item;
234 | }
235 |
236 | /* Deletes an item allocated previously */
237 | void Delete(Type *t)
238 | {
239 | ((block_item *) t) -> next_free = first_free;
240 | first_free = (block_item *) t;
241 | }
242 |
243 | /***********************************************************************/
244 |
245 | private:
246 |
247 | typedef union block_item_st
248 | {
249 | Type t;
250 | block_item_st *next_free;
251 | } block_item;
252 |
253 | typedef struct block_st
254 | {
255 | struct block_st *next;
256 | block_item data[1];
257 | } block;
258 |
259 | int block_size;
260 | block *first;
261 | block_item *first_free;
262 |
263 | void (*error_function)(const char *);
264 | };
265 |
266 |
267 | #endif
268 |
269 |
--------------------------------------------------------------------------------
/Project1/src/gco/energy.h:
--------------------------------------------------------------------------------
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 |
35 | ///////////////////////////////////////////////////
36 |
37 | #include
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 |
70 | ///////////////////////////////////////////////////
71 | */
72 |
73 | #ifndef __ENERGY_H__
74 | #define __ENERGY_H__
75 |
76 | #include
77 | #include "graph.h"
78 |
79 | template class Energy: public Graph
80 | {
81 | typedef Graph GraphT;
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
187 | inline Energy::Energy(int var_num_max, int edge_num_max, void (*err_function)(const char *)) : Graph(var_num_max, edge_num_max, err_function)
188 | {
189 | Econst = 0;
190 | error_function = err_function;
191 | }
192 |
193 | template
194 | inline Energy::~Energy() {}
195 |
196 | template
197 | inline typename Energy::Var Energy::add_variable(int num)
198 | { return GraphT::add_node(num); }
199 |
200 | template
201 | inline void Energy::add_constant(Value A) { Econst += A; }
202 |
203 | template
204 | inline void Energy::add_term1(Var x,
205 | Value A, Value B)
206 | {
207 | this->add_tweights(x, B, A);
208 | }
209 |
210 | template
211 | inline void Energy::add_term2(Var x, Var y,
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
256 | inline void Energy::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
324 | inline typename Energy::TotalValue Energy::minimize() {
325 | return Econst + GraphT::maxflow(); }
326 |
327 | template
328 | inline int Energy::get_var(Var x) { return (int) this->what_segment(x); }
329 |
330 | #endif
331 |
--------------------------------------------------------------------------------
/Project1/src/gco/example.cpp:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////
2 | // Example illustrating the use of GCoptimization.cpp
3 | //
4 | /////////////////////////////////////////////////////////////////////////////
5 | //
6 | // Optimization problem:
7 | // is a set of sites (pixels) of width 10 and hight 5. Thus number of pixels is 50
8 | // grid neighborhood: each pixel has its left, right, up, and bottom pixels as neighbors
9 | // 7 labels
10 | // Data costs: D(pixel,label) = 0 if pixel < 25 and label = 0
11 | // : D(pixel,label) = 10 if pixel < 25 and label is not 0
12 | // : D(pixel,label) = 0 if pixel >= 25 and label = 5
13 | // : D(pixel,label) = 10 if pixel >= 25 and label is not 5
14 | // Smoothness costs: V(p1,p2,l1,l2) = min( (l1-l2)*(l1-l2) , 4 )
15 | // Below in the main program, we illustrate different ways of setting data and smoothness costs
16 | // that our interface allow and solve this optimizaiton problem
17 |
18 | // For most of the examples, we use no spatially varying pixel dependent terms.
19 | // For some examples, to demonstrate spatially varying terms we use
20 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
21 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include "GCoptimization.h"
29 |
30 |
31 | struct ForDataFn{
32 | int numLab;
33 | int *data;
34 | };
35 |
36 |
37 | int smoothFn(int p1, int p2, int l1, int l2)
38 | {
39 | if ( (l1-l2)*(l1-l2) <= 4 ) return((l1-l2)*(l1-l2));
40 | else return(4);
41 | }
42 |
43 | int dataFn(int p, int l, void *data)
44 | {
45 | ForDataFn *myData = (ForDataFn *) data;
46 | int numLab = myData->numLab;
47 |
48 | return( myData->data[p*numLab+l] );
49 | }
50 |
51 |
52 |
53 | ////////////////////////////////////////////////////////////////////////////////
54 | // smoothness and data costs are set up one by one, individually
55 | // grid neighborhood structure is assumed
56 | //
57 | void GridGraph_Individually(int width,int height,int num_pixels,int num_labels)
58 | {
59 |
60 | int *result = new int[num_pixels]; // stores result of optimization
61 |
62 |
63 |
64 | try{
65 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels);
66 |
67 | // first set up data costs individually
68 | for ( int i = 0; i < num_pixels; i++ )
69 | for (int l = 0; l < num_labels; l++ )
70 | if (i < 25 ){
71 | if( l == 0 ) gc->setDataCost(i,l,0);
72 | else gc->setDataCost(i,l,10);
73 | }
74 | else {
75 | if( l == 5 ) gc->setDataCost(i,l,0);
76 | else gc->setDataCost(i,l,10);
77 | }
78 |
79 | // next set up smoothness costs individually
80 | for ( int l1 = 0; l1 < num_labels; l1++ )
81 | for (int l2 = 0; l2 < num_labels; l2++ ){
82 | int cost = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4;
83 | gc->setSmoothCost(l1,l2,cost);
84 | }
85 |
86 | printf("\nBefore optimization energy is %d",gc->compute_energy());
87 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
88 | printf("\nAfter optimization energy is %d",gc->compute_energy());
89 |
90 | for ( int i = 0; i < num_pixels; i++ )
91 | result[i] = gc->whatLabel(i);
92 |
93 | delete gc;
94 | }
95 | catch (GCException e){
96 | e.Report();
97 | }
98 |
99 | delete [] result;
100 | }
101 |
102 | ////////////////////////////////////////////////////////////////////////////////
103 | // in this version, set data and smoothness terms using arrays
104 | // grid neighborhood structure is assumed
105 | //
106 | void GridGraph_DArraySArray(int width,int height,int num_pixels,int num_labels)
107 | {
108 |
109 | int *result = new int[num_pixels]; // stores result of optimization
110 |
111 | // first set up the array for data costs
112 | int *data = new int[num_pixels*num_labels];
113 | for ( int i = 0; i < num_pixels; i++ )
114 | for (int l = 0; l < num_labels; l++ )
115 | if (i < 25 ){
116 | if( l == 0 ) data[i*num_labels+l] = 0;
117 | else data[i*num_labels+l] = 10;
118 | }
119 | else {
120 | if( l == 5 ) data[i*num_labels+l] = 0;
121 | else data[i*num_labels+l] = 10;
122 | }
123 | // next set up the array for smooth costs
124 | int *smooth = new int[num_labels*num_labels];
125 | for ( int l1 = 0; l1 < num_labels; l1++ )
126 | for (int l2 = 0; l2 < num_labels; l2++ )
127 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4;
128 |
129 |
130 | try{
131 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels);
132 | gc->setDataCost(data);
133 | gc->setSmoothCost(smooth);
134 | printf("\nBefore optimization energy is %d",gc->compute_energy());
135 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
136 | printf("\nAfter optimization energy is %d",gc->compute_energy());
137 |
138 | for ( int i = 0; i < num_pixels; i++ )
139 | result[i] = gc->whatLabel(i);
140 |
141 | delete gc;
142 | }
143 | catch (GCException e){
144 | e.Report();
145 | }
146 |
147 | delete [] result;
148 | delete [] smooth;
149 | delete [] data;
150 |
151 | }
152 | ////////////////////////////////////////////////////////////////////////////////
153 | // in this version, set data and smoothness terms using arrays
154 | // grid neighborhood structure is assumed
155 | //
156 | void GridGraph_DfnSfn(int width,int height,int num_pixels,int num_labels)
157 | {
158 |
159 | int *result = new int[num_pixels]; // stores result of optimization
160 |
161 | // first set up the array for data costs
162 | int *data = new int[num_pixels*num_labels];
163 | for ( int i = 0; i < num_pixels; i++ )
164 | for (int l = 0; l < num_labels; l++ )
165 | if (i < 25 ){
166 | if( l == 0 ) data[i*num_labels+l] = 0;
167 | else data[i*num_labels+l] = 10;
168 | }
169 | else {
170 | if( l == 5 ) data[i*num_labels+l] = 0;
171 | else data[i*num_labels+l] = 10;
172 | }
173 |
174 |
175 | try{
176 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels);
177 |
178 | // set up the needed data to pass to function for the data costs
179 | ForDataFn toFn;
180 | toFn.data = data;
181 | toFn.numLab = num_labels;
182 |
183 | gc->setDataCost(&dataFn,&toFn);
184 |
185 | // smoothness comes from function pointer
186 | gc->setSmoothCost(&smoothFn);
187 |
188 | printf("\nBefore optimization energy is %d",gc->compute_energy());
189 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
190 | printf("\nAfter optimization energy is %d",gc->compute_energy());
191 |
192 | for ( int i = 0; i < num_pixels; i++ )
193 | result[i] = gc->whatLabel(i);
194 |
195 | delete gc;
196 | }
197 | catch (GCException e){
198 | e.Report();
199 | }
200 |
201 | delete [] result;
202 | delete [] data;
203 |
204 | }
205 | ////////////////////////////////////////////////////////////////////////////////
206 | // Uses spatially varying smoothness terms. That is
207 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
208 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
209 | void GridGraph_DArraySArraySpatVarying(int width,int height,int num_pixels,int num_labels)
210 | {
211 | int *result = new int[num_pixels]; // stores result of optimization
212 |
213 | // first set up the array for data costs
214 | int *data = new int[num_pixels*num_labels];
215 | for ( int i = 0; i < num_pixels; i++ )
216 | for (int l = 0; l < num_labels; l++ )
217 | if (i < 25 ){
218 | if( l == 0 ) data[i*num_labels+l] = 0;
219 | else data[i*num_labels+l] = 10;
220 | }
221 | else {
222 | if( l == 5 ) data[i*num_labels+l] = 0;
223 | else data[i*num_labels+l] = 10;
224 | }
225 | // next set up the array for smooth costs
226 | int *smooth = new int[num_labels*num_labels];
227 | for ( int l1 = 0; l1 < num_labels; l1++ )
228 | for (int l2 = 0; l2 < num_labels; l2++ )
229 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4;
230 |
231 | // next set up spatially varying arrays V and H
232 |
233 | int *V = new int[num_pixels];
234 | int *H = new int[num_pixels];
235 |
236 |
237 | for ( int i = 0; i < num_pixels; i++ ){
238 | H[i] = i+(i+1)%3;
239 | V[i] = i*(i+width)%7;
240 | }
241 |
242 |
243 | try{
244 | GCoptimizationGridGraph *gc = new GCoptimizationGridGraph(width,height,num_labels);
245 | gc->setDataCost(data);
246 | gc->setSmoothCostVH(smooth,V,H);
247 | printf("\nBefore optimization energy is %d",gc->compute_energy());
248 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
249 | printf("\nAfter optimization energy is %d",gc->compute_energy());
250 |
251 | for ( int i = 0; i < num_pixels; i++ )
252 | result[i] = gc->whatLabel(i);
253 |
254 | delete gc;
255 | }
256 | catch (GCException e){
257 | e.Report();
258 | }
259 |
260 | delete [] result;
261 | delete [] smooth;
262 | delete [] data;
263 |
264 |
265 | }
266 |
267 | ////////////////////////////////////////////////////////////////////////////////
268 | // in this version, set data and smoothness terms using arrays
269 | // grid neighborhood is set up "manually"
270 | //
271 | void GeneralGraph_DArraySArray(int width,int height,int num_pixels,int num_labels)
272 | {
273 |
274 | int *result = new int[num_pixels]; // stores result of optimization
275 |
276 | // first set up the array for data costs
277 | int *data = new int[num_pixels*num_labels];
278 | for ( int i = 0; i < num_pixels; i++ )
279 | for (int l = 0; l < num_labels; l++ )
280 | if (i < 25 ){
281 | if( l == 0 ) data[i*num_labels+l] = 0;
282 | else data[i*num_labels+l] = 10;
283 | }
284 | else {
285 | if( l == 5 ) data[i*num_labels+l] = 0;
286 | else data[i*num_labels+l] = 10;
287 | }
288 | // next set up the array for smooth costs
289 | int *smooth = new int[num_labels*num_labels];
290 | for ( int l1 = 0; l1 < num_labels; l1++ )
291 | for (int l2 = 0; l2 < num_labels; l2++ )
292 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4;
293 |
294 |
295 | try{
296 | GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels);
297 | gc->setDataCost(data);
298 | gc->setSmoothCost(smooth);
299 |
300 | // now set up a grid neighborhood system
301 | // first set up horizontal neighbors
302 | for (int y = 0; y < height; y++ )
303 | for (int x = 1; x < width; x++ )
304 | gc->setNeighbors(x+y*width,x-1+y*width);
305 |
306 | // next set up vertical neighbors
307 | for (int y = 1; y < height; y++ )
308 | for (int x = 0; x < width; x++ )
309 | gc->setNeighbors(x+y*width,x+(y-1)*width);
310 |
311 | printf("\nBefore optimization energy is %d",gc->compute_energy());
312 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
313 | printf("\nAfter optimization energy is %d",gc->compute_energy());
314 |
315 | for ( int i = 0; i < num_pixels; i++ )
316 | result[i] = gc->whatLabel(i);
317 |
318 | delete gc;
319 | }
320 | catch (GCException e){
321 | e.Report();
322 | }
323 |
324 | delete [] result;
325 | delete [] smooth;
326 | delete [] data;
327 |
328 | }
329 | ////////////////////////////////////////////////////////////////////////////////
330 | // in this version, set data and smoothness terms using arrays
331 | // grid neighborhood is set up "manually". Uses spatially varying terms. Namely
332 | // V(p1,p2,l1,l2) = w_{p1,p2}*[min((l1-l2)*(l1-l2),4)], with
333 | // w_{p1,p2} = p1+p2 if |p1-p2| == 1 and w_{p1,p2} = p1*p2 if |p1-p2| is not 1
334 |
335 | void GeneralGraph_DArraySArraySpatVarying(int width,int height,int num_pixels,int num_labels)
336 | {
337 | int *result = new int[num_pixels]; // stores result of optimization
338 |
339 | // first set up the array for data costs
340 | int *data = new int[num_pixels*num_labels];
341 | for ( int i = 0; i < num_pixels; i++ )
342 | for (int l = 0; l < num_labels; l++ )
343 | if (i < 25 ){
344 | if( l == 0 ) data[i*num_labels+l] = 0;
345 | else data[i*num_labels+l] = 10;
346 | }
347 | else {
348 | if( l == 5 ) data[i*num_labels+l] = 0;
349 | else data[i*num_labels+l] = 10;
350 | }
351 | // next set up the array for smooth costs
352 | int *smooth = new int[num_labels*num_labels];
353 | for ( int l1 = 0; l1 < num_labels; l1++ )
354 | for (int l2 = 0; l2 < num_labels; l2++ )
355 | smooth[l1+l2*num_labels] = (l1-l2)*(l1-l2) <= 4 ? (l1-l2)*(l1-l2):4;
356 |
357 |
358 | try{
359 | GCoptimizationGeneralGraph *gc = new GCoptimizationGeneralGraph(num_pixels,num_labels);
360 | gc->setDataCost(data);
361 | gc->setSmoothCost(smooth);
362 |
363 | // now set up a grid neighborhood system
364 | // first set up horizontal neighbors
365 | for (int y = 0; y < height; y++ )
366 | for (int x = 1; x < width; x++ ){
367 | int p1 = x-1+y*width;
368 | int p2 =x+y*width;
369 | gc->setNeighbors(p1,p2,p1+p2);
370 | }
371 |
372 | // next set up vertical neighbors
373 | for (int y = 1; y < height; y++ )
374 | for (int x = 0; x < width; x++ ){
375 | int p1 = x+(y-1)*width;
376 | int p2 =x+y*width;
377 | gc->setNeighbors(p1,p2,p1*p2);
378 | }
379 |
380 | printf("\nBefore optimization energy is %d",gc->compute_energy());
381 | gc->expansion(2);// run expansion for 2 iterations. For swap use gc->swap(num_iterations);
382 | printf("\nAfter optimization energy is %d",gc->compute_energy());
383 |
384 | for ( int i = 0; i < num_pixels; i++ )
385 | result[i] = gc->whatLabel(i);
386 |
387 | delete gc;
388 | }
389 | catch (GCException e){
390 | e.Report();
391 | }
392 |
393 | delete [] result;
394 | delete [] smooth;
395 | delete [] data;
396 |
397 |
398 | }
399 | ////////////////////////////////////////////////////////////////////////////////
400 |
401 | int main(int argc, char **argv)
402 | {
403 | int width = 10;
404 | int height = 5;
405 | int num_pixels = width*height;
406 | int num_labels = 7;
407 |
408 |
409 | // smoothness and data costs are set up one by one, individually
410 | GridGraph_Individually(width,height,num_pixels,num_labels);
411 |
412 | // smoothness and data costs are set up using arrays
413 | GridGraph_DArraySArray(width,height,num_pixels,num_labels);
414 |
415 | // smoothness and data costs are set up using functions
416 | GridGraph_DfnSfn(width,height,num_pixels,num_labels);
417 |
418 | // smoothness and data costs are set up using arrays.
419 | // spatially varying terms are present
420 | GridGraph_DArraySArraySpatVarying(width,height,num_pixels,num_labels);
421 |
422 | //Will pretend our graph is
423 | //general, and set up a neighborhood system
424 | // which actually is a grid
425 | GeneralGraph_DArraySArray(width,height,num_pixels,num_labels);
426 |
427 | //Will pretend our graph is general, and set up a neighborhood system
428 | // which actually is a grid. Also uses spatially varying terms
429 | GeneralGraph_DArraySArraySpatVarying(width,height,num_pixels,num_labels);
430 |
431 | printf("\n Finished %d (%d) clock per sec %d",clock()/CLOCKS_PER_SEC,clock(),CLOCKS_PER_SEC);
432 |
433 | return 0;
434 | }
435 |
436 | /////////////////////////////////////////////////////////////////////////////////
437 |
438 |
--------------------------------------------------------------------------------
/Project1/src/gco/graph.cpp:
--------------------------------------------------------------------------------
1 | /* graph.cpp */
2 |
3 |
4 | #include
5 | #include
6 | #include
7 | #include "graph.h"
8 |
9 |
10 | template
11 | Graph::Graph(int node_num_max, int edge_num_max, void (*err_function)(const char *))
12 | : node_num(0),
13 | nodeptr_block(NULL),
14 | error_function(err_function)
15 | {
16 | if (node_num_max < 16) node_num_max = 16;
17 | if (edge_num_max < 16) edge_num_max = 16;
18 |
19 | nodes = (node*) malloc(node_num_max*sizeof(node));
20 | arcs = (arc*) malloc(2*edge_num_max*sizeof(arc));
21 | if (!nodes || !arcs) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
22 |
23 | node_last = nodes;
24 | node_max = nodes + node_num_max;
25 | arc_last = arcs;
26 | arc_max = arcs + 2*edge_num_max;
27 |
28 | maxflow_iteration = 0;
29 | flow = 0;
30 | }
31 |
32 | template
33 | Graph::~Graph()
34 | {
35 | if (nodeptr_block)
36 | {
37 | delete nodeptr_block;
38 | nodeptr_block = NULL;
39 | }
40 | free(nodes);
41 | free(arcs);
42 | }
43 |
44 | template
45 | void Graph::reset()
46 | {
47 | node_last = nodes;
48 | arc_last = arcs;
49 | node_num = 0;
50 |
51 | if (nodeptr_block)
52 | {
53 | delete nodeptr_block;
54 | nodeptr_block = NULL;
55 | }
56 |
57 | maxflow_iteration = 0;
58 | flow = 0;
59 | }
60 |
61 | template
62 | void Graph::reallocate_nodes(int num)
63 | {
64 | int node_num_max = (int)(node_max - nodes);
65 | node* nodes_old = nodes;
66 |
67 | node_num_max += node_num_max / 2;
68 | if (node_num_max < node_num + num) node_num_max = node_num + num;
69 | nodes = (node*) realloc(nodes_old, node_num_max*sizeof(node));
70 | if (!nodes) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
71 |
72 | node_last = nodes + node_num;
73 | node_max = nodes + node_num_max;
74 |
75 | if (nodes != nodes_old)
76 | {
77 | arc* a;
78 | for (a=arcs; ahead = (node*) ((char*)a->head + (((char*) nodes) - ((char*) nodes_old)));
81 | }
82 | }
83 | }
84 |
85 | template
86 | void Graph::reallocate_arcs()
87 | {
88 | int arc_num_max = (int)(arc_max - arcs);
89 | int arc_num = (int)(arc_last - arcs);
90 | arc* arcs_old = arcs;
91 |
92 | arc_num_max += arc_num_max / 2; if (arc_num_max & 1) arc_num_max ++;
93 | arcs = (arc*) realloc(arcs_old, arc_num_max*sizeof(arc));
94 | if (!arcs) { if (error_function) (*error_function)("Not enough memory!"); exit(1); }
95 |
96 | arc_last = arcs + arc_num;
97 | arc_max = arcs + arc_num_max;
98 |
99 | if (arcs != arcs_old)
100 | {
101 | node* i;
102 | arc* a;
103 | for (i=nodes; ifirst) i->first = (arc*) ((char*)i->first + (((char*) arcs) - ((char*) arcs_old)));
106 | }
107 | for (a=arcs; anext) a->next = (arc*) ((char*)a->next + (((char*) arcs) - ((char*) arcs_old)));
110 | a->sister = (arc*) ((char*)a->sister + (((char*) arcs) - ((char*) arcs_old)));
111 | }
112 | }
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/Project1/src/gco/graph.h:
--------------------------------------------------------------------------------
1 | /* graph.h */
2 | /*
3 | This software library implements the maxflow algorithm
4 | described in
5 |
6 | "An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy Minimization in Vision."
7 | Yuri Boykov and Vladimir Kolmogorov.
8 | In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI),
9 | September 2004
10 |
11 | This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov
12 | at Siemens Corporate Research. To make it available for public use,
13 | it was later reimplemented by Vladimir Kolmogorov based on open publications.
14 |
15 | If you use this software for research purposes, you should cite
16 | the aforementioned paper in any resulting publication.
17 |
18 | ----------------------------------------------------------------------
19 |
20 | REUSING TREES:
21 |
22 | Starting with version 3.0, there is a also an option of reusing search
23 | trees from one maxflow computation to the next, as described in
24 |
25 | "Efficiently Solving Dynamic Markov Random Fields Using Graph Cuts."
26 | Pushmeet Kohli and Philip H.S. Torr
27 | International Conference on Computer Vision (ICCV), 2005
28 |
29 | If you use this option, you should cite
30 | the aforementioned paper in any resulting publication.
31 | */
32 |
33 |
34 |
35 | /*
36 | For description, license, example usage see README.TXT.
37 | */
38 |
39 | #ifndef __GRAPH_H__
40 | #define __GRAPH_H__
41 |
42 | #include
43 | #include "block.h"
44 |
45 | #include
46 | // NOTE: in UNIX you need to use -DNDEBUG preprocessor option to supress assert's!!!
47 |
48 |
49 |
50 | // captype: type of edge capacities (excluding t-links)
51 | // tcaptype: type of t-links (edges between nodes and terminals)
52 | // flowtype: type of total flow
53 | //
54 | // Current instantiations are in instances.inc
55 | template class Graph
56 | {
57 | public:
58 | typedef enum
59 | {
60 | SOURCE = 0,
61 | SINK = 1
62 | } termtype; // terminals
63 | typedef int node_id;
64 |
65 | /////////////////////////////////////////////////////////////////////////
66 | // BASIC INTERFACE FUNCTIONS //
67 | // (should be enough for most applications) //
68 | /////////////////////////////////////////////////////////////////////////
69 |
70 | // Constructor.
71 | // The first argument gives an estimate of the maximum number of nodes that can be added
72 | // to the graph, and the second argument is an estimate of the maximum number of edges.
73 | // The last (optional) argument is the pointer to the function which will be called
74 | // if an error occurs; an error message is passed to this function.
75 | // If this argument is omitted, exit(1) will be called.
76 | //
77 | // IMPORTANT: It is possible to add more nodes to the graph than node_num_max
78 | // (and node_num_max can be zero). However, if the count is exceeded, then
79 | // the internal memory is reallocated (increased by 50%) which is expensive.
80 | // Also, temporarily the amount of allocated memory would be more than twice than needed.
81 | // Similarly for edges.
82 | // If you wish to avoid this overhead, you can download version 2.2, where nodes and edges are stored in blocks.
83 | Graph(int node_num_max, int edge_num_max, void (*err_function)(const char *) = NULL);
84 |
85 | // Destructor
86 | ~Graph();
87 |
88 | // Adds node(s) to the graph. By default, one node is added (num=1); then first call returns 0, second call returns 1, and so on.
89 | // If num>1, then several nodes are added, and node_id of the first one is returned.
90 | // IMPORTANT: see note about the constructor
91 | node_id add_node(int num = 1);
92 |
93 | // Adds a bidirectional edge between 'i' and 'j' with the weights 'cap' and 'rev_cap'.
94 | // IMPORTANT: see note about the constructor
95 | void add_edge(node_id i, node_id j, captype cap, captype rev_cap);
96 |
97 | // Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights.
98 | // Can be called multiple times for each node.
99 | // Weights can be negative.
100 | // NOTE: the number of such edges is not counted in edge_num_max.
101 | // No internal memory is allocated by this call.
102 | void add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink);
103 |
104 |
105 | // Computes the maxflow. Can be called several times.
106 | // FOR DESCRIPTION OF reuse_trees, SEE mark_node().
107 | // FOR DESCRIPTION OF changed_list, SEE remove_from_changed_list().
108 | flowtype maxflow(bool reuse_trees = false, Block* changed_list = NULL);
109 |
110 | // After the maxflow is computed, this function returns to which
111 | // segment the node 'i' belongs (Graph::SOURCE or Graph::SINK).
112 | //
113 | // Occasionally there may be several minimum cuts. If a node can be assigned
114 | // to both the source and the sink, then default_segm is returned.
115 | termtype what_segment(node_id i, termtype default_segm = SOURCE);
116 |
117 |
118 |
119 | //////////////////////////////////////////////
120 | // ADVANCED INTERFACE FUNCTIONS //
121 | // (provide access to the graph) //
122 | //////////////////////////////////////////////
123 |
124 | private:
125 | struct node;
126 | struct arc;
127 |
128 | public:
129 |
130 | ////////////////////////////
131 | // 1. Reallocating graph. //
132 | ////////////////////////////
133 |
134 | // Removes all nodes and edges.
135 | // After that functions add_node() and add_edge() must be called again.
136 | //
137 | // Advantage compared to deleting Graph and allocating it again:
138 | // no calls to delete/new (which could be quite slow).
139 | //
140 | // If the graph structure stays the same, then an alternative
141 | // is to go through all nodes/edges and set new residual capacities
142 | // (see functions below).
143 | void reset();
144 |
145 | ////////////////////////////////////////////////////////////////////////////////
146 | // 2. Functions for getting pointers to arcs and for reading graph structure. //
147 | // NOTE: adding new arcs may invalidate these pointers (if reallocation //
148 | // happens). So it's best not to add arcs while reading graph structure. //
149 | ////////////////////////////////////////////////////////////////////////////////
150 |
151 | // The following two functions return arcs in the same order that they
152 | // were added to the graph. NOTE: for each call add_edge(i,j,cap,cap_rev)
153 | // the first arc returned will be i->j, and the second j->i.
154 | // If there are no more arcs, then the function can still be called, but
155 | // the returned arc_id is undetermined.
156 | typedef arc* arc_id;
157 | arc_id get_first_arc();
158 | arc_id get_next_arc(arc_id a);
159 |
160 | // other functions for reading graph structure
161 | int get_node_num() { return node_num; }
162 | int get_arc_num() { return (int)(arc_last - arcs); }
163 | void get_arc_ends(arc_id a, node_id& i, node_id& j); // returns i,j to that a = i->j
164 |
165 | ///////////////////////////////////////////////////
166 | // 3. Functions for reading residual capacities. //
167 | ///////////////////////////////////////////////////
168 |
169 | // returns residual capacity of SOURCE->i minus residual capacity of i->SINK
170 | tcaptype get_trcap(node_id i);
171 | // returns residual capacity of arc a
172 | captype get_rcap(arc* a);
173 |
174 | /////////////////////////////////////////////////////////////////
175 | // 4. Functions for setting residual capacities. //
176 | // NOTE: If these functions are used, the value of the flow //
177 | // returned by maxflow() will not be valid! //
178 | /////////////////////////////////////////////////////////////////
179 |
180 | void set_trcap(node_id i, tcaptype trcap);
181 | void set_rcap(arc* a, captype rcap);
182 |
183 | ////////////////////////////////////////////////////////////////////
184 | // 5. Functions related to reusing trees & list of changed nodes. //
185 | ////////////////////////////////////////////////////////////////////
186 |
187 | // If flag reuse_trees is true while calling maxflow(), then search trees
188 | // are reused from previous maxflow computation.
189 | // In this case before calling maxflow() the user must
190 | // specify which parts of the graph have changed by calling mark_node():
191 | // add_tweights(i),set_trcap(i) => call mark_node(i)
192 | // add_edge(i,j),set_rcap(a) => call mark_node(i); mark_node(j)
193 | //
194 | // This option makes sense only if a small part of the graph is changed.
195 | // The initialization procedure goes only through marked nodes then.
196 | //
197 | // mark_node(i) can either be called before or after graph modification.
198 | // Can be called more than once per node, but calls after the first one
199 | // do not have any effect.
200 | //
201 | // NOTE:
202 | // - This option cannot be used in the first call to maxflow().
203 | // - It is not necessary to call mark_node() if the change is ``not essential'',
204 | // i.e. sign(trcap) is preserved for a node and zero/nonzero status is preserved for an arc.
205 | // - To check that you marked all necessary nodes, you can call maxflow(false) after calling maxflow(true).
206 | // If everything is correct, the two calls must return the same value of flow. (Useful for debugging).
207 | void mark_node(node_id i);
208 |
209 | // If changed_list is not NULL while calling maxflow(), then the algorithm
210 | // keeps a list of nodes which could potentially have changed their segmentation label.
211 | // Nodes which are not in the list are guaranteed to keep their old segmentation label (SOURCE or SINK).
212 | // Example usage:
213 | //
214 | // typedef Graph G;
215 | // G* g = new Graph(nodeNum, edgeNum);
216 | // Block* changed_list = new Block(128);
217 | //
218 | // ... // add nodes and edges
219 | //
220 | // g->maxflow(); // first call should be without arguments
221 | // for (int iter=0; iter<10; iter++)
222 | // {
223 | // ... // change graph, call mark_node() accordingly
224 | //
225 | // g->maxflow(true, changed_list);
226 | // G::node_id* ptr;
227 | // for (ptr=changed_list->ScanFirst(); ptr; ptr=changed_list->ScanNext())
228 | // {
229 | // G::node_id i = *ptr; assert(i>=0 && iremove_from_changed_list(i);
231 | // // do something with node i...
232 | // if (g->what_segment(i) == G::SOURCE) { ... }
233 | // }
234 | // changed_list->Reset();
235 | // }
236 | // delete changed_list;
237 | //
238 | // NOTE:
239 | // - If changed_list option is used, then reuse_trees must be used as well.
240 | // - In the example above, the user may omit calls g->remove_from_changed_list(i) and changed_list->Reset() in a given iteration.
241 | // Then during the next call to maxflow(true, &changed_list) new nodes will be added to changed_list.
242 | // - If the next call to maxflow() does not use option reuse_trees, then calling remove_from_changed_list()
243 | // is not necessary. ("changed_list->Reset()" or "delete changed_list" should still be called, though).
244 | void remove_from_changed_list(node_id i)
245 | {
246 | assert(i>=0 && i* g0);
251 |
252 |
253 |
254 |
255 | /////////////////////////////////////////////////////////////////////////
256 | /////////////////////////////////////////////////////////////////////////
257 | /////////////////////////////////////////////////////////////////////////
258 |
259 | private:
260 | // internal variables and functions
261 |
262 | struct node
263 | {
264 | arc *first; // first outcoming arc
265 |
266 | arc *parent; // node's parent
267 | node *next; // pointer to the next active node
268 | // (or to itself if it is the last node in the list)
269 | int TS; // timestamp showing when DIST was computed
270 | int DIST; // distance to the terminal
271 | int is_sink : 1; // flag showing whether the node is in the source or in the sink tree (if parent!=NULL)
272 | int is_marked : 1; // set by mark_node()
273 | int is_in_changed_list : 1; // set by maxflow if
274 |
275 | tcaptype tr_cap; // if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node
276 | // otherwise -tr_cap is residual capacity of the arc node->SINK
277 |
278 | };
279 |
280 | struct arc
281 | {
282 | node *head; // node the arc points to
283 | arc *next; // next arc with the same originating node
284 | arc *sister; // reverse arc
285 |
286 | captype r_cap; // residual capacity
287 | };
288 |
289 | struct nodeptr
290 | {
291 | node *ptr;
292 | nodeptr *next;
293 | };
294 | static const int NODEPTR_BLOCK_SIZE = 128;
295 |
296 | node *nodes, *node_last, *node_max; // node_last = nodes+node_num, node_max = nodes+node_num_max;
297 | arc *arcs, *arc_last, *arc_max; // arc_last = arcs+2*edge_num, arc_max = arcs+2*edge_num_max;
298 |
299 | int node_num;
300 |
301 | DBlock *nodeptr_block;
302 |
303 | void (*error_function)(const char *); // this function is called if a error occurs,
304 | // with a corresponding error message
305 | // (or exit(1) is called if it's NULL)
306 |
307 | flowtype flow; // total flow
308 |
309 | // reusing trees & list of changed pixels
310 | int maxflow_iteration; // counter
311 | Block *changed_list;
312 |
313 | /////////////////////////////////////////////////////////////////////////
314 |
315 | node *queue_first[2], *queue_last[2]; // list of active nodes
316 | nodeptr *orphan_first, *orphan_last; // list of pointers to orphans
317 | int TIME; // monotonically increasing global counter
318 |
319 | /////////////////////////////////////////////////////////////////////////
320 |
321 | void reallocate_nodes(int num); // num is the number of new nodes
322 | void reallocate_arcs();
323 |
324 | // functions for processing active list
325 | void set_active(node *i);
326 | node *next_active();
327 |
328 | // functions for processing orphans list
329 | void set_orphan_front(node* i); // add to the beginning of the list
330 | void set_orphan_rear(node* i); // add to the end of the list
331 |
332 | void add_to_changed_list(node* i);
333 |
334 | void maxflow_init(); // called if reuse_trees == false
335 | void maxflow_reuse_trees_init(); // called if reuse_trees == true
336 | void augment(arc *middle_arc);
337 | void process_source_orphan(node *i);
338 | void process_sink_orphan(node *i);
339 |
340 | void test_consistency(node* current_node=NULL); // debug function
341 | };
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 | ///////////////////////////////////////
354 | // Implementation - inline functions //
355 | ///////////////////////////////////////
356 |
357 |
358 |
359 | template
360 | inline typename Graph::node_id Graph::add_node(int num)
361 | {
362 | assert(num > 0);
363 |
364 | if (node_last + num > node_max) reallocate_nodes(num);
365 |
366 | if (num == 1)
367 | {
368 | node_last -> first = NULL;
369 | node_last -> tr_cap = 0;
370 | node_last -> is_marked = 0;
371 | node_last -> is_in_changed_list = 0;
372 |
373 | node_last ++;
374 | return node_num ++;
375 | }
376 | else
377 | {
378 | memset(node_last, 0, num*sizeof(node));
379 |
380 | node_id i = node_num;
381 | node_num += num;
382 | node_last += num;
383 | return i;
384 | }
385 | }
386 |
387 | template
388 | inline void Graph::add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink)
389 | {
390 | assert(i >= 0 && i < node_num);
391 |
392 | tcaptype delta = nodes[i].tr_cap;
393 | if (delta > 0) cap_source += delta;
394 | else cap_sink -= delta;
395 | flow += (cap_source < cap_sink) ? cap_source : cap_sink;
396 | nodes[i].tr_cap = cap_source - cap_sink;
397 | }
398 |
399 | template
400 | inline void Graph::add_edge(node_id _i, node_id _j, captype cap, captype rev_cap)
401 | {
402 | assert(_i >= 0 && _i < node_num);
403 | assert(_j >= 0 && _j < node_num);
404 | assert(_i != _j);
405 | assert(cap >= 0);
406 | assert(rev_cap >= 0);
407 |
408 | if (arc_last == arc_max) reallocate_arcs();
409 |
410 | arc *a = arc_last ++;
411 | arc *a_rev = arc_last ++;
412 |
413 | node* i = nodes + _i;
414 | node* j = nodes + _j;
415 |
416 | a -> sister = a_rev;
417 | a_rev -> sister = a;
418 | a -> next = i -> first;
419 | i -> first = a;
420 | a_rev -> next = j -> first;
421 | j -> first = a_rev;
422 | a -> head = j;
423 | a_rev -> head = i;
424 | a -> r_cap = cap;
425 | a_rev -> r_cap = rev_cap;
426 | }
427 |
428 | template
429 | inline typename Graph::arc* Graph::get_first_arc()
430 | {
431 | return arcs;
432 | }
433 |
434 | template
435 | inline typename Graph::arc* Graph::get_next_arc(arc* a)
436 | {
437 | return a + 1;
438 | }
439 |
440 | template
441 | inline void Graph::get_arc_ends(arc* a, node_id& i, node_id& j)
442 | {
443 | assert(a >= arcs && a < arc_last);
444 | i = (node_id) (a->sister->head - nodes);
445 | j = (node_id) (a->head - nodes);
446 | }
447 |
448 | template
449 | inline tcaptype Graph::get_trcap(node_id i)
450 | {
451 | assert(i>=0 && i
456 | inline captype Graph::get_rcap(arc* a)
457 | {
458 | assert(a >= arcs && a < arc_last);
459 | return a->r_cap;
460 | }
461 |
462 | template
463 | inline void Graph::set_trcap(node_id i, tcaptype trcap)
464 | {
465 | assert(i>=0 && i
470 | inline void Graph::set_rcap(arc* a, captype rcap)
471 | {
472 | assert(a >= arcs && a < arc_last);
473 | a->r_cap = rcap;
474 | }
475 |
476 |
477 | template
478 | inline typename Graph::termtype Graph::what_segment(node_id i, termtype default_segm)
479 | {
480 | if (nodes[i].parent)
481 | {
482 | return (nodes[i].is_sink) ? SINK : SOURCE;
483 | }
484 | else
485 | {
486 | return default_segm;
487 | }
488 | }
489 |
490 | template
491 | inline void Graph::mark_node(node_id _i)
492 | {
493 | node* i = nodes + _i;
494 | if (!i->next)
495 | {
496 | /* it's not in the list yet */
497 | if (queue_last[1]) queue_last[1] -> next = i;
498 | else queue_first[1] = i;
499 | queue_last[1] = i;
500 | i -> next = i;
501 | }
502 | i->is_marked = 1;
503 | }
504 |
505 |
506 | #endif
507 |
--------------------------------------------------------------------------------
/Project1/src/gco/maxflow.cpp:
--------------------------------------------------------------------------------
1 | /* maxflow.cpp */
2 |
3 |
4 | #include
5 | #include "graph.h"
6 |
7 |
8 | /*
9 | special constants for node->parent
10 | */
11 | #define TERMINAL ( (arc *) 1 ) /* to terminal */
12 | #define ORPHAN ( (arc *) 2 ) /* orphan */
13 |
14 |
15 | #define INFINITE_D ((int)(((unsigned)-1)/2)) /* infinite distance to the terminal */
16 |
17 | /***********************************************************************/
18 |
19 | /*
20 | Functions for processing active list.
21 | i->next points to the next node in the list
22 | (or to i, if i is the last node in the list).
23 | If i->next is NULL iff i is not in the list.
24 |
25 | There are two queues. Active nodes are added
26 | to the end of the second queue and read from
27 | the front of the first queue. If the first queue
28 | is empty, it is replaced by the second queue
29 | (and the second queue becomes empty).
30 | */
31 |
32 |
33 | template
34 | inline void Graph::set_active(node *i)
35 | {
36 | if (!i->next)
37 | {
38 | /* it's not in the list yet */
39 | if (queue_last[1]) queue_last[1] -> next = i;
40 | else queue_first[1] = i;
41 | queue_last[1] = i;
42 | i -> next = i;
43 | }
44 | }
45 |
46 | /*
47 | Returns the next active node.
48 | If it is connected to the sink, it stays in the list,
49 | otherwise it is removed from the list
50 | */
51 | template
52 | inline typename Graph::node* Graph::next_active()
53 | {
54 | node *i;
55 |
56 | while ( 1 )
57 | {
58 | if (!(i=queue_first[0]))
59 | {
60 | queue_first[0] = i = queue_first[1];
61 | queue_last[0] = queue_last[1];
62 | queue_first[1] = NULL;
63 | queue_last[1] = NULL;
64 | if (!i) return NULL;
65 | }
66 |
67 | /* remove it from the active list */
68 | if (i->next == i) queue_first[0] = queue_last[0] = NULL;
69 | else queue_first[0] = i -> next;
70 | i -> next = NULL;
71 |
72 | /* a node in the list is active iff it has a parent */
73 | if (i->parent) return i;
74 | }
75 | }
76 |
77 | /***********************************************************************/
78 |
79 | template
80 | inline void Graph::set_orphan_front(node *i)
81 | {
82 | nodeptr *np;
83 | i -> parent = ORPHAN;
84 | np = nodeptr_block -> New();
85 | np -> ptr = i;
86 | np -> next = orphan_first;
87 | orphan_first = np;
88 | }
89 |
90 | template
91 | inline void Graph::set_orphan_rear(node *i)
92 | {
93 | nodeptr *np;
94 | i -> parent = ORPHAN;
95 | np = nodeptr_block -> New();
96 | np -> ptr = i;
97 | if (orphan_last) orphan_last -> next = np;
98 | else orphan_first = np;
99 | orphan_last = np;
100 | np -> next = NULL;
101 | }
102 |
103 | /***********************************************************************/
104 |
105 | template
106 | inline void Graph::add_to_changed_list(node *i)
107 | {
108 | if (changed_list && !i->is_in_changed_list)
109 | {
110 | node_id* ptr = changed_list->New();
111 | *ptr = (node_id)(i - nodes);
112 | i->is_in_changed_list = true;
113 | }
114 | }
115 |
116 | /***********************************************************************/
117 |
118 | template
119 | void Graph::maxflow_init()
120 | {
121 | node *i;
122 |
123 | queue_first[0] = queue_last[0] = NULL;
124 | queue_first[1] = queue_last[1] = NULL;
125 | orphan_first = NULL;
126 |
127 | TIME = 0;
128 |
129 | for (i=nodes; i next = NULL;
132 | i -> is_marked = 0;
133 | i -> is_in_changed_list = 0;
134 | i -> TS = TIME;
135 | if (i->tr_cap > 0)
136 | {
137 | /* i is connected to the source */
138 | i -> is_sink = 0;
139 | i -> parent = TERMINAL;
140 | set_active(i);
141 | i -> DIST = 1;
142 | }
143 | else if (i->tr_cap < 0)
144 | {
145 | /* i is connected to the sink */
146 | i -> is_sink = 1;
147 | i -> parent = TERMINAL;
148 | set_active(i);
149 | i -> DIST = 1;
150 | }
151 | else
152 | {
153 | i -> parent = NULL;
154 | }
155 | }
156 | }
157 |
158 | template
159 | void Graph::maxflow_reuse_trees_init()
160 | {
161 | node* i;
162 | node* j;
163 | node* queue = queue_first[1];
164 | arc* a;
165 | nodeptr* np;
166 |
167 | queue_first[0] = queue_last[0] = NULL;
168 | queue_first[1] = queue_last[1] = NULL;
169 | orphan_first = orphan_last = NULL;
170 |
171 | TIME ++;
172 |
173 | while ((i=queue))
174 | {
175 | queue = i->next;
176 | if (queue == i) queue = NULL;
177 | i->next = NULL;
178 | i->is_marked = 0;
179 | set_active(i);
180 |
181 | if (i->tr_cap == 0)
182 | {
183 | if (i->parent) set_orphan_rear(i);
184 | continue;
185 | }
186 |
187 | if (i->tr_cap > 0)
188 | {
189 | if (!i->parent || i->is_sink)
190 | {
191 | i->is_sink = 0;
192 | for (a=i->first; a; a=a->next)
193 | {
194 | j = a->head;
195 | if (!j->is_marked)
196 | {
197 | if (j->parent == a->sister) set_orphan_rear(j);
198 | if (j->parent && j->is_sink && a->r_cap > 0) set_active(j);
199 | }
200 | }
201 | add_to_changed_list(i);
202 | }
203 | }
204 | else
205 | {
206 | if (!i->parent || !i->is_sink)
207 | {
208 | i->is_sink = 1;
209 | for (a=i->first; a; a=a->next)
210 | {
211 | j = a->head;
212 | if (!j->is_marked)
213 | {
214 | if (j->parent == a->sister) set_orphan_rear(j);
215 | if (j->parent && !j->is_sink && a->sister->r_cap > 0) set_active(j);
216 | }
217 | }
218 | add_to_changed_list(i);
219 | }
220 | }
221 | i->parent = TERMINAL;
222 | i -> TS = TIME;
223 | i -> DIST = 1;
224 | }
225 |
226 | //test_consistency();
227 |
228 | /* adoption */
229 | while ((np=orphan_first))
230 | {
231 | orphan_first = np -> next;
232 | i = np -> ptr;
233 | nodeptr_block -> Delete(np);
234 | if (!orphan_first) orphan_last = NULL;
235 | if (i->is_sink) process_sink_orphan(i);
236 | else process_source_orphan(i);
237 | }
238 | /* adoption end */
239 |
240 | //test_consistency();
241 | }
242 |
243 | template
244 | void Graph::augment(arc *middle_arc)
245 | {
246 | node *i;
247 | arc *a;
248 | tcaptype bottleneck;
249 |
250 |
251 | /* 1. Finding bottleneck capacity */
252 | /* 1a - the source tree */
253 | bottleneck = middle_arc -> r_cap;
254 | for (i=middle_arc->sister->head; ; i=a->head)
255 | {
256 | a = i -> parent;
257 | if (a == TERMINAL) break;
258 | if (bottleneck > a->sister->r_cap) bottleneck = a -> sister -> r_cap;
259 | }
260 | if (bottleneck > i->tr_cap) bottleneck = i -> tr_cap;
261 | /* 1b - the sink tree */
262 | for (i=middle_arc->head; ; i=a->head)
263 | {
264 | a = i -> parent;
265 | if (a == TERMINAL) break;
266 | if (bottleneck > a->r_cap) bottleneck = a -> r_cap;
267 | }
268 | if (bottleneck > - i->tr_cap) bottleneck = - i -> tr_cap;
269 |
270 |
271 | /* 2. Augmenting */
272 | /* 2a - the source tree */
273 | middle_arc -> sister -> r_cap += bottleneck;
274 | middle_arc -> r_cap -= bottleneck;
275 | for (i=middle_arc->sister->head; ; i=a->head)
276 | {
277 | a = i -> parent;
278 | if (a == TERMINAL) break;
279 | a -> r_cap += bottleneck;
280 | a -> sister -> r_cap -= bottleneck;
281 | if (!a->sister->r_cap)
282 | {
283 | set_orphan_front(i); // add i to the beginning of the adoption list
284 | }
285 | }
286 | i -> tr_cap -= bottleneck;
287 | if (!i->tr_cap)
288 | {
289 | set_orphan_front(i); // add i to the beginning of the adoption list
290 | }
291 | /* 2b - the sink tree */
292 | for (i=middle_arc->head; ; i=a->head)
293 | {
294 | a = i -> parent;
295 | if (a == TERMINAL) break;
296 | a -> sister -> r_cap += bottleneck;
297 | a -> r_cap -= bottleneck;
298 | if (!a->r_cap)
299 | {
300 | set_orphan_front(i); // add i to the beginning of the adoption list
301 | }
302 | }
303 | i -> tr_cap += bottleneck;
304 | if (!i->tr_cap)
305 | {
306 | set_orphan_front(i); // add i to the beginning of the adoption list
307 | }
308 |
309 |
310 | flow += bottleneck;
311 | }
312 |
313 | /***********************************************************************/
314 |
315 | template
316 | void Graph::process_source_orphan(node *i)
317 | {
318 | node *j;
319 | arc *a0, *a0_min = NULL, *a;
320 | int d, d_min = INFINITE_D;
321 |
322 | /* trying to find a new parent */
323 | for (a0=i->first; a0; a0=a0->next)
324 | if (a0->sister->r_cap)
325 | {
326 | j = a0 -> head;
327 | if (!j->is_sink && (a=j->parent))
328 | {
329 | /* checking the origin of j */
330 | d = 0;
331 | while ( 1 )
332 | {
333 | if (j->TS == TIME)
334 | {
335 | d += j -> DIST;
336 | break;
337 | }
338 | a = j -> parent;
339 | d ++;
340 | if (a==TERMINAL)
341 | {
342 | j -> TS = TIME;
343 | j -> DIST = 1;
344 | break;
345 | }
346 | if (a==ORPHAN) { d = INFINITE_D; break; }
347 | j = a -> head;
348 | }
349 | if (dhead; j->TS!=TIME; j=j->parent->head)
358 | {
359 | j -> TS = TIME;
360 | j -> DIST = d --;
361 | }
362 | }
363 | }
364 | }
365 |
366 | if (i->parent = a0_min)
367 | {
368 | i -> TS = TIME;
369 | i -> DIST = d_min + 1;
370 | }
371 | else
372 | {
373 | /* no parent is found */
374 | add_to_changed_list(i);
375 |
376 | /* process neighbors */
377 | for (a0=i->first; a0; a0=a0->next)
378 | {
379 | j = a0 -> head;
380 | if (!j->is_sink && (a=j->parent))
381 | {
382 | if (a0->sister->r_cap) set_active(j);
383 | if (a!=TERMINAL && a!=ORPHAN && a->head==i)
384 | {
385 | set_orphan_rear(j); // add j to the end of the adoption list
386 | }
387 | }
388 | }
389 | }
390 | }
391 |
392 | template
393 | void Graph::process_sink_orphan(node *i)
394 | {
395 | node *j;
396 | arc *a0, *a0_min = NULL, *a;
397 | int d, d_min = INFINITE_D;
398 |
399 | /* trying to find a new parent */
400 | for (a0=i->first; a0; a0=a0->next)
401 | if (a0->r_cap)
402 | {
403 | j = a0 -> head;
404 | if (j->is_sink && (a=j->parent))
405 | {
406 | /* checking the origin of j */
407 | d = 0;
408 | while ( 1 )
409 | {
410 | if (j->TS == TIME)
411 | {
412 | d += j -> DIST;
413 | break;
414 | }
415 | a = j -> parent;
416 | d ++;
417 | if (a==TERMINAL)
418 | {
419 | j -> TS = TIME;
420 | j -> DIST = 1;
421 | break;
422 | }
423 | if (a==ORPHAN) { d = INFINITE_D; break; }
424 | j = a -> head;
425 | }
426 | if (dhead; j->TS!=TIME; j=j->parent->head)
435 | {
436 | j -> TS = TIME;
437 | j -> DIST = d --;
438 | }
439 | }
440 | }
441 | }
442 |
443 | if (i->parent = a0_min)
444 | {
445 | i -> TS = TIME;
446 | i -> DIST = d_min + 1;
447 | }
448 | else
449 | {
450 | /* no parent is found */
451 | add_to_changed_list(i);
452 |
453 | /* process neighbors */
454 | for (a0=i->first; a0; a0=a0->next)
455 | {
456 | j = a0 -> head;
457 | if (j->is_sink && (a=j->parent))
458 | {
459 | if (a0->r_cap) set_active(j);
460 | if (a!=TERMINAL && a!=ORPHAN && a->head==i)
461 | {
462 | set_orphan_rear(j); // add j to the end of the adoption list
463 | }
464 | }
465 | }
466 | }
467 | }
468 |
469 | /***********************************************************************/
470 |
471 | template
472 | flowtype Graph::maxflow(bool reuse_trees, Block* _changed_list)
473 | {
474 | node *i, *j, *current_node = NULL;
475 | arc *a;
476 | nodeptr *np, *np_next;
477 |
478 | if (!nodeptr_block)
479 | {
480 | nodeptr_block = new DBlock(NODEPTR_BLOCK_SIZE, error_function);
481 | }
482 |
483 | changed_list = _changed_list;
484 | if (maxflow_iteration == 0 && reuse_trees) { if (error_function) (*error_function)("reuse_trees cannot be used in the first call to maxflow()!"); exit(1); }
485 | if (changed_list && !reuse_trees) { if (error_function) (*error_function)("changed_list cannot be used without reuse_trees!"); exit(1); }
486 |
487 | if (reuse_trees) maxflow_reuse_trees_init();
488 | else maxflow_init();
489 |
490 | // main loop
491 | while ( 1 )
492 | {
493 | // test_consistency(current_node);
494 |
495 | if ((i=current_node))
496 | {
497 | i -> next = NULL; /* remove active flag */
498 | if (!i->parent) i = NULL;
499 | }
500 | if (!i)
501 | {
502 | if (!(i = next_active())) break;
503 | }
504 |
505 | /* growth */
506 | if (!i->is_sink)
507 | {
508 | /* grow source tree */
509 | for (a=i->first; a; a=a->next)
510 | if (a->r_cap)
511 | {
512 | j = a -> head;
513 | if (!j->parent)
514 | {
515 | j -> is_sink = 0;
516 | j -> parent = a -> sister;
517 | j -> TS = i -> TS;
518 | j -> DIST = i -> DIST + 1;
519 | set_active(j);
520 | add_to_changed_list(j);
521 | }
522 | else if (j->is_sink) break;
523 | else if (j->TS <= i->TS &&
524 | j->DIST > i->DIST)
525 | {
526 | /* heuristic - trying to make the distance from j to the source shorter */
527 | j -> parent = a -> sister;
528 | j -> TS = i -> TS;
529 | j -> DIST = i -> DIST + 1;
530 | }
531 | }
532 | }
533 | else
534 | {
535 | /* grow sink tree */
536 | for (a=i->first; a; a=a->next)
537 | if (a->sister->r_cap)
538 | {
539 | j = a -> head;
540 | if (!j->parent)
541 | {
542 | j -> is_sink = 1;
543 | j -> parent = a -> sister;
544 | j -> TS = i -> TS;
545 | j -> DIST = i -> DIST + 1;
546 | set_active(j);
547 | add_to_changed_list(j);
548 | }
549 | else if (!j->is_sink) { a = a -> sister; break; }
550 | else if (j->TS <= i->TS &&
551 | j->DIST > i->DIST)
552 | {
553 | /* heuristic - trying to make the distance from j to the sink shorter */
554 | j -> parent = a -> sister;
555 | j -> TS = i -> TS;
556 | j -> DIST = i -> DIST + 1;
557 | }
558 | }
559 | }
560 |
561 | TIME ++;
562 |
563 | if (a)
564 | {
565 | i -> next = i; /* set active flag */
566 | current_node = i;
567 |
568 | /* augmentation */
569 | augment(a);
570 | /* augmentation end */
571 |
572 | /* adoption */
573 | while ((np=orphan_first))
574 | {
575 | np_next = np -> next;
576 | np -> next = NULL;
577 |
578 | while ((np=orphan_first))
579 | {
580 | orphan_first = np -> next;
581 | i = np -> ptr;
582 | nodeptr_block -> Delete(np);
583 | if (!orphan_first) orphan_last = NULL;
584 | if (i->is_sink) process_sink_orphan(i);
585 | else process_source_orphan(i);
586 | }
587 |
588 | orphan_first = np_next;
589 | }
590 | /* adoption end */
591 | }
592 | else current_node = NULL;
593 | }
594 | // test_consistency();
595 |
596 | if (!reuse_trees || (maxflow_iteration % 64) == 0)
597 | {
598 | delete nodeptr_block;
599 | nodeptr_block = NULL;
600 | }
601 |
602 | maxflow_iteration ++;
603 | return flow;
604 | }
605 |
606 | /***********************************************************************/
607 |
608 |
609 | template
610 | void Graph::test_consistency(node* current_node)
611 | {
612 | node *i;
613 | arc *a;
614 | int r;
615 | int num1 = 0, num2 = 0;
616 |
617 | // test whether all nodes i with i->next!=NULL are indeed in the queue
618 | for (i=nodes; inext || i==current_node) num1 ++;
621 | }
622 | for (r=0; r<3; r++)
623 | {
624 | i = (r == 2) ? current_node : queue_first[r];
625 | if (i)
626 | for ( ; ; i=i->next)
627 | {
628 | num2 ++;
629 | if (i->next == i)
630 | {
631 | if (r<2) assert(i == queue_last[r]);
632 | else assert(i == current_node);
633 | break;
634 | }
635 | }
636 | }
637 | assert(num1 == num2);
638 |
639 | for (i=nodes; iparent == NULL) {}
643 | else if (i->parent == ORPHAN) {}
644 | else if (i->parent == TERMINAL)
645 | {
646 | if (!i->is_sink) assert(i->tr_cap > 0);
647 | else assert(i->tr_cap < 0);
648 | }
649 | else
650 | {
651 | if (!i->is_sink) assert (i->parent->sister->r_cap > 0);
652 | else assert (i->parent->r_cap > 0);
653 | }
654 | // test whether passive nodes in search trees have neighbors in
655 | // a different tree through non-saturated edges
656 | if (i->parent && !i->next)
657 | {
658 | if (!i->is_sink)
659 | {
660 | assert(i->tr_cap >= 0);
661 | for (a=i->first; a; a=a->next)
662 | {
663 | if (a->r_cap > 0) assert(a->head->parent && !a->head->is_sink);
664 | }
665 | }
666 | else
667 | {
668 | assert(i->tr_cap <= 0);
669 | for (a=i->first; a; a=a->next)
670 | {
671 | if (a->sister->r_cap > 0) assert(a->head->parent && a->head->is_sink);
672 | }
673 | }
674 | }
675 | // test marking invariants
676 | if (i->parent && i->parent!=ORPHAN && i->parent!=TERMINAL)
677 | {
678 | assert(i->TS <= i->parent->head->TS);
679 | if (i->TS == i->parent->head->TS) assert(i->DIST > i->parent->head->DIST);
680 | }
681 | }
682 | }
683 |
684 | template
685 | void Graph::Copy(Graph* g0)
686 | {
687 | node* i;
688 | arc* a;
689 |
690 | reset();
691 |
692 | if (node_max < nodes + g0->node_num)
693 | {
694 | free(nodes);
695 | nodes = node_last = (node*) malloc(g0->node_num*sizeof(node));
696 | node_max = nodes + g0->node_num;
697 | }
698 | if (arc_max < arcs + (g0->arc_last - g0->arcs))
699 | {
700 | free(arcs);
701 | arcs = arc_last = (arc*) malloc((g0->arc_last - g0->arcs)*sizeof(arc));
702 | arc_max = arcs + (g0->arc_last - g0->arcs);
703 | }
704 |
705 | node_num = g0->node_num;
706 | node_last = nodes + node_num;
707 | memcpy(nodes, g0->nodes, node_num*sizeof(node));
708 | for (i=nodes; ifirst) i->first = (arc*)((char*)arcs + (((char*)i->first) - ((char*)g0->arcs)));
711 | if (i->parent && i->parent!=TERMINAL && i->parent!=ORPHAN) i->parent = (arc*)((char*)arcs + (((char*)i->parent) - ((char*)g0->arcs)));
712 | if (i->next) i->next = (node*)((char*)nodes + (((char*)i->next) - ((char*)g0->nodes)));
713 | }
714 |
715 | arc_last = arcs + (g0->arc_last - g0->arcs);
716 | memcpy(arcs, g0->arcs, (g0->arc_last - g0->arcs)*sizeof(arc));
717 | for (a=arcs; ahead = (node*)((char*)nodes + (((char*)a->head) - ((char*)g0->nodes)));
720 | if (a->next) a->next = (arc*)((char*)arcs + (((char*)a->next) - ((char*)g0->arcs)));
721 | a->sister = (arc*)((char*)arcs + (((char*)a->sister) - ((char*)g0->arcs)));
722 | }
723 |
724 | error_function = g0->error_function;
725 | flow = g0->flow;
726 | maxflow_iteration = g0->maxflow_iteration;
727 |
728 | queue_first[0] = (g0->queue_first[0]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_first[0]) - ((char*)g0->nodes)));
729 | queue_first[1] = (g0->queue_first[1]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_first[1]) - ((char*)g0->nodes)));
730 | queue_last[0] = (g0->queue_last[0]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_last[0]) - ((char*)g0->nodes)));
731 | queue_last[1] = (g0->queue_last[1]==NULL) ? NULL : (node*)((char*)nodes + (((char*)g0->queue_last[1]) - ((char*)g0->nodes)));
732 | TIME = g0->TIME;
733 | }
734 |
--------------------------------------------------------------------------------
/Project1/src/inpainter.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Project1/src/inpainter.cpp
--------------------------------------------------------------------------------
/Project1/src/inpainter.h:
--------------------------------------------------------------------------------
1 | /*M///////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 | //
5 | // By downloading, copying, installing or using the software you agree to this license.
6 | // If you do not agree to this license, do not download, install,
7 | // copy or use the software.
8 | //
9 | //
10 | // License Agreement
11 | // For Open Source Computer Vision Library
12 | //
13 | // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 | // Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved.
15 | // Third party copyrights are property of their respective owners.
16 | //
17 | // Redistribution and use in source and binary forms, with or without modification,
18 | // are permitted provided that the following conditions are met:
19 | //
20 | // * Redistribution's of source code must retain the above copyright notice,
21 | // this list of conditions and the following disclaimer.
22 | //
23 | // * Redistribution's in binary form must reproduce the above copyright notice,
24 | // this list of conditions and the following disclaimer in the documentation
25 | // and/or other materials provided with the distribution.
26 | //
27 | // * The name of the copyright holders may not be used to endorse or promote products
28 | // derived from this software without specific prior written permission.
29 | //
30 | // This software is provided by the copyright holders and contributors "as is" and
31 | // any express or implied warranties, including, but not limited to, the implied
32 | // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 | // In no event shall the Intel Corporation or contributors be liable for any direct,
34 | // indirect, incidental, special, exemplary, or consequential damages
35 | // (including, but not limited to, procurement of substitute goods or services;
36 | // loss of use, data, or profits; or business interruption) however caused
37 | // and on any theory of liability, whether in contract, strict liability,
38 | // or tort (including negligence or otherwise) arising in any way out of
39 | // the use of this software, even if advised of the possibility of such damage.
40 | //
41 | //M*/
42 |
43 | #ifndef INPAINTER_H
44 | #define INPAINTER_H
45 |
46 |
47 | #include
48 | #include "utils.h"
49 | #include "gco/GCoptimization.h"
50 |
51 | using namespace cv;
52 |
53 | typedef struct
54 | {
55 | Point pOffset;
56 | int nVoteNum;
57 | }ST_Offset;
58 |
59 | class Inpainter
60 | {
61 | public:
62 | const static int ERROR_INPUT_MAT_INVALID_TYPE=0;
63 | const static int ERROR_INPUT_MASK_INVALID_TYPE=1;
64 | const static int ERROR_MASK_INPUT_SIZE_MISMATCH=2;
65 | const static int ERROR_HALF_PATCH_WIDTH_ZERO=3;
66 | const static int CHECK_VALID=4;
67 |
68 | Inpainter(cv::Mat inputImage,cv::Mat mask,int halfPatchWidth=4,int mode=1);
69 |
70 |
71 | int k;
72 | int tau;
73 |
74 | cv::Mat inputImage;
75 | cv::Mat mask;
76 | cv::Mat result;
77 | cv::Mat workImage;
78 |
79 | Mat Label;
80 |
81 | int halfPatchWidth;
82 | int PatchSize;
83 |
84 | int checkValidInputs();
85 |
86 | void inpaint();
87 |
88 | void VisualizeResultLabelMap(GCoptimizationGeneralGraph *gc);
89 | private:
90 |
91 |
92 |
93 | Mat ann, annd;
94 |
95 | void GetKDominateOffSet();
96 | };
97 |
98 |
99 | #endif // INPAINTER_H
100 |
--------------------------------------------------------------------------------
/Project1/src/main.cpp:
--------------------------------------------------------------------------------
1 | /*M///////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 | //
5 | // By downloading, copying, installing or using the software you agree to this license.
6 | // If you do not agree to this license, do not download, install,
7 | // copy or use the software.
8 | //
9 | //
10 | // License Agreement
11 | // For Open Source Computer Vision Library
12 | //
13 | // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 | // Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved.
15 | // Third party copyrights are property of their respective owners.
16 | //
17 | // Redistribution and use in source and binary forms, with or without modification,
18 | // are permitted provided that the following conditions are met:
19 | //
20 | // * Redistribution's of source code must retain the above copyright notice,
21 | // this list of conditions and the following disclaimer.
22 | //
23 | // * Redistribution's in binary form must reproduce the above copyright notice,
24 | // this list of conditions and the following disclaimer in the documentation
25 | // and/or other materials provided with the distribution.
26 | //
27 | // * The name of the copyright holders may not be used to endorse or promote products
28 | // derived from this software without specific prior written permission.
29 | //
30 | // This software is provided by the copyright holders and contributors "as is" and
31 | // any express or implied warranties, including, but not limited to, the implied
32 | // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 | // In no event shall the Intel Corporation or contributors be liable for any direct,
34 | // indirect, incidental, special, exemplary, or consequential damages
35 | // (including, but not limited to, procurement of substitute goods or services;
36 | // loss of use, data, or profits; or business interruption) however caused
37 | // and on any theory of liability, whether in contract, strict liability,
38 | // or tort (including negligence or otherwise) arising in any way out of
39 | // the use of this software, even if advised of the possibility of such damage.
40 | //
41 | //M*/
42 |
43 | #include "inpainter.h"
44 |
45 | cv::Mat image,originalImage,inpaintMask;
46 | cv::Point prevPt(-1,-1);
47 | int thickness=5;
48 | static void onMouse( int event, int x, int y, int flags, void* )
49 | {
50 | if(event == cv::EVENT_LBUTTONUP||!(flags & cv::EVENT_FLAG_LBUTTON) )
51 | prevPt = cv::Point(-1,-1);
52 | else if( event == cv::EVENT_LBUTTONDOWN )
53 | prevPt = cv::Point(x,y);
54 | else if( event == cv::EVENT_MOUSEMOVE && (flags & cv::EVENT_FLAG_LBUTTON) )
55 | {
56 | cv::Point pt(x,y);
57 | if( prevPt.x < 0 )
58 | prevPt = pt;
59 | cv::line( inpaintMask, prevPt, pt, cv::Scalar::all(255), thickness, 8, 0 );
60 | cv::line( image, prevPt, pt, cv::Scalar::all(255), thickness, 8, 0 );
61 | prevPt = pt;
62 | cv::imshow("image", image);
63 | }
64 | }
65 |
66 |
67 |
68 |
69 | int main(int argc, char *argv[])
70 | {
71 |
72 | //we expect three arguments.
73 | //the first is the image path.
74 | //the second is the mask path.
75 | //the third argument is the halfPatchWidth
76 |
77 | //in case halPatchWidth is not specified we use a default value of 3.
78 | //in case only image path is speciifed, we use manual marking of mask over the image.
79 | //in case image name is also not specified , we use default image default.jpg.
80 |
81 |
82 | int halfPatchWidth = 3;
83 |
84 | if(argc>=4)
85 | {
86 | std::stringstream ss;
87 | ss<>halfPatchWidth;
89 | }
90 |
91 | char* imageName = argc >= 2 ? argv[1] : (char*)"..\\testsImage\\man.png";
92 |
93 | originalImage=cv::imread(imageName,CV_LOAD_IMAGE_COLOR);
94 |
95 | if(!originalImage.data){
96 | std::cout<= 3){
109 | maskName=argv[2];
110 | maskSpecified=true;
111 | }
112 |
113 | if(maskSpecified){
114 |
115 | inpaintMask=cv::imread(maskName.c_str(), 0);
116 | Inpainter i(originalImage,inpaintMask,halfPatchWidth);
117 |
118 |
119 | if(i.checkValidInputs()==i.CHECK_VALID){
120 | i.inpaint();
121 |
122 | cv::imwrite("..\\Output\\lableMap.jpg", i.Label);
123 | cv::imwrite("..\\Output\\graphCut.jpg", i.workImage);
124 | cv::imwrite("..\\Output\\result.jpg",i.result);
125 | cv::namedWindow("result");
126 | cv::imshow("result",i.result);
127 | cv::waitKey();
128 | }
129 | else
130 | {
131 | std::cout<12)
183 | thickness=12;
184 | }
185 |
186 | }
187 |
188 |
189 |
190 |
191 |
192 | return 0;
193 | }
194 |
--------------------------------------------------------------------------------
/Project1/src/pm_minimal.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/Project1/src/pm_minimal.cpp
--------------------------------------------------------------------------------
/Project1/src/utils.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "utils.h"
3 |
4 | // hsv ת rgb
5 | Vec3f HSVtoRGB(Vec3f hsv)
6 | {
7 | int i;
8 | float f, p, q, t;
9 | if (hsv[1] == 0) {
10 |
11 | // achromatic (grey)
12 | return Vec3f(hsv[2], hsv[2], hsv[2]);;
13 | }
14 | hsv[0] /= 60; // sector 0 to 5
15 | i = floor(hsv[0]);
16 | f = hsv[0] - i; // factorial part of h
17 | p = hsv[2] * (1 - hsv[1]);
18 | q = hsv[2] * (1 - hsv[1] * f);
19 | t = hsv[2] * (1 - hsv[1] * (1 - f));
20 | switch (i)
21 | {
22 | case 0:
23 | return Vec3f(hsv[2], t, p);
24 | case 1:
25 | return Vec3f(q, hsv[2], p);
26 | case 2:
27 | return Vec3f(p, hsv[2], t);
28 | case 3:
29 | return Vec3f(p, q, hsv[2]);
30 | case 4:
31 | return Vec3f(t, p, hsv[2]);
32 | default: // case 5:
33 | return Vec3f(hsv[2], p, q);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Project1/src/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | using namespace cv;
4 |
5 |
6 | Vec3f HSVtoRGB(Vec3f hsv);
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Image Completion approaches using the statistics of Similar Patches"
2 |
3 |
4 |
5 | 参考了一些Github上的代码自己实现了何凯明大神的这个算法,算法思路比较简单,但是效果还不错。
6 |
7 | 第二个man的效果比paper中的效果差一些,可能是由于计算patch offset的时候使用的是PatchMatch,其精度速度都会更差一些。其他参数我都只做了一些简单的调整。
8 |
9 |
10 |
11 | | 原图 | label | result |
12 | | ---------------------------- | --------------------------- | ------ |
13 | |  |  |  |
14 | |  |  |  |
15 |
16 | # Implementation detail
17 |
18 | 1. calculate the patch offsets histogram by PatchMatch
19 | 2. get the k dominate offset
20 | 3. multi-label by graph-cut
21 | 4. gradient-domain fusion
22 |
23 | # Requires
24 |
25 | 1. OpenCV
26 | 2. Eigen to fullfill the possion fusion
27 |
28 |
29 | developed by vs2017 community
30 |
31 | tested only on win10
32 |
33 | # reference
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/inpainting.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.168
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project1", "Project1\Project1.vcxproj", "{2F283BAE-C334-4CD9-96C3-B95022D720E2}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Debug|x64.ActiveCfg = Debug|x64
17 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Debug|x64.Build.0 = Debug|x64
18 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Debug|x86.ActiveCfg = Debug|Win32
19 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Debug|x86.Build.0 = Debug|Win32
20 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Release|x64.ActiveCfg = Release|x64
21 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Release|x64.Build.0 = Release|x64
22 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Release|x86.ActiveCfg = Release|Win32
23 | {2F283BAE-C334-4CD9-96C3-B95022D720E2}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {992FB2F1-A95A-4FE3-9CED-FEDB3C6E8043}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/pami14completion.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/pami14completion.pdf
--------------------------------------------------------------------------------
/testsImage/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/image1.jpg
--------------------------------------------------------------------------------
/testsImage/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/image2.jpg
--------------------------------------------------------------------------------
/testsImage/image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/image3.jpg
--------------------------------------------------------------------------------
/testsImage/image4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/image4.jpg
--------------------------------------------------------------------------------
/testsImage/man-mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/man-mask.png
--------------------------------------------------------------------------------
/testsImage/man.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/man.png
--------------------------------------------------------------------------------
/testsImage/mask1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/mask1.jpg
--------------------------------------------------------------------------------
/testsImage/mask2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/mask2.jpg
--------------------------------------------------------------------------------
/testsImage/mask3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/mask3.jpg
--------------------------------------------------------------------------------
/testsImage/mask4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/mask4.jpg
--------------------------------------------------------------------------------
/testsImage/result1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/result1.jpg
--------------------------------------------------------------------------------
/testsImage/result2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/result2.jpg
--------------------------------------------------------------------------------
/testsImage/result3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chwahaha/statistic-of-similar-patch-offset/8db8c200ee41c9c09cd8977175094e1e1f1c806d/testsImage/result3.jpg
--------------------------------------------------------------------------------