EstervQrCode 1.1.1
Library for qr code manipulation
gcgraph.hpp
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 
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;
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 
394 
395 #endif // OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP
T back(T... args)
T empty(T... args)
T fabs(T... args)
void * parent
Definition: core_c.h:1913
const void * first
Definition: core_c.h:1906
unsigned char uchar
Definition: interface.h:51
#define MIN(a, b)
Definition: cvdef.h:513
#define CV_Assert(expr)
Checks a condition at runtime and throws exception if it fails.
Definition: base.hpp:342
CvArr * edges
Definition: imgproc_c.h:860
CV_EXPORTS OutputArray int double double InputArray OutputArray int int bool double k
Definition: imgproc.hpp:2133
InputArray int InputArray CV_IN_OUT Ptr< float > OutputArray flow
Definition: imgproc.hpp:3388
OutputArray dst
Definition: imgproc.hpp:3564
T memset(T... args)
"black box" representation of the file storage associated with a file on disk.
Definition: calib3d.hpp:441
T next(T... args)
T pop_back(T... args)
T push_back(T... args)