├── 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< 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 | | ![](/testsImage/image4.jpg) | ![](/Output/lableMap4.jpg) | ![](./Output/result4.jpg) | 14 | | ![](./testsImage/man.png) | ![](./Output/lableMap-man.jpg) | ![](./Output/result-man.jpg) | 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 --------------------------------------------------------------------------------