void AddControlPointsWithCheck(CPVector &cpv, CPVector &new_cp, Panorama *pano=NULL) { for(unsigned int i=0;i<new_cp.size();i++) { HuginBase::ControlPoint cp=new_cp[i]; bool duplicate=false; for(unsigned int j=0;j<cpv.size();j++) { if(cp==cpv[j]) { duplicate=true; break; } }; if(!duplicate) { cpv.push_back(cp); if(pano!=NULL) pano->addCtrlPoint(cp); }; }; };
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++) { unsigned int stack_nr=variable_groups->getStacks().getPartNumber(i); //check, if this stack is already in list bool found=false; unsigned int index=0; for(index=0; index<stack_images.size(); index++) { found=(stack_images[index].layer_nr==stack_nr); if(found) { break; }; }; if(!found) { //new stack stack_images.resize(stack_images.size()+1); index=stack_images.size()-1; //add new stack stack_images[index].layer_nr=stack_nr; }; //add new image unsigned int new_image_index=stack_images[index].images.size(); stack_images[index].images.resize(new_image_index+1); stack_images[index].images[new_image_index].img_nr=i; stack_images[index].images[new_image_index].ev=_panoramaInfo->getImage(i).getExposure(); }; delete variable_groups; //get image with median exposure for search with cp generator vector<size_t> images_layer; UIntSet images_layer_set; for(unsigned int i=0; i<stack_images.size(); i++) { std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev); unsigned int index=0; if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev) { index=stack_images[i].images.size() / 2; }; images_layer.push_back(stack_images[i].images[index].img_nr); images_layer_set.insert(stack_images[i].images[index].img_nr); if(stack_images[i].images.size()>1) { //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[img1]); aM._i2=&(_filesData[img2]); checkedImagePairs[img1].insert(img2); checkedImagePairs[img2].insert(img1); }; }; }; //build match data list for image pairs if(images_layer.size()>1) { std::sort(images_layer.begin(), images_layer.end()); 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[img1]); aM._i2 = &(_filesData[img2]); checkedImagePairs[img1].insert(img2); checkedImagePairs[img2].insert(img1); }; }; TRACE_INFO(endl<< "--- Find matches ---" << 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)); // step 2: connect all image groups _matchesData.clear(); Panorama mediumPano=_panoramaInfo->getSubset(images_layer_set); CPGraph graph; createCPGraph(mediumPano, graph); CPComponents comps; unsigned int n = findCPComponents(graph, comps); if(n>1) { vector<unsigned int> ImagesGroups; for(unsigned int i=0; i<n; i++) { ImagesGroups.push_back(images_layer[*(comps[i].begin())]); if(comps[i].size()>1) { ImagesGroups.push_back(images_layer[*(comps[i].rbegin())]); } }; for(unsigned int i=0; i<ImagesGroups.size()-1; i++) { 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[img1]); aM._i2 = &(_filesData[img2]); checkedImagePairs[img1].insert(img2); checkedImagePairs[img2].insert(img1); }; }; TRACE_INFO(endl<< "--- Find matches in images groups ---" << 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; } 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)); }; // step 3: now connect all overlapping images _matchesData.clear(); PT::Panorama optPano=_panoramaInfo->getSubset(images_layer_set); createCPGraph(optPano, graph); if(findCPComponents(graph, comps)==1) { if(images_layer.size()>2) { //reset translation parameters VariableMapVector varMapVec=optPano.getVariables(); for(size_t i=0; i<varMapVec.size(); i++) { map_get(varMapVec[i], "TrX").setValue(0); map_get(varMapVec[i], "TrY").setValue(0); map_get(varMapVec[i], "TrZ").setValue(0); }; optPano.updateVariables(varMapVec); //next steps happens only when all images are connected; //now optimize panorama PanoramaOptions opts = optPano.getOptions(); opts.setProjection(PanoramaOptions::EQUIRECTANGULAR); opts.optimizeReferenceImage=0; // calculate proper scaling, 1:1 resolution. // Otherwise optimizer distances are meaningless. opts.setWidth(30000, false); opts.setHeight(15000); optPano.setOptions(opts); int w = optPano.calcOptimalWidth(); opts.setWidth(w); opts.setHeight(w/2); optPano.setOptions(opts); //generate optimize vector, optimize only yaw and pitch OptimizeVector optvars; const SrcPanoImage& anchorImage = optPano.getImage(opts.optimizeReferenceImage); for (unsigned i=0; i < optPano.getNrOfImages(); i++) { std::set<std::string> imgopt; if(i==opts.optimizeReferenceImage) { //optimize only anchors pitch, not yaw imgopt.insert("p"); } else { imgopt.insert("p"); imgopt.insert("y"); }; optvars.push_back(imgopt); } optPano.setOptimizeVector(optvars); // remove vertical and horizontal control points CPVector cps = optPano.getCtrlPoints(); CPVector newCP; for (CPVector::const_iterator it = cps.begin(); it != cps.end(); it++) { if (it->mode == ControlPoint::X_Y) { newCP.push_back(*it); } } optPano.setCtrlPoints(newCP); if (getVerbose() < 2) { PT_setProgressFcn(ptProgress); PT_setInfoDlgFcn(ptinfoDlg); }; //in a first step do a pairwise optimisation HuginBase::AutoOptimise::autoOptimise(optPano, false); //now the final optimisation HuginBase::PTools::optimize(optPano); if (getVerbose() < 2) { PT_setProgressFcn(NULL); PT_setInfoDlgFcn(NULL); }; //now match overlapping images if(!matchPrealigned(aExecutor, &optPano, checkedImagePairs, images_layer, false)) { return false; }; }; } else { if(!match(aExecutor, checkedImagePairs)) { return false; }; }; return true; };
CPVector AutoPanoSiftMultiRow::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() < 2) { return cps; }; std::vector<wxString> keyFiles(pano.getNrOfImages()); //generate cp for every consecutive image pair unsigned int counter=0; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ) { if(counter==imgs.size()-1) break; counter++; UIntSet ImagePair; ImagePair.clear(); ImagePair.insert(*it); it++; ImagePair.insert(*it); AutoPanoSift matcher; CPVector new_cps; new_cps.clear(); if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); if(ret_value!=0) { Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; }; // now connect all image groups // generate temporary panorama to add all found cps UIntSet allImgs; fill_set(allImgs, 0, pano.getNrOfImages()-1); Panorama optPano=pano.getSubset(allImgs); for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it) optPano.addCtrlPoint(*it); CPGraph graph; createCPGraph(optPano, graph); CPComponents comps; int n = findCPComponents(graph, comps); if(n>1) { UIntSet ImagesGroups; for(unsigned int i=0;i<n;i++) { ImagesGroups.insert(*(comps[i].begin())); if(comps[i].size()>1) ImagesGroups.insert(*(comps[i].rbegin())); }; AutoPanoSift matcher; CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps,&optPano); if(ret_value!=0) { Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; createCPGraph(optPano,graph); n=findCPComponents(graph, comps); }; if(n==1 && setting.GetOption()) { //next steps happens only when all images are connected; //now optimize panorama PanoramaOptions opts = pano.getOptions(); opts.setProjection(PanoramaOptions::EQUIRECTANGULAR); // calculate proper scaling, 1:1 resolution. // Otherwise optimizer distances are meaningless. opts.setWidth(30000, false); opts.setHeight(15000); optPano.setOptions(opts); int w = optPano.calcOptimalWidth(); opts.setWidth(w); opts.setHeight(w/2); optPano.setOptions(opts); //generate optimize vector, optimize only yaw and pitch OptimizeVector optvars; const SrcPanoImage & anchorImage = optPano.getImage(opts.optimizeReferenceImage); for (unsigned i=0; i < optPano.getNrOfImages(); i++) { std::set<std::string> imgopt; if(i==opts.optimizeReferenceImage) { //optimize only anchors pitch, not yaw imgopt.insert("p"); } else { // do not optimize anchor image's stack for position. if(!optPano.getImage(i).YawisLinkedWith(anchorImage)) { imgopt.insert("p"); imgopt.insert("y"); }; }; optvars.push_back(imgopt); } optPano.setOptimizeVector(optvars); // remove vertical and horizontal control points CPVector backupOldCPS = optPano.getCtrlPoints(); CPVector backupNewCPS; for (CPVector::const_iterator it = backupOldCPS.begin(); it != backupOldCPS.end(); it++) { if (it->mode == ControlPoint::X_Y) { backupNewCPS.push_back(*it); } } optPano.setCtrlPoints(backupNewCPS); // do a first pairwise optimisation step HuginBase::AutoOptimise::autoOptimise(optPano,false); HuginBase::PTools::optimize(optPano); optPano.setCtrlPoints(backupOldCPS); //and find cp on overlapping images //work only on image pairs, which are not yet connected AutoPanoSiftPreAlign matcher; CPDetectorSetting newSetting; newSetting.SetProg(setting.GetProg()); newSetting.SetArgs(setting.GetArgs()); if(setting.IsTwoStepDetector()) { newSetting.SetProgMatcher(setting.GetProgMatcher()); newSetting.SetArgsMatcher(setting.GetArgsMatcher()); }; newSetting.SetOption(true); CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); }; Cleanup(setting, pano, imgs, keyFiles, parent); return cps; };