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