diff --git a/src/meshlabplugins/filter_feature_alignment/feature_alignment.h b/src/meshlabplugins/filter_feature_alignment/feature_alignment.h index 59414eaa2..b05f835b8 100644 --- a/src/meshlabplugins/filter_feature_alignment/feature_alignment.h +++ b/src/meshlabplugins/filter_feature_alignment/feature_alignment.h @@ -382,6 +382,7 @@ template class FeatureAlignment int totalTime; int baseSelectionTime; int matchingTime; + int branchBoundTime; int rankTime; int shortConsTime; int fullConsTime; @@ -403,6 +404,7 @@ template class FeatureAlignment shortConsTime = 0; fullConsTime = 0; baseSelectionTime = 0; + branchBoundTime = 0; rankTime = 0; errorMsg = "An unkown error occurred."; } @@ -501,6 +503,7 @@ template class FeatureAlignment //auxiliary vectors needed inside the loop vector* baseVec = new vector(); + vector > matches; vector* candidates = new vector(); //variables needed for progress bar callback @@ -518,15 +521,23 @@ template class FeatureAlignment res.baseSelectionTime = timer.elapsed(); if(param.log) param.log(3,"%i bases found in %i msec.", baseVec->size(), res.baseSelectionTime); - timer.start(); for(int i = 0; isize(); i++) { - int errCode = FeatureAlignment::Matching(*vecFFix, *vecFMov, fkdTree, (*baseVec)[i], *candidates, param); + timer.start(); + int errCode = FeatureAlignment::Matching(*vecFFix, *vecFMov, fkdTree, (*baseVec)[i], matches, param); + res.matchingTime+= timer.elapsed(); + + timer.start(); + errCode = FeatureAlignment::BranchAndBound((*baseVec)[i], matches, *candidates, param); + matches.clear(); //make matches vec ready for another iteration + res.branchBoundTime+= timer.elapsed(); + if(cb){ progBar+=(20.0f/baseVec->size()); cb(int(progBar),"Matching..."); } } - res.matchingTime = timer.elapsed(); res.numMatches = candidates->size(); - if(param.log) param.log(3,"%i candidates found in %i msec.", candidates->size(), res.matchingTime); + if(param.log) param.log(3,"%matching performed in %i msec.", res.matchingTime); + if(param.log) param.log(3,"%Branch&Bound performed in %i msec.", res.branchBoundTime); + if(param.log) param.log(3,"%i candidates found in %i msec.", candidates->size(), res.matchingTime+res.branchBoundTime); timer.start(); for(unsigned int j=0; jsize(); j++) @@ -546,12 +557,12 @@ template class FeatureAlignment if(cb){ progBar+=(20.0f/candidates->size()); cb(int(progBar),"Ranking candidates..."); } } + //sort candidates by summed point distances + sort(candidates->begin(), candidates->end(), CandidateType::SortByDistance); + res.rankTime = timer.elapsed(); if(param.log) param.log(3,"Ranking performed in %i msec.", res.rankTime); - //sort candidates by summed point distances - sort(candidates->begin(), candidates->end(), CandidateType::SortByDistance); -for(int i=0; i<50;i++)if(param.log) param.log(3,"%i spd %.2f.", i,(*candidates)[i].summedPointDist); //variable needed for progress bar callback float offset = (20.0f/math::Min(param.maxNumShortConsensus,int(candidates->size()))); @@ -565,15 +576,14 @@ for(int i=0; i<50;i++)if(param.log) param.log(3,"%i spd %.2f.", i,(*candidates)[ consParam.samples=param.short_cons_samples; consParam.threshold = param.shortConsOffset*param.overlap/100.0f; currCandidate.shortCons = cons.Check(consParam); //compute short consensus - if(param.log) param.log(3,"%i short cons %i.", j,currCandidate.shortCons); - ResetTransformation(mMov, oldTr); //restore old tranformation + ResetTransformation(mMov, oldTr); //restore old tranformation if(currCandidate.shortCons >= short_cons_succ) res.numWonShortCons++; //count how many won, and use this as bound later if(cb){ progBar+=offset; cb(int(progBar),"Short consensus..."); } } res.shortConsTime = timer.elapsed(); - if(param.log) param.log(3,"Short consensus performed in %i msec.", res.shortConsTime); + if(param.log) param.log(3,"%i short consensus performed in %i msec.",(param.maxNumShortConsensussize()))? param.maxNumShortConsensus : candidates->size(), res.shortConsTime); //sort candidates by short consensus sort(candidates->begin(), candidates->end(), CandidateType::SortByScore); @@ -591,8 +601,7 @@ for(int i=0; i<50;i++)if(param.log) param.log(3,"%i spd %.2f.", i,(*candidates)[ consParam.samples=param.fullConsensusSamples; consParam.threshold = param.consOffset*param.overlap/100.0f; consParam.bestScore = bestConsensus; - int consensus = cons.Check(consParam); //compute full consensus - if(param.log) param.log(3,"%i short cons %i.", j,consensus); + int consensus = cons.Check(consParam); //compute full consensus ResetTransformation(mMov, oldTr); //restore old tranformation if(consensus >= cons_succ) res.numWonFullCons++; @@ -612,7 +621,7 @@ for(int i=0; i<50;i++)if(param.log) param.log(3,"%i spd %.2f.", i,(*candidates)[ } res.fullConsTime = timer.elapsed(); res.totalTime = tot_timer.elapsed(); - if(param.log) param.log(3,"Full consensus performed in %i msec.", res.fullConsTime); + if(param.log) param.log(3,"%i full consensus performed in %i msec.", (param.maxNumFullConsensus& vecFFix, vector& vecFMov, ANNkd_tree* kdTree, FEATURE_TYPE** base, vector& candidates, Parameters& param, CallBackPos *cb=NULL) + static int Matching(vector& vecFFix, vector& vecFMov, ANNkd_tree* kdTree, FEATURE_TYPE** base, vector >& matches, Parameters& param, CallBackPos *cb=NULL) { float pBar = 0, offset = 100.0f/param.nBase; //used for progresss bar callback if(cb) cb(0, "Matching..."); - assert(param.k<=int(vecFFix.size())); //not enough features in kdtree to pick k neighboors - - //compute needed params - float errDist = param.mutualErrDist*(param.mMovBBoxDiag/100.0f); - + assert(param.k<=int(vecFFix.size())); //not enough features in kdtree to pick k neighbors assert((int)vecFFix.size()>=param.nBase); + assert(matches.size()==0); //matches vectors have to be provided empty //fill fqueryPts with feature's descriptions in base ANNpointArray fqueryPts; FeatureAlignment::SetupKDTreeQuery(base, param.nBase, &fqueryPts, FeatureType::getFeatureDimension()); //additional variables needed - ANNidxArray fnnIdx = new ANNidx[param.k]; // allocate near neigh indices + ANNidxArray fnnIdx = new ANNidx[param.k]; // allocate near neigh indices ANNdistArray fdists = new ANNdist[param.k]; // allocate near neigh dists - vector* >* matchedVec = new vector* >(); - + vector neighbors; //foreach feature in the base find the best matching using fkdTree for(int i = 0; i < param.nBase; i++) { @@ -808,30 +813,30 @@ for(int i=0; i<50;i++)if(param.log) param.log(3,"%i spd %.2f.", i,(*candidates)[ assert(fdists[0]!=ANN_DIST_INF); //if this check fails, it means that no feature have been found! - vector* matches = new vector(); - - for(int j=0; jpush_back(vecFFix[fnnIdx[j]]); //store all features - - matchedVec->push_back(matches); + for(int j=0; jsize())==param.nBase); - - //branch and bound - int* curSolution = new int[param.nBase]; - for(int i=0; i* >::iterator it=matchedVec->begin(); it!=matchedVec->end(); it++){ - if(*it!=NULL){ delete *it; *it = NULL; } - } - delete matchedVec; matchedVec = NULL; + return 0; + } + + static int BranchAndBound(FEATURE_TYPE** base, vector >& matches, vector& candidates, Parameters& param) + { + //compute needed params + float errDist = param.mutualErrDist*(param.mMovBBoxDiag/100.0f); + + //branch and bound + int curSolution[param.nBase]; + for(int i=0; i* >& matchedVec, int nBase, int level, int curSolution[], vector& candidates, float errDist, CallBackPos *cb = NULL) + static void Match(FEATURE_TYPE** base, vector >& matches, int nBase, int level, int curSolution[], vector& candidates, float errDist, CallBackPos *cb = NULL) { assert(levelsize(); j++){ + for(unsigned int j=0; j* >& matchedVec, int level, int curSolution[], float errDist) + static bool MatchSolution(FEATURE_TYPE** base, vector >& matches, int level, int curSolution[], float errDist) { if (level==0) return true; for(int j=0; jpos, base[j]->pos); - float distM = vcg::Distance((*(matchedVec[level]))[curSolution[level]]->pos, (*(matchedVec[j]))[curSolution[j]]->pos); + float distF = Distance(base[level]->pos, base[j]->pos); + float distM = Distance(matches[level][curSolution[level]]->pos, matches[j][curSolution[j]]->pos); if( math::Abs(distF-distM)>errDist) return false; } return true; diff --git a/src/meshlabplugins/filter_feature_alignment/filter_feature_alignment.cpp b/src/meshlabplugins/filter_feature_alignment/filter_feature_alignment.cpp index c8c6e0b2b..60c7a12f8 100644 --- a/src/meshlabplugins/filter_feature_alignment/filter_feature_alignment.cpp +++ b/src/meshlabplugins/filter_feature_alignment/filter_feature_alignment.cpp @@ -200,7 +200,7 @@ void FilterFeatureAlignment::initParameterSet(QAction *a, MeshDocument& md, Filt par.addEnum("featureType", 0, l,"Feature type:", "The feature that you want to compute for the current mesh."); par.addMesh("mFix", 0, "Fix mesh:", "The mesh that stays still and grow large after alignment."); par.addMesh("mMov", 1, "Move mesh:", "The mesh that moves to fit Fix Mesh."); - par.addInt("ransacIter", 5000, "Iterations:", "Number of iterations of the RANSAC algorithm. Greater values provides a greater success probability but requires more time."); + par.addInt("ransacIter", 500, "Iterations:", "Number of iterations of the RANSAC algorithm. Greater values provides a greater success probability but requires more time."); par.addFloat("overlap", 75.0, "Overlap:", "A measure, expressed in percentage, of how much Move Mesh overlaps with Fix Mesh. It is very important to provide an actual esteem: lower values can produce false positive results or too rough alignments; higher values produce a small success probability and no alignements at all."); par.addFloat("consensusDist", 2, "Consensus distance:","Consensus distance expressed in percentage of Move Mesh bounding box diagonal. It states how close two verteces must be to be in consensus."); par.addInt("k", 75, "Number of neighboors:", "Number of neighboor feature points picked by kNN search during matching. Greater values produce a greater success probability but make the alignment process slower."); @@ -211,6 +211,7 @@ void FilterFeatureAlignment::initParameterSet(QAction *a, MeshDocument& md, Filt { QStringList l; l << "GMSmooth curvature" + << "APSS curvature" << "RGB"; par.addEnum("featureType", 0, l,"Feature type:", "The feature that you want to compute for the current mesh."); par.addMesh("mFix", 0, "Fix mesh:", "The mesh that stays still and grow large after alignment."); @@ -219,9 +220,9 @@ void FilterFeatureAlignment::initParameterSet(QAction *a, MeshDocument& md, Filt par.addFloat("consensusDist", 2, "Consensus distance:","Consensus distance expressed in percentage of Move Mesh bounding box diagonal. It states how close two verteces must be to be in consensus."); par.addInt("k", 75, "Number of neighboors:", "Number of neighboor feature points picked by kNN search during matching. Greater values produce a greater success probability but make the alignment process slower."); par.addInt("trials", 100, "Trials:", "How many times the alignment process is repeated with the same amount of RANSAC iterations."); - par.addInt("from", 1000, "From iteration:", "Number of RANSAC iteration used to perform the first battery of alignments."); - par.addInt("to", 5000, "To iteration:", "Number of RANSAC iteration over which no more alignments are performed."); - par.addInt("step", 1000, "Step:", "Step used to increment RANSAC iterations after that the specified number of attempts has been done."); + par.addInt("from", 100, "From iteration:", "Number of RANSAC iteration used to perform the first battery of alignments."); + par.addInt("to", 1000, "To iteration:", "Number of RANSAC iteration over which no more alignments are performed."); + par.addInt("step", 100, "Step:", "Step used to increment RANSAC iterations after that the specified number of attempts has been done."); break; } default: assert(0); @@ -480,6 +481,15 @@ bool FilterFeatureAlignment::applyFilter(QAction *filter, MeshDocument &md, Filt return logResult(ID(filter), res, errorMessage); } case 1:{ + typedef APSSCurvatureFeature FeatureType; //define needed typedef FeatureType + typedef FeatureAlignment AlignerType; //define the Aligner class + typedef AlignerType::Result ResultType; + AlignerType::Parameters alignerParam(mFix->cm, mMov->cm); + setAlignmentParameters(mFix->cm, mMov->cm, par, alignerParam); + ResultType res = RansacDiagramOperation(*mFix, *mMov, alignerParam, trials, from, to, step, cb); + return logResult(ID(filter), res, errorMessage); + } + case 2:{ typedef FeatureRGB FeatureType; //define needed typedef FeatureType typedef FeatureAlignment AlignerType; //define the Aligner class typedef AlignerType::Result ResultType; @@ -550,6 +560,7 @@ typename ALIGNER_TYPE::Result FilterFeatureAlignment::MatchingOperation(MeshMode //create vectors to hold tuples of bases and matches vector* baseVec = new vector(); + vector > matches; vector* candidates = new vector(); AlignerType aligner; @@ -559,8 +570,8 @@ typename ALIGNER_TYPE::Result FilterFeatureAlignment::MatchingOperation(MeshMode //execute matching procedure with requested parameters; int errCode = AlignerType::SelectBase(*(aligner.vecFMov),*baseVec,param); if(errCode){ AlignerType::setError(errCode, res); return res; } - errCode = AlignerType::Matching(*(aligner.vecFFix), *(aligner.vecFMov), aligner.fkdTree, (*baseVec)[baseVec->size()-1], *candidates, param, cb); - if(errCode){ AlignerType::setError(errCode, res); return res; } + errCode = AlignerType::Matching(*(aligner.vecFFix), *(aligner.vecFMov), aligner.fkdTree, (*baseVec)[baseVec->size()-1], matches, param, cb); + errCode = AlignerType::BranchAndBound((*baseVec)[baseVec->size()-1], matches, *candidates, param); res.numMatches = candidates->size(); //store the numeber of matches found @@ -590,6 +601,7 @@ typename ALIGNER_TYPE::Result FilterFeatureAlignment::RigidTransformationOperati //create vectors to hold tuples of bases and matches vector* baseVec = new vector(); + vector > matches; vector* candidates = new vector(); AlignerType aligner; @@ -599,8 +611,8 @@ typename ALIGNER_TYPE::Result FilterFeatureAlignment::RigidTransformationOperati //execute matching procedure with requested parameters; int errCode = AlignerType::SelectBase(*(aligner.vecFMov),*baseVec,param); if(errCode){ AlignerType::setError(errCode, res); return res; } - errCode = AlignerType::Matching(*(aligner.vecFFix), *(aligner.vecFMov), aligner.fkdTree, (*baseVec)[baseVec->size()-1], *candidates, param, cb); - if(errCode){ AlignerType::setError(errCode, res); return res; } + errCode = AlignerType::Matching(*(aligner.vecFFix), *(aligner.vecFMov), aligner.fkdTree, (*baseVec)[baseVec->size()-1], matches, param, cb); + errCode = AlignerType::BranchAndBound((*baseVec)[baseVec->size()-1], matches, *candidates, param); res.numMatches = candidates->size(); //store the numeber of matches found assert(baseVec->size()==1); //now baseVec must hold exactly one base of features