123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /*M///////////////////////////////////////////////////////////////////////////////////////
- //
- // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- //
- // By downloading, copying, installing or using the software you agree to this license.
- // If you do not agree to this license, do not download, install,
- // copy or use the software.
- //
- //
- // Intel License Agreement
- // For Open Source Computer Vision Library
- //
- // Copyright (C) 2000, Intel Corporation, all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistribution's of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // * Redistribution's in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // * The name of Intel Corporation may not be used to endorse or promote products
- // derived from this software without specific prior written permission.
- //
- // This software is provided by the copyright holders and contributors "as is" and
- // any express or implied warranties, including, but not limited to, the implied
- // warranties of merchantability and fitness for a particular purpose are disclaimed.
- // In no event shall the Intel Corporation or contributors be liable for any direct,
- // indirect, incidental, special, exemplary, or consequential damages
- // (including, but not limited to, procurement of substitute goods or services;
- // loss of use, data, or profits; or business interruption) however caused
- // and on any theory of liability, whether in contract, strict liability,
- // or tort (including negligence or otherwise) arising in any way out of
- // the use of this software, even if advised of the possibility of such damage.
- //
- //M*/
- #ifndef OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP
- #define OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP
- //! @cond IGNORED
- namespace cv { namespace detail {
- template <class TWeight> class GCGraph
- {
- public:
- GCGraph();
- GCGraph( unsigned int vtxCount, unsigned int edgeCount );
- ~GCGraph();
- void create( unsigned int vtxCount, unsigned int edgeCount );
- int addVtx();
- void addEdges( int i, int j, TWeight w, TWeight revw );
- void addTermWeights( int i, TWeight sourceW, TWeight sinkW );
- TWeight maxFlow();
- bool inSourceSegment( int i );
- private:
- class Vtx
- {
- public:
- Vtx *next; // initialized and used in maxFlow() only
- int parent;
- int first;
- int ts;
- int dist;
- TWeight weight;
- uchar t;
- };
- class Edge
- {
- public:
- int dst;
- int next;
- TWeight weight;
- };
- std::vector<Vtx> vtcs;
- std::vector<Edge> edges;
- TWeight flow;
- };
- template <class TWeight>
- GCGraph<TWeight>::GCGraph()
- {
- flow = 0;
- }
- template <class TWeight>
- GCGraph<TWeight>::GCGraph( unsigned int vtxCount, unsigned int edgeCount )
- {
- create( vtxCount, edgeCount );
- }
- template <class TWeight>
- GCGraph<TWeight>::~GCGraph()
- {
- }
- template <class TWeight>
- void GCGraph<TWeight>::create( unsigned int vtxCount, unsigned int edgeCount )
- {
- vtcs.reserve( vtxCount );
- edges.reserve( edgeCount + 2 );
- flow = 0;
- }
- template <class TWeight>
- int GCGraph<TWeight>::addVtx()
- {
- Vtx v;
- memset( &v, 0, sizeof(Vtx));
- vtcs.push_back(v);
- return (int)vtcs.size() - 1;
- }
- template <class TWeight>
- void GCGraph<TWeight>::addEdges( int i, int j, TWeight w, TWeight revw )
- {
- CV_Assert( i>=0 && i<(int)vtcs.size() );
- CV_Assert( j>=0 && j<(int)vtcs.size() );
- CV_Assert( w>=0 && revw>=0 );
- CV_Assert( i != j );
- if( !edges.size() )
- edges.resize( 2 );
- Edge fromI, toI;
- fromI.dst = j;
- fromI.next = vtcs[i].first;
- fromI.weight = w;
- vtcs[i].first = (int)edges.size();
- edges.push_back( fromI );
- toI.dst = i;
- toI.next = vtcs[j].first;
- toI.weight = revw;
- vtcs[j].first = (int)edges.size();
- edges.push_back( toI );
- }
- template <class TWeight>
- void GCGraph<TWeight>::addTermWeights( int i, TWeight sourceW, TWeight sinkW )
- {
- CV_Assert( i>=0 && i<(int)vtcs.size() );
- TWeight dw = vtcs[i].weight;
- if( dw > 0 )
- sourceW += dw;
- else
- sinkW -= dw;
- flow += (sourceW < sinkW) ? sourceW : sinkW;
- vtcs[i].weight = sourceW - sinkW;
- }
- template <class TWeight>
- TWeight GCGraph<TWeight>::maxFlow()
- {
- CV_Assert(!vtcs.empty());
- CV_Assert(!edges.empty());
- const int TERMINAL = -1, ORPHAN = -2;
- Vtx stub, *nilNode = &stub, *first = nilNode, *last = nilNode;
- int curr_ts = 0;
- stub.next = nilNode;
- Vtx *vtxPtr = &vtcs[0];
- Edge *edgePtr = &edges[0];
- std::vector<Vtx*> orphans;
- // initialize the active queue and the graph vertices
- for( int i = 0; i < (int)vtcs.size(); i++ )
- {
- Vtx* v = vtxPtr + i;
- v->ts = 0;
- if( v->weight != 0 )
- {
- last = last->next = v;
- v->dist = 1;
- v->parent = TERMINAL;
- v->t = v->weight < 0;
- }
- else
- v->parent = 0;
- }
- first = first->next;
- last->next = nilNode;
- nilNode->next = 0;
- // run the search-path -> augment-graph -> restore-trees loop
- for(;;)
- {
- Vtx* v, *u;
- int e0 = -1, ei = 0, ej = 0;
- TWeight minWeight, weight;
- uchar vt;
- // grow S & T search trees, find an edge connecting them
- while( first != nilNode )
- {
- v = first;
- if( v->parent )
- {
- vt = v->t;
- for( ei = v->first; ei != 0; ei = edgePtr[ei].next )
- {
- if( edgePtr[ei^vt].weight == 0 )
- continue;
- u = vtxPtr+edgePtr[ei].dst;
- if( !u->parent )
- {
- u->t = vt;
- u->parent = ei ^ 1;
- u->ts = v->ts;
- u->dist = v->dist + 1;
- if( !u->next )
- {
- u->next = nilNode;
- last = last->next = u;
- }
- continue;
- }
- if( u->t != vt )
- {
- e0 = ei ^ vt;
- break;
- }
- if( u->dist > v->dist+1 && u->ts <= v->ts )
- {
- // reassign the parent
- u->parent = ei ^ 1;
- u->ts = v->ts;
- u->dist = v->dist + 1;
- }
- }
- if( e0 > 0 )
- break;
- }
- // exclude the vertex from the active list
- first = first->next;
- v->next = 0;
- }
- if( e0 <= 0 )
- break;
- // find the minimum edge weight along the path
- minWeight = edgePtr[e0].weight;
- CV_Assert( minWeight > 0 );
- // k = 1: source tree, k = 0: destination tree
- for( int k = 1; k >= 0; k-- )
- {
- for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
- {
- if( (ei = v->parent) < 0 )
- break;
- weight = edgePtr[ei^k].weight;
- minWeight = MIN(minWeight, weight);
- CV_Assert( minWeight > 0 );
- }
- weight = fabs(v->weight);
- minWeight = MIN(minWeight, weight);
- CV_Assert( minWeight > 0 );
- }
- // modify weights of the edges along the path and collect orphans
- edgePtr[e0].weight -= minWeight;
- edgePtr[e0^1].weight += minWeight;
- flow += minWeight;
- // k = 1: source tree, k = 0: destination tree
- for( int k = 1; k >= 0; k-- )
- {
- for( v = vtxPtr+edgePtr[e0^k].dst;; v = vtxPtr+edgePtr[ei].dst )
- {
- if( (ei = v->parent) < 0 )
- break;
- edgePtr[ei^(k^1)].weight += minWeight;
- if( (edgePtr[ei^k].weight -= minWeight) == 0 )
- {
- orphans.push_back(v);
- v->parent = ORPHAN;
- }
- }
- v->weight = v->weight + minWeight*(1-k*2);
- if( v->weight == 0 )
- {
- orphans.push_back(v);
- v->parent = ORPHAN;
- }
- }
- // restore the search trees by finding new parents for the orphans
- curr_ts++;
- while( !orphans.empty() )
- {
- Vtx* v2 = orphans.back();
- orphans.pop_back();
- int d, minDist = INT_MAX;
- e0 = 0;
- vt = v2->t;
- for( ei = v2->first; ei != 0; ei = edgePtr[ei].next )
- {
- if( edgePtr[ei^(vt^1)].weight == 0 )
- continue;
- u = vtxPtr+edgePtr[ei].dst;
- if( u->t != vt || u->parent == 0 )
- continue;
- // compute the distance to the tree root
- for( d = 0;; )
- {
- if( u->ts == curr_ts )
- {
- d += u->dist;
- break;
- }
- ej = u->parent;
- d++;
- if( ej < 0 )
- {
- if( ej == ORPHAN )
- d = INT_MAX-1;
- else
- {
- u->ts = curr_ts;
- u->dist = 1;
- }
- break;
- }
- u = vtxPtr+edgePtr[ej].dst;
- }
- // update the distance
- if( ++d < INT_MAX )
- {
- if( d < minDist )
- {
- minDist = d;
- e0 = ei;
- }
- for( u = vtxPtr+edgePtr[ei].dst; u->ts != curr_ts; u = vtxPtr+edgePtr[u->parent].dst )
- {
- u->ts = curr_ts;
- u->dist = --d;
- }
- }
- }
- if( (v2->parent = e0) > 0 )
- {
- v2->ts = curr_ts;
- v2->dist = minDist;
- continue;
- }
- /* no parent is found */
- v2->ts = 0;
- for( ei = v2->first; ei != 0; ei = edgePtr[ei].next )
- {
- u = vtxPtr+edgePtr[ei].dst;
- ej = u->parent;
- if( u->t != vt || !ej )
- continue;
- if( edgePtr[ei^(vt^1)].weight && !u->next )
- {
- u->next = nilNode;
- last = last->next = u;
- }
- if( ej > 0 && vtxPtr+edgePtr[ej].dst == v2 )
- {
- orphans.push_back(u);
- u->parent = ORPHAN;
- }
- }
- }
- }
- return flow;
- }
- template <class TWeight>
- bool GCGraph<TWeight>::inSourceSegment( int i )
- {
- CV_Assert( i>=0 && i<(int)vtcs.size() );
- return vtcs[i].t == 0;
- }
- }} // namespace detail, cv
- //! @endcond
- #endif // OPENCV_IMGPROC_DETAIL_GCGRAPH_HPP
|