Read@CVL
GCGraph.hpp
Go to the documentation of this file.
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 #pragma once
43 
44 // namespace for 3rd party classes
45 namespace rd3 {
46 
47 template <class TWeight> class GCGraph
48 {
49 public:
50  GCGraph();
51  GCGraph( unsigned int vtxCount, unsigned int edgeCount );
52  ~GCGraph();
53  void create( unsigned int vtxCount, unsigned int edgeCount );
54  int addVtx();
55  void addEdges( int i, int j, TWeight w, TWeight revw );
56  void addTermWeights( int i, TWeight sourceW, TWeight sinkW );
57  TWeight maxFlow();
58  bool inSourceSegment( int i );
59  uchar vtxT( int i ) const;
60 
61 private:
62  class Vtx
63  {
64  public:
65  Vtx *next; // initialized and used in maxFlow() only
66  int parent;
67  int first;
68  int ts;
69  int dist;
70  TWeight weight;
71  uchar t;
72  };
73  class Edge
74  {
75  public:
76  int dst;
77  int next;
78  TWeight weight;
79  };
80 
81  std::vector<Vtx> vtcs;
82  std::vector<Edge> edges;
83  TWeight flow;
84 };
85 
86 template <class TWeight>
88 {
89  flow = 0;
90 }
91 template <class TWeight>
92 GCGraph<TWeight>::GCGraph( unsigned int vtxCount, unsigned int edgeCount )
93 {
94  create( vtxCount, edgeCount );
95 }
96 template <class TWeight>
98 {
99 }
100 template <class TWeight>
101 void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount )
102 {
103  vtcs.reserve( vtxCount );
104  edges.reserve( edgeCount + 2 );
105  flow = 0;
106 }
107 
108 template <class TWeight>
110 {
111  Vtx v;
112  memset( &v, 0, sizeof(Vtx));
113  vtcs.push_back(v);
114  return (int)vtcs.size() - 1;
115 }
116 
117 template <class TWeight>
118 void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw )
119 {
120  CV_Assert( i>=0 && i<(int)vtcs.size() );
121  CV_Assert( j>=0 && j<(int)vtcs.size() );
122  CV_Assert( w>=0 && revw>=0 );
123  CV_Assert( i != j );
124 
125  if( !edges.size() )
126  edges.resize( 2 );
127 
128  Edge fromI, toI;
129  fromI.dst = j;
130  fromI.next = vtcs[i].first;
131  fromI.weight = w;
132  vtcs[i].first = (int)edges.size();
133  edges.push_back( fromI );
134 
135  toI.dst = i;
136  toI.next = vtcs[j].first;
137  toI.weight = revw;
138  vtcs[j].first = (int)edges.size();
139  edges.push_back( toI );
140 }
141 
142 template <class TWeight>
143 void GCGraph<TWeight>::addTermWeights( int i, TWeight sourceW, TWeight sinkW )
144 {
145  CV_Assert( i>=0 && i<(int)vtcs.size() );
146 
147  TWeight dw = vtcs[i].weight;
148  if( dw > 0 )
149  sourceW += dw;
150  else
151  sinkW -= dw;
152  flow += (sourceW < sinkW) ? sourceW : sinkW;
153  vtcs[i].weight = sourceW - sinkW;
154 }
155 
156 template <class TWeight>
158 {
159  const int TERMINAL = -1, ORPHAN = -2;
160  Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode;
161  int curr_ts = 0;
162  stub.next = nilNode;
163  Vtx *vtxPtr = &vtcs[0];
164  Edge *edgePtr = &edges[0];
165 
166  std::vector<Vtx*> orphans;
167 
168  // initialize the active queue and the graph vertices
169  for( int i = 0; i < (int)vtcs.size(); i++ )
170  {
171  Vtx* v = vtxPtr + i;
172  v->ts = 0;
173  if( v->weight != 0 )
174  {
175  last = last->next = v;
176  v->dist = 1;
177  v->parent = TERMINAL;
178  v->t = v->weight < 0;
179  }
180  else
181  v->parent = 0;
182  }
183  first = first->next;
184  last->next = nilNode;
185  nilNode->next = 0;
186 
187  // run the search-path -> augment-graph -> restore-trees loop
188  for(;;)
189  {
190  Vtx* v, *u;
191  int e0 = -1, ei = 0, ej = 0;
192  TWeight minWeight, weight;
193  uchar vt;
194 
195  // grow S & T search trees, find an edge connecting them
196  while( first != nilNode )
197  {
198  v = first;
199  if( v->parent )
200  {
201  vt = v->t;
202  for( ei = v->first; ei != 0; ei = edgePtr[ei].next )
203  {
204  if( edgePtr[ei^vt].weight == 0 )
205  continue;
206  u = vtxPtr+edgePtr[ei].dst;
207  if( !u->parent )
208  {
209  u->t = vt;
210  u->parent = ei ^ 1;
211  u->ts = v->ts;
212  u->dist = v->dist + 1;
213  if( !u->next )
214  {
215  u->next = nilNode;
216  last = last->next = u;
217  }
218  continue;
219  }
220 
221  if( u->t != vt )
222  {
223  e0 = ei ^ vt;
224  break;
225  }
226 
227  if( u->dist > v->dist+1 && u->ts <= v->ts )
228  {
229  // reassign the parent
230  u->parent = ei ^ 1;
231  u->ts = v->ts;
232  u->dist = v->dist + 1;
233  }
234  }
235  if( e0 > 0 )
236  break;
237  }
238  // exclude the vertex from the active list
239  first = first->next;
240  v->next = 0;
241  }
242 
243  if( e0 <= 0 )
244  break;
245 
246  // find the minimum edge weight along the path
247  minWeight = edgePtr[e0].weight;
248  CV_Assert( minWeight > 0 );
249  // k = 1: source tree, k = 0: destination tree
250  for( int k = 1; k >= 0; k-- )
251  {
252  for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
253  {
254  if( (ei = v->parent) < 0 )
255  break;
256  weight = edgePtr[ei^k].weight;
257  minWeight = MIN(minWeight, weight);
258  CV_Assert( minWeight > 0 );
259  }
260  weight = fabs(v->weight);
261  minWeight = MIN(minWeight, weight);
262  CV_Assert( minWeight > 0 );
263  }
264 
265  // modify weights of the edges along the path and collect orphans
266  edgePtr[e0].weight -= minWeight;
267  edgePtr[e0^1].weight += minWeight;
268  flow += minWeight;
269 
270  // k = 1: source tree, k = 0: destination tree
271  for( int k = 1; k >= 0; k-- )
272  {
273  for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
274  {
275  if( (ei = v->parent) < 0 )
276  break;
277  edgePtr[ei^(k^1)].weight += minWeight;
278  if( (edgePtr[ei^k].weight -= minWeight) == 0 )
279  {
280  orphans.push_back(v);
281  v->parent = ORPHAN;
282  }
283  }
284 
285  v->weight = v->weight + minWeight*(1-k*2);
286  if( v->weight == 0 )
287  {
288  orphans.push_back(v);
289  v->parent = ORPHAN;
290  }
291  }
292 
293  // restore the search trees by finding new parents for the orphans
294  curr_ts++;
295  while( !orphans.empty() )
296  {
297  Vtx* v2 = orphans.back();
298  orphans.pop_back();
299 
300  int d, minDist = INT_MAX;
301  e0 = 0;
302  vt = v2->t;
303 
304  for( ei = v2->first; ei != 0; ei = edgePtr[ei].next )
305  {
306  if( edgePtr[ei^(vt^1)].weight == 0 )
307  continue;
308  u = vtxPtr+edgePtr[ei].dst;
309  if( u->t != vt || u->parent == 0 )
310  continue;
311  // compute the distance to the tree root
312  for( d = 0;; )
313  {
314  if( u->ts == curr_ts )
315  {
316  d += u->dist;
317  break;
318  }
319  ej = u->parent;
320  d++;
321  if( ej < 0 )
322  {
323  if( ej == ORPHAN )
324  d = INT_MAX-1;
325  else
326  {
327  u->ts = curr_ts;
328  u->dist = 1;
329  }
330  break;
331  }
332  u = vtxPtr+edgePtr[ej].dst;
333  }
334 
335  // update the distance
336  if( ++d < INT_MAX )
337  {
338  if( d < minDist )
339  {
340  minDist = d;
341  e0 = ei;
342  }
343  for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst )
344  {
345  u->ts = curr_ts;
346  u->dist = --d;
347  }
348  }
349  }
350 
351  if( (v2->parent = e0) > 0 )
352  {
353  v2->ts = curr_ts;
354  v2->dist = minDist;
355  continue;
356  }
357 
358  /* no parent is found */
359  v2->ts = 0;
360  for( ei = v2->first; ei != 0; ei = edgePtr[ei].next )
361  {
362  u = vtxPtr+edgePtr[ei].dst;
363  ej = u->parent;
364  if( u->t != vt || !ej )
365  continue;
366  if( edgePtr[ei^(vt^1)].weight && !u->next )
367  {
368  u->next = nilNode;
369  last = last->next = u;
370  }
371  if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 )
372  {
373  orphans.push_back(u);
374  u->parent = ORPHAN;
375  }
376  }
377  }
378  }
379  return flow;
380 }
381 
382 template <class TWeight>
384 {
385  CV_Assert( i>=0 && i<(int)vtcs.size() );
386  return vtcs[i].t == 0;
387 }
388 
389 template <class TWeight>
390 uchar GCGraph<TWeight>::vtxT( int i ) const
391 {
392  CV_Assert( i>=0 && i<(int)vtcs.size() );
393  return vtcs[i].t;
394 }
395 
396 }
#define ORPHAN
Definition: maxflow.cpp:15
uchar vtxT(int i) const
Definition: GCGraph.hpp:390
#define TERMINAL
Definition: maxflow.cpp:14
Definition: GCGraph.hpp:45
Definition: GCGraph.hpp:47
void create(unsigned int vtxCount, unsigned int edgeCount)
Definition: GCGraph.hpp:101
bool inSourceSegment(int i)
Definition: GCGraph.hpp:383
GCGraph()
Definition: GCGraph.hpp:87
void addEdges(int i, int j, TWeight w, TWeight revw)
Definition: GCGraph.hpp:118
~GCGraph()
Definition: GCGraph.hpp:97
TWeight maxFlow()
Definition: GCGraph.hpp:157
void addTermWeights(int i, TWeight sourceW, TWeight sinkW)
Definition: GCGraph.hpp:143
int addVtx()
Definition: GCGraph.hpp:109