/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::BuildGeodesicParametrization( GW_GeodesicMesh& Mesh ) { Mesh.RegisterForceStopCallbackFunction( FastMarchingCallbackFunction_Parametrization ); Mesh.ResetParametrizationData(); /* for each base vertex, perform front propagation on the surrounding faces */ for( GW_U32 i=0; i<this->GetNbrVertex(); ++i ) { CurrentTargetVertex_.clear(); pCurrentVoronoiVertex_ = (GW_VoronoiVertex*) this->GetVertex(i); // set up global data for callback function GW_ASSERT( pCurrentVoronoiVertex_!=NULL ); GW_OutputComment("Performing local fast marching."); this->PerformLocalFastMarching( Mesh, *pCurrentVoronoiVertex_ ); /* register geodesic boundaries length */ for( GW_VertexIterator it=pCurrentVoronoiVertex_->BeginVertexIterator(); it!=pCurrentVoronoiVertex_->EndVertexIterator(); ++it ) { GW_VoronoiVertex* pNeighbor = (GW_VoronoiVertex*) *it; GW_ASSERT( pNeighbor!=NULL ); GW_GeodesicVertex* pGeodesicVert = pNeighbor->GetBaseVertex(); GW_ASSERT( pGeodesicVert!=NULL ); GW_U32 nID = GW_Vertex::ComputeUniqueId( *pCurrentVoronoiVertex_, *pNeighbor ); if( GeodesicDistanceMap_.find(nID)==GeodesicDistanceMap_.end() ) { GW_ASSERT( pGeodesicVert->GetState()==GW_GeodesicVertex::kDead ); /* this is the first time the distance is computed */ if( pGeodesicVert->GetState()==GW_GeodesicVertex::kDead ) GeodesicDistanceMap_[nID] = pGeodesicVert->GetDistance(); } else { GW_ASSERT( pGeodesicVert->GetState()==GW_GeodesicVertex::kDead ); if( pGeodesicVert->GetState()==GW_GeodesicVertex::kDead ) { /* distance alreay computed in the reverse direction : take the average */ GW_Float rPrevDist = GeodesicDistanceMap_[nID]; GW_Float rNewDist = pGeodesicVert->GetDistance(); GeodesicDistanceMap_[nID] = GW_MIN(rPrevDist, rNewDist); //(rPrevDist+rNewDist)*0.5; } } } } /* now really compute the 3 parameters for each vertex */ GW_OutputComment("Computing geodesic parametrisation."); this->ComputeVertexParameters( Mesh ); pCurrentVoronoiVertex_ = NULL; Mesh.RegisterForceStopCallbackFunction( NULL ); }
/*------------------------------------------------------------------------------*/ GW_Bool GW_VoronoiMesh::FastMarchingCallbackFunction_Boundaries( GW_GeodesicVertex& CurVert ) { // \todo for the moment propagate on the full neighborhood // for( IT_VoronoiVertexList it=CurrentTargetVertex_.begin(); it!=CurrentTargetVertex_.end(); ++it ) // { GW_ASSERT( pCurrentVoronoiVertex_!=NULL ); for( GW_VertexIterator it=pCurrentVoronoiVertex_->BeginVertexIterator(); it!=pCurrentVoronoiVertex_->EndVertexIterator(); ++it ) { GW_VoronoiVertex* pVornoiVert = (GW_VoronoiVertex*) *it; GW_ASSERT( pVornoiVert!=NULL ); GW_GeodesicVertex* pVert = pVornoiVert->GetBaseVertex(); GW_ASSERT( pVert!=NULL ); if( pVert->GetState()!=GW_GeodesicVertex::kDead ) return GW_False; } return GW_True; }
/*------------------------------------------------------------------------------*/ GW_Vertex* GW_GeodesicMesh::GetRandomVertex(GW_Bool bForceFar) { GW_U32 nNumber = 0; GW_GeodesicVertex* pStartVertex = NULL; while( pStartVertex==NULL ) { if( nNumber>=this->GetNbrVertex()/10 ) return NULL; GW_U32 nNumVert = (GW_U32) floor(GW_RAND*this->GetNbrVertex()); pStartVertex = (GW_GeodesicVertex*) this->GetVertex( nNumVert ); if( bForceFar==GW_True && pStartVertex->GetState()!=GW_GeodesicVertex::kFar ) pStartVertex = NULL; if( pStartVertex!=NULL && pStartVertex->GetFace()==NULL ) pStartVertex = NULL; nNumber++; } return pStartVertex; }
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[] ) { nbr_iter = 0; /* retrive arguments */ if( nrhs<6 ) mexErrMsgTxt("6 or 7 input arguments are required."); if( nlhs<1 ) mexErrMsgTxt("1 or 2 output arguments are required."); // arg1 : vertex vertex = mxGetPr(prhs[0]); nverts = mxGetN(prhs[0]); if( mxGetM(prhs[0])!=3 ) mexErrMsgTxt("vertex must be of size 3 x nverts."); // arg2 : faces faces = mxGetPr(prhs[1]); nfaces = mxGetN(prhs[1]); if( mxGetM(prhs[1])!=3 ) mexErrMsgTxt("face must be of size 3 x nfaces."); // arg3 : W Ww = mxGetPr(prhs[2]); int m = mxGetM(prhs[2]); if( m!=nverts ) mexErrMsgTxt("W must be of same size as vertex."); // arg4 : start_points start_points = mxGetPr(prhs[3]); nstart = mxGetM(prhs[3]); // arg5 : end_points end_points = mxGetPr(prhs[4]); nend = mxGetM(prhs[4]); // arg6 : niter_max niter_max = (int) *mxGetPr(prhs[5]); // arg7 : H if( nrhs>=7 ) { H = mxGetPr(prhs[6]); int m =mxGetM(prhs[6]); if( m>0 && m!=nverts ) mexErrMsgTxt("H must be of size nverts."); if( m==0 ) H = NULL; } else { H = NULL; } // arg8 : L if( nrhs>=8 ) { L = mxGetPr(prhs[7]); int m =mxGetM(prhs[7]); if( m>0 && mxGetM(prhs[7])!=nverts ) mexErrMsgTxt("L must be of size nverts."); if( m==0 ) L = NULL; } else L = NULL; // argument 9: value list if( nrhs>=9 ) { values = mxGetPr(prhs[8]); if( mxGetM(prhs[8])==0 && mxGetN(prhs[8])==0 ) values=NULL; if( values!=NULL && (mxGetM(prhs[8])!=nstart || mxGetN(prhs[8])!=1) ) mexErrMsgTxt("values must be of size nb_start_points x 1."); } else values = NULL; // argument 10: dmax if( nrhs>=9 ) dmax = *mxGetPr(prhs[9]); else dmax = 1e9; // first ouput : distance plhs[0] = mxCreateDoubleMatrix(nverts, 1, mxREAL); D = mxGetPr(plhs[0]); // second output : state plhs[1] = mxCreateDoubleMatrix(nverts, 1, mxREAL); S = mxGetPr(plhs[1]); // second output : segmentation plhs[2] = mxCreateDoubleMatrix(nverts, 1, mxREAL); Q = mxGetPr(plhs[2]); // create the mesh GW_GeodesicMesh Mesh; Mesh.SetNbrVertex(nverts); for( int i=0; i<nverts; ++i ) { GW_GeodesicVertex& vert = (GW_GeodesicVertex&) Mesh.CreateNewVertex(); vert.SetPosition( GW_Vector3D(vertex_(0,i),vertex_(1,i),vertex_(2,i)) ); Mesh.SetVertex(i, &vert); } Mesh.SetNbrFace(nfaces); for( int i=0; i<nfaces; ++i ) { GW_GeodesicFace& face = (GW_GeodesicFace&) Mesh.CreateNewFace(); GW_Vertex* v1 = Mesh.GetVertex((int) faces_(0,i)); GW_ASSERT( v1!=NULL ); GW_Vertex* v2 = Mesh.GetVertex((int) faces_(1,i)); GW_ASSERT( v2!=NULL ); GW_Vertex* v3 = Mesh.GetVertex((int) faces_(2,i)); GW_ASSERT( v3!=NULL ); face.SetVertex( *v1,*v2,*v3 ); Mesh.SetFace(i, &face); } Mesh.BuildConnectivity(); // set up fast marching Mesh.ResetGeodesicMesh(); for( int i=0; i<nstart; ++i ) { GW_GeodesicVertex* v = (GW_GeodesicVertex*) Mesh.GetVertex((GW_U32) start_points[i]); GW_ASSERT( v!=NULL ); Mesh.AddStartVertex( *v ); } Mesh.SetUpFastMarching(); Mesh.RegisterWeightCallbackFunction( WeightCallback ); Mesh.RegisterForceStopCallbackFunction( StopMarchingCallback ); Mesh.RegisterVertexInsersionCallbackFunction( InsersionCallback ); if( H!=NULL ) Mesh.RegisterHeuristicToGoalCallbackFunction( HeuristicCallback ); // initialize the distance of the starting points if( values!=NULL ) for( int i=0; i<nstart; ++i ) { GW_GeodesicVertex* v = (GW_GeodesicVertex*) Mesh.GetVertex((GW_U32) start_points[i]); GW_ASSERT( v!=NULL ); v->SetDistance( values[i] ); } // perform fast marching // display_message("itermax=%d", niter_max); Mesh.PerformFastMarching(); // output result for( int i=0; i<nverts; ++i ) { GW_GeodesicVertex* v = (GW_GeodesicVertex*) Mesh.GetVertex((GW_U32) i); GW_ASSERT( v!=NULL ); D[i] = v->GetDistance(); S[i] = v->GetState(); GW_GeodesicVertex* v1 = v->GetFront(); if( v1==NULL ) Q[i] = -1; else Q[i] = v1->GetID(); } return; }
/*------------------------------------------------------------------------------*/ void GW_VoronoiMesh::BuildGeodesicBoundaries( GW_GeodesicMesh& Mesh ) { Mesh.RegisterForceStopCallbackFunction( FastMarchingCallbackFunction_Boundaries ); VertexPathMap_.clear(); GeodesicDistanceMap_.clear(); BoundaryEdgeMap_.clear(); for( GW_U32 i=0; i<this->GetNbrVertex(); ++i ) { CurrentTargetVertex_.clear(); pCurrentVoronoiVertex_ = (GW_VoronoiVertex*) this->GetVertex(i); GW_ASSERT( pCurrentVoronoiVertex_!=NULL ); /* set the list of vertex to which the boundary needs to be computed */ for( GW_VertexIterator it=pCurrentVoronoiVertex_->BeginVertexIterator(); it!=pCurrentVoronoiVertex_->EndVertexIterator(); ++it ) { GW_VoronoiVertex* pVert = (GW_VoronoiVertex*) *it; GW_ASSERT( pVert!=NULL ); GW_U32 nID = GW_Vertex::ComputeUniqueId( *pCurrentVoronoiVertex_, *pVert ); if( VertexPathMap_.find( nID )==VertexPathMap_.end() ) CurrentTargetVertex_.push_back( pVert ); } /* compute fast marching */ GW_GeodesicVertex* pGeodesicVert = pCurrentVoronoiVertex_->GetBaseVertex(); GW_ASSERT( pGeodesicVert!=NULL ); Mesh.ResetGeodesicMesh(); GW_OutputComment("Performing Fast Marching."); Mesh.PerformFastMarching( pGeodesicVert ); /* track back and compute geodesic path */ for( IT_VoronoiVertexList it=CurrentTargetVertex_.begin(); it!=CurrentTargetVertex_.end(); ++it ) { GW_VoronoiVertex* pVert = *it; GW_ASSERT( pVert!=NULL ); GW_GeodesicVertex* pGeodesicVert = pVert->GetBaseVertex(); GW_ASSERT( pGeodesicVert!=NULL ); GW_ASSERT( pGeodesicVert->GetState()==GW_GeodesicVertex::kDead ); GW_U32 nID = GW_Vertex::ComputeUniqueId( *pCurrentVoronoiVertex_, *pVert ); GW_ASSERT( VertexPathMap_.find( nID ) ==VertexPathMap_.end() ); T_GeodesicVertexList* pVertexGeodesicEdge = new T_GeodesicVertexList; VertexPathMap_[nID] = pVertexGeodesicEdge; /* track back and compute the path */ GW_OutputComment("Computing geodesic path."); GW_GeodesicPath GeodesicPath; GeodesicPath.ComputePath( *pGeodesicVert, 5000 ); /* convert the path into vertex */ this->AddPathToMeshVertex( Mesh, GeodesicPath, *pVertexGeodesicEdge ); } } /* \todo This is just a debug test, remove it */ for( IT_VertexPathMap it = VertexPathMap_.begin(); it!=VertexPathMap_.end(); ++it ) { T_GeodesicVertexList* pPath = it->second; GW_GeodesicVertex* pPrevVert = NULL; GW_U32 nNum = 0; for( IT_GeodesicVertexList itVert = pPath->begin(); itVert!=pPath->end(); ++itVert ) { GW_GeodesicVertex* pVert = *itVert; if( pPrevVert==NULL ) pPrevVert = pVert; else { GW_Face* pFace1, *pFace2; pPrevVert->GetFaces( *pVert, pFace1, pFace2 ); // GW_ASSERT( pFace1!=NULL || pFace2!=NULL ) // \todo FIX THIS BUG if( pFace1!=NULL || pFace2!=NULL ) { // cout << "Gap in a geodesic boundary." << endl; } pPrevVert = pVert; } nNum++; } } Mesh.RegisterForceStopCallbackFunction( NULL ); Mesh.ResetGeodesicMesh(); }