github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/opencv4/include/opencv2/imgproc/detail/gcgraph.hpp (about) 1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #ifndef OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP 43 #define OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP 44 45 //! @cond IGNORED 46 47 namespace cv { namespace detail { 48 template <class TWeight> class GCGraph 49 { 50 public: 51 GCGraph(); 52 GCGraph( unsigned int vtxCount, unsigned int edgeCount ); 53 ~GCGraph(); 54 void create( unsigned int vtxCount, unsigned int edgeCount ); 55 int addVtx(); 56 void addEdges( int i, int j, TWeight w, TWeight revw ); 57 void addTermWeights( int i, TWeight sourceW, TWeight sinkW ); 58 TWeight maxFlow(); 59 bool inSourceSegment( int i ); 60 private: 61 class Vtx 62 { 63 public: 64 Vtx *next; // initialized and used in maxFlow() only 65 int parent; 66 int first; 67 int ts; 68 int dist; 69 TWeight weight; 70 uchar t; 71 }; 72 class Edge 73 { 74 public: 75 int dst; 76 int next; 77 TWeight weight; 78 }; 79 80 std::vector<Vtx> vtcs; 81 std::vector<Edge> edges; 82 TWeight flow; 83 }; 84 85 template <class TWeight> 86 GCGraph<TWeight>::GCGraph() 87 { 88 flow = 0; 89 } 90 template <class TWeight> 91 GCGraph<TWeight>::GCGraph( unsigned int vtxCount, unsigned int edgeCount ) 92 { 93 create( vtxCount, edgeCount ); 94 } 95 template <class TWeight> 96 GCGraph<TWeight>::~GCGraph() 97 { 98 } 99 template <class TWeight> 100 void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount ) 101 { 102 vtcs.reserve( vtxCount ); 103 edges.reserve( edgeCount + 2 ); 104 flow = 0; 105 } 106 107 template <class TWeight> 108 int GCGraph<TWeight>::addVtx() 109 { 110 Vtx v; 111 memset( &v, 0, sizeof(Vtx)); 112 vtcs.push_back(v); 113 return (int)vtcs.size() - 1; 114 } 115 116 template <class TWeight> 117 void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw ) 118 { 119 CV_Assert( i>=0 && i<(int)vtcs.size() ); 120 CV_Assert( j>=0 && j<(int)vtcs.size() ); 121 CV_Assert( w>=0 && revw>=0 ); 122 CV_Assert( i != j ); 123 124 if( !edges.size() ) 125 edges.resize( 2 ); 126 127 Edge fromI, toI; 128 fromI.dst = j; 129 fromI.next = vtcs[i].first; 130 fromI.weight = w; 131 vtcs[i].first = (int)edges.size(); 132 edges.push_back( fromI ); 133 134 toI.dst = i; 135 toI.next = vtcs[j].first; 136 toI.weight = revw; 137 vtcs[j].first = (int)edges.size(); 138 edges.push_back( toI ); 139 } 140 141 template <class TWeight> 142 void GCGraph<TWeight>::addTermWeights( int i, TWeight sourceW, TWeight sinkW ) 143 { 144 CV_Assert( i>=0 && i<(int)vtcs.size() ); 145 146 TWeight dw = vtcs[i].weight; 147 if( dw > 0 ) 148 sourceW += dw; 149 else 150 sinkW -= dw; 151 flow += (sourceW < sinkW) ? sourceW : sinkW; 152 vtcs[i].weight = sourceW - sinkW; 153 } 154 155 template <class TWeight> 156 TWeight GCGraph<TWeight>::maxFlow() 157 { 158 CV_Assert(!vtcs.empty()); 159 CV_Assert(!edges.empty()); 160 const int TERMINAL = -1, ORPHAN = -2; 161 Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode; 162 int curr_ts = 0; 163 stub.next = nilNode; 164 Vtx *vtxPtr = &vtcs[0]; 165 Edge *edgePtr = &edges[0]; 166 167 std::vector<Vtx*> orphans; 168 169 // initialize the active queue and the graph vertices 170 for( int i = 0; i < (int)vtcs.size(); i++ ) 171 { 172 Vtx* v = vtxPtr + i; 173 v->ts = 0; 174 if( v->weight != 0 ) 175 { 176 last = last->next = v; 177 v->dist = 1; 178 v->parent = TERMINAL; 179 v->t = v->weight < 0; 180 } 181 else 182 v->parent = 0; 183 } 184 first = first->next; 185 last->next = nilNode; 186 nilNode->next = 0; 187 188 // run the search-path -> augment-graph -> restore-trees loop 189 for(;;) 190 { 191 Vtx* v, *u; 192 int e0 = -1, ei = 0, ej = 0; 193 TWeight minWeight, weight; 194 uchar vt; 195 196 // grow S & T search trees, find an edge connecting them 197 while( first != nilNode ) 198 { 199 v = first; 200 if( v->parent ) 201 { 202 vt = v->t; 203 for( ei = v->first; ei != 0; ei = edgePtr[ei].next ) 204 { 205 if( edgePtr[ei^vt].weight == 0 ) 206 continue; 207 u = vtxPtr+edgePtr[ei].dst; 208 if( !u->parent ) 209 { 210 u->t = vt; 211 u->parent = ei ^ 1; 212 u->ts = v->ts; 213 u->dist = v->dist + 1; 214 if( !u->next ) 215 { 216 u->next = nilNode; 217 last = last->next = u; 218 } 219 continue; 220 } 221 222 if( u->t != vt ) 223 { 224 e0 = ei ^ vt; 225 break; 226 } 227 228 if( u->dist > v->dist+1 && u->ts <= v->ts ) 229 { 230 // reassign the parent 231 u->parent = ei ^ 1; 232 u->ts = v->ts; 233 u->dist = v->dist + 1; 234 } 235 } 236 if( e0 > 0 ) 237 break; 238 } 239 // exclude the vertex from the active list 240 first = first->next; 241 v->next = 0; 242 } 243 244 if( e0 <= 0 ) 245 break; 246 247 // find the minimum edge weight along the path 248 minWeight = edgePtr[e0].weight; 249 CV_Assert( minWeight > 0 ); 250 // k = 1: source tree, k = 0: destination tree 251 for( int k = 1; k >= 0; k-- ) 252 { 253 for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) 254 { 255 if( (ei = v->parent) < 0 ) 256 break; 257 weight = edgePtr[ei^k].weight; 258 minWeight = MIN(minWeight, weight); 259 CV_Assert( minWeight > 0 ); 260 } 261 weight = fabs(v->weight); 262 minWeight = MIN(minWeight, weight); 263 CV_Assert( minWeight > 0 ); 264 } 265 266 // modify weights of the edges along the path and collect orphans 267 edgePtr[e0].weight -= minWeight; 268 edgePtr[e0^1].weight += minWeight; 269 flow += minWeight; 270 271 // k = 1: source tree, k = 0: destination tree 272 for( int k = 1; k >= 0; k-- ) 273 { 274 for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst ) 275 { 276 if( (ei = v->parent) < 0 ) 277 break; 278 edgePtr[ei^(k^1)].weight += minWeight; 279 if( (edgePtr[ei^k].weight -= minWeight) == 0 ) 280 { 281 orphans.push_back(v); 282 v->parent = ORPHAN; 283 } 284 } 285 286 v->weight = v->weight + minWeight*(1-k*2); 287 if( v->weight == 0 ) 288 { 289 orphans.push_back(v); 290 v->parent = ORPHAN; 291 } 292 } 293 294 // restore the search trees by finding new parents for the orphans 295 curr_ts++; 296 while( !orphans.empty() ) 297 { 298 Vtx* v2 = orphans.back(); 299 orphans.pop_back(); 300 301 int d, minDist = INT_MAX; 302 e0 = 0; 303 vt = v2->t; 304 305 for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) 306 { 307 if( edgePtr[ei^(vt^1)].weight == 0 ) 308 continue; 309 u = vtxPtr+edgePtr[ei].dst; 310 if( u->t != vt || u->parent == 0 ) 311 continue; 312 // compute the distance to the tree root 313 for( d = 0;; ) 314 { 315 if( u->ts == curr_ts ) 316 { 317 d += u->dist; 318 break; 319 } 320 ej = u->parent; 321 d++; 322 if( ej < 0 ) 323 { 324 if( ej == ORPHAN ) 325 d = INT_MAX-1; 326 else 327 { 328 u->ts = curr_ts; 329 u->dist = 1; 330 } 331 break; 332 } 333 u = vtxPtr+edgePtr[ej].dst; 334 } 335 336 // update the distance 337 if( ++d < INT_MAX ) 338 { 339 if( d < minDist ) 340 { 341 minDist = d; 342 e0 = ei; 343 } 344 for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst ) 345 { 346 u->ts = curr_ts; 347 u->dist = --d; 348 } 349 } 350 } 351 352 if( (v2->parent = e0) > 0 ) 353 { 354 v2->ts = curr_ts; 355 v2->dist = minDist; 356 continue; 357 } 358 359 /* no parent is found */ 360 v2->ts = 0; 361 for( ei = v2->first; ei != 0; ei = edgePtr[ei].next ) 362 { 363 u = vtxPtr+edgePtr[ei].dst; 364 ej = u->parent; 365 if( u->t != vt || !ej ) 366 continue; 367 if( edgePtr[ei^(vt^1)].weight && !u->next ) 368 { 369 u->next = nilNode; 370 last = last->next = u; 371 } 372 if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 ) 373 { 374 orphans.push_back(u); 375 u->parent = ORPHAN; 376 } 377 } 378 } 379 } 380 return flow; 381 } 382 383 template <class TWeight> 384 bool GCGraph<TWeight>::inSourceSegment( int i ) 385 { 386 CV_Assert( i>=0 && i<(int)vtcs.size() ); 387 return vtcs[i].t == 0; 388 } 389 390 }} // namespace detail, cv 391 392 393 //! @endcond 394 395 #endif // OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP