/*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*/ #include "_cvaux.h" #if 0 //#include "windows.h" //#define ALPHA_EXPANSION #ifndef ALPHA_EXPANSION #define ALPHA_BETA_EXCHANGE #endif #define MAX_LABEL 20 #define CV_MODULE(xxx) \ ( (xxx) < 0 ? -(xxx) : (xxx) ) #define CV_MAX3(xxx1,xxx2,xxx3) \ ( (xxx1) > (xxx2) && (xxx1) > (xxx3) ? (xxx1) : \ (xxx2) > (xxx3) ? (xxx2) : (xxx3) ) #define CV_MIN2(xxx1,xxx2) \ ( (xxx1) < (xxx2) ? (xxx1) : (xxx2) ) #define getSizeForGraph(xxxType) \ ( sizeof(xxxType) < 8 ? 8 : sizeof(xxxType) + 4 - sizeof(xxxType) % 4 ) #define INT_INFINITY 1000000000 #define MAX_DIFFERENCE 10 // struct Vertex is used for storing vertices of graph // coord - coordinate corresponding pixel on the real image line struct Vertex { CvGraphVtx vtx; int coord; }; // struct Edge is used for storing edges of graph // weight - weight of the edge ( maximum flow via the edge ) // flow - current flow via the edge // srcVtx - coordinate of source vertex on the real image line // destVtx - coordinate of destination vertex on the real image line struct Edge { CV_GRAPH_EDGE_FIELDS() int weight; int flow; int srcVtx; int destVtx; }; // function vFunc is energy function which determines the difference // between two labels ( alpha and beta ) // alpha - label number one // beta - label number two inline int vFunc( int alpha, int beta ) { if( alpha == beta ) return 0; else return /*1*//*5*/10; } // function dFunc is energy function which determines energy of interaction // between pixel ( having coordinate xCoord ) and label // leftLine - line of left image // rightLine - line of right image // xCoord - coordinate of pixel on the left image // label - label corresponding to the pixel // width - width of the image line in pixels inline int dFunc( unsigned char* leftLine, unsigned char* rightLine, int xCoord, int label, int width) { assert( xCoord >= 0 && xCoord < width ); int r, g, b; int yCoord = xCoord + label; if( yCoord >= width ) yCoord = width; if( yCoord < 0 ) yCoord = 0; r = leftLine[ 3 * xCoord ] - rightLine[ 3 * yCoord ]; g = leftLine[ 3 * xCoord + 1 ] - rightLine[ 3 * yCoord + 1 ]; b = leftLine[ 3 * xCoord + 2 ] - rightLine[ 3 * yCoord + 2 ]; r = CV_MODULE( r ); g = CV_MODULE( g ); b = CV_MODULE( b ); return CV_MAX3( r, g, b ); } // function allocTempMem allocates all temporary memory needed for work // of some function // memPtr - pointer to pointer to the large block of memory // verticesPtr - pointer to pointer to block of memory for // temporary storing vertices // width - width of line in pixels void allocTempMem( int** memPtr, int** verticesPtr, int width ) { int* tempPtr = ( int* ) malloc( ( width + 2 ) * 7 * sizeof( int ) ); *verticesPtr = tempPtr; *memPtr = *verticesPtr + width + 2; } // function freeTempMem frees all allocated by allocTempMem function memory // memPtr - pointer to pointer to the large block of memory // verticesPtr - pointer to pointer to block of memory for // temporary storing vertices void freeTempMem( int** memPtr, int** verticesPtr ) { free( ( void* )( *verticesPtr ) ); *verticesPtr = NULL; *memPtr = NULL; } // function makeGraph creates initial graph to find maximum flow in it // graphPtr - pointer to pointer to CvGraph structure to be filled // leftLine - pointer to the left image line // rightLine - pointer to the right image line // alpha - label number one for doing exchange // beta - label number two for doing exchange // corr - pointer to array of correspondences ( each element // of array includes disparity of pixel on right image // for pixel each on left image ). This pointer direct // to correspondence ofr one line only // width - width of image lines in pixels // storage - pointer to CvMemStorage structure which contains // memory storage void makeGraph( CvGraph** graphPtr, unsigned char* leftLine, unsigned char* rightLine, int alpha, int beta, int* corr, int width, CvMemStorage* storage ) { int i; if( *graphPtr ) { cvClearGraph( *graphPtr ); } /*else {*/ *graphPtr = cvCreateGraph( CV_SEQ_KIND_GRAPH | CV_GRAPH_FLAG_ORIENTED, sizeof( CvGraph ), getSizeForGraph( Vertex ), getSizeForGraph( Edge ), storage ); /*}*/ CvGraph* graph = *graphPtr; #ifdef ALPHA_BETA_EXCHANGE CvGraphVtx* newVtxPtr; for( i = 0; i < width; i ++ ) { if( corr[i] == alpha || corr[i] == beta ) { cvGraphAddVtx( graph, NULL, &newVtxPtr ); ( ( Vertex* )newVtxPtr ) -> coord = i; } } /* for( i = 0; i < width; i ++ ) */ cvGraphAddVtx( graph, NULL, &newVtxPtr ); if( newVtxPtr ) ( ( Vertex* )newVtxPtr ) -> coord = -2; /* adding alpha vertex */ cvGraphAddVtx( graph, NULL, &newVtxPtr ); if( newVtxPtr ) ( ( Vertex* )newVtxPtr ) -> coord = -1; /* adding beta vertex */ int alphaVtx = graph -> total - 2; int betaVtx = graph -> total - 1; CvGraphEdge* newEdgePtr; CvGraphVtx* vtxPtr; if( graph -> total > 2 ) { for( i = 0; i < alphaVtx; i ++ ) { vtxPtr = cvGetGraphVtx( graph, i ); /* adding edge oriented from alpha vertex to current vertex */ cvGraphAddEdge( graph, alphaVtx, i, NULL, &newEdgePtr ); ( ( Edge* )newEdgePtr ) -> weight = dFunc( leftLine, rightLine, ( ( Vertex* )vtxPtr ) -> coord, alpha, width ); ( ( Edge* )newEdgePtr ) -> flow = 0; if( i != 0 ) { CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i - 1 ); /* if vertices are neighbours */ if( ( ( Vertex* )tempVtxPtr ) -> coord + 1 == ( ( Vertex* )vtxPtr ) -> coord ) { ( ( Edge* )newEdgePtr ) -> weight += vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ], alpha ); /* adding neighbour edge oriented from current vertex to the previous one */ CvGraphEdge* tempEdgePtr; cvGraphAddEdge( graph, i, i - 1, NULL, &tempEdgePtr ); ( ( Edge* )tempEdgePtr ) -> weight = vFunc( alpha, beta ); ( ( Edge* )tempEdgePtr ) -> flow = 0; ( ( Edge* )tempEdgePtr ) -> srcVtx = ( ( Vertex* )vtxPtr ) -> coord; ( ( Edge* )tempEdgePtr ) -> destVtx = ( ( Vertex* )tempVtxPtr ) -> coord; } } /* if( i != 0 ) */ if( i != alphaVtx - 1 ) { CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i + 1 ); /* if vertices are neighbours */ if( ( ( Vertex* )tempVtxPtr ) -> coord - 1 == ( ( Vertex* )vtxPtr ) -> coord ) { ( ( Edge* )newEdgePtr ) -> weight += vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ], alpha ); /* adding neighbour edge oriented from current vertex to the next one */ CvGraphEdge* tempEdgePtr; cvGraphAddEdge( graph, i, i + 1, NULL, &tempEdgePtr ); ( ( Edge* )tempEdgePtr ) -> weight = vFunc( alpha, beta ); ( ( Edge* )tempEdgePtr ) -> flow = 0; ( ( Edge* )tempEdgePtr ) -> srcVtx = ( ( Vertex* )vtxPtr ) -> coord; ( ( Edge* )tempEdgePtr ) -> destVtx = ( ( Vertex* )tempVtxPtr ) -> coord; } } /* if( i != alphaVtx - 1 ) */ ( ( Edge* )newEdgePtr ) -> flow = 0; ( ( Edge* )newEdgePtr ) -> srcVtx = -1; /* source vertex is alpha vertex */ ( ( Edge* )newEdgePtr ) -> destVtx = ( ( Vertex* )vtxPtr ) -> coord; /* adding edge oriented from current vertex to beta vertex */ cvGraphAddEdge( graph, i, betaVtx, NULL, &newEdgePtr ); ( ( Edge* )newEdgePtr ) -> weight = dFunc( leftLine, rightLine, ( ( Vertex* )vtxPtr ) -> coord, beta, width ); ( ( Edge* )newEdgePtr ) -> flow = 0; if( i != 0 ) { CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i - 1 ); /* if vertices are neighbours */ if( ( ( Vertex* )tempVtxPtr ) -> coord + 1 == ( ( Vertex* )vtxPtr ) -> coord ) { ( ( Edge* )newEdgePtr ) -> weight += vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ], beta ); } } /* if( i != 0 ) */ if( i != alphaVtx - 1 ) { CvGraphVtx* tempVtxPtr = cvGetGraphVtx( graph, i + 1 ); /* if vertices are neighbours */ if( ( ( Vertex* )tempVtxPtr ) -> coord - 1 == ( ( Vertex* )vtxPtr ) -> coord ) { ( ( Edge* )newEdgePtr ) -> weight += vFunc( corr[ ( ( Vertex* )tempVtxPtr ) -> coord ], beta ); } } /* if( i != alphaVtx - 1 ) */ ( ( Edge* )newEdgePtr ) -> flow = 0; ( ( Edge* )newEdgePtr ) -> srcVtx = ( ( Vertex* )vtxPtr ) -> coord; ( ( Edge* )newEdgePtr ) -> destVtx = -2; /* destination vertex is beta vertex */ } /* for( i = 0; i < graph -> total - 2; i ++ ) */ } /* if( graph -> total > 2 ) */ #endif /* #ifdef ALPHA_BETA_EXCHANGE */ #ifdef ALPHA_EXPANSION #endif /* #ifdef ALPHA_EXPANSION */ } /* makeGraph */ // function makeHelpGraph creates help graph using initial graph // graph - pointer to initial graph ( represented by CvGraph // structure ) // hlpGraphPtr - pointer to pointer to new help graph // storage - pointer to CvStorage structure // mem - pointer to memory allocated by allocTempMem function // vertices - pointer to memory allocated by allocTempMem function // verticesCountPtr- pointer to value containing number of vertices // in vertices array // width - width of image line in pixels int makeHelpGraph( CvGraph* graph, CvGraph** hlpGraphPtr, CvMemStorage* storage, int* mem, int* vertices, int* verticesCountPtr, int width ) { int u, v; int* order = mem; int* lengthArr = order + width + 2; int s = graph -> total - 2; /* source vertex */ int t = graph -> total - 1; /* terminate vertex */ int orderFirst; int orderCount; int &verticesCount = *verticesCountPtr; CvGraph* hlpGraph; if( *hlpGraphPtr ) { cvClearGraph( *hlpGraphPtr ); } else { *hlpGraphPtr = cvCreateGraph( CV_SEQ_KIND_GRAPH | CV_GRAPH_FLAG_ORIENTED, sizeof( CvGraph ), getSizeForGraph( Vertex ), getSizeForGraph( Edge ), storage ); } hlpGraph = *hlpGraphPtr; /* initialization */ for( u = 0; u < graph -> total; u ++ ) { lengthArr[ u ] = INT_INFINITY; cvGraphAddVtx( hlpGraph, NULL, NULL ); } /* for( u = 0; u < graph -> total - 1; u ++ ) */ orderFirst = 0; orderCount = 0; verticesCount = 0; lengthArr[ s ] = 0; /* add vertex s to order */ order[ orderCount ] = s; orderCount ++; while( orderCount != orderFirst ) { /* getting u from order */ u = order[ orderFirst ]; orderFirst ++; /* adding u to vertex array */ vertices[ verticesCount ] = u; verticesCount ++; int ofs; CvGraphVtx* graphVtx = cvGetGraphVtx( graph, u ); /* processing all vertices outgoing from vertex u */ CvGraphEdge* graphEdge = graphVtx -> first; while( graphEdge ) { int tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[1] ); ofs = tempVtxIdx == u; if( !ofs ) { v = tempVtxIdx; CvGraphEdge* tempGraphEdge = cvFindGraphEdge( graph, u, v ); if( ( lengthArr[ u ] < lengthArr[ v ] ) && ( lengthArr[ v ] <= lengthArr[ t ] ) && ( ( ( Edge* )tempGraphEdge ) -> flow < ( ( Edge* )tempGraphEdge ) -> weight ) ) { if( lengthArr[ v ] == INT_INFINITY ) { /* adding vertex v to order */ order[ orderCount ] = v; orderCount ++; lengthArr[ v ] = lengthArr[ u ] + 1; CvGraphEdge* tempGraphEdge2; cvGraphAddEdge( hlpGraph, u, v, NULL, &tempGraphEdge2 ); ( ( Edge* )tempGraphEdge2 ) -> flow = 0; ( ( Edge* )tempGraphEdge2 ) -> weight = ( ( Edge* )tempGraphEdge ) -> weight - ( ( Edge* )tempGraphEdge ) -> flow; } /* if( length[ v ] == INT_INFINITY ) */ } /* if( ( lengthArr[ u ] < lengthArr[ v ] ) ... */ } /* if( !ofs ) */ graphEdge = graphEdge -> next[ ofs ]; } /* while( graphEdge ) */ /* processing all vertices incoming to vertex u */ graphEdge = graphVtx -> first; while( graphEdge ) { int tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[1] ); ofs = tempVtxIdx == u; if( ofs ) { tempVtxIdx = cvGraphVtxIdx( graph, graphEdge -> vtx[0] ); v = tempVtxIdx; CvGraphEdge* tempGraphEdge = cvFindGraphEdge( graph, v, u ); if( ( lengthArr[ u ] < lengthArr[ v ] ) && ( lengthArr[ v ] <= lengthArr[ t ] ) && ( ( ( Edge* )tempGraphEdge ) -> flow > 0 ) ) { if( lengthArr[ v ] == INT_INFINITY ) { /* adding vertex v to order */ order[ orderCount ] = v; orderCount ++; lengthArr[ v ] = lengthArr[ u ] + 1; CvGraphEdge* tempGraphEdge3 = cvFindGraphEdge( hlpGraph, u, v ); if( tempGraphEdge3 == NULL || ( ( Edge* )tempGraphEdge3 ) -> weight == 0 ) { CvGraphEdge* tempGraphEdge2; cvGraphAddEdge( hlpGraph, u, v, NULL, &tempGraphEdge2 ); ( ( Edge* )tempGraphEdge2 ) -> flow = 0; ( ( Edge* )tempGraphEdge2 ) -> weight = 0; } /* if( tempGraphEdge3 == NULL || ... */ ( ( Edge* )tempGraphEdge3 ) -> weight += ( ( Edge* )tempGraphEdge ) -> flow; } /* if( length[ v ] == INT_INFINITY ) */ } /* if( ( lengthArr[ u ] < lengthArr[ v ] ) ... */ } /* if( ofs ) */ graphEdge = graphEdge -> next[ ofs ]; } /* while( graphEdge ) */ } /* while( orderCount != orderFirst ) */ int i; for( i = 0; i < hlpGraph -> total - 2; i ++ ) { CvGraphVtx* hlpGraphVtxTemp = cvGetGraphVtx( hlpGraph, i ); if( hlpGraphVtxTemp ) { if( !hlpGraphVtxTemp -> first ) { cvGraphRemoveVtxByPtr( hlpGraph, hlpGraphVtxTemp ); } } } /* for( i = 0; i < hlpGraph -> total - 2; i ++ ) */ return lengthArr[ t ]; } /* makeHelpGraph */ // function makePseudoMaxFlow increases flow in graph by using hlpGraph // graph - pointer to initial graph // hlpGraph - pointer to help graph // vertices - pointer to vertices array // verticesCount - number of vertices in vertices array // mem - pointer to memory allocated by allocTempMem function // width - width of image line in pixels void makePseudoMaxFlow( CvGraph* graph, CvGraph* hlpGraph, int* vertices, int verticesCount, int* mem, int width ) { int stekCount; int orderFirst; int orderCount; int i; int v, u; int* stek = mem; int* order = stek + width + 2; int* incomFlow = order + width + 2; int* outgoFlow = incomFlow + width + 2; int* flow = outgoFlow + width + 2; int* cargo = flow+ width + 2; int s = graph -> total - 2; /* source vertex */ int t = graph -> total - 1; /* terminate vertex */ int realVerticesCount = verticesCount; stekCount = 0; for( i = 0; i < verticesCount; i ++ ) { v = vertices[ i ]; incomFlow[ v ] = outgoFlow[ v ] = 0; if( v == s ) { incomFlow[ v ] = INT_INFINITY; } /* if( v == s ) */ else { CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v ); CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first; int ofs; while( hlpGraphEdge ) { int vtxIdx = cvGraphVtxIdx( hlpGraph, hlpGraphEdge -> vtx[1] ); ofs = vtxIdx == v; if( ofs ) { incomFlow[ v ] += ( ( Edge* )hlpGraphEdge ) -> weight; } /* if( ofs ) */ hlpGraphEdge = hlpGraphEdge -> next[ ofs ]; } /* while( hlpGraphEdge ) */ } /* if( v == s ) else */ if( v == t ) { outgoFlow[ v ] = INT_INFINITY; } /* if( v == t ) */ else { CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v ); CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first; int ofs; while( hlpGraphEdge ) { int vtxIdx = cvGraphVtxIdx( hlpGraph, hlpGraphEdge -> vtx[1] ); ofs = vtxIdx == v; if( !ofs ) { outgoFlow[ v ] += ( ( Edge* )hlpGraphEdge ) -> weight; } /* if( ofs ) */ hlpGraphEdge = hlpGraphEdge -> next[ ofs ]; } /* while( hlpGraphEdge ) */ } /* if( v == t ) else */ flow[ v ] = CV_MIN2( incomFlow[ v ], outgoFlow[ v ] ); if( !flow[ v ] ) { stek[ stekCount ] = v; stekCount ++; } /* if( !flow[ v ] ) */ } /* for( i = 0; i < verticesCount; i ++ ) */ for( i = 0; i < verticesCount; i ++ ) { v = vertices[ i ]; cargo[ v ] = 0; } /* for( i = 0; i < verticesCount; i ++ ) */ while( realVerticesCount > 2 ) { /* deleting all vertices included in stek */ while( stekCount ) { v = stek[ stekCount - 1 ]; stekCount --; /* deleting edges incoming to v and outgoing from v */ int ofs; CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v ); CvGraphEdge* hlpGraphEdge; if( hlpGraphVtx ) { hlpGraphEdge = hlpGraphVtx -> first; } else { hlpGraphEdge = NULL; } while( hlpGraphEdge ) { CvGraphVtx* hlpGraphVtx2 = hlpGraphEdge -> vtx[ 1 ]; int hlpGraphVtxIdx2 = cvGraphVtxIdx( hlpGraph, hlpGraphVtx2 ); ofs = hlpGraphVtxIdx2 == v; if( ofs ) { /* hlpGraphEdge is incoming edge */ CvGraphVtx* hlpGraphVtx3 = hlpGraphEdge -> vtx[0]; u = cvGraphVtxIdx( hlpGraph, hlpGraphVtx3 ); outgoFlow[ u ] -= ( ( Edge* )hlpGraphEdge ) -> weight - ( ( Edge* )hlpGraphEdge ) -> flow; cvGraphRemoveEdgeByPtr( hlpGraph, hlpGraphVtx3, hlpGraphVtx2 ); if( flow[ u ] != 0 ) { flow[ u ] = CV_MIN2( incomFlow[u], outgoFlow[u] ); if( flow[ u ] == 0 ) { stek[ stekCount ] = u; stekCount ++; } } } /* if( ofs ) */ else { /* hlpGraphEdge is outgoing edge */ CvGraphVtx* hlpGraphVtx3 = hlpGraphEdge -> vtx[1]; int u = cvGraphVtxIdx( hlpGraph, hlpGraphVtx3 ); incomFlow[ u ] -= ( ( Edge* )hlpGraphEdge ) -> weight - ( ( Edge* )hlpGraphEdge ) -> flow; cvGraphRemoveEdgeByPtr( hlpGraph, hlpGraphVtx2, hlpGraphVtx3 ); if( flow[ u ] != 0 ) { flow[ u ] = CV_MIN2( incomFlow[u], outgoFlow[u] ); if( flow[ u ] == 0 ) { stek[ stekCount ] = u; stekCount ++; } } } /* if( ofs ) else */ hlpGraphEdge = hlpGraphEdge -> next[ ofs ]; } /* while( hlpGraphEdge ) */ /* deleting vertex v */ cvGraphRemoveVtx( hlpGraph, v ); realVerticesCount --; } /* while( stekCount ) */ if( realVerticesCount > 2 ) /* the flow is not max still */ { int p = INT_INFINITY; int r = -1; CvGraphVtx* graphVtx; if( realVerticesCount == 3 ) { r = r; } for( i = 0; i < hlpGraph -> total - 2; i ++ ) { graphVtx = cvGetGraphVtx( hlpGraph, i ); if( graphVtx ) { v = cvGraphVtxIdx( hlpGraph, graphVtx ); if( flow[ v ] < p ) { r = v; p = flow[ v ]; } } } /* for( i = 0; i < hlpGraph -> total - 2; i ++ ) */ /* building of size p flow from r to t */ orderCount = orderFirst = 0; order[ orderCount ] = r; orderCount ++; v = order[ orderFirst ]; orderFirst ++; cargo[ r ] = p; do /* while( v != t ) */ { incomFlow[ v ] -= cargo[ v ]; outgoFlow[ v ] -= cargo[ v ]; flow[ v ] -= cargo[ v ]; if( flow[ v ] == 0 ) { stek[ stekCount ] = v; stekCount ++; } if( v == t ) { cargo[ v ] = p; } else { int ofs; CvGraphVtx* hlpGraphVtx2; CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v ); CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first; CvGraphEdge* hlpGraphEdge2 = NULL; while( hlpGraphEdge && cargo[ v ] > 0 ) { hlpGraphVtx2 = hlpGraphEdge -> vtx[ 1 ]; u = cvGraphVtxIdx( hlpGraph, hlpGraphVtx2 ); ofs = u == v; if( !ofs ) { if( cargo[ u ] == 0 ) { order[ orderCount ] = u; orderCount ++; } int delta = ( ( Edge* )hlpGraphEdge ) -> weight - ( ( Edge* )hlpGraphEdge ) -> flow; delta = CV_MIN2( cargo[ v ], delta ); ( ( Edge* )hlpGraphEdge ) -> flow += delta; cargo[ v ] -= delta; cargo[ u ] += delta; if( ( ( Edge* )hlpGraphEdge ) -> weight == ( ( Edge* )hlpGraphEdge ) -> flow ) { /* deleting hlpGraphEdge */ hlpGraphEdge2 = hlpGraphEdge -> next[ ofs ]; CvGraphEdge* graphEdge = cvFindGraphEdge( graph, v, u ); ( ( Edge* )graphEdge ) -> flow += ( ( Edge* )hlpGraphEdge ) -> flow; cvGraphRemoveEdgeByPtr( hlpGraph, hlpGraphEdge -> vtx[0], hlpGraphEdge -> vtx[1] ); } } /* if( !ofs ) */ if( hlpGraphEdge2 ) { hlpGraphEdge = hlpGraphEdge2; hlpGraphEdge2 = NULL; } else { hlpGraphEdge = hlpGraphEdge -> next[ ofs ]; } } /* while( hlpGraphEdge && cargo[ v ] > 0 ) */ } /* if( v == t ) else */ v = order[ orderFirst ]; orderFirst ++; } while( v != t ); /* do */ /* building of size p flow from s to r */ orderCount = orderFirst = 0; order[ orderCount ] = r; orderCount ++; v = order[ orderFirst ]; orderFirst ++; cargo[ r ] = p; do /* while( v != s ) */ { if( v != r ) { incomFlow[ v ] -= cargo[ v ]; outgoFlow[ v ] -= cargo[ v ]; flow[ v ] -= cargo[ v ]; if( flow[ v ] == 0 ) { stek[ stekCount ] = v; stekCount ++; } } /* if( v != r ) */ if( v == s ) { cargo[ v ] = 0; } /* if( v == s ) */ else { int ofs; CvGraphVtx* hlpGraphVtx = cvGetGraphVtx( hlpGraph, v ); CvGraphEdge* hlpGraphEdge = hlpGraphVtx -> first; CvGraphEdge* hlpGraphEdge2 = NULL; while( hlpGraphEdge && cargo[ v ] > 0 ) { u = cvGraphVtxIdx( hlpGraph, hlpGraphEdge -> vtx[ 1 ] ); ofs = u == v; if( ofs ) { u = cvGraphVtxIdx( hlpGraph, hlpGraphEdge -> vtx[ 0 ] ); if( cargo[ u ] == 0 ) { order[ orderCount ] = u; orderCount ++; } int delta = ( ( Edge* )hlpGraphEdge ) -> weight - ( ( Edge* )hlpGraphEdge ) -> flow; delta = CV_MIN2( cargo[ v ], delta ); (( ( Edge* )hlpGraphEdge ) -> flow) += delta; cargo[ v ] -= delta; cargo[ u ] += delta; if( ( ( Edge* )hlpGraphEdge ) -> weight == ( ( Edge* )hlpGraphEdge ) -> flow ) { hlpGraphEdge2 = hlpGraphEdge -> next[ ofs ]; CvGraphEdge* graphEdge = cvFindGraphEdge( graph, u, v ); ( ( Edge* )graphEdge ) -> flow += ( ( Edge* )hlpGraphEdge ) -> flow; cvGraphRemoveEdgeByPtr( hlpGraph, hlpGraphEdge -> vtx[0], hlpGraphEdge -> vtx[1] ); } } /* if( ofs ) */ if( hlpGraphEdge2 ) { hlpGraphEdge = hlpGraphEdge2; hlpGraphEdge2 = NULL; } else { hlpGraphEdge = hlpGraphEdge -> next[ ofs ]; } } /* while( hlpGraphEdge && cargo[ v ] > 0 ) */ } /* if( v == s ) else */ v = order[ orderFirst ]; //added orderFirst ++; //added } while( v != s ); /* do */ } /* if( hlpGraph -> total > 2 ) */ } /* while( hlpGraph -> total > 2 ) */ } /* makePseudoMaxFlow */ // function oneStep produces one alpha-beta exchange for one line of images // leftLine - pointer to the left image line // rightLine - pointer to the right image line // alpha - label number one // beta - label number two // corr - pointer to correspondence array for this line // width - width of image line in pixels // mem - pointer to memory allocated by allocTempMem function // vertices - pointer to vertices array allocated by allocTempMem // function // storage - pointer to CvMemStorage structure bool oneStep( unsigned char* leftLine, unsigned char* rightLine, int alpha, int beta, int* corr, int width, int* mem, int* vertices, CvMemStorage* storage ) { CvGraph* graph = NULL; CvGraph* hlpGraph = NULL; CvMemStoragePos storagePos; int i; bool change = false; cvSaveMemStoragePos( storage, &storagePos ); int verticesCount; makeGraph( &graph, leftLine, rightLine, alpha, beta, corr, width, storage ); int s = graph -> total - 2; /* source vertex - alpha vertex */ //int t = graph -> total - 1; /* terminate vertex - beta vertex */ int length = makeHelpGraph( graph, &hlpGraph, storage, mem, vertices, &verticesCount, width ); while( length != INT_INFINITY ) { change = true; makePseudoMaxFlow( graph, hlpGraph, vertices, verticesCount, mem, width ); cvClearGraph( hlpGraph ); length = makeHelpGraph( graph, &hlpGraph, storage, mem, vertices, &verticesCount, width ); } /* while( length != INT_INFINITY ) */ int coord; CvGraphVtx* graphVtx; for( i = 0; i < s; i ++ ) { CvGraphEdge* graphEdge = cvFindGraphEdge( graph, s, i ); if( ( ( Edge* )graphEdge ) -> weight == ( ( Edge* )graphEdge ) -> flow ) { /* this vertex must have alpha label */ graphVtx = cvGetGraphVtx( graph, i ); coord = ( ( Vertex* )graphVtx )-> coord; if( corr[ coord ] != alpha ) { corr[ coord ] = alpha; //added change = true; } else { corr[ coord ] = alpha; } } /* if( ( ( Edge* )graphEdge ) -> weight == ... */ else { /* this vertex must have beta label */ graphVtx = cvGetGraphVtx( graph, i ); coord = ( ( Vertex* )graphVtx )-> coord; if( corr[ coord ] != beta ) { corr[ coord ] = beta; //added change = true; } else { corr[ coord ] = beta; } } /* if( ( ( Edge* )graphEdge ) -> weight == ... else */ } /* for( i = 0; i < s; i ++ ) */ cvClearGraph( hlpGraph ); cvClearGraph( graph ); cvRestoreMemStoragePos( storage, &storagePos ); return change; } /* oneStep */ // function initCorr fills correspondence array with initial values // corr - pointer to correspondence array for this line // width - width of image line in pixels // maxPixelDifference - maximum value of difference between the same // point painted on two images void initCorr( int* corr, int width, int maxPixelDifference ) { int i; int pixelDifferenceRange = maxPixelDifference * 2 + 1; for( i = 0; i < width; i ++ ) { corr[ i ] = i % pixelDifferenceRange - maxPixelDifference; } } /* initCorr */ // function oneLineCorr fully computes one line of images // leftLine - pointer to the left image line // rightLine - pointer to the right image line // corr - pointer to the correspondence array for one // line // mem - pointer to memory allocated by allocTempMem // function // vertices - pointer to memory allocated by allocTempMem // function // width - width of image line in pixels // maxPixelDifference - maximum value of pixel differences in pixels // storage - pointer to CvMemStorage struct which // contains memory storage void oneLineCorr( unsigned char* leftLine, unsigned char* rightLine, int* corr, int* mem, int* vertices, int width, int maxPixelDifference, CvMemStorage* storage ) { int result = 1; int count = 0; int i, j; initCorr( corr, width, maxPixelDifference ); while( result ) { result = 0; for( i = - maxPixelDifference; i < maxPixelDifference; i ++ ) for( j = i + 1; j <= maxPixelDifference; j ++ ) { result += (int)oneStep( leftLine, rightLine, i, j, corr, width, mem, vertices, storage ); } /* for( j = i + 1; j < width; j ++ ) */ count ++; if( count > /*0*//*1*/2 ) { break; } } /* while( result ) */ } /* oneLineCorr */ // function allLinesCorr computes all lines on the images // leftImage - pointer to the left image // leftLineStep - size of line on the left image in bytes // rightImage - pointer to the right image // rightLineStep - size of line on the right image in bytes // width - width of line in pixels // height - height of image in pixels // corr - pointer to correspondence array for all lines // maxPixelDifference - maximum value of difference between the same // point painted on two images // storage - pointer to CvMemStorage which contains memory // storage void allLinesCorr( unsigned char* leftImage, int leftLineStep, unsigned char* rightImage, int rightLineStep, int width, int height, int* corr, int maxPixelDifference, CvMemStorage* storage ) { int i; unsigned char* leftLine = leftImage; unsigned char* rightLine = rightImage; int* mem; int* vertices; allocTempMem( &mem, &vertices, width ); for( i = 0; i < height; i ++ ) { oneLineCorr( leftLine, rightLine, corr + i * width, mem, vertices, width, maxPixelDifference, storage ); leftLine += leftLineStep; rightLine += rightLineStep; } /* for( i = 0; i < height; i ++ ) */ freeTempMem( &mem, &vertices ); } /* allLinesCorr */ // This function produces morphing of two images into one image, which includes morphed // image or depth map // _leftImage - pointer to left image // _leftLineStep - size of line on left image in bytes // _rightImage - pointer to right image // _rightLineStep - size of line on right image in bytes // _resultImage - pointer to result morphed image // _resultLineStep - size of line on result image in bytes // _corrArray - pointer to array with correspondences // _numCorrArray - pointer to array with numbers correspondeces on each line // width - width of images // height - height of images // alpha - position of virtual camera ( 0 corresponds to left image, 1 - to right one ) // imageNeed - defines your wishes. if you want to see normal morphed image you have to set // this parameter to morphNormalImage ( this is default value ), else if you want // to see depth map you have to set this parameter to morphDepthMap and set the // next parameter ( maxPixelDifference ) to real value // maxPixelDifference - maximum value of pixel difference on two images void CCvGraphCutMorpher::Morph( unsigned char* _leftImage, int _leftLineStep, unsigned char* _rightImage, int _rightLineStep, unsigned char* _resultImage, int _resultLineStep, int* _corrArray, int width, int height, float alpha, morphImageType imageNeed, int maxDifference ) { unsigned char* leftArray = _leftImage; unsigned char* middleArray = _resultImage; unsigned char* rightArray = _rightImage; int leftLineSize = _leftLineStep; int middleLineSize = _resultLineStep; int rightLineSize = _rightLineStep; int lineNumber; unsigned char* leftTemp; unsigned char* middleTemp; unsigned char* rightTemp; int leftPixel; int prevLeftPixel; int middlePixel; int prevMiddlePixel; int rightPixel; int prevRightPixel; int leftPixel3; int middlePixel3; int rightPixel3; int i; int j; int tempIndex; int* result; int number; float alpha1 = 1.0f - alpha; for( lineNumber = 0; lineNumber < height; lineNumber ++ ) { leftTemp = leftArray + leftLineSize * lineNumber; middleTemp = middleArray + middleLineSize * lineNumber; rightTemp = rightArray + rightLineSize * lineNumber; memset( ( void* )middleTemp, 0, middleLineSize ); result = _corrArray + width * lineNumber; number = width; prevLeftPixel = 0; prevRightPixel = prevLeftPixel + result[ 0 ]; if( prevRightPixel >= width ) { prevRightPixel = width - 1; } else if ( prevRightPixel < 0 ) { prevRightPixel = 0; } prevMiddlePixel = (int)( prevLeftPixel * alpha1 + prevRightPixel * alpha ); for( i = 0; i < number - 1; i ++ ) { leftPixel = i; rightPixel = i + result[ i ]; if( rightPixel >= width ) { rightPixel = width - 1; } else if( rightPixel < 0 ) { rightPixel = 0; } middlePixel = (int)( leftPixel * alpha1 + rightPixel * alpha ); leftPixel3 = leftPixel * 3; middlePixel3 = middlePixel * 3; rightPixel3 = rightPixel * 3; if( imageNeed == morphDepthMap ) { int t = leftPixel - rightPixel + maxDifference; t = t < 0 ? -t : t; t = t * 255 / maxDifference / 2; middleTemp[ middlePixel3 ] = ( unsigned char )t; middleTemp[ middlePixel3 + 1 ] = ( unsigned char )t; middleTemp[ middlePixel3 + 2 ] = ( unsigned char )t; } // if( imageNeed == morphDepthMap ) else { middleTemp[ middlePixel3 ] = (unsigned char)( leftTemp[ leftPixel3 ] * alpha1 + rightTemp[ rightPixel3 ] * alpha ); middleTemp[ middlePixel3 + 1 ] = (unsigned char)( leftTemp[ leftPixel3 + 1 ] * alpha1 + rightTemp[ rightPixel3 + 1 ] * alpha ); middleTemp[ middlePixel3 + 2 ] = (unsigned char)( leftTemp[ leftPixel3 + 2 ] * alpha1 + rightTemp[ rightPixel3 + 2 ] * alpha ); if( middlePixel - prevMiddlePixel > 1 ) // occlusion { if( leftPixel - prevLeftPixel > 1 ) { int LenSrc = leftPixel - prevLeftPixel - 2; int LenDest = middlePixel - prevMiddlePixel - 1; for( j = prevMiddlePixel + 1; j < middlePixel; j ++ ) { tempIndex = prevLeftPixel + 1 + LenSrc * ( j - prevMiddlePixel - 1 ) / LenDest; middleTemp[ j * 3 ] = leftTemp[ tempIndex * 3 ]; middleTemp[ j * 3 + 1 ] = leftTemp[ tempIndex * 3 + 1 ]; middleTemp[ j * 3 + 2 ] = leftTemp[ tempIndex * 3 + 2 ]; } } // if( leftPixel - prevLeftPixel > 1 ) else { int LenSrc = rightPixel - prevRightPixel - 2; int LenDest = middlePixel - prevMiddlePixel - 1; for( j = prevMiddlePixel + 1; j < middlePixel; j ++ ) { tempIndex = prevRightPixel + 1 + LenSrc * ( j - prevMiddlePixel - 1 ) / LenDest; middleTemp[ j * 3 ] = rightTemp[ tempIndex * 3 ]; middleTemp[ j * 3 + 1 ] = rightTemp[ tempIndex * 3 + 1 ]; middleTemp[ j * 3 + 2 ] = rightTemp[ tempIndex * 3 + 2 ]; } } // if( leftPixel - prevLeftPixel > 1 ) else } // if( middlePixel - prevMiddlePixel > 1 ) } // if( imageNeed == morphDepthMap ) else if( middlePixel > prevMiddlePixel ) { if( leftPixel > prevLeftPixel ) prevLeftPixel = leftPixel; if( rightPixel > prevRightPixel ) prevRightPixel = rightPixel; prevMiddlePixel = middlePixel; } } // for( i = number - 1; i >= 0; i -- ) } // for( lineNumber = 0; lineNumber < LeftImage -> m_Raster -> GetHeight() ) } // Morph bool CCvGraphCutMorpher::OnCalculateStereo() { CvSize imageSizeLeft = GetImageSize( m_left_img ), imageSizeRight = GetImageSize( m_right_img ); if( ( imageSizeLeft.width != imageSizeRight.width ) || ( imageSizeLeft.height != imageSizeRight.height ) ) { return false; } if( m_corr ) { free( m_corr ); m_corr = NULL; } m_corr = ( int* ) malloc( m_left_img -> width * m_left_img -> height * sizeof( int ) ); if( !m_storage ) { m_storage = cvCreateMemStorage( 0 ); m_isStorageAllocated = true; } // Find correspondence for full image and store it to corr array allLinesCorr( ( unsigned char* )m_left_img -> imageData, m_left_img -> widthStep, ( unsigned char* )m_right_img -> imageData, m_right_img -> widthStep, m_left_img -> width, m_left_img -> height, m_corr, m_maxPixelDifference, m_storage ); m_isStereoReady = true; return true; } bool CCvGraphCutMorpher::OnCalculateVirtualImage() { // Output image to ResultImage window Morph( ( unsigned char* )m_left_img -> imageData, m_left_img ->widthStep, ( unsigned char* )m_right_img -> imageData, m_right_img -> widthStep, ( unsigned char* )m_virtual_img -> imageData, m_virtual_img -> widthStep, m_corr, m_left_img -> width, m_left_img -> height, m_pan ); m_isVirtualImageReady = true; return true; } bool CCvGraphCutMorpher::OnCalculateDisparity() { Morph( ( unsigned char* )m_left_img -> imageData, m_left_img ->widthStep, ( unsigned char* )m_right_img -> imageData, m_right_img -> widthStep, ( unsigned char* )m_disparity_img -> imageData, m_disparity_img -> widthStep, m_corr, m_left_img -> width, m_left_img -> height, m_pan, morphDepthMap, m_maxPixelDifference ); return true; } bool CCvGraphCutMorpher::OnCalculateDisparityImage() { Morph( ( unsigned char* )m_left_img -> imageData, m_left_img ->widthStep, ( unsigned char* )m_right_img -> imageData, m_right_img -> widthStep, ( unsigned char* )m_disparity_img -> imageData, m_disparity_img -> widthStep, m_corr, m_left_img -> width, m_left_img -> height, m_pan, morphDepthMap, m_maxPixelDifference ); return true; } CCvGraphCutMorpher::CCvGraphCutMorpher() { m_maxPixelDifference = MAX_DIFFERENCE; m_corr = 0; m_isStereoReady = false; m_isVirtualImageReady = false; m_isDisparityReady = false; m_storage = NULL; m_isStorageAllocated = false; } #endif /* End of file */