Home | History | Annotate | Download | only in src
      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 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 /*
     44  * Implementation of an optimized EMD for histograms based in
     45  * the papers "EMD-L1: An efficient and Robust Algorithm
     46  * for comparing histogram-based descriptors", by Haibin Ling and
     47  * Kazunori Okuda; and "The Earth Mover's Distance is the Mallows
     48  * Distance: Some Insights from Statistics", by Elizaveta Levina and
     49  * Peter Bickel, based on HAIBIN LING AND KAZUNORI OKADA implementation.
     50  */
     51 
     52 #include "precomp.hpp"
     53 #include "emdL1_def.hpp"
     54 #include <limits>
     55 
     56 /****************************************************************************************\
     57 *                                   EMDL1 Class                                         *
     58 \****************************************************************************************/
     59 
     60 float EmdL1::getEMDL1(cv::Mat &sig1, cv::Mat &sig2)
     61 {
     62     // Initialization
     63     CV_Assert((sig1.rows==sig2.rows) && (sig1.cols==sig2.cols) && (!sig1.empty()) && (!sig2.empty()));
     64     if(!initBaseTrees(sig1.rows, 1))
     65         return -1;
     66 
     67     float *H1=new float[sig1.rows], *H2 = new float[sig2.rows];
     68     for (int ii=0; ii<sig1.rows; ii++)
     69     {
     70         H1[ii]=sig1.at<float>(ii,0);
     71         H2[ii]=sig2.at<float>(ii,0);
     72     }
     73 
     74     fillBaseTrees(H1,H2); // Initialize histograms
     75     greedySolution(); // Construct an initial Basic Feasible solution
     76     initBVTree(); // Initialize BVTree
     77 
     78     // Iteration
     79     bool bOptimal = false;
     80     m_nItr = 0;
     81     while(!bOptimal && m_nItr<nMaxIt)
     82     {
     83         // Derive U=(u_ij) for row i and column j
     84         if(m_nItr==0) updateSubtree(m_pRoot);
     85         else updateSubtree(m_pEnter->pChild);
     86 
     87         // Optimality test
     88         bOptimal = isOptimal();
     89 
     90         // Find new solution
     91         if(!bOptimal)
     92             findNewSolution();
     93         ++m_nItr;
     94     }
     95     delete [] H1;
     96     delete [] H2;
     97     // Output the total flow
     98     return compuTotalFlow();
     99 }
    100 
    101 void EmdL1::setMaxIteration(int _nMaxIt)
    102 {
    103     nMaxIt=_nMaxIt;
    104 }
    105 
    106 //-- SubFunctions called in the EMD algorithm
    107 bool EmdL1::initBaseTrees(int n1, int n2, int n3)
    108 {
    109     if(binsDim1==n1 && binsDim2==n2 && binsDim3==n3)
    110         return true;
    111     binsDim1 = n1;
    112     binsDim2 = n2;
    113     binsDim3 = n3;
    114     if(binsDim1==0 || binsDim2==0) dimension = 0;
    115     else dimension	= (binsDim3==0)?2:3;
    116 
    117     if(dimension==2)
    118     {
    119         m_Nodes.resize(binsDim1);
    120         m_EdgesUp.resize(binsDim1);
    121         m_EdgesRight.resize(binsDim1);
    122         for(int i1=0; i1<binsDim1; i1++)
    123         {
    124             m_Nodes[i1].resize(binsDim2);
    125             m_EdgesUp[i1].resize(binsDim2);
    126             m_EdgesRight[i1].resize(binsDim2);
    127         }
    128         m_NBVEdges.resize(binsDim1*binsDim2*4+2);
    129         m_auxQueue.resize(binsDim1*binsDim2+2);
    130         m_fromLoop.resize(binsDim1*binsDim2+2);
    131         m_toLoop.resize(binsDim1*binsDim2+2);
    132     }
    133     else if(dimension==3)
    134     {
    135         m_3dNodes.resize(binsDim1);
    136         m_3dEdgesUp.resize(binsDim1);
    137         m_3dEdgesRight.resize(binsDim1);
    138         m_3dEdgesDeep.resize(binsDim1);
    139         for(int i1=0; i1<binsDim1; i1++)
    140         {
    141             m_3dNodes[i1].resize(binsDim2);
    142             m_3dEdgesUp[i1].resize(binsDim2);
    143             m_3dEdgesRight[i1].resize(binsDim2);
    144             m_3dEdgesDeep[i1].resize(binsDim2);
    145             for(int i2=0; i2<binsDim2; i2++)
    146             {
    147                 m_3dNodes[i1][i2].resize(binsDim3);
    148                 m_3dEdgesUp[i1][i2].resize(binsDim3);
    149                 m_3dEdgesRight[i1][i2].resize(binsDim3);
    150                 m_3dEdgesDeep[i1][i2].resize(binsDim3);
    151             }
    152         }
    153         m_NBVEdges.resize(binsDim1*binsDim2*binsDim3*6+4);
    154         m_auxQueue.resize(binsDim1*binsDim2*binsDim3+4);
    155         m_fromLoop.resize(binsDim1*binsDim2*binsDim3+4);
    156         m_toLoop.resize(binsDim1*binsDim2*binsDim3+2);
    157     }
    158     else
    159         return false;
    160 
    161     return true;
    162 }
    163 
    164 bool EmdL1::fillBaseTrees(float *H1, float *H2)
    165 {
    166     //- Set global counters
    167     m_pRoot	= NULL;
    168     // Graph initialization
    169     float *p1 = H1;
    170     float *p2 = H2;
    171     if(dimension==2)
    172     {
    173         for(int c=0; c<binsDim2; c++)
    174         {
    175             for(int r=0; r<binsDim1; r++)
    176             {
    177                 //- initialize nodes and links
    178                 m_Nodes[r][c].pos[0] = r;
    179                 m_Nodes[r][c].pos[1] = c;
    180                 m_Nodes[r][c].d = *(p1++)-*(p2++);
    181                 m_Nodes[r][c].pParent = NULL;
    182                 m_Nodes[r][c].pChild = NULL;
    183                 m_Nodes[r][c].iLevel = -1;
    184 
    185                 //- initialize edges
    186                 // to the right
    187                 m_EdgesRight[r][c].pParent = &(m_Nodes[r][c]);
    188                 m_EdgesRight[r][c].pChild = &(m_Nodes[r][(c+1)%binsDim2]);
    189                 m_EdgesRight[r][c].flow	= 0;
    190                 m_EdgesRight[r][c].iDir	= 1;
    191                 m_EdgesRight[r][c].pNxt	= NULL;
    192 
    193                 // to the upward
    194                 m_EdgesUp[r][c].pParent	= &(m_Nodes[r][c]);
    195                 m_EdgesUp[r][c].pChild	= &(m_Nodes[(r+1)%binsDim1][c]);
    196                 m_EdgesUp[r][c].flow = 0;
    197                 m_EdgesUp[r][c].iDir = 1;
    198                 m_EdgesUp[r][c].pNxt = NULL;
    199             }
    200         }
    201     }
    202     else if(dimension==3)
    203     {
    204         for(int z=0; z<binsDim3; z++)
    205         {
    206             for(int c=0; c<binsDim2; c++)
    207             {
    208                 for(int r=0; r<binsDim1; r++)
    209                 {
    210                     //- initialize nodes and edges
    211                     m_3dNodes[r][c][z].pos[0] = r;
    212                     m_3dNodes[r][c][z].pos[1] = c;
    213                     m_3dNodes[r][c][z].pos[2] = z;
    214                     m_3dNodes[r][c][z].d = *(p1++)-*(p2++);
    215                     m_3dNodes[r][c][z].pParent = NULL;
    216                     m_3dNodes[r][c][z].pChild = NULL;
    217                     m_3dNodes[r][c][z].iLevel = -1;
    218 
    219                     //- initialize edges
    220                     // to the upward
    221                     m_3dEdgesUp[r][c][z].pParent= &(m_3dNodes[r][c][z]);
    222                     m_3dEdgesUp[r][c][z].pChild	= &(m_3dNodes[(r+1)%binsDim1][c][z]);
    223                     m_3dEdgesUp[r][c][z].flow = 0;
    224                     m_3dEdgesUp[r][c][z].iDir = 1;
    225                     m_3dEdgesUp[r][c][z].pNxt = NULL;
    226 
    227                     // to the right
    228                     m_3dEdgesRight[r][c][z].pParent	= &(m_3dNodes[r][c][z]);
    229                     m_3dEdgesRight[r][c][z].pChild	= &(m_3dNodes[r][(c+1)%binsDim2][z]);
    230                     m_3dEdgesRight[r][c][z].flow	= 0;
    231                     m_3dEdgesRight[r][c][z].iDir	= 1;
    232                     m_3dEdgesRight[r][c][z].pNxt	= NULL;
    233 
    234                     // to the deep
    235                     m_3dEdgesDeep[r][c][z].pParent	= &(m_3dNodes[r][c][z]);
    236                     m_3dEdgesDeep[r][c][z].pChild	= &(m_3dNodes[r][c])[(z+1)%binsDim3];
    237                     m_3dEdgesDeep[r][c][z].flow = 0;
    238                     m_3dEdgesDeep[r][c][z].iDir = 1;
    239                     m_3dEdgesDeep[r][c][z].pNxt = NULL;
    240                 }
    241             }
    242         }
    243     }
    244     return true;
    245 }
    246 
    247 bool EmdL1::greedySolution()
    248 {
    249     return dimension==2?greedySolution2():greedySolution3();
    250 }
    251 
    252 bool EmdL1::greedySolution2()
    253 {
    254     //- Prepare auxiliary array, D=H1-H2
    255     int	c,r;
    256     floatArray2D D(binsDim1);
    257     for(r=0; r<binsDim1; r++)
    258     {
    259         D[r].resize(binsDim2);
    260         for(c=0; c<binsDim2; c++) D[r][c] = m_Nodes[r][c].d;
    261     }
    262     // compute integrated values along each dimension
    263     std::vector<float> d2s(binsDim2);
    264     d2s[0] = 0;
    265     for(c=0; c<binsDim2-1; c++)
    266     {
    267         d2s[c+1] = d2s[c];
    268         for(r=0; r<binsDim1; r++) d2s[c+1]-= D[r][c];
    269     }
    270 
    271     std::vector<float> d1s(binsDim1);
    272     d1s[0] = 0;
    273     for(r=0; r<binsDim1-1; r++)
    274     {
    275         d1s[r+1] = d1s[r];
    276         for(c=0; c<binsDim2; c++) d1s[r+1]-= D[r][c];
    277     }
    278 
    279     //- Greedy algorithm for initial solution
    280     cvPEmdEdge pBV;
    281     float dFlow;
    282     bool bUpward = false;
    283     nNBV = 0; // number of NON-BV edges
    284 
    285     for(c=0; c<binsDim2-1; c++)
    286     for(r=0; r<binsDim1; r++)
    287     {
    288         dFlow = D[r][c];
    289         bUpward = (r<binsDim1-1) && (fabs(dFlow+d2s[c+1]) > fabs(dFlow+d1s[r+1]));	// Move upward or right
    290 
    291         // modify basic variables, record BV and related values
    292         if(bUpward)
    293         {
    294             // move to up
    295             pBV	= &(m_EdgesUp[r][c]);
    296             m_NBVEdges[nNBV++]	= &(m_EdgesRight[r][c]);
    297             D[r+1][c] += dFlow;		// auxilary matrix maintanence
    298             d1s[r+1] += dFlow;		// auxilary matrix maintanence
    299         }
    300         else
    301         {
    302             // move to right, no other choice
    303             pBV	= &(m_EdgesRight[r][c]);
    304             if(r<binsDim1-1)
    305                 m_NBVEdges[nNBV++]	= &(m_EdgesUp[r][c]);
    306 
    307             D[r][c+1] += dFlow;		// auxilary matrix maintanence
    308             d2s[c+1] += dFlow;		// auxilary matrix maintanence
    309         }
    310         pBV->pParent->pChild = pBV;
    311         pBV->flow = fabs(dFlow);
    312         pBV->iDir = dFlow>0;		// 1:outward, 0:inward
    313     }
    314 
    315     //- rightmost column, no choice but move upward
    316     c = binsDim2-1;
    317     for(r=0; r<binsDim1-1; r++)
    318     {
    319         dFlow = D[r][c];
    320         pBV = &(m_EdgesUp[r][c]);
    321         D[r+1][c] += dFlow;		// auxilary matrix maintanence
    322         pBV->pParent->pChild= pBV;
    323         pBV->flow = fabs(dFlow);
    324         pBV->iDir = dFlow>0;		// 1:outward, 0:inward
    325     }
    326     return true;
    327 }
    328 
    329 bool EmdL1::greedySolution3()
    330 {
    331     //- Prepare auxiliary array, D=H1-H2
    332     int i1,i2,i3;
    333     std::vector<floatArray2D> D(binsDim1);
    334     for(i1=0; i1<binsDim1; i1++)
    335     {
    336         D[i1].resize(binsDim2);
    337         for(i2=0; i2<binsDim2; i2++)
    338         {
    339             D[i1][i2].resize(binsDim3);
    340             for(i3=0; i3<binsDim3; i3++)
    341                 D[i1][i2][i3] = m_3dNodes[i1][i2][i3].d;
    342         }
    343     }
    344 
    345     // compute integrated values along each dimension
    346     std::vector<float> d1s(binsDim1);
    347     d1s[0] = 0;
    348     for(i1=0; i1<binsDim1-1; i1++)
    349     {
    350         d1s[i1+1] = d1s[i1];
    351         for(i2=0; i2<binsDim2; i2++)
    352         {
    353             for(i3=0; i3<binsDim3; i3++)
    354                 d1s[i1+1] -= D[i1][i2][i3];
    355         }
    356     }
    357 
    358     std::vector<float> d2s(binsDim2);
    359     d2s[0] = 0;
    360     for(i2=0; i2<binsDim2-1; i2++)
    361     {
    362         d2s[i2+1] = d2s[i2];
    363         for(i1=0; i1<binsDim1; i1++)
    364         {
    365             for(i3=0; i3<binsDim3; i3++)
    366                 d2s[i2+1] -= D[i1][i2][i3];
    367         }
    368     }
    369 
    370     std::vector<float> d3s(binsDim3);
    371     d3s[0] = 0;
    372     for(i3=0; i3<binsDim3-1; i3++)
    373     {
    374         d3s[i3+1]	= d3s[i3];
    375         for(i1=0; i1<binsDim1; i1++)
    376         {
    377             for(i2=0; i2<binsDim2; i2++)
    378                 d3s[i3+1] -= D[i1][i2][i3];
    379         }
    380     }
    381 
    382     //- Greedy algorithm for initial solution
    383     cvPEmdEdge pBV;
    384     float dFlow, f1,f2,f3;
    385     nNBV = 0; // number of NON-BV edges
    386     for(i3=0; i3<binsDim3; i3++)
    387     {
    388         for(i2=0; i2<binsDim2; i2++)
    389         {
    390             for(i1=0; i1<binsDim1; i1++)
    391             {
    392                 if(i3==binsDim3-1 && i2==binsDim2-1 && i1==binsDim1-1) break;
    393 
    394                 //- determine which direction to move, either right or upward
    395                 dFlow = D[i1][i2][i3];
    396                 f1 = (i1<(binsDim1-1))?fabs(dFlow+d1s[i1+1]):std::numeric_limits<float>::max();
    397                 f2 = (i2<(binsDim2-1))?fabs(dFlow+d2s[i2+1]):std::numeric_limits<float>::max();
    398                 f3 = (i3<(binsDim3-1))?fabs(dFlow+d3s[i3+1]):std::numeric_limits<float>::max();
    399 
    400                 if(f1<f2 && f1<f3)
    401                 {
    402                     pBV	= &(m_3dEdgesUp[i1][i2][i3]); // up
    403                     if(i2<binsDim2-1) m_NBVEdges[nNBV++] = &(m_3dEdgesRight[i1][i2][i3]);	// right
    404                     if(i3<binsDim3-1) m_NBVEdges[nNBV++] = &(m_3dEdgesDeep[i1][i2][i3]); // deep
    405                     D[i1+1][i2][i3]	+= dFlow; // maintain auxilary matrix
    406                     d1s[i1+1] += dFlow;
    407                 }
    408                 else if(f2<f3)
    409                 {
    410                     pBV	= &(m_3dEdgesRight[i1][i2][i3]); // right
    411                     if(i1<binsDim1-1) m_NBVEdges[nNBV++] = &(m_3dEdgesUp[i1][i2][i3]); // up
    412                     if(i3<binsDim3-1) m_NBVEdges[nNBV++] = &(m_3dEdgesDeep[i1][i2][i3]); // deep
    413                     D[i1][i2+1][i3]	+= dFlow; // maintain auxilary matrix
    414                     d2s[i2+1] += dFlow;
    415                 }
    416                 else
    417                 {
    418                     pBV	= &(m_3dEdgesDeep[i1][i2][i3]); // deep
    419                     if(i2<binsDim2-1) m_NBVEdges[nNBV++] = &(m_3dEdgesRight[i1][i2][i3]);	// right
    420                     if(i1<binsDim1-1) m_NBVEdges[nNBV++] = &(m_3dEdgesUp[i1][i2][i3]); // up
    421                     D[i1][i2][i3+1]	+= dFlow; // maintain auxilary matrix
    422                     d3s[i3+1] += dFlow;
    423                 }
    424 
    425                 pBV->flow = fabs(dFlow);
    426                 pBV->iDir = dFlow>0; // 1:outward, 0:inward
    427                 pBV->pParent->pChild= pBV;
    428             }
    429         }
    430     }
    431     return true;
    432 }
    433 
    434 void EmdL1::initBVTree()
    435 {
    436     // initialize BVTree from the initial BF solution
    437     //- Using the center of the graph as the root
    438     int r = (int)(0.5*binsDim1-.5);
    439     int c = (int)(0.5*binsDim2-.5);
    440     int z = (int)(0.5*binsDim3-.5);
    441     m_pRoot	= dimension==2 ? &(m_Nodes[r][c]) : &(m_3dNodes[r][c][z]);
    442     m_pRoot->u = 0;
    443     m_pRoot->iLevel	= 0;
    444     m_pRoot->pParent= NULL;
    445     m_pRoot->pPEdge	= NULL;
    446 
    447     //- Prepare a queue
    448     m_auxQueue[0] = m_pRoot;
    449     int nQueue = 1; // length of queue
    450     int iQHead = 0; // head of queue
    451 
    452     //- Recursively build subtrees
    453     cvPEmdEdge pCurE=NULL, pNxtE=NULL;
    454     cvPEmdNode pCurN=NULL, pNxtN=NULL;
    455     int	nBin = binsDim1*binsDim2*std::max(binsDim3,1);
    456     while(iQHead<nQueue && nQueue<nBin)
    457     {
    458         pCurN = m_auxQueue[iQHead++];	// pop out from queue
    459         r = pCurN->pos[0];
    460         c = pCurN->pos[1];
    461         z = pCurN->pos[2];
    462 
    463         // check connection from itself
    464         pCurE = pCurN->pChild;	// the initial child from initial solution
    465         if(pCurE)
    466         {
    467             pNxtN = pCurE->pChild;
    468             pNxtN->pParent = pCurN;
    469             pNxtN->pPEdge = pCurE;
    470             m_auxQueue[nQueue++] = pNxtN;
    471         }
    472 
    473         // check four neighbor nodes
    474         int	nNB	= dimension==2?4:6;
    475         for(int k=0;k<nNB;k++)
    476         {
    477             if(dimension==2)
    478             {
    479                 if(k==0 && c>0) pNxtN = &(m_Nodes[r][c-1]);		// left
    480                 else if(k==1 && r>0) pNxtN	= &(m_Nodes[r-1][c]);		// down
    481                 else if(k==2 && c<binsDim2-1) pNxtN	= &(m_Nodes[r][c+1]);		// right
    482                 else if(k==3 && r<binsDim1-1) pNxtN	= &(m_Nodes[r+1][c]);		// up
    483                 else continue;
    484             }
    485             else if(dimension==3)
    486             {
    487                 if(k==0 && c>0) pNxtN = &(m_3dNodes[r][c-1][z]); // left
    488                 else if(k==1 && c<binsDim2-1) pNxtN	= &(m_3dNodes[r][c+1][z]); // right
    489                 else if(k==2 && r>0) pNxtN	= &(m_3dNodes[r-1][c][z]); // down
    490                 else if(k==3 && r<binsDim1-1) pNxtN	= &(m_3dNodes[r+1][c][z]); // up
    491                 else if(k==4 && z>0) pNxtN = &(m_3dNodes[r][c][z-1]); // shallow
    492                 else if(k==5 && z<binsDim3-1) pNxtN	= &(m_3dNodes[r][c][z+1]); // deep
    493                 else continue;
    494             }
    495             if(pNxtN != pCurN->pParent)
    496             {
    497                 pNxtE = pNxtN->pChild;
    498                 if(pNxtE && pNxtE->pChild==pCurN) // has connection
    499                 {
    500                     pNxtN->pParent = pCurN;
    501                     pNxtN->pPEdge = pNxtE;
    502                     pNxtN->pChild = NULL;
    503                     m_auxQueue[nQueue++] = pNxtN;
    504 
    505                     pNxtE->pParent = pCurN; // reverse direction
    506                     pNxtE->pChild = pNxtN;
    507                     pNxtE->iDir = !pNxtE->iDir;
    508 
    509                     if(pCurE) pCurE->pNxt = pNxtE;	// add to edge list
    510                     else pCurN->pChild = pNxtE;
    511                     pCurE = pNxtE;
    512                 }
    513             }
    514         }
    515     }
    516 }
    517 
    518 void EmdL1::updateSubtree(cvPEmdNode pRoot)
    519 {
    520     // Initialize auxiliary queue
    521     m_auxQueue[0] = pRoot;
    522     int nQueue = 1; // queue length
    523     int iQHead = 0; // head of queue
    524 
    525     // BFS browing
    526     cvPEmdNode pCurN=NULL,pNxtN=NULL;
    527     cvPEmdEdge pCurE=NULL;
    528     while(iQHead<nQueue)
    529     {
    530         pCurN = m_auxQueue[iQHead++];	// pop out from queue
    531         pCurE = pCurN->pChild;
    532 
    533         // browsing all children
    534         while(pCurE)
    535         {
    536             pNxtN = pCurE->pChild;
    537             pNxtN->iLevel = pCurN->iLevel+1;
    538             pNxtN->u = pCurE->iDir ? (pCurN->u - 1) : (pCurN->u + 1);
    539             pCurE = pCurE->pNxt;
    540             m_auxQueue[nQueue++] = pNxtN;
    541         }
    542     }
    543 }
    544 
    545 bool EmdL1::isOptimal()
    546 {
    547     int iC, iMinC = 0;
    548     cvPEmdEdge pE;
    549     m_pEnter = NULL;
    550     m_iEnter = -1;
    551 
    552     // test each NON-BV edges
    553     for(int k=0; k<nNBV; ++k)
    554     {
    555         pE = m_NBVEdges[k];
    556         iC = 1 - pE->pParent->u + pE->pChild->u;
    557         if(iC<iMinC)
    558         {
    559             iMinC = iC;
    560             m_iEnter= k;
    561         }
    562         else
    563         {
    564             // Try reversing the direction
    565             iC	= 1 + pE->pParent->u - pE->pChild->u;
    566             if(iC<iMinC)
    567             {
    568                 iMinC = iC;
    569                 m_iEnter= k;
    570             }
    571         }
    572     }
    573 
    574     if(m_iEnter>=0)
    575     {
    576         m_pEnter = m_NBVEdges[m_iEnter];
    577         if(iMinC == (1 - m_pEnter->pChild->u + m_pEnter->pParent->u))	{
    578             // reverse direction
    579             cvPEmdNode pN = m_pEnter->pParent;
    580             m_pEnter->pParent = m_pEnter->pChild;
    581             m_pEnter->pChild = pN;
    582         }
    583 
    584         m_pEnter->iDir = 1;
    585     }
    586     return m_iEnter==-1;
    587 }
    588 
    589 void EmdL1::findNewSolution()
    590 {
    591     // Find loop formed by adding the Enter BV edge.
    592     findLoopFromEnterBV();
    593     // Modify flow values along the loop
    594     cvPEmdEdge pE = NULL;
    595     float	minFlow = m_pLeave->flow;
    596     int k;
    597     for(k=0; k<m_iFrom; k++)
    598     {
    599         pE = m_fromLoop[k];
    600         if(pE->iDir) pE->flow += minFlow; // outward
    601         else pE->flow -= minFlow; // inward
    602     }
    603     for(k=0; k<m_iTo; k++)
    604     {
    605         pE = m_toLoop[k];
    606         if(pE->iDir) pE->flow -= minFlow; // outward
    607         else pE->flow += minFlow; // inward
    608     }
    609 
    610     // Update BV Tree, removing the Leaving-BV edge
    611     cvPEmdNode pLParentN = m_pLeave->pParent;
    612     cvPEmdNode pLChildN = m_pLeave->pChild;
    613     cvPEmdEdge pPreE = pLParentN->pChild;
    614     if(pPreE==m_pLeave)
    615     {
    616         pLParentN->pChild = m_pLeave->pNxt; // Leaving-BV is the first child
    617     }
    618     else
    619     {
    620         while(pPreE->pNxt != m_pLeave)
    621             pPreE	= pPreE->pNxt;
    622         pPreE->pNxt	= m_pLeave->pNxt; // remove Leaving-BV from child list
    623     }
    624     pLChildN->pParent = NULL;
    625     pLChildN->pPEdge = NULL;
    626 
    627     m_NBVEdges[m_iEnter]= m_pLeave; // put the leaving-BV into the NBV array
    628 
    629     // Add the Enter BV edge
    630     cvPEmdNode pEParentN = m_pEnter->pParent;
    631     cvPEmdNode pEChildN = m_pEnter->pChild;
    632     m_pEnter->flow = minFlow;
    633     m_pEnter->pNxt = pEParentN->pChild;		// insert the Enter BV as the first child
    634     pEParentN->pChild = m_pEnter;					//		of its parent
    635 
    636     // Recursively update the tree start from pEChildN
    637     cvPEmdNode pPreN = pEParentN;
    638     cvPEmdNode pCurN = pEChildN;
    639     cvPEmdNode pNxtN;
    640     cvPEmdEdge pNxtE, pPreE0;
    641     pPreE = m_pEnter;
    642     while(pCurN)
    643     {
    644         pNxtN = pCurN->pParent;
    645         pNxtE = pCurN->pPEdge;
    646         pCurN->pParent = pPreN;
    647         pCurN->pPEdge = pPreE;
    648         if(pNxtN)
    649         {
    650             // remove the edge from pNxtN's child list
    651             if(pNxtN->pChild==pNxtE)
    652             {
    653                 pNxtN->pChild	= pNxtE->pNxt;			// first child
    654             }
    655             else
    656             {
    657                 pPreE0	= pNxtN->pChild;
    658                 while(pPreE0->pNxt != pNxtE)
    659                     pPreE0	= pPreE0->pNxt;
    660                 pPreE0->pNxt	= pNxtE->pNxt;			// remove Leaving-BV from child list
    661             }
    662             // reverse the parent-child direction
    663             pNxtE->pParent = pCurN;
    664             pNxtE->pChild = pNxtN;
    665             pNxtE->iDir = !pNxtE->iDir;
    666             pNxtE->pNxt = pCurN->pChild;
    667             pCurN->pChild = pNxtE;
    668             pPreE = pNxtE;
    669             pPreN = pCurN;
    670         }
    671         pCurN = pNxtN;
    672     }
    673 
    674     // Update U at the child of the Enter BV
    675     pEChildN->u = m_pEnter->iDir?(pEParentN->u-1):(pEParentN->u + 1);
    676     pEChildN->iLevel = pEParentN->iLevel+1;
    677 }
    678 
    679 void EmdL1::findLoopFromEnterBV()
    680 {
    681     // Initialize Leaving-BV edge
    682     float minFlow	= std::numeric_limits<float>::max();
    683     cvPEmdEdge pE = NULL;
    684     int iLFlag = 0;	// 0: in the FROM list, 1: in the TO list
    685 
    686     // Using two loop list to store the loop nodes
    687     cvPEmdNode pFrom = m_pEnter->pParent;
    688     cvPEmdNode pTo = m_pEnter->pChild;
    689     m_iFrom	= 0;
    690     m_iTo = 0;
    691     m_pLeave = NULL;
    692 
    693     // Trace back to make pFrom and pTo at the same level
    694     while(pFrom->iLevel > pTo->iLevel)
    695     {
    696         pE = pFrom->pPEdge;
    697         m_fromLoop[m_iFrom++] = pE;
    698         if(!pE->iDir && pE->flow<minFlow)
    699         {
    700             minFlow = pE->flow;
    701             m_pLeave = pE;
    702             iLFlag = 0;	// 0: in the FROM list
    703         }
    704         pFrom = pFrom->pParent;
    705     }
    706 
    707     while(pTo->iLevel > pFrom->iLevel)
    708     {
    709         pE = pTo->pPEdge;
    710         m_toLoop[m_iTo++] = pE;
    711         if(pE->iDir && pE->flow<minFlow)
    712         {
    713             minFlow = pE->flow;
    714             m_pLeave = pE;
    715             iLFlag = 1;	// 1: in the TO list
    716         }
    717         pTo	= pTo->pParent;
    718     }
    719 
    720     // Trace pTo and pFrom simultaneously till find their common ancester
    721     while(pTo!=pFrom)
    722     {
    723         pE = pFrom->pPEdge;
    724         m_fromLoop[m_iFrom++] = pE;
    725         if(!pE->iDir && pE->flow<minFlow)
    726         {
    727             minFlow = pE->flow;
    728             m_pLeave = pE;
    729             iLFlag = 0;	// 0: in the FROM list, 1: in the TO list
    730         }
    731         pFrom = pFrom->pParent;
    732 
    733         pE = pTo->pPEdge;
    734         m_toLoop[m_iTo++] = pE;
    735         if(pE->iDir && pE->flow<minFlow)
    736         {
    737             minFlow = pE->flow;
    738             m_pLeave = pE;
    739             iLFlag = 1;	// 0: in the FROM list, 1: in the TO list
    740         }
    741         pTo	= pTo->pParent;
    742     }
    743 
    744     // Reverse the direction of the Enter BV edge if necessary
    745     if(iLFlag==0)
    746     {
    747         cvPEmdNode pN = m_pEnter->pParent;
    748         m_pEnter->pParent = m_pEnter->pChild;
    749         m_pEnter->pChild = pN;
    750         m_pEnter->iDir = !m_pEnter->iDir;
    751     }
    752 }
    753 
    754 float EmdL1::compuTotalFlow()
    755 {
    756     // Computing the total flow as the final distance
    757     float f = 0;
    758 
    759     // Initialize auxiliary queue
    760     m_auxQueue[0] = m_pRoot;
    761     int nQueue = 1; // length of queue
    762     int iQHead = 0; // head of queue
    763 
    764     // BFS browing the tree
    765     cvPEmdNode pCurN=NULL,pNxtN=NULL;
    766     cvPEmdEdge pCurE=NULL;
    767     while(iQHead<nQueue)
    768     {
    769         pCurN = m_auxQueue[iQHead++];	// pop out from queue
    770         pCurE = pCurN->pChild;
    771 
    772         // browsing all children
    773         while(pCurE)
    774         {
    775             f += pCurE->flow;
    776             pNxtN = pCurE->pChild;
    777             pCurE = pCurE->pNxt;
    778             m_auxQueue[nQueue++] = pNxtN;
    779         }
    780     }
    781     return f;
    782 }
    783 
    784 /****************************************************************************************\
    785 *                                   EMDL1 Function                                      *
    786 \****************************************************************************************/
    787 
    788 float cv::EMDL1(InputArray _signature1, InputArray _signature2)
    789 {
    790     Mat signature1 = _signature1.getMat(), signature2 = _signature2.getMat();
    791     EmdL1 emdl1;
    792     return emdl1.getEMDL1(signature1, signature2);
    793 }
    794