CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file, PT::Panorama & pano) { ifstream stream(file.c_str()); if (! stream.is_open()) { DEBUG_ERROR("Could not open autopano output: " << file); return CPVector(); } Panorama tmpp; PanoramaMemento newPano; int ptoVersion = 0; newPano.loadPTScript(stream, ptoVersion, ""); tmpp.setMemento(newPano); // create mapping between the panorama images. map<unsigned int, unsigned int> imgMapping; for (unsigned int ni = 0; ni < tmpp.getNrOfImages(); ni++) { std::string nname = stripPath(tmpp.getImage(ni).getFilename()); for (unsigned int oi=0; oi < pano.getNrOfImages(); oi++) { std::string oname = stripPath(pano.getImage(oi).getFilename()); if (nname == oname) { // insert image imgMapping[ni] = oi; break; } } if (! set_contains(imgMapping, ni)) { DEBUG_ERROR("Could not find image " << ni << ", name: " << tmpp.getImage(ni).getFilename() << " in autopano output"); return CPVector(); } } // get control points CPVector ctrlPoints = tmpp.getCtrlPoints(); // make sure they are in correct order for (CPVector::iterator it= ctrlPoints.begin(); it != ctrlPoints.end(); ++it) { (*it).image1Nr = imgMapping[(*it).image1Nr]; (*it).image2Nr = imgMapping[(*it).image2Nr]; } return ctrlPoints; }
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); }; }; };
CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file, PT::Panorama & pano, const PT::UIntSet & imgs) { ifstream stream(file.c_str()); if (! stream.is_open()) { DEBUG_ERROR("Could not open control point detector output: " << file); return CPVector(); } Panorama tmpp; PanoramaMemento newPano; int ptoVersion = 0; newPano.loadPTScript(stream, ptoVersion, ""); tmpp.setMemento(newPano); //check if sizes matches if(tmpp.getNrOfImages()!=imgs.size()) { return CPVector(); }; // create mapping between the panorama images. vector<size_t> imgMapping(imgs.size()); size_t i=0; for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++) { imgMapping[i++]=*it; }; // get control points CPVector ctrlPoints = tmpp.getCtrlPoints(); // make sure they are in correct order for (CPVector::iterator it= ctrlPoints.begin(); it != ctrlPoints.end(); ++it) { (*it).image1Nr = imgMapping[(*it).image1Nr]; (*it).image2Nr = imgMapping[(*it).image2Nr]; } return ctrlPoints; }
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; };
CPVector AutoPanoSiftMultiRowStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() == 0) { return cps; }; std::vector<stack_img> stack_images; HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano); for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it); //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=*it; stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure(); }; delete variable_groups; //get image with median exposure for search with cp generator UIntSet images_layer; 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.insert(stack_images[i].images[index].img_nr); }; ret_value=0; //work on all stacks if(!setting.GetProgStack().IsEmpty()) { CPDetectorSetting stack_setting; stack_setting.SetType(CPDetector_AutoPanoSift); stack_setting.SetProg(setting.GetProgStack()); stack_setting.SetArgs(setting.GetArgsStack()); for(unsigned int i=0;i<stack_images.size();i++) { UIntSet images_stack; images_stack.clear(); for(unsigned int j=0;j<stack_images[i].images.size();j++) images_stack.insert(stack_images[i].images[j].img_nr); if(images_stack.size()>1) { AutoPanoSift matcher; CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); if(ret_value!=0) { std::vector<wxString> emptyKeyfiles; Cleanup(setting, pano, imgs, emptyKeyfiles, parent); return cps; }; }; }; } //generate cp for median exposure with multi-row algorithm if(images_layer.size()>1) { UIntSet allImgs; fill_set(allImgs, 0, pano.getNrOfImages()-1); Panorama newPano=pano.getSubset(allImgs); if(cps.size()>0) for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it) newPano.addCtrlPoint(*it); AutoPanoSiftMultiRow matcher; CPVector new_cps=matcher.automatch(setting, newPano, images_layer, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); }; return cps; };