branch:
details: http://hugin.hg.sourceforge.net/hgweb/hugin/hugin/hgroot/hugin/hugin/rev/d82c6a3fc1c2
changeset: 5745:d82c6a3fc1c2
user: tmodes
date: Sun Mar 18 09:04:50 2012 +0100
description:
Cpfind: Add prealign matching strategy
diffstat:
src/hugin_cpfind/cpfind/PanoDetector.cpp | 200 +++++++++++++++++++-----------
src/hugin_cpfind/cpfind/PanoDetector.h | 46 ++++--
src/hugin_cpfind/cpfind/main.cpp | 87 +++++++++----
3 files changed, 215 insertions(+), 118 deletions(-)
diffs (truncated from 532 to 500 lines):
diff -r babf1fca3074 -r d82c6a3fc1c2 src/hugin_cpfind/cpfind/PanoDetector.cpp
--- a/src/hugin_cpfind/cpfind/PanoDetector.cpp Sun Mar 18 08:55:16 2012 +0100
+++ b/src/hugin_cpfind/cpfind/PanoDetector.cpp Sun Mar 18 09:04:50 2012 +0100
@@ -113,8 +113,9 @@
_sieve1Width(10), _sieve1Height(10), _sieve1Size(100),
_kdTreeSearchSteps(200), _kdTreeSecondDistance(0.25), _ransacIters(1000), _ransacDistanceThres(50),
_sieve2Width(5), _sieve2Height(5),_sieve2Size(1), _test(false), _cores(utils::getCPUCount()),
- _minimumMatches(6), _linearMatch(false), _linearMatchLen(1), _downscale(true), _cache(false), _cleanup(false),
- _keypath(""), _outputFile("default.pto"), _outputGiven(false), _celeste(false), _celesteThreshold(0.5), _celesteRadius(20), _multirow(false)
+ _minimumMatches(6), _linearMatchLen(1), _downscale(true), _cache(false), _cleanup(false),
+ _keypath(""), _outputFile("default.pto"), _outputGiven(false), _celeste(false), _celesteThreshold(0.5), _celesteRadius(20),
+ _matchingStrategy(ALLPAIRS)
{
_panoramaInfo = new Panorama();
}
@@ -129,12 +130,6 @@
return false;
}
- if(_linearMatch && _multirow)
- {
- std::cout << "Linear match and multi row matching strategy does not work together." << std::endl;
- return false;
- };
-
// check the test mode
if (_test)
{
@@ -185,20 +180,20 @@
cout << " Search steps : " << _kdTreeSearchSteps << endl;
cout << " Second match distance : " << _kdTreeSecondDistance << endl;
cout << "Matching Options" << endl;
- if(_linearMatch)
+ switch(_matchingStrategy)
{
- cout << " Mode : Linear match with length of " << _linearMatch << " image" << endl;
- }
- else
- {
- if(_multirow)
- {
+ case ALLPAIRS:
+ cout << " Mode : All pairs" << endl;
+ break;
+ case LINEAR:
+ cout << " Mode : Linear match with length of " << _linearMatchLen << " image" << endl;
+ break;
+ case MULTIROW:
cout << " Mode : Multi row" << endl;
- }
- else
- {
- cout << " Mode : All pairs" << endl;
- };
+ break;
+ case PREALIGNED:
+ cout << " Mode : Prealigned positions" << endl;
+ break;
};
cout << " Distance threshold : " << _ransacDistanceThres << endl;
cout << "RANSAC Options" << endl;
@@ -577,19 +572,47 @@
// Detect matches if writeKeyPoints wasn't set
if(_keyPointsIdx.size() == 0)
{
- if(_multirow)
+ switch (getMatchingStrategy())
{
- if(!matchMultiRow(aExecutor))
- {
- return;
- };
- }
- else
- {
- if(!match(aExecutor))
- {
- return;
- };
+ case ALLPAIRS:
+ case LINEAR:
+ if(!match(aExecutor))
+ {
+ return;
+ };
+ break;
+ case MULTIROW:
+ if(!matchMultiRow(aExecutor))
+ {
+ return;
+ };
+ break;
+ case PREALIGNED:
+ {
+ //check, which image pairs are already connected by control points
+ std::vector<HuginBase::UIntSet> connectedImages(_panoramaInfo->getNrOfImages());
+ HuginBase::CPVector cps=_panoramaInfo->getCtrlPoints();
+ for(HuginBase::CPVector::const_iterator it=cps.begin();it!=cps.end(); it++)
+ {
+ if((*it).mode==HuginBase::ControlPoint::X_Y)
+ {
+ connectedImages[(*it).image1Nr].insert((*it).image2Nr);
+ connectedImages[(*it).image2Nr].insert((*it).image1Nr);
+ };
+ };
+ //build dummy map
+ std::vector<size_t> imgMap(_panoramaInfo->getNrOfImages());
+ for(size_t i=0; i<_panoramaInfo->getNrOfImages(); i++)
+ {
+ imgMap[i]=i;
+ };
+ //and the final matching step
+ if(!matchPrealigned(aExecutor,_panoramaInfo, connectedImages, imgMap))
+ {
+ return;
+ };
+ }
+ break;
};
}
@@ -821,7 +844,7 @@
void PanoDetector::prepareMatches()
{
unsigned int aLen = _filesData.size();
- if (_linearMatch)
+ if (getMatchingStrategy()==LINEAR)
{
aLen = _linearMatchLen;
}
@@ -869,6 +892,7 @@
bool PanoDetector::matchMultiRow(PoolExecutor& aExecutor)
{
//step 1
+ std::vector<HuginBase::UIntSet> checkedImagePairs(_panoramaInfo->getNrOfImages());
std::vector<stack_img> stack_images;
HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(*_panoramaInfo);
for(unsigned int i=0; i<_panoramaInfo->getNrOfImages(); i++)
@@ -901,7 +925,7 @@
};
delete variable_groups;
//get image with median exposure for search with cp generator
- vector<unsigned int> images_layer;
+ vector<size_t> images_layer;
UIntSet images_layer_set;
for(unsigned int i=0; i<stack_images.size(); i++)
{
@@ -918,10 +942,14 @@
//build match list for stacks
for(unsigned int j=0; j<stack_images[i].images.size()-1; j++)
{
+ size_t img1=stack_images[i].images[j].img_nr;
+ size_t img2=stack_images[i].images[j+1].img_nr;
_matchesData.push_back(MatchData());
MatchData& aM=_matchesData.back();
- aM._i1=&(_filesData[stack_images[i].images[j].img_nr]);
- aM._i2=&(_filesData[stack_images[i].images[j+1].img_nr]);
+ aM._i1=&(_filesData[img1]);
+ aM._i2=&(_filesData[img2]);
+ checkedImagePairs[img1].insert(img2);
+ checkedImagePairs[img2].insert(img1);
};
};
};
@@ -930,10 +958,14 @@
{
for(unsigned int i=0; i<images_layer.size()-1; i++)
{
+ size_t img1=images_layer[i];
+ size_t img2=images_layer[i+1];
_matchesData.push_back(MatchData());
MatchData& aM = _matchesData.back();
- aM._i1 = &(_filesData[images_layer[i]]);
- aM._i2 = &(_filesData[images_layer[i+1]]);
+ aM._i1 = &(_filesData[img1]);
+ aM._i2 = &(_filesData[img2]);
+ checkedImagePairs[img1].insert(img2);
+ checkedImagePairs[img2].insert(img1);
};
};
TRACE_INFO(endl<< "--- Find matches ---" << endl);
@@ -976,10 +1008,19 @@
{
for(unsigned int j=i+1; j<ImagesGroups.size(); j++)
{
+ size_t img1=ImagesGroups[i];
+ size_t img2=ImagesGroups[j];
+ //skip already checked image pairs
+ if(set_contains(checkedImagePairs[img1],img2))
+ {
+ continue;
+ };
_matchesData.push_back(MatchData());
MatchData& aM = _matchesData.back();
- aM._i1 = &(_filesData[ImagesGroups[i]]);
- aM._i2 = &(_filesData[ImagesGroups[j]]);
+ aM._i1 = &(_filesData[img1]);
+ aM._i2 = &(_filesData[img2]);
+ checkedImagePairs[img1].insert(img2);
+ checkedImagePairs[img2].insert(img1);
};
};
TRACE_INFO(endl<< "--- Find matches in images groups ---" << endl);
@@ -1068,40 +1109,57 @@
PT_setInfoDlgFcn(NULL);
};
- HuginBase::CalculateImageOverlap overlap(&optPano);
- overlap.calculate(10);
- for(unsigned int i=0; i<images_layer.size()-2; i++)
+ //now match overlapping images
+ if(!matchPrealigned(aExecutor, &optPano, checkedImagePairs, images_layer))
{
- for(unsigned int j=i+2; j<images_layer.size(); j++)
- {
- if(overlap.getOverlap(i,j)>0)
- {
- _matchesData.push_back(MatchData());
- MatchData& aM = _matchesData.back();
- aM._i1 = &(_filesData[images_layer[i]]);
- aM._i2 = &(_filesData[images_layer[j]]);
- };
- };
+ return false;
};
- TRACE_INFO(endl<< "--- Find matches for overlapping images ---" << endl);
- try
- {
- BOOST_FOREACH(MatchData& aMD, _matchesData)
- aExecutor.execute(new MatchDataRunnable(aMD, *this));
- aExecutor.wait();
- }
- catch(Synchronization_Exception& e)
- {
- TRACE_ERROR(e.what() << endl);
- return false;
- }
-
- // Add detected matches to _panoramaInfo
- BOOST_FOREACH(MatchData& aM, _matchesData)
- BOOST_FOREACH(lfeat::PointMatchPtr& aPM, aM._matches)
- _panoramaInfo->addCtrlPoint(ControlPoint(aM._i1->_number, aPM->_img1_x, aPM->_img1_y,
- aM._i2->_number, aPM->_img2_x, aPM->_img2_y));
};
return true;
};
+bool PanoDetector::matchPrealigned(PoolExecutor& aExecutor, Panorama* pano, std::vector<HuginBase::UIntSet> &connectedImages, std::vector<size_t> imgMap)
+{
+ HuginBase::CalculateImageOverlap overlap(pano);
+ overlap.calculate(10);
+ for(size_t i=0; i<pano->getNrOfImages()-1; i++)
+ {
+ for(size_t j=i+1; j<pano->getNrOfImages(); j++)
+ {
+ if(set_contains(connectedImages[imgMap[i]],imgMap[j]))
+ {
+ continue;
+ };
+ if(overlap.getOverlap(i,j)>0)
+ {
+ _matchesData.push_back(MatchData());
+ MatchData& aM = _matchesData.back();
+ aM._i1 = &(_filesData[imgMap[i]]);
+ aM._i2 = &(_filesData[imgMap[j]]);
+ connectedImages[imgMap[i]].insert(imgMap[j]);
+ connectedImages[imgMap[j]].insert(imgMap[i]);
+ };
+ };
+ };
+
+ TRACE_INFO(endl<< "--- Find matches for overlapping images ---" << endl);
+ try
+ {
+ BOOST_FOREACH(MatchData& aMD, _matchesData)
+ aExecutor.execute(new MatchDataRunnable(aMD, *this));
+ aExecutor.wait();
+ }
+ catch(Synchronization_Exception& e)
+ {
+ TRACE_ERROR(e.what() << endl);
+ return false;
+ }
+
+ // Add detected matches to _panoramaInfo
+ BOOST_FOREACH(MatchData& aM, _matchesData)
+ BOOST_FOREACH(lfeat::PointMatchPtr& aPM, aM._matches)
+ _panoramaInfo->addCtrlPoint(ControlPoint(imgMap[aM._i1->_number], aPM->_img1_x, aPM->_img1_y,
+ imgMap[aM._i2->_number], aPM->_img2_x, aPM->_img2_y));
+
+ return true;
+};
diff -r babf1fca3074 -r d82c6a3fc1c2 src/hugin_cpfind/cpfind/PanoDetector.h
--- a/src/hugin_cpfind/cpfind/PanoDetector.h Sun Mar 18 08:55:16 2012 +0100
+++ b/src/hugin_cpfind/cpfind/PanoDetector.h Sun Mar 18 09:04:50 2012 +0100
@@ -57,15 +57,32 @@
typedef lfeat::KeyPointDetector KeyPointDetector;
+ /** for selecting matching strategy */
+ enum MatchingStrategy
+ {
+ ALLPAIRS=0,
+ LINEAR,
+ MULTIROW,
+ PREALIGNED
+ };
+
PanoDetector();
- bool checkData();
- void printDetails();
+ bool checkData();
+ void printDetails();
void printFilenames();
- void printHelp();
- void run();
+ void printHelp();
+ void run();
bool match(ZThread::PoolExecutor& aExecutor);
bool matchMultiRow(ZThread::PoolExecutor& aExecutor);
+ /** does only matches image pairs which overlaps and don't have control points
+ @param aExecutor executor for threading
+ @param pano pano, which should be used for determing of overlap, can contain also less images than _panoramaInfo
+ @param connectedImages contains a list of already connected or tested image pairs, which should be skipped
+ @param imgMap map of image nr in partial pano and full panorama
+ @return true, if detection was successful
+ */
+ bool matchPrealigned(ZThread::PoolExecutor& aExecutor, Panorama* pano, std::vector<HuginBase::UIntSet> &connectedImages, std::vector<size_t> imgMap);
// accessors
@@ -180,7 +197,7 @@
{
return _ransacDistanceThres;
}
- inline RANSACOptimizer::Mode setRansacMode()
+ inline RANSACOptimizer::Mode getRansacMode()
{
return _ransacMode;
}
@@ -210,29 +227,21 @@
return _sieve2Size;
}
- inline void setLinearMatch(bool iLin)
- {
- _linearMatch = iLin;
- }
inline void setLinearMatchLen(int iLen)
{
_linearMatchLen = iLen;
}
- inline bool getLinearMatch() const
- {
- return _linearMatch;
- }
inline int getLinearMatchLen() const
{
return _linearMatchLen;
}
- inline void setMultiRow(bool iMultirow)
+ inline void setMatchingStrategy(MatchingStrategy iMatchStrategy)
{
- _multirow = iMultirow;
+ _matchingStrategy = iMatchStrategy;
}
- inline bool getMultiRow() const
+ inline MatchingStrategy getMatchingStrategy() const
{
- return _multirow;
+ return _matchingStrategy;
}
inline bool getDownscale() const
@@ -341,9 +350,8 @@
int _sieve2Height;
int _sieve2Size;
- bool _linearMatch;
+ MatchingStrategy _matchingStrategy;
int _linearMatchLen;
- bool _multirow;
bool _test;
int _cores;
diff -r babf1fca3074 -r d82c6a3fc1c2 src/hugin_cpfind/cpfind/main.cpp
--- a/src/hugin_cpfind/cpfind/main.cpp Sun Mar 18 08:55:16 2012 +0100
+++ b/src/hugin_cpfind/cpfind/main.cpp Sun Mar 18 09:04:50 2012 +0100
@@ -39,7 +39,6 @@
virtual void failure(CmdLineInterface& c, ArgException& e)
{
std::cerr << "Parse error: " << e.argId() << std::endl << " " << e.error() << std::endl << std::endl << endl;
- usage(c);
}
virtual void usage(CmdLineInterface& c)
@@ -99,24 +98,35 @@
SwitchArg aArgQuiet("q","quiet", "Do not output progress\n", false);
SwitchArg aArgVerbose("v","verbose", "Increase verbosity of output\n", false);
- SwitchArg aArgFullScale("","fullscale", "Uses full scale image to detect keypoints (default:false)\n", false);
- ValueArg<int> aArgSieve1Width("","sieve1width", "Sieve 1 : Number of buckets on width (default : 10)", false, 10, "int");
- ValueArg<int> aArgSieve1Height("","sieve1height", "Sieve 1 : Number of buckets on height (default : 10)", false, 10, "int");
- ValueArg<int> aArgSieve1Size("","sieve1size", "Sieve 1 : Max points per bucket (default : 100)\n", false, 100, "int");
- SwitchArg aArgLinearMatch("","linearmatch", "Enable linear images matching (default : all pairs)", false);
- ValueArg<int> aArgLinearMatchLen("","linearmatchlen", "Number of images to match in linear matching (default:1)\n", false, 1 ,"int");
- SwitchArg aArgMultiRow("","multirow", "Enable heuristic multi row matching (default: off)",false);
+ SwitchArg aArgFullScale("","fullscale", "Uses full scale image to detect keypoints\t(default:false)\n", false);
+ ValueArg<int> aArgSieve1Width("","sieve1width", "Sieve 1: Number of buckets on width\t(default: 10)", false, 10, "int");
+ ValueArg<int> aArgSieve1Height("","sieve1height", "Sieve 1: Number of buckets on height\t(default: 10)", false, 10, "int");
+ ValueArg<int> aArgSieve1Size("","sieve1size", "Sieve 1: Max points per bucket (default: 100)\n", false, 100, "int");
- ValueArg<int> aArgKDTreeSearchSteps("","kdtreesteps", "KDTree : search steps (default : 200)", false, 200, "int");
- ValueArg<double> aArgKDTreeSecondDist("","kdtreeseconddist", "KDTree : distance of 2nd match (default : 0.25)\n", false, 0.25, "double");
- ValueArg<int> aArgMinMatches("","minmatches", "Minimum matches (default : 6)", false, 6, "int");
- ValueArg<std::string> aArgRansacMode("","ransacmode", "Ransac : mode (auto, hom, rpy, rpyv, rpyvb (default : auto)", false, "auto", "string");
- ValueArg<int> aArgRansacIter("","ransaciter", "Ransac : iterations (default : 1000)", false, 1000, "int");
- ValueArg<int> aArgRansacDist("","ransacdist", "Ransac : homography estimation distance threshold (pixels)"
- "\t (default : 50)", false, 50, "int");
- ValueArg<int> aArgSieve2Width("","sieve2width", "Sieve 2 : Number of buckets on width (default : 5)", false, 5, "int");
- ValueArg<int> aArgSieve2Height("","sieve2height", "Sieve 2 : Number of buckets on height (default : 5)", false, 5, "int");
- ValueArg<int> aArgSieve2Size("","sieve2size", "Sieve 2 : Max points per bucket (default : 1)\n", false, 1 ,"int");
+ SwitchArg aArgLinearMatch("","linearmatch", "Enable linear images matching (default: off)", false);
+ ValueArg<int> aArgLinearMatchLen("","linearmatchlen", "Number of images to match in linear matching\t(default: 1)\n", false, 1 ,"int");
+ SwitchArg aArgMultiRow("","multirow", "Enable heuristic multi row matching\t(default: off)",false);
+ SwitchArg aArgPreAligned("", "prealigned", "Match only overlapping images\trequires a rough aligned panorama. (default: off)",false);
+
+ ValueArg<int> aArgKDTreeSearchSteps("","kdtreesteps", "KDTree search steps (default: 200)", false, 200, "int");
+ ValueArg<double> aArgKDTreeSecondDist("","kdtreeseconddist", "KDTree: distance of 2nd match (default: 0.25)\n", false, 0.25, "double");
+ ValueArg<int> aArgMinMatches("","minmatches", "Minimum matches (default: 6)", false, 6, "int");
+
+ std::vector<std::string> allowedRansacMode;
+ allowedRansacMode.push_back("auto");
+ allowedRansacMode.push_back("hom");
+ allowedRansacMode.push_back("rpy");
+ allowedRansacMode.push_back("rpyv");
+ allowedRansacMode.push_back("rpyvb");
+ ValuesConstraint<string> allowedRansacVals(allowedRansacMode);
+ ValueArg<std::string> aArgRansacMode("","ransacmode", "Ransac mode (default: auto)\n", false, "auto", &allowedRansacVals);
+ ValueArg<int> aArgRansacIter("","ransaciter", "Ransac iterations (default: 1000)", false, 1000, "int");
+ ValueArg<int> aArgRansacDist("","ransacdist", "Ransac: homography estimation distance threshold \t(in pixels) "
+ "(default: 50)", false, 50, "int");
+
+ ValueArg<int> aArgSieve2Width("","sieve2width", "Sieve 2: Number of buckets on width (default: 5)", false, 5, "int");
+ ValueArg<int> aArgSieve2Height("","sieve2height", "Sieve 2: Number of buckets on height (default: 5)", false, 5, "int");
+ ValueArg<int> aArgSieve2Size("","sieve2size", "Sieve 2: Max points per bucket (default: 1)\n", false, 1 ,"int");
cmd.add(aArgQuiet);
cmd.add(aArgVerbose);
@@ -130,6 +140,7 @@
cmd.add(aArgLinearMatchLen);
cmd.add(aArgLinearMatch);
cmd.add(aArgMultiRow);
+ cmd.add(aArgPreAligned);
cmd.add(aArgKDTreeSecondDist);
cmd.add(aArgKDTreeSearchSteps);
cmd.add(aArgSieve1Size);
@@ -140,10 +151,10 @@
SwitchArg aArgTest("t","test", "Enables test mode\n", false);
cmd.add( aArgTest );
- ValueArg<int> aArgCores("n","ncores", "Number of CPU/Cores (default:autodetect)", false, utils::getCPUCount(), "int");
+ ValueArg<int> aArgCores("n","ncores", "Number of CPU/Cores (default:autodetect)", false, utils::getCPUCount(), "int");
cmd.add( aArgCores );
- UnlabeledValueArg<string> aArgInputFile("fileName", "Input Project File", true, "default","string");
+ UnlabeledValueArg<string> aArgInputFile("filename", "Input Project File", true, "default","string");
cmd.add( aArgInputFile );
ValueArg<string> aArgOutputFile("o","output","Output file",false, "default", "string");
@@ -164,7 +175,7 @@
ValueArg<string> aArgKeypath("p","keypath","Path to cache keyfiles",false,"","string");
cmd.add(aArgKeypath);
- SwitchArg aArgCeleste("","celeste", "Run celeste after loading images",false);
+ SwitchArg aArgCeleste("","celeste", "Run celeste after loading images\n",false);
cmd.add(aArgCeleste);
ValueArg<double> aArgCelesteThreshold("","celesteThreshold","Threshold for celeste (default 0.5)",false,0.5,"double");
cmd.add(aArgCelesteThreshold);
@@ -183,7 +194,8 @@
}
else
{
- cout << "ERROR: Input project file is missing." << endl;
+ // can also be happen with invalid command line parameters, does not show message
+ // cout << "ERROR: Input project file is missing." << endl;
return false;
}
if (aArgOutputFile.isSet())
@@ -274,16 +286,35 @@
}
if (aArgLinearMatch.isSet())
{
- ioPanoDetector.setLinearMatch(aArgLinearMatch.getValue());
- }
+ if(aArgMultiRow.isSet() || aArgPreAligned.isSet())
+ {
+ std::cout << "ERROR: --linearmatch does not work together with --multirow or --prealigned." << endl;
+ return false;
|