You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			396 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			396 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
/*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
 |