├── Carlevaris ├── README.txt ├── dark_chan_prior.m ├── gco-v3.0 │ ├── GCO_README.TXT │ ├── GCoptimization.cpp │ ├── GCoptimization.h │ ├── LinkedBlockList.cpp │ ├── LinkedBlockList.h │ ├── block.h │ ├── energy.h │ ├── example.cpp │ ├── graph.cpp │ ├── graph.h │ ├── matlab │ │ ├── GCO_BuildLib.m │ │ ├── GCO_ComputeEnergy.m │ │ ├── GCO_Create.m │ │ ├── GCO_Delete.m │ │ ├── GCO_ExpandOnAlpha.m │ │ ├── GCO_Expansion.m │ │ ├── GCO_GetLabeling.m │ │ ├── GCO_ListHandles.m │ │ ├── GCO_LoadLib.m │ │ ├── GCO_SetDataCost.m │ │ ├── GCO_SetLabelCost.m │ │ ├── GCO_SetLabelOrder.m │ │ ├── GCO_SetLabeling.m │ │ ├── GCO_SetNeighbors.m │ │ ├── GCO_SetSmoothCost.m │ │ ├── GCO_SetVerbosity.m │ │ ├── GCO_Swap.m │ │ ├── GCO_UnitTest.m │ │ ├── README.TXT │ │ ├── bin │ │ │ └── gco_matlab.mexw64 │ │ ├── gco_matlab.cpp │ │ └── test.m │ └── maxflow.cpp ├── getLaplacian1.m ├── grid_nb.m ├── grid_nb_weighted.m ├── images │ └── img.jpg ├── laplacian_matting.m └── oceans.m ├── DPATN ├── Airlight_water.m ├── Dehazefun.m ├── JointTraining_5x5_2500new.mat ├── SimplestColorBalance.m ├── boxfilter.m ├── demo_underwater.m ├── denoisingOneStepGMixMFs.m ├── gen_dct2.m ├── guidedfilter.m ├── images │ └── 1.jpg ├── lut_eval.c ├── lut_eval.mexw64 ├── save_trained_model.m └── t_initialize.m └── ImageEnhanceViaFusion ├── SimplestColorBalance.m ├── UICM.m ├── UIConM.m ├── UIQM.m ├── UISM.m ├── autolevel.m ├── bilateralFilter.m ├── boxfilter.m ├── clahe.m ├── fuse.m ├── gaussian_pyramid.m ├── guidedfilter.m ├── lab_to_rgb.m ├── laplacian_pyramid.m ├── load_image.m ├── main.m ├── main_test_diff_weights.m ├── main_using_optimized.m ├── maxfilt2.m ├── pyramid_reconstruct.m ├── rgb_to_lab.m ├── saliency_detection.m ├── test.m ├── vanherk.m └── white_balance.m /Carlevaris/README.txt: -------------------------------------------------------------------------------- 1 | It should be pretty straight forward to run. It relies on the graph cuts 2 | library which needs to be compiled. Out of the box it should run on Windows 7 3 | 64bit. On other operating systems you may need to recompile. Just a warning, 4 | if you want to dehaze megapixel and larger images it might take quite a bit of 5 | memory (especially the Laplacian matting step). 6 | 7 | The main file to run is oceans.m which is setup to run a few sample images and 8 | pretty well commented. There are two tuning parameters, win and lambda, that I 9 | found to be very important in order to get the best results. There is a 10 | comment in the code that gives some rough ranges of appropriate values for 11 | these parameters. 12 | -------------------------------------------------------------------------------- /Carlevaris/dark_chan_prior.m: -------------------------------------------------------------------------------- 1 | function [ t_est ] = dark_chan_prior(I, A, win, omega) 2 | %DARK_CHAN_PRIOR estimates the depth of a scene using the Dark Channel 3 | %Prior proposed by He et al in ... 4 | 5 | size_I = size(I); 6 | img_min_patch = single(zeros(size_I)); 7 | img_min_patch(:,:,1) = ordfilt2(I(:,:,1),1,ones(win,win),zeros(win,win),'symmetric'); 8 | img_min_patch(:,:,2) = ordfilt2(I(:,:,2),1,ones(win,win),zeros(win,win),'symmetric'); 9 | img_min_patch(:,:,3) = ordfilt2(I(:,:,3),1,ones(win,win),zeros(win,win),'symmetric'); 10 | img_min_patch(:,:,1) = img_min_patch(:,:,1)./A(1); 11 | img_min_patch(:,:,2) = img_min_patch(:,:,2)./A(2); 12 | img_min_patch(:,:,3) = img_min_patch(:,:,3)./A(3); 13 | % calculate the transmission estimate 14 | t_est = 1-omega*min(img_min_patch,[],3); 15 | 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_BuildLib.m: -------------------------------------------------------------------------------- 1 | function GCO_BuildLib(Options) 2 | % GCO_BuildLib Attempt to compile and link the GCO_MATLAB library. 3 | % GCO_BuildLib is used internally by all other GCO_MATLAB commands 4 | % to recompile the wrapper library if it is not yet built. 5 | % 6 | % YOU DO NOT NEED TO EXPLICITLY CALL THIS FUNCTION, unless you want to 7 | % customise the build settings via GCO_BuildLib(Options). 8 | % Default options: 9 | % Options.Debug=0 % optimised, detailed checking disabled 10 | % Options.EnergyType='long long' % int64 energy accumulator C type 11 | % Options.EnergyTermType='int' % int32 energy term C type; if not specified, same as EnergyType 12 | % 13 | % Example: 14 | % % Enable detailed assertions (e.g. than energy does not go up 15 | % % during expansion) and use double-precision float energy terms. 16 | % GCO_BuildLib(struct('Debug',1,'EnergyType','double')); 17 | % 18 | 19 | if (nargin < 1) 20 | Options = struct(); 21 | end 22 | if (~isfield(Options,'Debug')), Options.Debug = 0; end 23 | if (~isfield(Options,'EnergyType')), Options.EnergyType = ''; end 24 | if (~isfield(Options,'EnergyTermType')), Options.EnergyTermType = ''; end 25 | if (~isfield(Options,'EnergyType32')), Options.EnergyType32 = 0; end 26 | if (~isfield(Options,'Force')), Options.Force = 1; end 27 | 28 | MEXFLAGS = ''; 29 | if (strcmp(computer(),'GLNXA64') || strcmp(computer(),'PCWIN64') || strcmp(computer(),'MACI64')) 30 | MEXFLAGS = [MEXFLAGS ' -largeArrayDims -DA64BITS']; 31 | end 32 | if (Options.Debug) 33 | MEXFLAGS = [MEXFLAGS ' -g']; 34 | end 35 | if (Options.EnergyType32) 36 | MEXFLAGS = [MEXFLAGS ' -DGCO_ENERGYTYPE32']; 37 | end 38 | if (Options.EnergyType) 39 | MEXFLAGS = [MEXFLAGS ' -DGCO_ENERGYTYPE=' Options.EnergyType]; 40 | end 41 | if (Options.EnergyTermType) 42 | MEXFLAGS = [MEXFLAGS ' -DGCO_ENERGYTERMTYPE=' Options.EnergyTermType]; 43 | end 44 | if (strcmp(computer(),'PCWIN')) % link with libut for user interruptibility 45 | MEXFLAGS = [MEXFLAGS ' -D_WIN32 "' matlabroot() '\extern\lib\win32\microsoft\libut.lib"' ]; 46 | elseif (strcmp(computer(),'PCWIN64')) 47 | MEXFLAGS = [MEXFLAGS ' -D_WIN64 "' matlabroot() '\extern\lib\win64\microsoft\libut.lib"' ]; 48 | else 49 | MEXFLAGS = [MEXFLAGS ' -lut' ]; 50 | end 51 | 52 | LIB_NAME = 'gco_matlab'; 53 | GCOMATDIR = fileparts(mfilename('fullpath')); 54 | GCODIR = fileparts(GCOMATDIR); 55 | OUTDIR = [ GCOMATDIR filesep 'bin' ]; 56 | [status msg msgid] = mkdir(GCOMATDIR, 'bin'); % Create bin directory 57 | addpath(OUTDIR); % and add it to search path 58 | if (~Options.Force && exist('gco_matlab')==3) 59 | return; 60 | end 61 | clear gco_matlab; 62 | 63 | mexcmd = ['mex ' MEXFLAGS ' -outdir ''' OUTDIR ''' -output ' LIB_NAME ' ' ]; 64 | 65 | % Append all source file names to the MEX command string 66 | SRCCPP = { 67 | [GCOMATDIR filesep 'gco_matlab.cpp'], 68 | [GCODIR filesep 'GCoptimization.cpp'], 69 | [GCODIR filesep 'graph.cpp'], 70 | [GCODIR filesep 'maxflow.cpp'], 71 | [GCODIR filesep 'LinkedBlockList.cpp'] 72 | }; 73 | for f=1:length(SRCCPP) 74 | mexcmd = [mexcmd ' ''' SRCCPP{f} ''' ']; 75 | end 76 | 77 | eval(mexcmd); % compile and link in one step 78 | 79 | end 80 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_ComputeEnergy.m: -------------------------------------------------------------------------------- 1 | function [Energy D S L] = GCO_ComputeEnergy(Handle) 2 | % GCO_ComputeEnergy Run alpha-expansion algorithm. 3 | % E = GCO_ComputeEnergy(Handle) returns energy of current labeling. 4 | % [E D S L] = GCO_ComputeEnergy(Handle) also provides a breakdown of 5 | % the energy into Data, Smooth, and Label costs. 6 | 7 | GCO_LoadLib(); 8 | [Energy D S L] = gco_matlab('gco_computeenergy',Handle); 9 | end 10 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_Create.m: -------------------------------------------------------------------------------- 1 | function Handle = GCO_Create(NumSites,NumLabels) 2 | % GCO_Create Create a GCoptimization object. 3 | % Handle = GCO_Create(NumSites,NumLabels) creates a new GCoptimization 4 | % object and returns a 'handle' to uniquely identify it. 5 | % Call GCO_Delete(Handle) to delete the object and free its memory. 6 | % Call GCO_Delete(GCO_ListHandles) to delete all GCO objects. 7 | 8 | GCO_LoadLib(); 9 | if (nargin < 2), error('Expected 2 arguments'); end 10 | Handle = gco_matlab('gco_create_general',int32(NumSites),int32(NumLabels)); 11 | end 12 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_Delete.m: -------------------------------------------------------------------------------- 1 | function GCO_Delete(Handle) 2 | % GCO_Delete Delete a GCoptimization object. 3 | % GCO_Delete(Handle) deletes the object corresponding to Handle 4 | % and frees its memory. 5 | 6 | gco_matlab('gco_delete',int32(Handle)); 7 | end 8 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_ExpandOnAlpha.m: -------------------------------------------------------------------------------- 1 | function GCO_ExpandOnAlpha(Handle,Alpha) 2 | % GCO_ExpandOnAlpha Perform a single alpha-expansion step. 3 | % GCO_Expansion(Handle,Alpha) takes the current labeling and performs 4 | % a single expansion step on label Alpha. 5 | 6 | GCO_LoadLib(); 7 | gco_matlab('gco_alphaexpansion',Handle,int32(Alpha)); 8 | end 9 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_Expansion.m: -------------------------------------------------------------------------------- 1 | function Energy = GCO_Expansion(Handle,MaxIter) 2 | % GCO_Expansion Run alpha-expansion algorithm. 3 | % GCO_Expansion(Handle) minimizes the current energy via 4 | % alpha-expansion until convergence. 5 | % GCO_Expansion(Handle,MaxIter) runs at most MaxIter expansion 6 | % Returns the energy of the computed labeling. 7 | % The labeling itself can be retrieved via GCO_GetLabeling. 8 | % The order of expansion can be influenced by GCO_SetLabelOrder. 9 | % If GCO_SetNeighbors is not called (i.e. no smoothness terms), then 10 | % Expansion will internally use a greedy algorithm (no graph cuts). 11 | % 12 | % IMPORTANT: the first version uses "adaptive cycles" (changed labels) 13 | % until convergence whereas the second applies up to MaxIter 14 | % "standard cycles" (all labels). Each strategy is faster/slower for 15 | % different applications, so see what works fastest for yours. 16 | % 17 | 18 | GCO_LoadLib(); 19 | if (nargin < 1), error('Expansion requires handle to GCO instance'); end 20 | if (nargin < 2), MaxIter = -1; end 21 | Energy = gco_matlab('gco_expansion',Handle,int32(MaxIter)); 22 | end 23 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_GetLabeling.m: -------------------------------------------------------------------------------- 1 | function Labeling = GCO_GetLabeling(Handle,varargin) 2 | % GCO_GetLabeling Retrieve the current labeling 3 | % GCO_GetLabeling(Handle) returns a column vector of all labels. 4 | % GCO_GetLabeling(Handle,i) returns the label of site i. 5 | % GCO_GetLabeling(Handle,i,count) returns labels i..i+count-1 6 | 7 | GCO_LoadLib(); 8 | Start = int32(1); 9 | Count = gco_matlab('gco_getnumsites',Handle); 10 | if (length(varargin) > 2) 11 | error('Too many input arguments.'); 12 | end 13 | if (length(varargin) >= 1), Start = int32(varargin{1}); Count = int32(1); end 14 | if (length(varargin) == 2), Count = int32(varargin{2}); end 15 | Labeling = gco_matlab('gco_getlabeling',Handle,Start,Count); 16 | end 17 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_ListHandles.m: -------------------------------------------------------------------------------- 1 | function Handles = GCO_ListHandles() 2 | % GCO_ListHandles Retrieve handles to all current GCO instances 3 | % Useful for cleaning up GCO instances that are using memory, 4 | % particularly when a script was interrupted. 5 | % Example: 6 | % GCO_Delete(GCO_ListHandles); % delete all GCO instances 7 | 8 | GCO_LoadLib(); 9 | Handles = gco_matlab('gco_listhandles'); 10 | end 11 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_LoadLib.m: -------------------------------------------------------------------------------- 1 | function GCO_LoadLib() 2 | % GCO_LoadLib Attempt to load the GCO_MATLAB library. 3 | % GCO_LoadLib is used internally by all other GCO_MATLAB commands 4 | % to compile (if necessary), load, and bind the wrapper library. 5 | 6 | if (isempty(getenv('GCO_MATLAB'))) 7 | GCO_BuildLib(struct('Force',false)); 8 | if (exist('gco_matlab') ~= 3) 9 | error('Failed to load gco_matlab library'); 10 | end 11 | warning on GCO:int32; 12 | setenv('GCO_MATLAB','LOADED'); % environment variables 10x faster than 'exists' 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetDataCost.m: -------------------------------------------------------------------------------- 1 | function GCO_SetDataCost(Handle,DataCost,Label) 2 | % GCO_SetDataCost Set the data cost of individual sites. 3 | % GCO_SetDataCost(Handle,DataCost) accepts a NumLabels-by-NumSites 4 | % int32 matrix where DataCost(k,i) is the cost of assigning 5 | % label k to site i. Unfortunately, in MATLAB 2014a the mxCreateReference, 6 | % function was removed, so the MEX extension (C++ code) now has to make 7 | % an internal copy of the DataCost array :( 8 | % 9 | % GCO_SetDataCost(Handle,DataCost,Label) accepts a 2-by-N int32 matrix 10 | % of (site,cost) pairs, i.e. DataCost(2,i) is the cost of assigning 11 | % Label to site DataCost(1,i). The site ids must be sorted in increasing 12 | % order. All ommitted site ids are assumed to be infeasible for Label. 13 | % This 'sparse' version of SetDataCost allows Expansion to run much 14 | % faster when labels are only feasible for a small subset of sites. 15 | % It is possible to assign infeasible labelings via GCO_SetLabeling, 16 | % but GCO_ComputeEnergy will add huge constants to represent each 17 | % infeasible assignment. 18 | % 19 | % SetDataCost can be called repeatedly, even after Expansion. 20 | % 21 | 22 | GCO_LoadLib(); 23 | if (nargin < 2), error('Expected at least 2 arguments'); end 24 | if (~isnumeric(DataCost)), error('DataCost must be numeric'); end 25 | if (~isreal(DataCost)), error('DataCost cannot be complex'); end 26 | NumLabels = gco_matlab('gco_getnumlabels',Handle); 27 | NumSites = gco_matlab('gco_getnumsites', Handle); 28 | EnergyTermClass = gco_matlab('gco_get_energyterm_class'); 29 | DataCostClass = class(DataCost); 30 | if (nargin == 2) 31 | Label = 0; % no specific label 32 | if (size(DataCost) ~= [ NumLabels NumSites ]) 33 | error('DataCost size must be [ NumLabels NumSites ]'); 34 | end 35 | else 36 | if (Label < 1 || Label > NumLabels) 37 | error('Label must be in range 1..NumLabels'); 38 | end 39 | if (size(DataCost,1) ~= 2) 40 | error('Sparse DataCost must contain two rows'); 41 | end 42 | end 43 | if (~strcmp(DataCostClass,EnergyTermClass)) 44 | OldDataCost = DataCost; 45 | DataCost = cast(OldDataCost,EnergyTermClass); 46 | if (NumSites*NumLabels > 200 || any(any(cast(DataCost, DataCostClass) ~= OldDataCost))) 47 | warning('GCO:type',['DataCost converted to ' EnergyTermClass]); 48 | end 49 | end 50 | gco_matlab('gco_setdatacost',Handle,DataCost,int32(Label)); 51 | end 52 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetLabelCost.m: -------------------------------------------------------------------------------- 1 | function GCO_SetLabelCost(Handle,LabelCost,LabelSubset) 2 | % GCO_SetLabelCost Set costs associated with using labels. 3 | % GCO_SetLabelCost(Handle,LabelCost) with scalar LabelCost gives the 4 | % same cost to all labels. 5 | % GCO_SetLabelCost(Handle,LabelCost) with 1xNumLabels LabelCost 6 | % associates cost LabelCost(k) to label k. 7 | % GCO_SetLabelCost(Handle,LabelCost,LabelSubset) sets the cost for using 8 | % at least one label mentioned in LabelSubset (i.e. LabelSubset is a 9 | % vector containing label indices). The cost is paid once. 10 | % SetLabelCost can be called before or after Expansion. 11 | 12 | GCO_LoadLib(); 13 | if (nargin < 2) 14 | error('Expected at least 2 arguments'); 15 | end 16 | NumLabels = gco_matlab('gco_getnumlabels',Handle); 17 | if (length(LabelCost) ~= 1 && length(LabelCost) ~= NumLabels) 18 | error('LabelCost must be scalar or of length NumLabels'); 19 | end 20 | EnergyTermClass = gco_matlab('gco_get_energyterm_class'); 21 | LabelCostClass = class(LabelCost); 22 | if (~strcmp(LabelCostClass,EnergyTermClass)) 23 | OldLabelCost = LabelCost; 24 | LabelCost = cast(OldLabelCost,EnergyTermClass); 25 | if (length(LabelCost) > 50 || any(any(cast(LabelCost, LabelCostClass) ~= OldLabelCost))) 26 | warning('GCO:type',['LabelCost converted to ' EnergyTermClass]); 27 | end 28 | end 29 | if (nargin < 3) 30 | gco_matlab('gco_setlabelcost',Handle,LabelCost); 31 | else 32 | if (length(LabelCost) ~= 1), error('LabelCost must be scalar'); end 33 | if (any(LabelSubset < 1) || any(LabelSubset > NumLabels)) 34 | error('LabelSubset must contain indices from 1..NumLabels'); 35 | end 36 | if (~isa(LabelSubset,'int32')) 37 | if (any(any(floor(LabelSubset) ~= LabelSubset))) 38 | error('LabelSubset must contain integers from 1..NumLabels'); 39 | end 40 | LabelSubset = int32(LabelSubset); 41 | end 42 | gco_matlab('gco_setlabelcost',Handle,LabelCost,LabelSubset); 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetLabelOrder.m: -------------------------------------------------------------------------------- 1 | function GCO_SetLabelOrder(Handle,Order) 2 | % GCO_SetLabelOrder Set label order for Expansion/Swap moves. 3 | % GCO_SetLabelOrder(Handle,Order) tells Expansion/Swap to select labels 4 | % in a specific order when Order contains integers from 1..NumLabels. 5 | % By default, Expansion/Swap use a consistent, prescribed order of labels 6 | % in until convergence. 7 | % Example: 8 | % GCO_SetLabelOrder(Handle,5:10); % only operate on labels 5..10 9 | % GCO_SetLabelOrder(Handle,randperm(NumLabels)); % random label order 10 | % 11 | 12 | GCO_LoadLib(); 13 | gco_matlab('gco_setlabelorder',Handle,int32(Order)); 14 | end 15 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetLabeling.m: -------------------------------------------------------------------------------- 1 | function GCO_SetLabeling(Handle,Labeling) 2 | % GCO_SetLabeling Sets the current labeling 3 | % GCO_SetLabeling(Handle,Labeling) sets the entire labeling. 4 | 5 | GCO_LoadLib(); 6 | if (isnumeric(Labeling)) 7 | NumSites = gco_matlab('gco_getnumsites',Handle); 8 | NumLabels = gco_matlab('gco_getnumlabels',Handle); 9 | if (length(Labeling) ~= NumSites) 10 | error('Labeling must be of length NumSites'); 11 | end 12 | if (~isa(Labeling,'int32')) 13 | if (any(floor(Labeling) ~= Labeling)) 14 | error('Labeling was not integer valued'); 15 | end 16 | Labeling = int32(Labeling); 17 | end 18 | if (min(Labeling) < 1 || max(Labeling) > NumLabels) 19 | error('Label must be in range 1..NumLabels'); 20 | end 21 | gco_matlab('gco_setlabeling',Handle,Labeling); 22 | end 23 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetNeighbors.m: -------------------------------------------------------------------------------- 1 | function GCO_SetNeighbors(Handle,Weights) 2 | % GCO_SetNeighbors Set (weighted) pairwise connectivity of all sites. 3 | % GCO_SetNeighbors(Handle,Weights) determines which sites are neighbors 4 | % and thereby have a SmoothCost associated with them. Weights is a 5 | % sparse NumSites-by-NumSites matrix, where Weights(i,j) > 0 indicates 6 | % that sites i and j are neighbors. If Weights is a 0-1 matrix, smooth 7 | % costs are spatially invariant. See SetSmoothCost for more. 8 | % 9 | % SetNeighbors cannot be called after Expansion. 10 | % Note: only the upper-triangular area of Weights is consulted 11 | % because the connectivity is undirected. 12 | 13 | GCO_LoadLib(); 14 | NumSites = gco_matlab('gco_getnumsites',Handle); 15 | if (size(Weights) ~= [ NumSites NumSites ]) 16 | error('Neighbors must be of size [ NumSites NumSites ]'); 17 | end 18 | if (~issparse(Weights)) 19 | if (NumSites > 100) 20 | warning('Sparsifying the Neighbors matrix (performance warning)'); 21 | end 22 | if (~isa(Weights,'double')) 23 | error('Neighbors matrix must be of type double, but with integral values'); 24 | end 25 | Weights = sparse(Weights); 26 | end 27 | gco_matlab('gco_setneighbors',Handle,Weights); 28 | end 29 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetSmoothCost.m: -------------------------------------------------------------------------------- 1 | function GCO_SetSmoothCost(Handle,SmoothCost) 2 | % GCO_SetSmoothCost Set the smooth cost of neighboring sites. 3 | % GCO_SetSmoothCost(Handle,SmoothCost) with a NumLabels-by-NumLabels 4 | % integer matrix makes SmoothCost(k,l) the unweighted cost 5 | % of assigning labels k and l to any neighboring sites. 6 | % For particular neighboring sites i,j the final, weighted cost 7 | % is actually Weights(i,j)*SmoothCost(k,l). The spatially-varying 8 | % weights are determined by GCO_SetNeighbors. 9 | % 10 | % If SetSmoothCost is never called, Potts model is used by default. 11 | % i.e. SmoothCost(k,l) = { 0 if k==l, 1 otherwise } 12 | % 13 | % SetSmoothCost can be called repeatedly, even after Expansion. 14 | 15 | GCO_LoadLib(); 16 | if (nargin < 2) 17 | error('Expected 2 arguments'); 18 | end 19 | if (~isnumeric(SmoothCost)) 20 | error('SmoothCost must be numeric'); 21 | end 22 | NumLabels = gco_matlab('gco_getnumlabels',Handle); 23 | if (size(SmoothCost) ~= [ NumLabels NumLabels ]) 24 | error('SmoothCost size must be [ NumLabels NumLabels ]'); 25 | end 26 | EnergyTermClass = gco_matlab('gco_get_energyterm_class'); 27 | SmoothCostClass = class(SmoothCost); 28 | if (~strcmp(SmoothCostClass,EnergyTermClass)) 29 | OldSmoothCost = SmoothCost; 30 | SmoothCost = cast(OldSmoothCost,EnergyTermClass); 31 | if (NumLabels > 50 || any(any(cast(SmoothCost, SmoothCostClass) ~= OldSmoothCost))) 32 | warning('GCO:type',['SmoothCost converted to ' EnergyTermClass]); 33 | end 34 | end 35 | if (any(SmoothCost ~= SmoothCost')) 36 | error('SmoothCost must be symmetric'); 37 | end 38 | gco_matlab('gco_setsmoothcost',Handle,SmoothCost); 39 | end 40 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_SetVerbosity.m: -------------------------------------------------------------------------------- 1 | function GCO_SetVerbosity(Handle,Level) 2 | % GCO_SetVerbosity Print status messages during Expansion/Swap. 3 | % Level 0 prints no output (full speed). 4 | % Level 1 prints cycle-level status messages. 5 | % Level 2 prints expansion/swap-level status messages. 6 | % The current energy is printed as 7 | % E=Total (E=DataCost+SmoothCost+LabelCost) 8 | % At level 2, the size of each binary graph cut problem is also 9 | % printed (# vars). 10 | % 11 | % Note that printing may have an effect on overall run time (tic/toc) 12 | % though the internal computation times are printed in milliseconds 13 | % and exclude the time to print. 14 | % 15 | % Example: 16 | % >> GCO_SetVerbosity(Handle,2); % Level 2 output 17 | % >> GCO_Expansion(Handle); 18 | % gco>> starting alpha-expansion w/ adaptive cycles 19 | % gco>> initial energy: E=18 (E=17+0+1) 20 | % gco>> after expansion(3): E=17 (E=14+1+2); 4 vars; (1 of 8); 0.003 ms 21 | % gco>> after expansion(7): E=15 (E=11+1+3); 2 vars; (2 of 8); 0.002 ms 22 | % ... 23 | % gco>> after cycle 1: E=12 (E=6+2+4); 8 expansions(s); 24 | 25 | GCO_LoadLib(); 26 | gco_matlab('gco_setverbosity',Handle,int32(Level)); 27 | end 28 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_Swap.m: -------------------------------------------------------------------------------- 1 | function Energy = GCO_Swap(Handle,MaxIter) 2 | % GCO_Swap Run alpha-beta-swap algorithm. 3 | % GCO_Swap(Handle) runs alpha-beta-swap until convergence. 4 | % GCO_Swap(Handle,MaxIter) runs at most MaxIter swap cycles. 5 | % Returns the energy of the computed labeling. 6 | % The labeling itself can be retrieved via GCO_GetLabeling. 7 | % The order of expansion can be influenced by GCO_SetLabelOrder. 8 | % 9 | % Note that neither label costs nor sparse data costs are currently 10 | % implement for alpha-beta-swap. 11 | 12 | GCO_LoadLib(); 13 | if (nargin < 1), error('Swap requires handle to GCO instance'); end 14 | if (nargin < 2), MaxIter = 1000000; end 15 | Energy = gco_matlab('gco_swap',Handle,int32(MaxIter)); 16 | end 17 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/GCO_UnitTest.m: -------------------------------------------------------------------------------- 1 | function GCO_UnitTest 2 | % GCO_UnitTest Compile, load, and test the GCO_MATLAB library. 3 | % GCO_UnitTest will make sure the wrapper compiles on the target 4 | % platform and then exercises the library to look for silly bugs. 5 | 6 | function Assert(cond,msg) % for older MATLAB without assert() 7 | if (exist('assert') == 5) 8 | if (nargin < 2) 9 | assert(cond); 10 | else 11 | assert(cond,msg); 12 | end 13 | elseif (~cond) 14 | if (nargin < 2) 15 | msg = 'Assertion failed'; 16 | end 17 | error(msg); 18 | end 19 | end 20 | 21 | function DoSetDataCost(h,dc,iter) 22 | if (iter == 1) 23 | % Set data costs as dense matrix 24 | GCO_SetDataCost(h,dc); 25 | else 26 | % Use the sparse mechanism to set dense data costs, 27 | % to verify that tests all give the same result. 28 | % Note that this is not a good test when the number 29 | % of sites is small, since only some of the sparse datacost 30 | % code path will get exercised. 31 | for label=1:size(dc,1) 32 | ids = find(dc(label,:) < 100000); 33 | GCO_SetDataCost(h,[ids; dc(label,ids)],label); 34 | end 35 | end 36 | end 37 | 38 | sc = [0 1 2 3 3 3 3 3 3; 39 | 1 0 1 2 3 3 3 3 3; 40 | 2 1 0 1 2 3 3 3 3; 41 | 3 2 1 0 1 2 3 3 3; 42 | 3 3 2 1 0 1 2 3 3; 43 | 3 3 3 2 1 0 1 2 3; 44 | 3 3 3 3 2 1 0 1 2; 45 | 3 3 3 3 3 2 1 0 1; 46 | 3 3 3 3 3 3 2 1 0;]; % truncated linear 47 | 48 | GCO_BuildLib; disp('BuildLib PASSED'); 49 | GCO_LoadLib; disp('LoadLib PASSED'); 50 | 51 | % Basic tests with no Create/Delete 52 | caught=false; try GCO_Delete(10); catch, caught=true; end, Assert(caught,'Expected an exception'); 53 | caught=false; try h = GCO_Create(1,1); catch, caught=true; end, Assert(caught,'Expected an exception'); 54 | caught=false; try h = GCO_Create(0,2); catch, caught=true; end, Assert(caught,'Expected an exception'); 55 | h1 = GCO_Create(4,8); 56 | h2 = GCO_Create(10,5); 57 | Assert(all(GCO_ListHandles == [h1; h2])); 58 | GCO_Delete(h1); 59 | caught=false; try GCO_ComputeEnergy(h1); catch, caught=true; end, Assert(caught,'Expected an exception'); 60 | caught=false; try GCO_Delete(h1); catch, caught=true; end, Assert(caught,'Expected an exception'); 61 | Assert(all(GCO_ListHandles == [h2])); 62 | Assert(length(GCO_GetLabeling(h2)) == 10); 63 | GCO_Delete(h2); 64 | Assert(isempty(GCO_ListHandles)); 65 | caught=false; try GCO_Delete(h2); catch, caught=true; end, Assert(caught,'Expected an exception'); 66 | disp('Create/Delete PASSED'); 67 | disp('ListHandles PASSED'); 68 | 69 | % Test Get/SetLabel when no optimization is used 70 | h = GCO_Create(4,3); 71 | Assert(GCO_ComputeEnergy(h) == 0); 72 | l = (mod((1:4),3)+1)'; 73 | caught=false; try GCO_SetLabeling(h,l(1:end-1)); catch, caught=true; end, Assert(caught,'Expected an exception'); 74 | caught=false; try GCO_SetLabeling(h,[l 1]); catch, caught=true; end, Assert(caught,'Expected an exception'); 75 | GCO_SetLabeling(h,l); 76 | Assert(all(GCO_GetLabeling(h) == l)); 77 | Assert(all(GCO_GetLabeling(h,3) == l(3))); 78 | Assert(all(GCO_GetLabeling(h,2,2) == l(2:3))); 79 | caught=false; try GCO_GetLabeling(h,0,1); catch, caught=true; end, Assert(caught,'Expected an exception'); 80 | caught=false; try GCO_GetLabeling(h,1,5); catch, caught=true; end, Assert(caught,'Expected an exception'); 81 | GCO_SetLabeling(h,4-l); 82 | Assert(all(GCO_GetLabeling(h) == 4-l)); 83 | GCO_Delete(h); 84 | disp('Get/SetLabeling PASSED'); 85 | 86 | % Test with NO costs 87 | h = GCO_Create(4,3); 88 | Assert(GCO_ComputeEnergy(h) == 0); 89 | GCO_Expansion(h); 90 | Assert(GCO_ComputeEnergy(h) == 0); 91 | GCO_SetLabeling(h,4-GCO_GetLabeling(h)); 92 | Assert(GCO_ComputeEnergy(h) == 0); 93 | GCO_Expansion(h); 94 | GCO_Delete(h); 95 | disp('Expansion-000 PASSED'); 96 | 97 | for iter=1:2 98 | if (iter == 2) 99 | fprintf('SetDataCost-Sparse...'); 100 | h = GCO_Create(3,2); 101 | GCO_SetDataCost(h,[1 1 1; 2 2 2]); % set dense, then make sure sparse is not allowed afterwards 102 | caught=false; try GCO_SetDataCost(h,[1 2 3; 5 5 5],1); catch, caught=true; end, Assert(caught,'Expected an exception'); 103 | GCO_Delete(h); 104 | % h = GCO_Create(3,2); 105 | % GCO_SetDataCost(h,[1 2 3; 5 6 7],1); % set sparse, then make sure dense is not allowed afterwards 106 | % GCO_SetDataCost(h,[1; 100 ],2); % make sure label cost can be replaced 107 | % Assert(GCO_ComputeEnergy(h) == 18); 108 | % GCO_SetDataCost(h,[1 2 3; 10 11 12],1); % make sure label cost can be replaced 109 | % Assert(GCO_ComputeEnergy(h) == 33); 110 | % % make sure unsorted ids will fail order is checked 111 | % caught=false; try GCO_SetDataCost(h,[1 1 2; 9 9 9],1); catch, caught=true; end, Assert(caught,'Expected an exception'); 112 | % % make sure dense can be used after sparse (though not vice versa) 113 | % GCO_SetDataCost(h,[1 1 1; 2 2 2]); 114 | % GCO_Delete(h); 115 | end 116 | 117 | % Test Expansion with DATA cost only 118 | h = GCO_Create(4,9); 119 | dc = [1 2 5 8 4 2 3 7 9; 120 | 3 1 2 5 4 5 5 5 5; 121 | 5 5 5 5 4 5 2 1 3; 122 | 9 7 3 2 4 8 5 2 1;]'; 123 | if (iter == 1) 124 | caught=false; try GCO_SetDataCost(h,[dc [0 0 0 0]']); catch, caught=true; end, Assert(caught,'Expected an exception'); 125 | caught=false; try GCO_SetDataCost(h,dc(:,1:end-1)); catch, caught=true; end, Assert(caught,'Expected an exception'); 126 | caught=false; try GCO_SetDataCost(h,dc(1:end-1,:)); catch, caught=true; end, Assert(caught,'Expected an exception'); 127 | else 128 | caught=false; try GCO_SetDataCost(h,[1:4; dc(1,:)],0); catch, caught=true; end, Assert(caught,'Expected an exception'); 129 | caught=false; try GCO_SetDataCost(h,[1:4; dc(1,:)],10); catch, caught=true; end, Assert(caught,'Expected an exception'); 130 | caught=false; try GCO_SetDataCost(h,[0:3; dc(1,:)],1); catch, caught=true; end, Assert(caught,'Expected an exception'); 131 | caught=false; try GCO_SetDataCost(h,[2:5; dc(1,:)],1); catch, caught=true; end, Assert(caught,'Expected an exception'); 132 | caught=false; try GCO_SetDataCost(h,[1 2 2;dc(1,1:3)],1);catch, caught=true; end, Assert(caught,'Expected an exception'); 133 | end 134 | DoSetDataCost(h,dc,iter); 135 | GCO_SetLabeling(h,[3 3 3 3]); 136 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))); 137 | GCO_SetLabeling(h,[1 2 3 4]); 138 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(3,3)+dc(4,4)); 139 | GCO_SetLabeling(h,[5 5 5 5]); 140 | GCO_ExpandOnAlpha(h,8); 141 | Assert(all(GCO_GetLabeling(h) == [5 5 8 8]')); 142 | GCO_ExpandOnAlpha(h,3); 143 | Assert(all(GCO_GetLabeling(h) == [5 3 8 8]')); 144 | GCO_Expansion(h); 145 | Assert(all(GCO_GetLabeling(h) == [1 2 8 9]')); 146 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(8,3)+dc(9,4)); 147 | GCO_Delete(h); 148 | if (iter==1), disp('Expansion-D00 PASSED'); end 149 | 150 | % Test DATA+SMOOTH cost 151 | h = GCO_Create(4,9); 152 | dc = [1 2 5 8 4 2 3 7 9; 153 | 3 1 1 5 4 5 5 5 5; 154 | 5 5 5 5 4 5 1 1 3; 155 | 9 7 3 2 4 8 5 2 1;]'; 156 | DoSetDataCost(h,dc,iter); 157 | caught=false; try GCO_SetSmoothCost(h,sc(:,1:end-1)); catch, caught=true; end, Assert(caught,'Expected an exception'); 158 | caught=false; try GCO_SetSmoothCost(h,sc(1:end-1,:)); catch, caught=true; end, Assert(caught,'Expected an exception'); 159 | GCO_SetSmoothCost(h,sc); 160 | caught=false; try GCO_SetNeighbors(h,eye(4)); catch, caught=true; end, Assert(caught,'Expected an exception'); 161 | caught=false; try GCO_SetNeighbors(h,zeros(5)); catch, caught=true; end, Assert(caught,'Expected an exception'); 162 | GCO_SetNeighbors(h,[0 2 0 0; 163 | 0 0 1 0; 164 | 0 0 0 2; 165 | 0 0 0 0]); 166 | GCO_SetLabeling(h,[3 3 3 3]); 167 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))); 168 | GCO_SetLabeling(h,[1 2 4 5]); 169 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(4,3)+dc(5,4) + 6); 170 | GCO_SetLabeling(h,[5 5 5 5]); 171 | GCO_Expansion(h); 172 | Assert(all(GCO_GetLabeling(h) == [2 2 8 8]')); 173 | GCO_Delete(h); 174 | if (iter==1) disp('Expansion-DS0 PASSED'); end 175 | 176 | % Test DATA+LABEL cost 177 | h = GCO_Create(4,9); 178 | dc = [1 2 5 8 4 2 3 7 9; 179 | 3 1 3 5 4 3 5 5 5; 180 | 5 5 5 5 4 5 1 1 3; 181 | 9 7 3 2 4 8 5 2 1;]'; 182 | lc = [9 9 1 1 1 2 1 9 9]; 183 | DoSetDataCost(h,dc,iter); 184 | caught=false; try GCO_SetLabelCost(h,[lc 10]); catch, caught=true; end, Assert(caught,'Expected an exception'); 185 | caught=false; try GCO_SetLabelCost(h,lc(1:end-1)); catch, caught=true; end, Assert(caught,'Expected an exception'); 186 | GCO_SetLabelCost(h,lc); 187 | GCO_SetLabeling(h,[3 3 3 3]); 188 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))+lc(3)); 189 | GCO_SetLabeling(h,[1 2 4 5]); 190 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(4,3)+dc(5,4) + sum(lc([1 2 4 5]))); 191 | GCO_SetLabeling(h,[5 5 5 5]); 192 | GCO_Expansion(h); 193 | Assert(all(GCO_GetLabeling(h) == [7 3 7 3]')); 194 | GCO_Delete(h); 195 | 196 | % Test when NumLabels < NumSites and make sure greedy doesn't crash when all labels 197 | % are added. This test thanks to Yangyan Li. 198 | h = GCO_Create(4,3); 199 | DoSetDataCost(h,[1 4 9; 5 2 5; 6 1 3; 5 7 1;]',iter); 200 | GCO_SetLabelCost(h,[1 1 1]); 201 | GCO_Expansion(h); 202 | GCO_Delete(h); 203 | 204 | 205 | % Now do the same test, except add label costs to subsets of labels, not 206 | % just individual labels 207 | h = GCO_Create(4,9); 208 | DoSetDataCost(h,dc,iter); 209 | GCO_SetLabelCost(h,lc); 210 | GCO_SetLabelCost(h,3,[1 3 4 5 6]); 211 | GCO_SetLabelCost(h,4,[4 8 9]); 212 | GCO_SetLabeling(h,[3 3 3 3]); 213 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))+lc(3)+3); 214 | GCO_SetLabeling(h,[5 5 8 9]); 215 | Assert(GCO_ComputeEnergy(h) == dc(5,1)+dc(5,2)+dc(8,3)+dc(9,4) + sum(lc([5 8 9]))+3+4); 216 | GCO_SetLabeling(h,[1 2 4 5]); 217 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(4,3)+dc(5,4) + sum(lc([1 2 4 5]))+3+4); 218 | GCO_SetLabeling(h,[5 5 5 5]); 219 | GCO_Expansion(h); 220 | Assert(all(GCO_GetLabeling(h) == [7 7 7 7]')); 221 | GCO_SetLabelCost(h,3,[2]); 222 | GCO_Expansion(h); 223 | Assert(all(GCO_GetLabeling(h) == [2 2 7 7]')); 224 | GCO_Delete(h); 225 | if (iter==1), disp('Expansion-D0L PASSED'); end 226 | 227 | % Test DATA+SMOOTH+LABEL cost 228 | h = GCO_Create(4,9); 229 | dc = [1 2 5 8 4 2 3 7 9; 230 | 3 1 3 5 4 2 5 5 5; 231 | 5 5 5 5 5 5 1 1 3; 232 | 9 7 3 2 4 8 5 2 1;]'; 233 | lc = [1 9 1 1 1 1 1 9 9]; 234 | GCO_SetSmoothCost(h,sc); 235 | GCO_SetNeighbors(h,[0 2 0 0; 236 | 0 0 1 0; 237 | 0 0 0 2; 238 | 0 0 0 0]); 239 | DoSetDataCost(h,dc,iter); 240 | GCO_SetLabelCost(h,lc); 241 | GCO_SetLabeling(h,[3 3 3 3]); 242 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))+lc(3)); 243 | GCO_SetLabeling(h,[1 2 4 5]); 244 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(4,3)+dc(5,4) + sum(lc([1 2 4 5])) + 6); 245 | GCO_SetLabeling(h,[5 5 5 5]); 246 | GCO_Expansion(h); 247 | Assert(all(GCO_GetLabeling(h) == [6 6 7 7]')); 248 | GCO_Delete(h); 249 | % Now do the same test, except add label costs to subsets of labels, not 250 | % just individual labels 251 | h = GCO_Create(4,9); 252 | GCO_SetSmoothCost(h,sc); 253 | GCO_SetNeighbors(h,[0 2 0 0; 254 | 0 0 1 0; 255 | 0 0 0 2; 256 | 0 0 0 0]); 257 | DoSetDataCost(h,dc,iter); 258 | GCO_SetLabelCost(h,lc); 259 | GCO_SetLabelCost(h,3,[1 3 4 5 6]); 260 | GCO_SetLabelCost(h,4,[5 8 9]); 261 | GCO_SetLabeling(h,[3 3 3 3]); 262 | Assert(GCO_ComputeEnergy(h) == sum(dc(3,:))+lc(3)+3); 263 | GCO_SetLabeling(h,[5 5 8 9]); 264 | Assert(GCO_ComputeEnergy(h) == dc(5,1)+dc(5,2)+dc(8,3)+dc(9,4) + sum(lc([5 8 9]))+3+4 + 5); 265 | GCO_SetLabeling(h,[1 2 4 5]); 266 | Assert(GCO_ComputeEnergy(h) == dc(1,1)+dc(2,2)+dc(4,3)+dc(5,4) + sum(lc([1 2 4 5]))+3+4 + 6); 267 | GCO_SetLabeling(h,[5 5 5 5]); 268 | GCO_Expansion(h); 269 | Assert(all(GCO_GetLabeling(h) == [7 7 7 7]')); 270 | GCO_SetLabelCost(h,0,[7]); % Try replacing an existing labelcost 271 | GCO_SetLabeling(h,[3 3 3 3]); 272 | GCO_Expansion(h); 273 | Assert(all(GCO_GetLabeling(h) == [7 7 7 7]')); 274 | [E D S L] = GCO_ComputeEnergy(h); 275 | Assert(L == 0); 276 | GCO_SetLabelCost(h,4,[7]); 277 | GCO_SetLabelCost(h,1,[1 3 4 5 6]); % Try replacing a labelcost subset 278 | GCO_Expansion(h); 279 | Assert(all(GCO_GetLabeling(h) == [6 6 4 4]')); 280 | [E D S L] = GCO_ComputeEnergy(h); 281 | Assert(L == 3); 282 | GCO_SetSmoothCost(h,sc*3); % Try replacing smoothcost 283 | GCO_SetLabeling(h,[5 5 7 9]); 284 | Assert(GCO_ComputeEnergy(h) == dc(5,1)+dc(5,2)+dc(7,3)+dc(9,4) + sum(lc([5 9]))+1+4+4 + 6*3); 285 | GCO_Delete(h); 286 | if (iter==1), disp('Expansion-DSL PASSED'); end 287 | 288 | % Test NON-METRIC SMOOTH cost, and make sure Expansion raises an exception 289 | % so that users do not accidentally get meaningless results. 290 | h = GCO_Create(4,9); 291 | dc = [1 1 1 1 1 1 1 1 1; 292 | 1 1 1 1 1 1 1 1 1; 293 | 1 1 1 1 1 1 1 1 1; 294 | 1 1 1 1 1 1 1 1 1;]'; 295 | DoSetDataCost(h,dc,iter); 296 | sc_nonmetric = sc.*sc; % truncated quadratic 297 | GCO_SetSmoothCost(h,sc_nonmetric); 298 | GCO_SetNeighbors(h,[0 2 0 0; 299 | 0 0 1 0; 300 | 0 0 0 2; 301 | 0 0 0 0]); 302 | GCO_SetLabeling(h,[5 5 7 4]); 303 | caught=false; try GCO_ExpandOnAlpha(h,5); catch, caught=true; end, Assert(caught,'Expected an exception'); 304 | GCO_Delete(h); 305 | if (iter==1), disp('Expansion-NonMetricWarning PASSED'); end 306 | 307 | 308 | if iter==1 309 | % Test Swap 310 | h = GCO_Create(4,9); 311 | dc = [1 2 5 8 4 2 3 7 9; 312 | 3 1 1 5 4 5 5 5 5; 313 | 5 5 5 5 4 5 1 1 3; 314 | 9 7 3 2 4 8 5 2 1;]'; 315 | GCO_SetDataCost(h,dc); 316 | GCO_SetLabeling(h,[5 5 5 5]); 317 | GCO_Swap(h); 318 | Assert(all(GCO_GetLabeling(h) == [1 2 7 9]')); 319 | GCO_Delete(h); 320 | disp('Swap-D0 PASSED'); 321 | h = GCO_Create(4,9); 322 | GCO_SetDataCost(h,dc); 323 | GCO_SetSmoothCost(h,sc); 324 | GCO_SetNeighbors(h,[0 2 0 0; 325 | 0 0 1 0; 326 | 0 0 0 2; 327 | 0 0 0 0]); 328 | GCO_SetLabeling(h,[5 5 5 5]); 329 | GCO_Swap(h); 330 | Assert(all(GCO_GetLabeling(h) == [2 2 8 8]')); 331 | GCO_Delete(h); 332 | disp('Swap-DS PASSED'); 333 | end 334 | 335 | % Make sure to generate errors if dangerously large coefficients are used 336 | dc = [1 1 1 1 1 1 1 1 1; 337 | 1 1 1 1 1 1 1 1 1; 338 | 1 1 1 1 1 1 1 1 10000001; % huge capacity, relative to int32 339 | 1 1 1 1 1 1 1 1 1;]'; 340 | lc = [1 1 0 0 0 0 0 0 10000001]; 341 | h = GCO_Create(4,9); 342 | caught=false; try GCO_SetLabelCost(h,lc); catch, caught=true; end, Assert(caught,'Expected an exception'); 343 | GCO_SetDataCost(h,dc); % test BadLabelCost, and then BadDataCost code path 344 | caught=false; try GCO_ExpandOnAlpha(h,9); catch, caught=true; end, Assert(caught,'Expected an exception'); 345 | GCO_Delete(h); 346 | 347 | h = GCO_Create(4,9); 348 | GCO_SetDataCost(h,dc); 349 | GCO_SetSmoothCost(h,sc); % test BadDataCost+GoodSmoothCost code path 350 | caught=false; try GCO_ExpandOnAlpha(h,9); catch, caught=true; end, Assert(caught,'Expected an exception'); 351 | GCO_Delete(h); 352 | 353 | h = GCO_Create(4,9); 354 | DoSetDataCost(h,min(dc,1),iter); 355 | GCO_SetSmoothCost(h,sc.*10); % test GoodDataCost+BadSmoothCost code path 356 | GCO_SetNeighbors(h,[0 2 0 0; 357 | 0 0 1 0; 358 | 0 0 0 10000001; 359 | 0 0 0 0]); 360 | GCO_SetLabeling(h,[1 1 1 1]); 361 | caught=false; try GCO_ExpandOnAlpha(h,5); catch, caught=true; end, Assert(caught,'Expected an exception'); 362 | GCO_Delete(h); 363 | if (iter==1), disp('IntegerOverflowWarnings PASSED'); end 364 | if (iter==2), fprintf('PASSED\n'); end 365 | 366 | 367 | % Test MEDIUM SCALE problems and make sure dense/sparse data costs 368 | % result in the exact same solution 369 | rand('twister', 987); % get the same random stream each time 370 | wd = 64; ht = 48; 371 | dc = int32(rand([500,wd*ht])*1000); 372 | dc(dc > 100) = 100000; % prune out about 10% of possible labels 373 | dc(1,:) = 1000; % but be sure to allow at least one label per variable 374 | nb = sparse(wd*ht,wd*ht); 375 | for y=1:ht % set up a grid-like neighbourhood, arbitrarily 376 | for x=1:wd 377 | if (x < wd), nb((y-1)*wd+x,(y-1)*wd+x+1) = 30; end 378 | if (y < ht), nb((y-1)*wd+x, y *wd+x ) = 30; end 379 | end 380 | end 381 | 382 | % Test greedy 383 | if (iter==1), fprintf('MediumScale-D0L...'); end 384 | if (iter==2), fprintf('MediumScale-D0L-Sparse...'); end 385 | h = GCO_Create(wd*ht,size(dc,1)); 386 | DoSetDataCost(h,dc,iter); 387 | GCO_SetLabelCost(h,3000); 388 | tic; GCO_Expansion(h); greedytime = toc; 389 | [E D S L] = GCO_ComputeEnergy(h); 390 | if (exist('EDLdense')) 391 | Assert(GCO_ComputeEnergy(h) == EDLdense); % Test D+L costs 392 | else 393 | EDLdense = GCO_ComputeEnergy(h); % remember for next time, to compare with "sparse data cost" solution 394 | end 395 | GCO_Delete(h); 396 | if (iter==1), fprintf('PASSED (%.3fsec greedy)\n',greedytime); end 397 | if (iter==2), fprintf('PASSED (%.3fsec greedy w/ 10%% of sites feasible)\n',greedytime); end 398 | 399 | 400 | % Test expansion 401 | if (iter==1), fprintf('MediumScale-DSL...'); end 402 | if (iter==2), fprintf('MediumScale-DSL-Sparse...'); end 403 | h = GCO_Create(wd*ht,size(dc,1)); 404 | DoSetDataCost(h,dc,iter); 405 | GCO_SetLabelCost(h,1000); 406 | GCO_SetLabelCost(h,5000,2:50); 407 | GCO_SetLabelCost(h,10000,100:200); 408 | GCO_SetNeighbors(h,nb); 409 | tic; GCO_Expansion(h); exptime = toc; 410 | 411 | [E D S L] = GCO_ComputeEnergy(h); 412 | if (exist('EDSLdense')) 413 | Assert(GCO_ComputeEnergy(h) == EDSLdense); % Test D+S+L costs 414 | else 415 | EDSLdense = GCO_ComputeEnergy(h); % remember for next time, to compare with "sparse data cost" solution 416 | end 417 | GCO_Delete(h); 418 | if (iter==1), fprintf('PASSED (%.3fsec expansion)\n',exptime); end 419 | if (iter==2), fprintf('PASSED (%.3fsec expansion w/ 10%% of sites feasible)\n',exptime); end 420 | end 421 | 422 | Assert(isempty(GCO_ListHandles)); % expect there to be no gc handles remaining 423 | 424 | end 425 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/README.TXT: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | GCO_MATLAB - a Matlab wrapper for Olga Veksler's C++ graph-cut optimization library 3 | 4 | GCO_MATLAB Author(s): 5 | Andrew Delong 6 | Anton Osokin 7 | 8 | We're especially grateful to Lena Gorelick for helpful suggestions and for 9 | tracking down so many bugs! 10 | 11 | GCoptimization Author(s): 12 | Olga Veksler 13 | 14 | Description: 15 | This download provides a Matlab wrapper for the latest version of 'GCoptimization', 16 | Olga Veksler's multi-label optimization library written in C++. 17 | 18 | Note: A wrapper for an earlier version GCoptimization was authored by Shai Bagon and 19 | is available at http://www.wisdom.weizmann.ac.il/~bagon/matlab.html 20 | 21 | Revision History: 22 | Oct 14, 2014; - Added GCO_ENERGYTERM and GCO_ENERGYTERMTYPE macros to make 23 | float/double terms easier. Please note that float/double energy terms 24 | can cause expansion/swap steps to report a very small increase in energy 25 | due to accumulated rounding error inside the maxflow library. 26 | If Inf or NaN values appear in the energy terms, behaviour is undefined. 27 | May 18, 2014; - Support Matlab R2014a by removing use of mxCreateReference 28 | Jan 15, 2014; - Compiles with gcc 4.6+ even without -fpermissive 29 | Apr 12, 2011; - Fixed bug when sparse data costs had a dense bucket (thanks Joseph Tighe!) 30 | Nov 25, 2010; - Detect MACI64 correctly (thanks Francis Lauzon) 31 | Aug 31, 2010; - Compiles with gcc 4.4.1 on opensuse 11.2 (thanks Wei Liu) 32 | Aug 7, 2010; - Fixed bug when data costs are computed in a callback (thanks Evan Herbst!) 33 | - Fixed bug where setAllNeighbours didn't apply neighbourhood (Evan Herbst again) 34 | Jul 22, 2010; - Compiles with gcc 4.4.1 (thanks Julius Ziegler for the patch!) 35 | Jul 8, 2010; - Fixed crash in greedy code path when all labels get added (thanks Yangyan Li!) 36 | Apr 25, 2010; - Faster code path for sparse data costs; fixed related bug in higher-order labels 37 | Apr 21, 2010; - Added basic "verbose" mode (print cycle, energy, timings etc) 38 | - Expansion cycles now focus on labels for which the energy decreased (faster) 39 | Apr 19, 2010; - Added sparse datacost support 40 | - Allow GCO_SetLabelOrder to specify exact label order 41 | Apr 13, 2010; - Potts model is now the default if SetNeighbors is called without SetSmoothCost 42 | - Fixed bug in higher-order label costs 43 | - Expansion is now interruptable from MATLAB; temporary memory is freed 44 | - Added GCO_ListHandles and allow GCO_Delete to accept multiple handles 45 | - Better error message if a bad handle is passed to GCO_* 46 | Nov 17, 2009; - Fixed integer overflow in label-cost construction 47 | - Fixed bug where greedy algorithm would sometimes skip a label 48 | Nov 6, 2009; - Fixed bug in re-setting label costs after Expansion 49 | - Fixed bug in GCO_LoadLib 50 | Oct 27, 2009; - Removed support for arbitrary smoothcost (too slow, hard to maintain) 51 | - Added support for re-setting data, smooth, and label costs after Expansion 52 | - Added support for label subset costs 53 | - Changed build process to directly use MEX command 54 | - Added integer overflow checks into GCoptimization 55 | - GCoptimization now uses maxflow-3.0 library 56 | Sep 12, 2009; - Added support for arbitrary smoothcost from Matlab via a function_handle 57 | - Added GCO_UnitTest 58 | - Build script now handles spaces in paths properly 59 | Aug 23, 2009; - First version for internal testing 60 | 61 | ***************************************************************************************/ 62 | 63 | 0. System Requirements 64 | 65 | - Matlab 7.4.0 (R2007a) or above for 32-bit. 66 | Matlab 7.6.0 (R2008) or above for 64-bit. 67 | 68 | - Mex must be pre-configured to use a C++ compiler. (Run "mex -setup" if you have 69 | not already.) The C++ code requires at least Visual C++ 2005 (VC8). 70 | 71 | 72 | ---------------------------------------------------------------------------------------- 73 | 1. Installation 74 | 75 | - The package should contain the following files: 76 | 77 | GCO_MATLAB files: 78 | gco\matlab\GCO_*.m ; the Matlab commands that you can run 79 | gco\matlab\gco_matlab.cpp ; the library that links Matlab to GCoptimization 80 | 81 | GCoptimization files: 82 | gco\*.{h,cpp} ; the GCoptimization C++ library 83 | 84 | - Start Matlab, and make gco\matlab your working directory or add it to your path. 85 | 86 | - To test your installation of GCO_MATLAB, run the GCO_UnitTest command. 87 | You should hopefully see output like below. 88 | >> GCO_UnitTest 89 | BuildLib PASSED 90 | LoadLib PASSED 91 | Create/Delete PASSED 92 | ... 93 | >> 94 | 95 | - 96 | 97 | ---------------------------------------------------------------------------------------- 98 | 2. Getting Started -- A basic example, and important usage notes 99 | 100 | Once GCO_UnitTest passes, you should be able run the example sequence of commands below. 101 | 102 | >> h = GCO_Create(4,3); % Create new object with NumSites=4, NumLabels=3 103 | >> GCO_SetDataCost(h,[ 104 | 0 9 2 0; % Sites 1,4 prefer label 1 105 | 3 0 3 3; % Site 2 prefers label 2 (strongly) 106 | 5 9 0 5; % Site 3 prefers label 3 107 | ]); 108 | >> GCO_SetSmoothCost(h,[ 109 | 0 1 2; % 110 | 1 0 1; % Linear (Total Variation) pairwise cost 111 | 2 1 0; % 112 | ]); 113 | >> GCO_SetNeighbors(h,[ 114 | 0 1 0 0; % Sites 1 and 2 connected with weight 1 115 | 0 0 1 0; % Sites 2 and 3 connected with weight 1 116 | 0 0 0 2; % Sites 3 and 4 connected with weight 2 117 | 0 0 0 0; 118 | ]); 119 | >> GCO_Expansion(h); % Compute optimal labeling via alpha-expansion 120 | >> GCO_GetLabeling(h) 121 | ans = 122 | 1 % Optimal labeling is (1,2,1,1) 123 | 2 124 | 1 125 | 1 126 | >> [E D S] = GCO_ComputeEnergy(h) % Energy = Data Energy + Smooth Energy 127 | E = 128 | 4 129 | D = 130 | 2 131 | S = 132 | 2 133 | >> GCO_Delete(h); % Delete the GCoptimization object when finished 134 | 135 | 136 | *** Before using the MATLAB wrapper, please note the following: *** 137 | 138 | - Sites and labels are identified with 1-based indices (i.e. 1..N and *not* 0..N-1) 139 | 140 | - By default, all numeric costs should be int32, not single or double! 141 | To use single/double energy terms with the library, please type "help GCO_BuildLib" 142 | at the MATLAB command prompt. 143 | You'll receive a conversion warning if you pass in a large matrix of the wrong type. 144 | The only function that accepts double is GCO_SetNeighbors, because it needs a sparse matrix 145 | and sparse matrices only support double in MATLAB. 146 | ** The weights themselves must still be integer valued!! ** (1.0, 17.0, 42.0 etc) 147 | 148 | ---------------------------------------------------------------------------------------- 149 | 3. GCO_MATLAB functions 150 | 151 | Run 'help' in MATLAB to see the documentation of each function, e.g. 152 | >> help GCO_SetSmoothCost 153 | 154 | Most of the GCO_MATLAB functions are one-to-one with the C++ methods in the 155 | GCoptimization library. 156 | For more detailed documentation, please refer to the C++ library itself. 157 | Relevant files are: 158 | GCO_README.TXT 159 | example.cpp 160 | GCoptimization.h 161 | -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/bin/gco_matlab.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/Carlevaris/gco-v3.0/matlab/bin/gco_matlab.mexw64 -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/matlab/test.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/Carlevaris/gco-v3.0/matlab/test.m -------------------------------------------------------------------------------- /Carlevaris/gco-v3.0/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 | -------------------------------------------------------------------------------- /Carlevaris/getLaplacian1.m: -------------------------------------------------------------------------------- 1 | % Function written by Anat Levin, Alex Rav-Acha, Dani Lischinski 2 | % From paper: Spectral Matting 3 | % See http://www.vision.huji.ac.il/SpectralMatting/ 4 | 5 | function A=getLaplacian1(I,consts,epsilon,win_size); 6 | 7 | if (~exist('epsilon','var')) 8 | epsilon=0.0000001; 9 | end 10 | if (isempty(epsilon)) 11 | epsilon=0.0000001; 12 | end 13 | if (~exist('win_size','var')) 14 | win_size=1; 15 | end 16 | if (isempty(win_size)) 17 | win_size=1; 18 | end 19 | 20 | neb_size=(win_size*2+1)^2; 21 | [h,w,c]=size(I); 22 | n=h; m=w; 23 | img_size=w*h; 24 | consts=imerode(consts,ones(win_size*2+1)); 25 | 26 | indsM=reshape([1:img_size],h,w); 27 | 28 | tlen=sum(sum(1-consts(win_size+1:end-win_size,win_size+1:end-win_size)))*(neb_size^2); 29 | 30 | row_inds=zeros(tlen ,1); 31 | col_inds=zeros(tlen,1); 32 | vals=zeros(tlen,1); 33 | len=0; 34 | for j=1+win_size:w-win_size 35 | for i=win_size+1:h-win_size 36 | if (consts(i,j)) 37 | continue 38 | end 39 | win_inds=indsM(i-win_size:i+win_size,j-win_size:j+win_size); 40 | win_inds=win_inds(:); 41 | winI=I(i-win_size:i+win_size,j-win_size:j+win_size,:); 42 | winI=reshape(winI,neb_size,c); 43 | win_mu=mean(winI,1)'; 44 | win_var=inv(winI'*winI/neb_size-win_mu*win_mu' +epsilon/neb_size*eye(c)); 45 | 46 | winI=winI-repmat(win_mu',neb_size,1); 47 | tvals=(1+winI*win_var*winI')/neb_size; 48 | 49 | row_inds(1+len:neb_size^2+len)=reshape(repmat(win_inds,1,neb_size),... 50 | neb_size^2,1); 51 | col_inds(1+len:neb_size^2+len)=reshape(repmat(win_inds',neb_size,1),... 52 | neb_size^2,1); 53 | vals(1+len:neb_size^2+len)=tvals(:); 54 | len=len+neb_size^2; 55 | end 56 | end 57 | 58 | vals=vals(1:len); 59 | row_inds=row_inds(1:len); 60 | col_inds=col_inds(1:len); 61 | A=sparse(row_inds,col_inds,vals,img_size,img_size); 62 | 63 | sumA=sum(A,2); 64 | A=spdiags(sumA(:),0,img_size,img_size)-A; 65 | 66 | return 67 | 68 | 69 | -------------------------------------------------------------------------------- /Carlevaris/grid_nb.m: -------------------------------------------------------------------------------- 1 | function [nb] = grid_nb(w, h); 2 | 3 | % Sets up a sparse matrix representing a grid neighbourhood 4 | 5 | nb = sparse(w*h,w*h); 6 | for y=1:h % set up a grid-like neighbourhood, arbitrarily 7 | for x=1:w 8 | if (x < w), nb((y-1)*w+x,(y-1)*w+x+1) = 1; end 9 | if (y < h), nb((y-1)*w+x, y *w+x ) = 1; end 10 | end 11 | end 12 | 13 | 14 | end -------------------------------------------------------------------------------- /Carlevaris/grid_nb_weighted.m: -------------------------------------------------------------------------------- 1 | function [nb] = grid_nb_weighted(w, h, t_est); 2 | 3 | % Sets up a sparse matrix representing a grid neighbourhood 4 | 5 | nb = sparse(w*h,w*h); 6 | for y=1:h % set up a grid-like neighbourhood, arbitrarily 7 | for x=1:w 8 | if (x < w), nb((y-1)*w+x,(y-1)*w+x+1) = 1-abs(t_est(y,x) - t_est(y,x+1)); end 9 | if (y < h), nb((y-1)*w+x, y *w+x ) = 1-abs(t_est(y,x) - t_est(y+1,x)); end 10 | end 11 | end 12 | 13 | 14 | end -------------------------------------------------------------------------------- /Carlevaris/images/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/Carlevaris/images/img.jpg -------------------------------------------------------------------------------- /Carlevaris/laplacian_matting.m: -------------------------------------------------------------------------------- 1 | function [t_est] = laplacian_matting( t_est, I, lambda) 2 | %LAPLACIAN_MATTING implementation of Natural Image Matting as proposed by 3 | %Levin et al in ... 4 | 5 | [m,n] = size(t_est); 6 | L = getLaplacian1(I,zeros(m,n)); 7 | [Lm Ln] = size(L); 8 | Atmp = (L+lambda*speye(Lm,Ln)); 9 | clear L 10 | btmp = (lambda.*reshape(t_est,m*n,1)); 11 | t_est = double(Atmp)\double(btmp); 12 | clear Atmp 13 | 14 | t_est = reshape(t_est,m,n); 15 | 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /Carlevaris/oceans.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/Carlevaris/oceans.m -------------------------------------------------------------------------------- /DPATN/Airlight_water.m: -------------------------------------------------------------------------------- 1 | function A = Airlight_water(HazeImg, wsz) 2 | % estimating A channel by channel separately 3 | minImg = ordfilt2(double(HazeImg(:, :, 1)), 1, ones(wsz), 'symmetric'); 4 | A(1) = mean(minImg(:)); 5 | for k = 2 : 3 6 | minImg = ordfilt2(double(HazeImg(:, :, k)), 1, ones(wsz), 'symmetric'); 7 | % A(k) = max(minImg(:)); 8 | % A=max(A,1) 9 | end 10 | 11 | [nRows, nCols, bt] = size(HazeImg); 12 | GrayImg =max( HazeImg(:,:,3)-HazeImg(:,:,1),HazeImg(:,:,2)-HazeImg(:,:,1)); 13 | topDark = sort(minImg(:), 'descend'); 14 | idx = round(0.005 * length(topDark)); 15 | val = topDark(idx); 16 | id_set = find(minImg >= val); % the top 0.1% brightest pixels in the dark channel 17 | BluePxls = GrayImg(id_set); 18 | iBlue = find(BluePxls >= max(BluePxls)); 19 | id = id_set(iBlue); id = id(1); 20 | row = mod(id, nRows); 21 | col = floor(id / nRows) + 1; 22 | % A is a vector 23 | row=max(row,1); 24 | A = HazeImg(row, col, :); 25 | A=max(A,0.001); 26 | A = double(A(:)); -------------------------------------------------------------------------------- /DPATN/Dehazefun.m: -------------------------------------------------------------------------------- 1 | 2 | function rImg = Dehazefun(HazeImg, t, A, delta) 3 | % dehaze an image given t and A 4 | 5 | % 6 | t = max(abs(t), 0.0001).^delta; 7 | 8 | % extropolation to dehaze 9 | HazeImg = double(HazeImg); 10 | if length(A) == 1 11 | A = A * ones(3, 1); 12 | end 13 | R = (HazeImg(:, :, 1) - A(1)) ./ t + A(1); %R = max(R, 0); R = min(R, 255); 14 | G = (HazeImg(:, :, 2) - A(2)) ./ t + A(2); %G = max(G, 0); G = min(G, 255); 15 | B = (HazeImg(:, :, 3) - A(3)) ./ t + A(3); %B = max(B, 0); B = min(B, 255); 16 | rImg = cat(3, R, G, B) ./ 255; -------------------------------------------------------------------------------- /DPATN/JointTraining_5x5_2500new.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/DPATN/JointTraining_5x5_2500new.mat -------------------------------------------------------------------------------- /DPATN/SimplestColorBalance.m: -------------------------------------------------------------------------------- 1 | function outval = SimplestColorBalance(im_org) 2 | num = 255; 3 | % SimplestColorBalance(im_orig, satLevel) 4 | % Performs color balancing via histogram normalization. 5 | % satLevel controls the percentage of pixels to clip to white and black. 6 | % Set plot = 0 or 1 to turn diagnostic plots on or off. 7 | if ndims(im_org) == 3 8 | 9 | R = sum(sum(im_org(:,:,1))); 10 | G = sum(sum(im_org(:,:,2))); 11 | B = sum(sum(im_org(:,:,3))); 12 | Max = max([R, G, B]); 13 | ratio = [Max / R, Max / G, Max / B]; 14 | 15 | satLevel1 = 0.005 * ratio; 16 | satLevel2 = 0.005 * ratio; 17 | 18 | [m, n, p] = size(im_org); 19 | imRGB_orig = zeros(p, m * n); 20 | for i = 1 : p 21 | imRGB_orig(i, :) = reshape(double(im_org(:, :, i)), [1, m * n]); 22 | %imRGB_orig(i, :) = imRGB_orig(i, :) / max(imRGB_orig(i, :)) * 255; 23 | end 24 | else 25 | 26 | satLevel1 = 0.001; 27 | satLevel2 = 0.005; 28 | [m, n] = size(im_org); 29 | p = 1; 30 | imRGB_orig = reshape(double(im_org), [1, m * n]); 31 | %imRGB_orig = imRGB_orig / max(imRGB_orig) * 255; 32 | end 33 | % full width histogram method 34 | % percentage of the image to saturate to black or white, tweakable param 35 | imRGB = zeros(size(imRGB_orig)); 36 | for ch = 1 : p 37 | q = [satLevel1(ch), 1 - satLevel2(ch)]; 38 | tiles = quantile(imRGB_orig(ch, :), q); 39 | temp = imRGB_orig(ch, :); 40 | temp(find(temp < tiles(1))) = tiles(1); 41 | temp(find(temp > tiles(2))) = tiles(2); 42 | imRGB(ch, :) = temp; 43 | bottom = min(imRGB(ch, :)); 44 | top = max(imRGB(ch, :)); 45 | imRGB(ch, :) = (imRGB(ch, :) - bottom) * num / (top - bottom); 46 | end 47 | if ndims(im_org) == 3 48 | outval = zeros(size(im_org)); 49 | for i = 1 : p 50 | outval(:, :, i) = reshape(imRGB(i, :), [m, n]); 51 | end 52 | else 53 | outval = reshape(imRGB, [m, n]); 54 | end 55 | outval = uint8(outval); 56 | %imshow([im_orig,uint8(outval)]) -------------------------------------------------------------------------------- /DPATN/boxfilter.m: -------------------------------------------------------------------------------- 1 | function imDst = boxfilter(imSrc, r) 2 | 3 | % BOXFILTER O(1) time box filtering using cumulative sum 4 | % 5 | % - Definition imDst(x, y)=sum(sum(imSrc(x-r:x+r,y-r:y+r))); 6 | % - Running time independent of r; 7 | % - Equivalent to the function: colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum); 8 | % - But much faster. 9 | 10 | [hei, wid] = size(imSrc); 11 | imDst = zeros(size(imSrc)); 12 | 13 | %cumulative sum over Y axis 14 | imCum = cumsum(imSrc, 1); 15 | %difference over Y axis 16 | imDst(1:r+1, :) = imCum(1+r:2*r+1, :); 17 | imDst(r+2:hei-r, :) = imCum(2*r+2:hei, :) - imCum(1:hei-2*r-1, :); 18 | imDst(hei-r+1:hei, :) = repmat(imCum(hei, :), [r, 1]) - imCum(hei-2*r:hei-r-1, :); 19 | 20 | %cumulative sum over X axis 21 | imCum = cumsum(imDst, 2); 22 | %difference over Y axis 23 | imDst(:, 1:r+1) = imCum(:, 1+r:2*r+1); 24 | imDst(:, r+2:wid-r) = imCum(:, 2*r+2:wid) - imCum(:, 1:wid-2*r-1); 25 | imDst(:, wid-r+1:wid) = repmat(imCum(:, wid), [1, r]) - imCum(:, wid-2*r:wid-r-1); 26 | end 27 | 28 | -------------------------------------------------------------------------------- /DPATN/demo_underwater.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/DPATN/demo_underwater.m -------------------------------------------------------------------------------- /DPATN/denoisingOneStepGMixMFs.m: -------------------------------------------------------------------------------- 1 | function x_star = denoisingOneStepGMixMFs(noisy, input, model) 2 | mfsAll = model.mfsAll; 3 | K = model.K; 4 | p = model.p; 5 | mfs = model.mfs; 6 | filtN = length(K); 7 | [r,c] = size(input); 8 | %% do a gradient descent step 9 | u = input; 10 | f = noisy; 11 | g = (u - f)*p; 12 | parfor i=1:filtN 13 | Ku = imfilter(u,K{i},'symmetric'); 14 | Ne1 = lut_eval(Ku(:)', mfs.offsetD, mfs.step, mfsAll{i}.P, 0, 0, 0); 15 | Ne1 = reshape(Ne1,r,c); 16 | g = g + imfilter(Ne1,rot90(rot90(K{i})),'symmetric'); 17 | end 18 | x_star = u - g; 19 | % x_star = max(0, min(x_star, 255)); -------------------------------------------------------------------------------- /DPATN/gen_dct2.m: -------------------------------------------------------------------------------- 1 | function C = gen_dct2(n) 2 | C = zeros(n^2,n^2); 3 | for i = 1:n 4 | for j = 1:n 5 | A = zeros(n,n); 6 | A(i,j) = 1; 7 | B = idct2(A); 8 | C(:,(j-1)*n + i) = B(:); 9 | end 10 | end -------------------------------------------------------------------------------- /DPATN/guidedfilter.m: -------------------------------------------------------------------------------- 1 | function q = guidedfilter(I, p, r, eps) 2 | % GUIDEDFILTER O(1) time implementation of guided filter. 3 | % 4 | % - guidance image: I (should be a gray-scale/single channel image) 5 | % - filtering input image: p (should be a gray-scale/single channel image) 6 | % - local window radius: r 7 | % - regularization parameter: eps 8 | 9 | [hei, wid] = size(I); 10 | N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. 11 | 12 | mean_I = boxfilter(I, r) ./ N; 13 | mean_p = boxfilter(p, r) ./ N; 14 | mean_Ip = boxfilter(I.*p, r) ./ N; 15 | cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. 16 | 17 | mean_II = boxfilter(I.*I, r) ./ N; 18 | var_I = mean_II - mean_I .* mean_I; 19 | 20 | a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper; 21 | b = mean_p - a .* mean_I; % Eqn. (6) in the paper; 22 | 23 | mean_a = boxfilter(a, r) ./ N; 24 | mean_b = boxfilter(b, r) ./ N; 25 | 26 | q = mean_a .* I + mean_b; % Eqn. (8) in the paper; 27 | end -------------------------------------------------------------------------------- /DPATN/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/DPATN/images/1.jpg -------------------------------------------------------------------------------- /DPATN/lut_eval.c: -------------------------------------------------------------------------------- 1 | //LUT_EVAL - Evaluate RBFMIX function value and gradients via lookup table with linear interpolation. 2 | // 3 | // Compiling: 4 | // Linux: mex lut_eval.c CFLAGS="\$CFLAGS -Wall -std=c99 -mtune=native -O3 -fopenmp" LDFLAGS="\$LDFLAGS -fopenmp" 5 | // Windows: mex lut_eval.c COMPFLAGS="$COMPFLAGS /Wall /TP" OPTIMFLAGS="$OPTIMFLAGS /openmp /O2" 6 | // 7 | // Author: Uwe Schmidt, TU Darmstadt (uwe.schmidt@gris.tu-darmstadt.de) 8 | // 9 | // This file is part of the implementation as described in the CVPR 2014 paper: 10 | // Uwe Schmidt and Stefan Roth. Shrinkage Fields for Effective Image Restoration. 11 | // Please see the file LICENSE.txt for the license governing this code. 12 | 13 | #include "mex.h" 14 | #include 15 | #include 16 | 17 | void lookup(const int nargout, double *outP, double *outGW, double *outGX, double *outQ, const double *x, const double origin, const double step, const double *P, const double *GW, const double *GX, const double *Q, const int ndata, const int nbins, const int nmeans) { 18 | omp_set_num_threads(64); 19 | #pragma omp parallel for 20 | for (int i = 0; i < ndata; i++) { 21 | 22 | const double x_hit = (x[i] - origin) / step; 23 | int xl = (int) floor(x_hit), xh = (int) ceil(x_hit); 24 | 25 | // boundary checks 26 | if (xl < 0) xl = 0; if (xl >= nbins) xl = nbins-1; 27 | if (xh < 0) xh = 0; if (xh >= nbins) xh = nbins-1; 28 | const double wh = x_hit - (double)xl; 29 | 30 | const double pl = P[xl], ph = P[xh]; 31 | outP[i] = pl + (ph-pl) * wh; 32 | 33 | if (nargout >= 2) { 34 | const double *GWlow = GW + xl*nmeans, *GWhigh = GW + xh*nmeans; 35 | double *outGWoff = outGW + i*nmeans; 36 | for (int j = 0; j < nmeans; j++) { 37 | const double gwl = *GWlow++, gwh = *GWhigh++; 38 | *outGWoff++ = gwl + (gwh-gwl) * wh; 39 | } 40 | // 41 | if (nargout >= 3) { 42 | const double gxl = GX[xl], gxh = GX[xh]; 43 | outGX[i] = gxl + (gxh-gxl) * wh; 44 | // 45 | if (nargout >= 4) { 46 | const double *Qlow = Q + xl*nmeans, *Qhigh = Q + xh*nmeans; 47 | double *outQoff = outQ + i*nmeans; 48 | for (int j = 0; j < nmeans; j++) { 49 | const double ql = *Qlow++, qh = *Qhigh++; 50 | *outQoff++ = ql + (qh-ql) * wh; 51 | } 52 | } 53 | } 54 | } 55 | 56 | } 57 | } 58 | 59 | mxArray* createUninitializedDoubleMatrix(const int M, const int N) { 60 | // mxArray *mxP = mxCreateNumericMatrix(M, N, mxDOUBLE_CLASS, mxREAL); 61 | mxArray *mxP = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); 62 | mxSetM(mxP, M); mxSetN(mxP, N); 63 | mxSetData(mxP, mxMalloc(sizeof(double) * (M*N))); 64 | return mxP; 65 | } 66 | 67 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 68 | 69 | if (nlhs == 0) return; 70 | if (nrhs != 7) mexErrMsgTxt("Seven inputs expected: lut_eval(x, origin, step, P, GW, GX, Q)"); 71 | 72 | const int ndata = mxGetNumberOfElements(prhs[0]); 73 | const int nbins = mxGetNumberOfElements(prhs[3]); 74 | const int nmeans = mxGetM(prhs[4]); 75 | const double *data = (const double*) mxGetPr(prhs[0]); 76 | const double origin = mxGetScalar(prhs[1]); 77 | const double step = mxGetScalar(prhs[2]); 78 | const double *P = (const double*) mxGetPr(prhs[3]); 79 | const double *GW = (const double*) mxGetPr(prhs[4]); 80 | const double *GX = (const double*) mxGetPr(prhs[5]); 81 | const double *Q = (const double*) mxGetPr(prhs[6]); 82 | 83 | double *outP=0, *outGW=0, *outGX=0, *outQ=0; 84 | if (nlhs > 0) { 85 | plhs[0] = createUninitializedDoubleMatrix(1, ndata); 86 | outP = (double*) mxGetPr(plhs[0]); 87 | if (nlhs > 1) { 88 | plhs[1] = createUninitializedDoubleMatrix(nmeans, ndata); 89 | outGW = (double*) mxGetPr(plhs[1]); 90 | if (nlhs > 2) { 91 | plhs[2] = createUninitializedDoubleMatrix(1, ndata); 92 | outGX = (double*) mxGetPr(plhs[2]); 93 | if (nlhs > 3) { 94 | plhs[3] = createUninitializedDoubleMatrix(nmeans, ndata); 95 | outQ = (double*) mxGetPr(plhs[3]); 96 | } 97 | } 98 | } 99 | } 100 | lookup(nlhs, outP, outGW, outGX, outQ, data, origin, step, P, GW, GX, Q, ndata, nbins, nmeans); 101 | } -------------------------------------------------------------------------------- /DPATN/lut_eval.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/DPATN/lut_eval.mexw64 -------------------------------------------------------------------------------- /DPATN/save_trained_model.m: -------------------------------------------------------------------------------- 1 | function trained_model = save_trained_model(cof, mfs, stage, KernelPara) 2 | basis = KernelPara.basis; 3 | filter_size = KernelPara.fsz; 4 | m = filter_size^2 - 1; 5 | filtN = KernelPara.filtN; 6 | 7 | trained_model = cell(stage,1); 8 | for s = 1:stage 9 | vcof = cof(:,s); 10 | part1 = vcof(1:filtN*m); 11 | cof_beta = reshape(part1,m,filtN); 12 | part3 = vcof(filtN*m+1); 13 | p = exp(part3); 14 | part4 = vcof(filtN*m+2:end); 15 | weights = reshape(part4,mfs.NumW,filtN); 16 | 17 | K = cell(filtN,1); 18 | f_norms = zeros(filtN,1); 19 | for i = 1:filtN 20 | x_cof = cof_beta(:,i); 21 | filter = basis*x_cof; 22 | f_norms(i) = norm(filter); 23 | filter = filter/(norm(filter) + eps); 24 | K{i} = reshape(filter,filter_size,filter_size); 25 | end 26 | %% update mfs 27 | mfsAll = cell(filtN,1); 28 | for i=1:filtN 29 | w = weights(:,i); 30 | Q = bsxfun(@times, mfs.G, w); 31 | mfsAll{i}.P = sum(Q,1); 32 | end 33 | %% construct model for one stage 34 | model.mfsAll = mfsAll; 35 | model.K = K; 36 | model.p = p; 37 | model.mfs = mfs; 38 | model.f_norms = f_norms; 39 | trained_model{s} = model; 40 | end 41 | -------------------------------------------------------------------------------- /DPATN/t_initialize.m: -------------------------------------------------------------------------------- 1 | 2 | function [t_bdcon, t_b] = t_initialize(HazeImg, A, C0, C1, sz) 3 | % patch-wise transmission 4 | if length(A) == 1 5 | A = A * ones(3, 1); 6 | end 7 | if length(C0) == 1 8 | C0 = C0 * ones(3, 1); 9 | end 10 | if length(C1) == 1 11 | C1 = C1 * ones(3, 1); 12 | end 13 | HazeImg = double(HazeImg); 14 | 15 | % pixel-wise boundary 16 | t_r = max((A(1) - HazeImg(:, :, 1)) ./ (A(1) - C0(1)), (HazeImg(:, :, 1) - A(1)) ./ (C1(1) - A(1) )); 17 | t_g = max((A(2) - HazeImg(:, :, 2)) ./ (A(2) - C0(2)), (HazeImg(:, :, 2) - A(2)) ./ (C1(2) - A(2) )); 18 | t_b = max((A(3) - HazeImg(:, :, 3)) ./ (A(3) - C0(3)), (HazeImg(:, :, 3) - A(3)) ./ (C1(3) - A(3) )); 19 | t_b = max(cat(3, t_r, t_g, t_b), [], 3); 20 | t_b = min(t_b, 1); 21 | 22 | % minimum filtering 23 | se = strel('square', sz); 24 | t_bdcon = imclose(t_b, se); 25 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/SimplestColorBalance.m: -------------------------------------------------------------------------------- 1 | function outval = SimplestColorBalance(im_org) 2 | num = 255; 3 | % SimplestColorBalance(im_orig, satLevel) 4 | % Performs color balancing via histogram normalization. 5 | % satLevel controls the percentage of pixels to clip to white and black. 6 | % Set plot = 0 or 1 to turn diagnostic plots on or off. 7 | if ndims(im_org) == 3 8 | 9 | R = sum(sum(im_org(:,:,1))); 10 | G = sum(sum(im_org(:,:,2))); 11 | B = sum(sum(im_org(:,:,3))); 12 | Max = max([R, G, B]); 13 | ratio = [Max / R, Max / G, Max / B]; 14 | 15 | satLevel1 = 0.005 * ratio; 16 | satLevel2 = 0.005 * ratio; 17 | 18 | [m, n, p] = size(im_org); 19 | imRGB_orig = zeros(p, m * n); 20 | for i = 1 : p 21 | imRGB_orig(i, :) = reshape(double(im_org(:, :, i)), [1, m * n]); 22 | %imRGB_orig(i, :) = imRGB_orig(i, :) / max(imRGB_orig(i, :)) * 255; 23 | end 24 | else 25 | 26 | satLevel1 = 0.001; 27 | satLevel2 = 0.005; 28 | [m, n] = size(im_org); 29 | p = 1; 30 | imRGB_orig = reshape(double(im_org), [1, m * n]); 31 | %imRGB_orig = imRGB_orig / max(imRGB_orig) * 255; 32 | end 33 | % full width histogram method 34 | % percentage of the image to saturate to black or white, tweakable param 35 | imRGB = zeros(size(imRGB_orig)); 36 | for ch = 1 : p 37 | q = [satLevel1(ch), 1 - satLevel2(ch)]; 38 | tiles = quantile(imRGB_orig(ch, :), q); 39 | temp = imRGB_orig(ch, :); 40 | temp(find(temp < tiles(1))) = tiles(1); 41 | temp(find(temp > tiles(2))) = tiles(2); 42 | imRGB(ch, :) = temp; 43 | bottom = min(imRGB(ch, :)); 44 | top = max(imRGB(ch, :)); 45 | imRGB(ch, :) = (imRGB(ch, :) - bottom) * num / (top - bottom); 46 | end 47 | if ndims(im_org) == 3 48 | outval = zeros(size(im_org)); 49 | for i = 1 : p 50 | outval(:, :, i) = reshape(imRGB(i, :), [m, n]); 51 | end 52 | else 53 | outval = reshape(imRGB, [m, n]); 54 | end 55 | outval = uint8(outval); 56 | %imshow([im_orig,uint8(outval)]) -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/UICM.m: -------------------------------------------------------------------------------- 1 | function [meanRG, deltaRG, meanYB, deltaYB, uicm] = UICM(img) 2 | R = double(img(:,:,1)); 3 | G = double(img(:,:,2)); 4 | B = double(img(:,:,3)); 5 | RG = R - G; 6 | YB = (R + G) / 2 - B; 7 | 8 | K = size(R,1) * size(R,2); 9 | 10 | % for R-G channel 11 | RG1 = reshape(RG, 1, K); 12 | RG1 = sort(RG1); 13 | alphaL = 0.1; 14 | alphaR = 0.1; 15 | RG1 = RG1(1, int32(alphaL*K+1) : int32(K*(1-alphaR))); 16 | N = K * (1 - alphaL - alphaR); 17 | meanRG = sum(RG1) / N; 18 | deltaRG = sqrt(sum((RG1 - meanRG).^2) / N); 19 | 20 | % for Y-B channel 21 | YB1 = reshape(YB, 1, K); 22 | YB1 = sort(YB1); 23 | alphaL = 0.1; 24 | alphaR = 0.1; 25 | YB1 = YB1(1, int32(alphaL*K+1) : int32(K*(1-alphaR))); 26 | N = K * (1 - alphaL - alphaR); 27 | meanYB = sum(YB1) / N; 28 | deltaYB = sqrt(sum((YB1 - meanYB).^2) / N); 29 | 30 | % UICM 31 | uicm = -0.0268 * sqrt(meanRG^2 + meanYB^2) + ... 32 | 0.1586* sqrt(deltaRG^2 + deltaYB^2); -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/UIConM.m: -------------------------------------------------------------------------------- 1 | function uiconm = UIConM(img) 2 | R = double(img(:,:,1)); 3 | G = double(img(:,:,2)); 4 | B = double(img(:,:,3)); 5 | 6 | patchsz = 5; 7 | [m, n] = size(R); 8 | % resize the input image to match the patch size 9 | if mod(m, patchsz) ~= 0 || mod(n, patchsz) ~= 0 10 | R = imresize(R, [m - mod(m, patchsz) + patchsz, ... 11 | n - mod(n, patchsz) + patchsz]); 12 | G = imresize(G, [m - mod(m, patchsz) + patchsz, ... 13 | n - mod(n, patchsz) + patchsz]); 14 | B = imresize(B, [m - mod(m, patchsz) + patchsz, ... 15 | n - mod(n, patchsz) + patchsz]); 16 | end 17 | [m, n] = size(R); 18 | k1 = m / patchsz; 19 | k2 = n / patchsz; 20 | 21 | AMEER = 0; 22 | for i = 1 : patchsz : m 23 | for j = 1 : patchsz : n 24 | sz = patchsz - 1; 25 | im = R(i:i+sz,j:j+sz); 26 | Max = max(max(im)); 27 | Min = min(min(im)); 28 | if ( (Max ~= 0 || Min ~= 0) && Max ~= Min ) 29 | AMEER = AMEER + ... 30 | log( (Max - Min) / (Max + Min) ) * ... 31 | ( (Max - Min) / (Max + Min) ); 32 | end 33 | end 34 | end 35 | AMEER = 1 / (k1 * k2) * abs(AMEER); 36 | AMEEG = 0; 37 | for i = 1 : patchsz : m 38 | for j = 1 : patchsz : n 39 | sz = patchsz - 1; 40 | im = G(i:i+sz,j:j+sz); 41 | Max = max(max(im)); 42 | Min = min(min(im)); 43 | if ( (Max ~= 0 || Min ~= 0) && Max ~= Min ) 44 | AMEEG = AMEEG + ... 45 | log( (Max - Min) / (Max + Min) ) * ... 46 | ( (Max - Min) / (Max + Min) ); 47 | end 48 | end 49 | end 50 | AMEEG = 1 / (k1 * k2) * abs(AMEEG); 51 | AMEEB = 0; 52 | for i = 1 : patchsz : m 53 | for j = 1 : patchsz : n 54 | sz = patchsz - 1; 55 | im = B(i:i+sz,j:j+sz); 56 | Max = max(max(im)); 57 | Min = min(min(im)); 58 | if ( (Max ~= 0 || Min ~= 0) && Max ~= Min ) 59 | AMEEB = AMEEB + ... 60 | log( (Max - Min) / (Max + Min) ) * ... 61 | ( (Max - Min) / (Max + Min) ); 62 | end 63 | end 64 | end 65 | AMEEB = 1 / (k1 * k2) * abs(AMEEB); 66 | uiconm = AMEER + AMEEG + AMEEB; -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/UIQM.m: -------------------------------------------------------------------------------- 1 | function uiqm = UIQM(img) 2 | 3 | c1 = 0.0282; 4 | c2 = 0.2953; 5 | c3 = 3.5753; 6 | 7 | uicm = UICM(img); 8 | uism = UISM(img); 9 | uiconm = UIConM(img); 10 | 11 | uiqm = c1 * uicm + c2 * uism + c3 * uiconm; 12 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/UISM.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/ImageEnhanceViaFusion/UISM.m -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/autolevel.m: -------------------------------------------------------------------------------- 1 | function imDst = autolevel(varargin) 2 | [I,lowCut,highCut] =parse_inputs(varargin{:}); 3 | [hei,wid,~] = size(I); 4 | 5 | PixelAmount = wid * hei; 6 | if size(I,3)==3 7 | 8 | [HistRed,~] = imhist(I(:,:,1)); 9 | [HistGreen,~] = imhist(I(:,:,2)); 10 | [HistBlue,~] = imhist(I(:,:,3)); 11 | 12 | CumRed = cumsum(HistRed); 13 | CumGreen = cumsum(HistGreen); 14 | CumBlue = cumsum(HistBlue); 15 | 16 | minR =find(CumRed>=PixelAmount*lowCut,1,'first'); 17 | minG = find(CumGreen>=PixelAmount*lowCut,1,'first'); 18 | minB =find(CumBlue>=PixelAmount*lowCut,1,'first'); 19 | 20 | maxR =find(CumRed>=PixelAmount*(1-highCut),1,'first'); 21 | maxG =find(CumGreen>=PixelAmount*(1-highCut),1,'first'); 22 | maxB = find(CumBlue>=PixelAmount*(1-highCut),1,'first'); 23 | 24 | RedMap = linearmap(minR,maxR); 25 | GreenMap = linearmap(minG,maxG); 26 | BlueMap = linearmap(minB,maxB); 27 | 28 | imDst = zeros(hei,wid,3,'uint8'); 29 | imDst(:,:,1) = RedMap (I(:,:,1)+1); 30 | imDst(:,:,2) = GreenMap(I(:,:,2)+1); 31 | imDst(:,:,3) = BlueMap(I(:,:,3)+1); 32 | 33 | else 34 | HistGray = imhist(I(:,:)); 35 | CumGray = cumsum(HistRed); 36 | minGray =find(CumGray>=PixelAmount*lowCut,1,'first'); 37 | maxGray =find(CumGray>=PixelAmount*(1-highCut),1,'first'); 38 | GrayMap = linearmap(minGray,maxGray); 39 | 40 | imDst = zeros(hei,wid,'uint8'); 41 | imDst(:,:) = GrayMap (I(:,:)+1); 42 | end 43 | 44 | %-------------------------------------------------------------------- 45 | function map = linearmap(low,high) 46 | map = [0:1:255]; 47 | for i=0:255 48 | if(ihigh) 51 | map(i+1) = 255; 52 | else 53 | map(i+1) =uint8((i-low)/(high-low)*255); 54 | end 55 | end 56 | 57 | 58 | %------------------------------------------------------------------- 59 | function [I,lowCut,highCut] = parse_inputs(varargin) 60 | narginchk(1,3) 61 | I = varargin{1}; 62 | validateattributes(I,{'double','logical','uint8','uint16','int16','single'},{},... 63 | mfilename,'Image',1); 64 | 65 | if nargin == 1 66 | lowCut = 0.005; 67 | highCut = 0.005; 68 | elseif nargin == 3 69 | lowCut = varargin{2}; 70 | highCut = varargin{3}; 71 | else 72 | error(message('images:im2double:invalidIndexedImage','single, or logical.')); 73 | end -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/bilateralFilter.m: -------------------------------------------------------------------------------- 1 | % 2 | % output = bilateralFilter( data, edge, ... 3 | % edgeMin, edgeMax, ... 4 | % sigmaSpatial, sigmaRange, ... 5 | % samplingSpatial, samplingRange ) 6 | % 7 | % Bilateral and Cross-Bilateral Filter using the Bilateral Grid. 8 | % 9 | % Bilaterally filters the image 'data' using the edges in the image 'edge'. 10 | % If 'data' == 'edge', then it the standard bilateral filter. 11 | % Otherwise, it is the 'cross' or 'joint' bilateral filter. 12 | % For convenience, you can also pass in [] for 'edge' for the normal 13 | % bilateral filter. 14 | % 15 | % Note that for the cross bilateral filter, data does not need to be 16 | % defined everywhere. Undefined values can be set to 'NaN'. However, edge 17 | % *does* need to be defined everywhere. 18 | % 19 | % data and edge should be of the greyscale, double-precision floating point 20 | % matrices of the same size (i.e. they should be [ height x width ]) 21 | % 22 | % data is the only required argument 23 | % 24 | % edgeMin and edgeMax specifies the min and max values of 'edge' (or 'data' 25 | % for the normal bilateral filter) and is useful when the input is in a 26 | % range that's not between 0 and 1. For instance, if you are filtering the 27 | % L channel of an image that ranges between 0 and 100, set edgeMin to 0 and 28 | % edgeMax to 100. 29 | % 30 | % edgeMin defaults to min( edge( : ) ) and edgeMax defaults to max( edge(:)). 31 | % This is probably *not* what you want, since the input may not span the 32 | % entire range. 33 | % 34 | % sigmaSpatial and sigmaRange specifies the standard deviation of the space 35 | % and range gaussians, respectively. 36 | % sigmaSpatial defaults to min( width, height ) / 16 37 | % sigmaRange defaults to ( edgeMax - edgeMin ) / 10. 38 | % 39 | % samplingSpatial and samplingRange specifies the amount of downsampling 40 | % used for the approximation. Higher values use less memory but are also 41 | % less accurate. The default and recommended values are: 42 | % 43 | % samplingSpatial = sigmaSpatial 44 | % samplingRange = sigmaRange 45 | % 46 | 47 | function output = bilateralFilter( data, edge, edgeMin, edgeMax,... 48 | sigmaSpatial, sigmaRange, samplingSpatial, samplingRange ) 49 | 50 | if( ndims( data ) > 2 ), 51 | error( 'data must be a greyscale image with size [ height, width ]' ); 52 | end 53 | 54 | if( ~isa( data, 'double' ) ), 55 | error( 'data must be of class "double"' ); 56 | end 57 | 58 | if ~exist( 'edge', 'var' ), 59 | edge = data; 60 | elseif isempty( edge ), 61 | edge = data; 62 | end 63 | 64 | if( ndims( edge ) > 2 ), 65 | error( 'edge must be a greyscale image with size [ height, width ]' ); 66 | end 67 | 68 | if( ~isa( edge, 'double' ) ), 69 | error( 'edge must be of class "double"' ); 70 | end 71 | 72 | inputHeight = size( data, 1 ); 73 | inputWidth = size( data, 2 ); 74 | 75 | if ~exist( 'edgeMin', 'var' ), 76 | edgeMin = min( edge( : ) ); 77 | %warning( 'edgeMin not set! Defaulting to: %f\n', edgeMin ); 78 | end 79 | 80 | if ~exist( 'edgeMax', 'var' ), 81 | edgeMax = max( edge( : ) ); 82 | %warning( 'edgeMax not set! Defaulting to: %f\n', edgeMax ); 83 | end 84 | 85 | edgeDelta = edgeMax - edgeMin; 86 | 87 | if ~exist( 'sigmaSpatial', 'var' ), 88 | sigmaSpatial = min( inputWidth, inputHeight ) / 16; 89 | %fprintf( 'Using default sigmaSpatial of: %f\n', sigmaSpatial ); 90 | end 91 | 92 | if ~exist( 'sigmaRange', 'var' ), 93 | sigmaRange = 0.1 * edgeDelta; 94 | %fprintf( 'Using default sigmaRange of: %f\n', sigmaRange ); 95 | end 96 | 97 | if ~exist( 'samplingSpatial', 'var' ), 98 | samplingSpatial = sigmaSpatial; 99 | end 100 | 101 | if ~exist( 'samplingRange', 'var' ), 102 | samplingRange = sigmaRange; 103 | end 104 | 105 | if size( data ) ~= size( edge ), 106 | error( 'data and edge must be of the same size' ); 107 | end 108 | 109 | % parameters 110 | derivedSigmaSpatial = sigmaSpatial / samplingSpatial; 111 | derivedSigmaRange = sigmaRange / samplingRange; 112 | 113 | paddingXY = floor( 2 * derivedSigmaSpatial ) + 1; 114 | paddingZ = floor( 2 * derivedSigmaRange ) + 1; 115 | 116 | % allocate 3D grid 117 | downsampledWidth = floor( ( inputWidth - 1 ) / samplingSpatial )... 118 | + 1 + 2 * paddingXY; 119 | downsampledHeight = floor( ( inputHeight - 1 ) / samplingSpatial )... 120 | + 1 + 2 * paddingXY; 121 | downsampledDepth = floor( edgeDelta / samplingRange ) + 1 + 2 * paddingZ; 122 | 123 | gridData = zeros( downsampledHeight, downsampledWidth, downsampledDepth ); 124 | gridWeights = zeros( downsampledHeight, downsampledWidth, downsampledDepth ); 125 | 126 | % compute downsampled indices 127 | [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); 128 | 129 | % ii = 130 | % 0 0 0 0 0 131 | % 1 1 1 1 1 132 | % 2 2 2 2 2 133 | 134 | % jj = 135 | % 0 1 2 3 4 136 | % 0 1 2 3 4 137 | % 0 1 2 3 4 138 | 139 | % so when iterating over ii( k ), jj( k ) 140 | % get: ( 0, 0 ), ( 1, 0 ), ( 2, 0 ), ... (down columns first) 141 | 142 | di = round( ii / samplingSpatial ) + paddingXY + 1; 143 | dj = round( jj / samplingSpatial ) + paddingXY + 1; 144 | dz = round( ( edge - edgeMin ) / samplingRange ) + paddingZ + 1; 145 | 146 | % perform scatter (there's probably a faster way than this) 147 | % normally would do downsampledWeights( di, dj, dk ) = 1, but we have to 148 | % perform a summation to do box downsampling 149 | for k = 1 : numel( dz ), 150 | 151 | dataZ = data( k ); % traverses the image column wise, same as di( k ) 152 | if ~isnan( dataZ ), 153 | 154 | dik = di( k ); 155 | djk = dj( k ); 156 | dzk = dz( k ); 157 | 158 | gridData( dik, djk, dzk ) = gridData( dik, djk, dzk ) + dataZ; 159 | gridWeights( dik, djk, dzk ) = gridWeights( dik, djk, dzk ) + 1; 160 | 161 | end 162 | end 163 | 164 | % make gaussian kernel 165 | kernelWidth = 2 * derivedSigmaSpatial + 1; 166 | kernelHeight = kernelWidth; 167 | kernelDepth = 2 * derivedSigmaRange + 1; 168 | 169 | halfKernelWidth = floor( kernelWidth / 2 ); 170 | halfKernelHeight = floor( kernelHeight / 2 ); 171 | halfKernelDepth = floor( kernelDepth / 2 ); 172 | 173 | [gridX, gridY, gridZ] = meshgrid( 0 : kernelWidth - 1,... 174 | 0 : kernelHeight - 1, 0 : kernelDepth - 1 ); 175 | gridX = gridX - halfKernelWidth; 176 | gridY = gridY - halfKernelHeight; 177 | gridZ = gridZ - halfKernelDepth; 178 | gridRSquared = ( gridX .* gridX + gridY .* gridY ) /... 179 | ( derivedSigmaSpatial * derivedSigmaSpatial ) +... 180 | ( gridZ .* gridZ ) / ( derivedSigmaRange * derivedSigmaRange ); 181 | kernel = exp( -0.5 * gridRSquared ); 182 | 183 | % convolve 184 | blurredGridData = convn( gridData, kernel, 'same' ); 185 | blurredGridWeights = convn( gridWeights, kernel, 'same' ); 186 | 187 | % divide 188 | % avoid divide by 0, won't read there anyway 189 | blurredGridWeights( blurredGridWeights == 0 ) = -2; 190 | normalizedBlurredGrid = blurredGridData ./ blurredGridWeights; 191 | % put 0s where it's undefined 192 | normalizedBlurredGrid( blurredGridWeights < -1 ) = 0; 193 | 194 | % for debugging 195 | % blurredGridWeights( blurredGridWeights < -1 ) = 0; % put zeros back 196 | 197 | % upsample 198 | % meshgrid does x, then y, so output arguments need to be reversed 199 | [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); 200 | % no rounding 201 | di = ( ii / samplingSpatial ) + paddingXY + 1; 202 | dj = ( jj / samplingSpatial ) + paddingXY + 1; 203 | dz = ( edge - edgeMin ) / samplingRange + paddingZ + 1; 204 | 205 | % interpn takes rows, then cols, etc 206 | % i.e. size(v,1), then size(v,2), ... 207 | output = interpn( normalizedBlurredGrid, di, dj, dz ); -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/boxfilter.m: -------------------------------------------------------------------------------- 1 | function imDst = boxfilter(imSrc, r) 2 | 3 | % BOXFILTER O(1) time box filtering using cumulative sum 4 | % 5 | % - Definition imDst(x, y)=sum(sum(imSrc(x-r:x+r,y-r:y+r))); 6 | % - Running time independent of r; 7 | % - Equivalent to the function: colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum); 8 | % - But much faster. 9 | 10 | [hei, wid] = size(imSrc); 11 | imDst = zeros(size(imSrc)); 12 | 13 | %cumulative sum over Y axis 14 | imCum = cumsum(imSrc, 1); 15 | %difference over Y axis 16 | imDst(1:r+1, :) = imCum(1+r:2*r+1, :); 17 | imDst(r+2:hei-r, :) = imCum(2*r+2:hei, :) - imCum(1:hei-2*r-1, :); 18 | imDst(hei-r+1:hei, :) = repmat(imCum(hei, :), [r, 1]) - imCum(hei-2*r:hei-r-1, :); 19 | 20 | %cumulative sum over X axis 21 | imCum = cumsum(imDst, 2); 22 | %difference over Y axis 23 | imDst(:, 1:r+1) = imCum(:, 1+r:2*r+1); 24 | imDst(:, r+2:wid-r) = imCum(:, 2*r+2:wid) - imCum(:, 1:wid-2*r-1); 25 | imDst(:, wid-r+1:wid) = repmat(imCum(:, wid), [1, r]) - imCum(:, wid-2*r:wid-r-1); 26 | end 27 | 28 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/clahe.m: -------------------------------------------------------------------------------- 1 | function img2=clahe(img) 2 | img1 = SimplestColorBalance(img); 3 | lab1 = rgb_to_lab(img1); 4 | % CLAHE 5 | 6 | lab2 = lab1; 7 | lab2(:, :, 1) = adapthisteq(lab2(:, :, 1)); 8 | %lab2(:, :, 1) = uint8(bilateralFilter(double(lab2(:, :, 1)))); 9 | img2 = lab_to_rgb(lab2); 10 | 11 | 12 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/fuse.m: -------------------------------------------------------------------------------- 1 | function fusion = fuse(img) %img Ϊimread 2 | 3 | %img = imread(strcat(file_path,name)); 4 | %[meanRG, deltaRG, meanYB, deltaYB, uicm] = UICM(img) 5 | % white balance 6 | %img1 = white_balance(img); 7 | img1 = SimplestColorBalance(img); 8 | %figure,imshow(img1) 9 | %img1 = white_balance(img); 10 | lab1 = rgb_to_lab(img1); 11 | %figure,imshow(img1) 12 | 13 | % CLAHE 14 | lab2 = lab1; 15 | lab2(:, :, 1) = adapthisteq(lab2(:, :, 1)); 16 | %lab2(:, :, 1) = uint8(bilateralFilter(double(lab2(:, :, 1)))); 17 | img2 = lab_to_rgb(lab2); 18 | %figure,imshow(img2); 19 | 20 | 21 | % input1 22 | R1 = double(lab1(:, :, 1)) / 255; 23 | % calculate laplacian contrast weight 24 | WL1 = abs(imfilter(R1, fspecial('Laplacian'), 'replicate', 'conv')); 25 | %calculate Local contrast weight 26 | h = 1/16* [1, 4, 6, 4, 1]; 27 | WC1 = imfilter(R1, h'*h, 'replicate', 'conv'); 28 | WC1(find(WC1 > (pi/2.75))) = pi/2.75; 29 | WC1 = (R1 - WC1).^2; 30 | % calculate the saliency weight 31 | WS1 = saliency_detection(img1); 32 | %max(max(WS1)) 33 | %min(min(WS1)) 34 | % calculate the exposedness weight 35 | sigma = 0.25; 36 | aver = 0.5; 37 | WE1 = exp(-(R1 - aver).^2 / (2*sigma^2)); 38 | 39 | % input2 40 | R2 = double(lab2(:, :, 1)) / 255; 41 | % calculate laplacian contrast weight 42 | WL2 = abs(imfilter(R1, fspecial('Laplacian'), 'replicate', 'conv')); 43 | %figure,imshow(WL2, []) 44 | %calculate Local contrast weight 45 | h = 1/16* [1, 4, 6, 4, 1]; 46 | WC2 = imfilter(R2, h'*h, 'replicate', 'conv'); 47 | WC2(find(WC2 > (pi/2.75))) = pi/2.75; 48 | WC2 = (R2 - WC2).^2; 49 | %figure,imshow(WC2, []) 50 | % calculate the saliency weight 51 | WS2 = saliency_detection(img2); 52 | %figure,imshow(WS2, []) 53 | % calculate the exposedness weight 54 | sigma = 0.25; 55 | aver = 0.5; 56 | WE2 = exp(-(R2 - aver).^2 / (2*sigma^2)); 57 | %figure,imshow(WE2, []) 58 | 59 | % calculate the normalized weight 60 | W1 = (WL1 + WC1 + WS1 + WE1) ./ ... 61 | (WL1 + WC1 + WS1 + WE1 + WL2 + WC2 + WS2 + WE2); 62 | W2 = (WL2 + WC2 + WS2 + WE2) ./ ... 63 | (WL1 + WC1 + WS1 + WE1 + WL2 + WC2 + WS2 + WE2); 64 | 65 | % calculate the gaussian pyramid 66 | level = 5; 67 | Weight1 = gaussian_pyramid(W1, level); 68 | Weight2 = gaussian_pyramid(W2, level); 69 | 70 | % calculate the laplacian pyramid 71 | % input1 72 | R1 = laplacian_pyramid(double(double(img1(:, :, 1))), level); 73 | G1 = laplacian_pyramid(double(double(img1(:, :, 2))), level); 74 | B1 = laplacian_pyramid(double(double(img1(:, :, 3))), level); 75 | % input2 76 | R2 = laplacian_pyramid(double(double(img2(:, :, 1))), level); 77 | G2 = laplacian_pyramid(double(double(img2(:, :, 2))), level); 78 | B2 = laplacian_pyramid(double(double(img2(:, :, 3))), level); 79 | 80 | % fusion 81 | for i = 1 : level 82 | R_r{i} = Weight1{i} .* R1{i} + Weight2{i} .* R2{i}; 83 | R_g{i} = Weight1{i} .* G1{i} + Weight2{i} .* G2{i}; 84 | R_b{i} = Weight1{i} .* B1{i} + Weight2{i} .* B2{i}; 85 | end 86 | 87 | % reconstruct & output 88 | R = pyramid_reconstruct(R_r); 89 | G = pyramid_reconstruct(R_g); 90 | B = pyramid_reconstruct(R_b); 91 | fusion = cat(3, uint8(R), uint8(G), uint8(B)); 92 | %fusion=im2double(fusion); 93 | %fusion = cat(3, R,G,B); 94 | 95 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/gaussian_pyramid.m: -------------------------------------------------------------------------------- 1 | function out = gaussian_pyramid(img, level) 2 | h = 1/16* [1, 4, 6, 4, 1]; 3 | filt = h'*h; 4 | out{1} = imfilter(img, filt, 'replicate', 'conv'); 5 | temp_img = img; 6 | for i = 2 : level 7 | temp_img = temp_img(1 : 2 : end, 1 : 2 : end); 8 | out{i} = imfilter(temp_img, filt, 'replicate', 'conv'); 9 | end -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/guidedfilter.m: -------------------------------------------------------------------------------- 1 | function q = guidedfilter(I, p, r, eps) 2 | % GUIDEDFILTER O(1) time implementation of guided filter. 3 | % 4 | % - guidance image: I (should be a gray-scale/single channel image) 5 | % - filtering input image: p (should be a gray-scale/single channel image) 6 | % - local window radius: r 7 | % - regularization parameter: eps 8 | 9 | [hei, wid] = size(I); 10 | N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. 11 | 12 | % imwrite(uint8(N), 'N.jpg'); 13 | % figure,imshow(N,[]),title('N'); 14 | 15 | 16 | mean_I = boxfilter(I, r) ./ N; 17 | mean_p = boxfilter(p, r) ./ N; 18 | mean_Ip = boxfilter(I.*p, r) ./ N; 19 | cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. 20 | 21 | mean_II = boxfilter(I.*I, r) ./ N; 22 | var_I = mean_II - mean_I .* mean_I; 23 | 24 | a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper; 25 | b = mean_p - a .* mean_I; % Eqn. (6) in the paper; 26 | 27 | mean_a = boxfilter(a, r) ./ N; 28 | mean_b = boxfilter(b, r) ./ N; 29 | 30 | q = mean_a .* I + mean_b; % Eqn. (8) in the paper; 31 | end -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/lab_to_rgb.m: -------------------------------------------------------------------------------- 1 | function rgb = lab_to_rgb(lab) 2 | cform = makecform('lab2srgb'); 3 | rgb = applycform(lab,cform); -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/laplacian_pyramid.m: -------------------------------------------------------------------------------- 1 | function out = laplacian_pyramid(img, level) 2 | h = 1/16* [1, 4, 6, 4, 1]; 3 | %filt = h'*h; 4 | out{1} = img; 5 | temp_img = img; 6 | for i = 2 : level 7 | temp_img = temp_img(1 : 2 : end, 1 : 2 : end); 8 | %out{i} = imfilter(temp_img, filt, 'replicate', 'conv'); 9 | out{i} = temp_img; 10 | end 11 | % calculate the DoG 12 | for i = 1 : level - 1 13 | [m, n] = size(out{i}); 14 | out{i} = out{i} - imresize(out{i+1}, [m, n]); 15 | end -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/load_image.m: -------------------------------------------------------------------------------- 1 | function img = load_image(num) 2 | % num is the num of image with 3 | 4 | prefix = 'Images/'; 5 | suffix = '.jpg'; 6 | path = [prefix,num2str(num),suffix]; 7 | 8 | img = imread(path); -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/main.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/ImageEnhanceViaFusion/main.m -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/main_test_diff_weights.m: -------------------------------------------------------------------------------- 1 | num = 8; 2 | img = load_image(num); 3 | 4 | % white balance 5 | img1 = SimplestColorBalance(img); 6 | lab1 = rgb_to_lab(img1); 7 | %figure,imshow(img1) 8 | 9 | % CLAHE 10 | lab2 = lab1; 11 | lab2(:, :, 1) = adapthisteq(lab2(:, :, 1)); 12 | lab2(:, :, 1) = uint8(bilateralFilter(double(lab2(:, :, 1)))); 13 | img2 = lab_to_rgb(lab2); 14 | %figure,imshow(img2); 15 | 16 | % input1 17 | R1 = double(lab1(:, :, 1)) / 255; 18 | % calculate laplacian contrast weight 19 | %WL1 = abs(imfilter(R1, fspecial('Laplacian'), 'replicate', 'conv')); 20 | %figure,imshow(WL1,[]) 21 | %calculate luminance weight 22 | WC1 = sqrt(( (double(img1(:,:,1))/255 - double(R1)).^2 + ... 23 | (double(img1(:,:,2))/255 - double(R1)).^2 + ... 24 | (double(img1(:,:,3))/255 - double(R1)).^2 ) / 3); 25 | %figure,imshow(WC1,[]) 26 | % calculate the saliency weight 27 | WS1 = saliency_detection(img1); 28 | figure,imshow(WS1,[]) 29 | % calculate the exposedness weight 30 | sigma = 0.25; 31 | aver = 0.5; 32 | %maximum = 1.0; 33 | WE1 = exp(-(R1 - aver).^2 / (2*sigma^2)); 34 | %figure,imshow(WE1,[]) 35 | 36 | % input2 37 | R2 = double(lab2(:, :, 1)) / 255; 38 | % calculate laplacian contrast weight 39 | %WL2 = abs(imfilter(R2, fspecial('Laplacian'), 'replicate', 'conv')); 40 | %figure,imshow(WL2,[]) 41 | %calculate luminance weight 42 | WC2 = sqrt(((double(img2(:,:,1))/255 - double(R2)).^2 + ... 43 | (double(img2(:,:,2))/255 - double(R2)).^2 + ... 44 | (double(img2(:,:,3))/255 - double(R2)).^2) / 3); 45 | %figure,imshow(R2) 46 | %figure,imshow(WC2 + 0.2) 47 | %WC2 = guidedfilter(WC2, R2, 5, 10^-6); 48 | %figure,imshow(WC2,[]) 49 | % calculate the saliency weight 50 | WS2 = saliency_detection(img2); 51 | figure,imshow(WS2,[]) 52 | % calculate the exposedness weight 53 | sigma = 0.25; 54 | %aver = 0.5; 55 | maximum = 1.0; 56 | WE2 = exp(-(R2 - maximum).^2 / (2*sigma^2)); 57 | %figure,imshow(WE2) 58 | 59 | % calculate the normalized weight 60 | W1 = (WC1 + WS1 + WE1) ./ ... 61 | (WC1 + WS1 + WE1 + WC2 + WS2 + WE2); 62 | W2 = (WC2 + WS2 + WE2) ./ ... 63 | (WC1 + WS1 + WE1 + WC2 + WS2 + WE2); 64 | %figure,imshow([W1]) 65 | %figure,imshow([W2]) 66 | 67 | % calculate the gaussian pyramid 68 | level = 5; 69 | Weight1 = gaussian_pyramid(W1, level); 70 | Weight2 = gaussian_pyramid(W2, level); 71 | 72 | % calculate the laplacian pyramid 73 | % input1 74 | R1 = laplacian_pyramid(double(double(img1(:, :, 1))), level); 75 | G1 = laplacian_pyramid(double(double(img1(:, :, 2))), level); 76 | B1 = laplacian_pyramid(double(double(img1(:, :, 3))), level); 77 | % input2 78 | R2 = laplacian_pyramid(double(double(img2(:, :, 1))), level); 79 | G2 = laplacian_pyramid(double(double(img2(:, :, 2))), level); 80 | B2 = laplacian_pyramid(double(double(img2(:, :, 3))), level); 81 | 82 | % fusion 83 | for i = 1 : level 84 | R_r{i} = Weight1{i} .* R1{i} + Weight2{i} .* R2{i}; 85 | R_g{i} = Weight1{i} .* G1{i} + Weight2{i} .* G2{i}; 86 | R_b{i} = Weight1{i} .* B1{i} + Weight2{i} .* B2{i}; 87 | end 88 | 89 | % reconstruct & output 90 | R = pyramid_reconstruct(R_r); 91 | G = pyramid_reconstruct(R_g); 92 | B = pyramid_reconstruct(R_b); 93 | fusion = cat(3, uint8(R), uint8(G), uint8(B)); 94 | 95 | %imshow([img1, img2, fusion]) 96 | %figure, imshow(fusion) -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/main_using_optimized.m: -------------------------------------------------------------------------------- 1 | addpath(genpath('optimized_contrast_enhance_method')); 2 | num = 57; 3 | img = load_image(num); 4 | %figure,imshow(img) 5 | 6 | % white balance 7 | img1 = SimplestColorBalance(img); 8 | lab1 = rgb_to_lab(img1); 9 | %figure,imshow(img1) 10 | 11 | % optimized contrast enhance ment method 12 | img2 = optimized_contrast_enhance_method(img1); 13 | img2 = uint8(img2); 14 | lab2 = rgb_to_lab(img2); 15 | %figure,imshow(img2); 16 | 17 | % input1 18 | R1 = double(lab1(:, :, 1)) / 255; 19 | % calculate laplacian contrast weight 20 | WL1 = abs(imfilter(R1, fspecial('Laplacian'), 'replicate', 'conv')); 21 | %calculate Luminance weight 22 | WC1 = sqrt(((double(img1(:,:,1))/255 - double(R1)).^2 + ... 23 | (double(img1(:,:,2))/255 - double(R1)).^2 + ... 24 | (double(img1(:,:,3))/255 - double(R1)).^2) / 3); 25 | % calculate the saliency weight 26 | WS1 = saliency_detection(img1); 27 | % calculate the exposedness weight 28 | sigma = 0.25; 29 | aver = 0.5; 30 | WE1 = exp(-(R1 - aver).^2 / (2*sigma^2)); 31 | 32 | % input2 33 | R2 = double(lab2(:, :, 1)) / 255; 34 | % calculate laplacian contrast weight 35 | WL2 = abs(imfilter(R2, fspecial('Laplacian'), 'replicate', 'conv')); 36 | %calculate Luminance weight 37 | WC2 = sqrt(((double(img2(:,:,1))/255 - double(R2)).^2 + ... 38 | (double(img2(:,:,2))/255 - double(R2)).^2 + ... 39 | (double(img2(:,:,3))/255 - double(R2)).^2) / 3); 40 | % calculate the saliency weight 41 | WS2 = saliency_detection(img2); 42 | % calculate the exposedness weight 43 | sigma = 0.25; 44 | aver = 0.5; 45 | WE2 = exp(-(R2 - aver).^2 / (2*sigma^2)); 46 | 47 | % calculate the normalized weight 48 | W1 = (WL1 + WC1 + WS1 + WE1) ./ ... 49 | (WL1 + WC1 + WS1 + WE1 + WL2 + WC2 + WS2 + WE2); 50 | W2 = (WL2 + WC2 + WS2 + WE2) ./ ... 51 | (WL1 + WC1 + WS1 + WE1 + WL2 + WC2 + WS2 + WE2); 52 | %W1 = (WC1 + WS1 + WE1) ./ ... 53 | % (WC1 + WS1 + WE1 + WC2 + WS2 + WE2); 54 | %W2 = (WC2 + WS2 + WE2) ./ ... 55 | % (WC1 + WS1 + WE1 + WC2 + WS2 + WE2); 56 | %figure,imshow(W1,[]); 57 | %figure,imshow(W2,[]); 58 | 59 | % calculate the gaussian pyramid 60 | level = 5; 61 | Weight1 = gaussian_pyramid(W1, level); 62 | Weight2 = gaussian_pyramid(W2, level); 63 | 64 | % calculate the laplacian pyramid 65 | % input1 66 | R1 = laplacian_pyramid(double(double(img1(:, :, 1))), level); 67 | G1 = laplacian_pyramid(double(double(img1(:, :, 2))), level); 68 | B1 = laplacian_pyramid(double(double(img1(:, :, 3))), level); 69 | % input2 70 | R2 = laplacian_pyramid(double(double(img2(:, :, 1))), level); 71 | G2 = laplacian_pyramid(double(double(img2(:, :, 2))), level); 72 | B2 = laplacian_pyramid(double(double(img2(:, :, 3))), level); 73 | 74 | % fusion 75 | for i = 1 : level 76 | R_r{i} = Weight1{i} .* R1{i} + Weight2{i} .* R2{i}; 77 | R_g{i} = Weight1{i} .* G1{i} + Weight2{i} .* G2{i}; 78 | R_b{i} = Weight1{i} .* B1{i} + Weight2{i} .* B2{i}; 79 | end 80 | 81 | % reconstruct & output 82 | R = pyramid_reconstruct(R_r); 83 | G = pyramid_reconstruct(R_g); 84 | B = pyramid_reconstruct(R_b); 85 | fusion = cat(3, uint8(R), uint8(G), uint8(B)); 86 | 87 | figure, imshow([img, img1, fusion]) 88 | 89 | rmpath 'optimized_contrast_enhance_method'; -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/maxfilt2.m: -------------------------------------------------------------------------------- 1 | function Y = maxfilt2(X,varargin) 2 | % MAXFILT2 Two-dimensional max filter 3 | % 4 | % Y = MAXFILT2(X,[M N]) performs two-dimensional maximum 5 | % filtering on the image X using an M-by-N window. The result 6 | % Y contains the maximun value in the M-by-N neighborhood around 7 | % each pixel in the original image. 8 | % This function uses the van Herk algorithm for max filters. 9 | % 10 | % Y = MAXFILT2(X,M) is the same as Y = MAXFILT2(X,[M M]) 11 | % 12 | % Y = MAXFILT2(X) uses a 3-by-3 neighborhood. 13 | % 14 | % Y = MAXFILT2(..., 'shape') returns a subsection of the 2D 15 | % filtering specified by 'shape' : 16 | % 'full' - Returns the full filtering result, 17 | % 'same' - (default) Returns the central filter area that is the 18 | % same size as X, 19 | % 'valid' - Returns only the area where no filter elements are outside 20 | % the image. 21 | % 22 | % See also : MINFILT2, VANHERK 23 | % 24 | 25 | % Initialization 26 | [S, shape] = parse_inputs(varargin{:}); 27 | 28 | % filtering 29 | Y = vanherk(X,S(1),'max',shape); 30 | Y = vanherk(Y,S(2),'max','col',shape); 31 | 32 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 33 | function [S, shape] = parse_inputs(varargin) 34 | shape = 'same'; 35 | flag = [0 0]; % size shape 36 | 37 | for i = 1 : nargin 38 | t = varargin{i}; 39 | if strcmp(t,'full') & flag(2) == 0 40 | shape = 'full'; 41 | flag(2) = 1; 42 | elseif strcmp(t,'same') & flag(2) == 0 43 | shape = 'same'; 44 | flag(2) = 1; 45 | elseif strcmp(t,'valid') & flag(2) == 0 46 | shape = 'valid'; 47 | flag(2) = 1; 48 | elseif flag(1) == 0 49 | S = t; 50 | flag(1) = 1; 51 | else 52 | error(['Too many / Unkown parameter : ' t ]) 53 | end 54 | end 55 | 56 | if flag(1) == 0 57 | S = [3 3]; 58 | end 59 | if length(S) == 1; 60 | S(2) = S(1); 61 | end 62 | if length(S) ~= 2 63 | error('Wrong window size parameter.') 64 | end 65 | 66 | -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/pyramid_reconstruct.m: -------------------------------------------------------------------------------- 1 | function out = pyramid_reconstruct(pyramid) 2 | level = length(pyramid); 3 | for i = level : -1 : 2 4 | %temp_pyramid = pyramid{i}; 5 | [m, n] = size(pyramid{i - 1}); 6 | %out = pyramid{i - 1} + imresize(temp_pyramid, [m, n]); 7 | pyramid{i - 1} = pyramid{i - 1} + imresize(pyramid{i}, [m, n]); 8 | end 9 | out = pyramid{1}; -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/rgb_to_lab.m: -------------------------------------------------------------------------------- 1 | function lab = rgb_to_lab(rgb) 2 | cform = makecform('srgb2lab'); 3 | lab = applycform(rgb,cform); -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/saliency_detection.m: -------------------------------------------------------------------------------- 1 | %--------------------------------------------------------- 2 | % Copyright (c) 2009 Radhakrishna Achanta [EPFL] 3 | % Contact: firstname.lastname@epfl.ch 4 | %--------------------------------------------------------- 5 | % Citation: 6 | % @InProceedings{LCAV-CONF-2009-012, 7 | % author = {Achanta, Radhakrishna and Hemami, Sheila and Estrada, 8 | % Francisco and S?strunk, Sabine}, 9 | % booktitle = {{IEEE} {I}nternational {C}onference on {C}omputer 10 | % {V}ision and {P}attern {R}ecognition}, 11 | % year = 2009 12 | % } 13 | %--------------------------------------------------------- 14 | % Please note that the saliency maps generated using this 15 | % code may be slightly different from those of the paper. 16 | % This seems to be because the RGB to Lab conversion is 17 | % different from the one used for the results in the C++ code. 18 | % The C++ code is available on the same page as this matlab 19 | % code (http://ivrg.epfl.ch/supplementary_material/RK_CVPR09/index.html) 20 | % One should preferably use the C++ as reference and use 21 | % this matlab implementation mostly as proof of concept 22 | % demo code. 23 | %--------------------------------------------------------- 24 | function sm = saliency_detection(img) 25 | % 26 | %--------------------------------------------------------- 27 | % Read image and blur it with a 3x3 or 5x5 Gaussian filter 28 | %--------------------------------------------------------- 29 | %img = imread('input_image.jpg');%Provide input image path 30 | gfrgb = imfilter(img, fspecial('gaussian', 3, 3), 'symmetric', 'conv'); 31 | %--------------------------------------------------------- 32 | % Perform sRGB to CIE Lab color space conversion (using D65) 33 | %--------------------------------------------------------- 34 | %cform = makecform('srgb2lab', 'whitepoint', whitepoint('d65')); 35 | cform = makecform('srgb2lab'); 36 | lab = applycform(gfrgb,cform); 37 | %--------------------------------------------------------- 38 | % Compute Lab average values (note that in the paper this 39 | % average is found from the unblurred original image, but 40 | % the results are quite similar) 41 | %--------------------------------------------------------- 42 | l = double(lab(:,:,1)); lm = mean(mean(l)); 43 | a = double(lab(:,:,2)); am = mean(mean(a)); 44 | b = double(lab(:,:,3)); bm = mean(mean(b)); 45 | %--------------------------------------------------------- 46 | % Finally compute the saliency map and display it. 47 | %--------------------------------------------------------- 48 | sm = (l-lm).^2 + (a-am).^2 + (b-bm).^2; 49 | %imshow(sm,[]); 50 | %--------------------------------------------------------- -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/test.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dlut-dimt/Underwater-image-enhancement-algorithms/490833683eaa04929eb581f96621e5ffbc7b1fc4/ImageEnhanceViaFusion/test.m -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/vanherk.m: -------------------------------------------------------------------------------- 1 | function Y = vanherk(X,N,TYPE,varargin) 2 | % VANHERK Fast max/min 1D filter 3 | % 4 | % Y = VANHERK(X,N,TYPE) performs the 1D max/min filtering of the row 5 | % vector X using a N-length filter. 6 | % The filtering type is defined by TYPE = 'max' or 'min'. This function 7 | % uses the van Herk algorithm for min/max filters that demands only 3 8 | % min/max calculations per element, independently of the filter size. 9 | % 10 | % If X is a 2D matrix, each row will be filtered separately. 11 | % 12 | % Y = VANHERK(...,'col') performs the filtering on the columns of X. 13 | % 14 | % Y = VANHERK(...,'shape') returns the subset of the filtering specified 15 | % by 'shape' : 16 | % 'full' - Returns the full filtering result, 17 | % 'same' - (default) Returns the central filter area that is the 18 | % same size as X, 19 | % 'valid' - Returns only the area where no filter elements are outside 20 | % the image. 21 | % 22 | % X can be uint8 or double. If X is uint8 the processing is quite faster, so 23 | % dont't use X as double, unless it is really necessary. 24 | % 25 | 26 | % Initialization 27 | [direc, shape] = parse_inputs(varargin{:}); 28 | if strcmp(direc,'col') 29 | X = X'; 30 | end 31 | if strcmp(TYPE,'max') 32 | maxfilt = 1; 33 | elseif strcmp(TYPE,'min') 34 | maxfilt = 0; 35 | else 36 | error([ 'TYPE must be ' char(39) 'max' char(39) ' or ' char(39) 'min' char(39) '.']) 37 | end 38 | 39 | % Correcting X size 40 | fixsize = 0; 41 | addel = 0; 42 | if mod(size(X,2),N) ~= 0 43 | fixsize = 1; 44 | addel = N-mod(size(X,2),N); 45 | if maxfilt 46 | f = [ X zeros(size(X,1), addel) ]; 47 | else 48 | f = [X repmat(X(:,end),1,addel)]; 49 | end 50 | else 51 | f = X; 52 | end 53 | lf = size(f,2); 54 | lx = size(X,2); 55 | clear X 56 | 57 | % Declaring aux. mat. 58 | g = f; 59 | h = g; 60 | 61 | % Filling g & h (aux. mat.) 62 | ig = 1:N:size(f,2); 63 | ih = ig + N - 1; 64 | 65 | g(:,ig) = f(:,ig); 66 | h(:,ih) = f(:,ih); 67 | 68 | if maxfilt 69 | for i = 2 : N 70 | igold = ig; 71 | ihold = ih; 72 | 73 | ig = ig + 1; 74 | ih = ih - 1; 75 | 76 | g(:,ig) = max(f(:,ig),g(:,igold)); 77 | h(:,ih) = max(f(:,ih),h(:,ihold)); 78 | end 79 | else 80 | for i = 2 : N 81 | igold = ig; 82 | ihold = ih; 83 | 84 | ig = ig + 1; 85 | ih = ih - 1; 86 | 87 | g(:,ig) = min(f(:,ig),g(:,igold)); 88 | h(:,ih) = min(f(:,ih),h(:,ihold)); 89 | end 90 | end 91 | clear f 92 | 93 | % Comparing g & h 94 | if strcmp(shape,'full') 95 | ig = [ N : 1 : lf ]; 96 | ih = [ 1 : 1 : lf-N+1 ]; 97 | if fixsize 98 | if maxfilt 99 | Y = [ g(:,1:N-1) max(g(:,ig), h(:,ih)) h(:,end-N+2:end-addel) ]; 100 | else 101 | Y = [ g(:,1:N-1) min(g(:,ig), h(:,ih)) h(:,end-N+2:end-addel) ]; 102 | end 103 | else 104 | if maxfilt 105 | Y = [ g(:,1:N-1) max(g(:,ig), h(:,ih)) h(:,end-N+2:end) ]; 106 | else 107 | Y = [ g(:,1:N-1) min(g(:,ig), h(:,ih)) h(:,end-N+2:end) ]; 108 | end 109 | end 110 | 111 | elseif strcmp(shape,'same') 112 | if fixsize 113 | if addel > (N-1)/2 114 | disp('hoi') 115 | ig = [ N : 1 : lf - addel + floor((N-1)/2) ]; 116 | ih = [ 1 : 1 : lf-N+1 - addel + floor((N-1)/2)]; 117 | if maxfilt 118 | Y = [ g(:,1+ceil((N-1)/2):N-1) max(g(:,ig), h(:,ih)) ]; 119 | else 120 | Y = [ g(:,1+ceil((N-1)/2):N-1) min(g(:,ig), h(:,ih)) ]; 121 | end 122 | else 123 | ig = [ N : 1 : lf ]; 124 | ih = [ 1 : 1 : lf-N+1 ]; 125 | if maxfilt 126 | Y = [ g(:,1+ceil((N-1)/2):N-1) max(g(:,ig), h(:,ih)) h(:,lf-N+2:lf-N+1+floor((N-1)/2)-addel) ]; 127 | else 128 | Y = [ g(:,1+ceil((N-1)/2):N-1) min(g(:,ig), h(:,ih)) h(:,lf-N+2:lf-N+1+floor((N-1)/2)-addel) ]; 129 | end 130 | end 131 | else % not fixsize (addel=0, lf=lx) 132 | ig = [ N : 1 : lx ]; 133 | ih = [ 1 : 1 : lx-N+1 ]; 134 | if maxfilt 135 | Y = [ g(:,N-ceil((N-1)/2):N-1) max( g(:,ig), h(:,ih) ) h(:,lx-N+2:lx-N+1+floor((N-1)/2)) ]; 136 | else 137 | Y = [ g(:,N-ceil((N-1)/2):N-1) min( g(:,ig), h(:,ih) ) h(:,lx-N+2:lx-N+1+floor((N-1)/2)) ]; 138 | end 139 | end 140 | 141 | elseif strcmp(shape,'valid') 142 | ig = [ N : 1 : lx]; 143 | ih = [ 1 : 1: lx-N+1]; 144 | if maxfilt 145 | Y = [ max( g(:,ig), h(:,ih) ) ]; 146 | else 147 | Y = [ min( g(:,ig), h(:,ih) ) ]; 148 | end 149 | end 150 | 151 | if strcmp(direc,'col') 152 | Y = Y'; 153 | end 154 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 155 | function [direc, shape] = parse_inputs(varargin) 156 | direc = 'lin'; 157 | shape = 'same'; 158 | flag = [0 0]; % [dir shape] 159 | 160 | for i = 1 : nargin 161 | t = varargin{i}; 162 | if strcmp(t,'col') & flag(1) == 0 163 | direc = 'col'; 164 | flag(1) = 1; 165 | elseif strcmp(t,'full') & flag(2) == 0 166 | shape = 'full'; 167 | flag(2) = 1; 168 | elseif strcmp(t,'same') & flag(2) == 0 169 | shape = 'same'; 170 | flag(2) = 1; 171 | elseif strcmp(t,'valid') & flag(2) == 0 172 | shape = 'valid'; 173 | flag(2) = 1; 174 | else 175 | error(['Too many / Unkown parameter : ' t ]) 176 | end 177 | end -------------------------------------------------------------------------------- /ImageEnhanceViaFusion/white_balance.m: -------------------------------------------------------------------------------- 1 | %my own white-balance function, created by Qu Jingwei 2 | function new_image = white_balance3(src_image) 3 | [height,width,dim] = size(src_image); 4 | temp = zeros(height,width); 5 | %transform the RGB color space to YCbCr color space 6 | ycbcr_image = rgb2ycbcr(src_image); 7 | Y = ycbcr_image(:,:,1); 8 | Cb = ycbcr_image(:,:,2); 9 | Cr = ycbcr_image(:,:,3); 10 | %calculate the average value of Cb,Cr 11 | Cb_ave = mean(mean(Cb)); 12 | Cr_ave = mean(mean(Cr)); 13 | %calculate the mean square error of Cb, Cr 14 | Db = sum(sum(abs(Cb-Cb_ave))) / (height*width); 15 | Dr = sum(sum(abs(Cr-Cr_ave))) / (height*width); 16 | %find the candidate reference white point 17 | %if meeting the following requriments 18 | %then the point is a candidate reference white point 19 | temp1 = abs(Cb - (Cb_ave + Db * sign(Cb_ave))); 20 | temp2 = abs(Cb - (1.5 * Cr_ave + Dr * sign(Cr_ave))); 21 | idx_1 = find(temp1<1.5*Db); 22 | idx_2 = find(temp2<1.5*Dr); 23 | idx = intersect(idx_1,idx_2); 24 | point = Y(idx); 25 | temp(idx) = Y(idx); 26 | count = length(point); 27 | count = count - 1; 28 | %sort the candidate reference white point set with descend value of Y 29 | temp_point = sort(point,'descend'); 30 | %get the 10% points of the candidate reference white point set, which is 31 | %closer to the white region, as the reference white point set 32 | n = round(count/10); 33 | white_point(1:n) = temp_point(1:n); 34 | temp_min = min(white_point); 35 | idx0 = find(temp=temp_min); 38 | temp(idx1) = 1; 39 | %get the reference white points' R,G,B 40 | white_R = double(src_image(:,:,1)).*temp; 41 | white_G = double(src_image(:,:,2)).*temp; 42 | white_B = double(src_image(:,:,3)).*temp; 43 | %get the averange value of the reference white points' R,G,B 44 | white_R_ave = mean(mean(white_R)); 45 | white_G_ave = mean(mean(white_G)); 46 | white_B_ave = mean(mean(white_B)); 47 | %the maximum Y value of the source image 48 | Ymax = double(max(max(Y))) / 15; 49 | %calculate the white-balance gain 50 | R_gain = Ymax / white_R_ave; 51 | G_gain = Ymax / white_G_ave; 52 | B_gain = Ymax / white_B_ave; 53 | %white-balance correction 54 | new_image(:,:,1) = R_gain * src_image(:,:,1); 55 | new_image(:,:,2) = G_gain * src_image(:,:,2); 56 | new_image(:,:,3) = B_gain * src_image(:,:,3); 57 | new_image = uint8(new_image); 58 | end --------------------------------------------------------------------------------