void PTools::optimize(Panorama & pano, utils::MultiProgressDisplay & progDisplay, int maxIter) { // VariableMapVector res; // setup data structures aPrefs aP; OptInfo opt; SetAdjustDefaults(&aP); AlignInfoWrap aInfo; // copy pano information int libpano data structures if (aInfo.setInfo(pano)) { aInfo.setGlobal(); opt.numVars = aInfo.gl.numParam; opt.numData = aInfo.gl.numPts; opt.SetVarsToX = SetLMParams; opt.SetXToVars = SetAlignParams; opt.fcn = aInfo.gl.fcn; *opt.message = 0; DEBUG_DEBUG("starting optimizer"); RunLMOptimizer( &opt ); #ifdef DEBUG fullPath path; StringtoFullPath(&path, "c:/debug_optimizer.txt"); aInfo.gl.data = opt.message; WriteResults( "debug_test", &path, &aInfo.gl, distSquared, 0); #endif std::ostringstream oss; /* oss << "optimizing images"; for (UIntVector::const_iterator it = imgs.begin(); it != imgs.end(); ++it) { if (it + 1 != imgs.end()) { oss << *it << ","; } else { oss << *it; } } oss << "\n" << opt.message; progDisplay.setMessage(oss.str()); */ DEBUG_DEBUG("optimizer finished:" << opt.message); pano.updateVariables(aInfo.getVariables()); pano.updateCtrlPointErrors( aInfo.getCtrlPoints()); } }
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; }
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; }
int main(int argc, char *argv[]) { // parse arguments const char * optstring = "alho:npqsv:m"; int c; string output; bool doPairwise = false; bool doAutoOpt = false; bool doNormalOpt = false; bool doLevel = false; bool chooseProj = false; bool quiet = false; bool doPhotometric = false; double hfov = 0.0; while ((c = getopt (argc, argv, optstring)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'p': doPairwise = true; break; case 'a': doAutoOpt = true; break; case 'n': doNormalOpt = true; break; case 'l': doLevel = true; break; case 's': chooseProj = true; break; case 'q': quiet = true; break; case 'v': hfov = atof(optarg); break; case 'm': doPhotometric = true; break; default: abort (); } } if (argc - optind != 1) { usage(argv[0]); return 1; } const char * scriptFile = argv[optind]; Panorama pano; if (scriptFile[0] == '-') { DocumentData::ReadWriteError err = pano.readData(std::cin); if (err != DocumentData::SUCCESSFUL) { cerr << "error while reading script file from stdin." << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } } else { ifstream prjfile(scriptFile); if (!prjfile.good()) { cerr << "could not open script : " << scriptFile << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "error while parsing panos tool script: " << scriptFile << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } } if (pano.getNrOfImages() == 0) { cerr << "Panorama should consist of at least one image" << endl; return 1; } // for bad HFOV (from autopano-SIFT) for (unsigned i=0; i < pano.getNrOfImages(); i++) { SrcPanoImage img = pano.getSrcImage(i); if (img.getProjection() == SrcPanoImage::RECTILINEAR && img.getHFOV() >= 180) { // something is wrong here, try to read from exif data double focalLength = 0; double cropFactor = 0; cerr << "HFOV of image " << img.getFilename() << " invalid, trying to read EXIF tags" << endl; bool ok = img.readEXIF(focalLength, cropFactor, true, false); if (! ok) { if (hfov) { img.setHFOV(hfov); } else { cerr << "EXIF reading failed, please specify HFOV with -v" << endl; return 1; } } pano.setSrcImage(i, img); } } if(pano.getNrOfCtrlPoints()==0 && (doPairwise || doAutoOpt || doNormalOpt)) { cerr << "Panorama have to have control points to optimise positions" << endl; return 1; }; if (doPairwise && ! doAutoOpt) { // do pairwise optimisation set<string> optvars; optvars.insert("r"); optvars.insert("p"); optvars.insert("y"); AutoOptimise::autoOptimise(pano); // do global optimisation if (!quiet) std::cerr << "*** Pairwise position optimisation" << endl; PTools::optimize(pano); } else if (doAutoOpt) { if (!quiet) std::cerr << "*** Adaptive geometric optimisation" << endl; SmartOptimise::smartOptimize(pano); } else if (doNormalOpt) { if (!quiet) std::cerr << "*** Optimising parameters specified in PTO file" << endl; PTools::optimize(pano); } else { if (!quiet) std::cerr << "*** Geometric parameters not optimized" << endl; } if (doLevel) { bool hasVerticalLines=false; CPVector allCP=pano.getCtrlPoints(); if(allCP.size()>0 && (doPairwise || doAutoOpt || doNormalOpt)) { for(size_t i=0;i<allCP.size() && !hasVerticalLines;i++) { hasVerticalLines=(allCP[i].mode==ControlPoint::X); }; }; // straighten only if there are no vertical control points if(hasVerticalLines) { cout << "Skipping automatic leveling because of existing vertical control points." << endl; } else { StraightenPanorama(pano).run(); CenterHorizontally(pano).run(); }; } if (chooseProj) { PanoramaOptions opts = pano.getOptions(); double hfov, vfov; CalculateFitPanorama fitPano = CalculateFitPanorama(pano); fitPano.run(); opts.setHFOV(fitPano.getResultHorizontalFOV()); opts.setHeight(roundi(fitPano.getResultHeight())); vfov = opts.getVFOV(); hfov = opts.getHFOV(); // avoid perspective projection if field of view > 100 deg double mf = 100; if (vfov < mf) { // cylindrical or rectilinear if (hfov < mf) { opts.setProjection(PanoramaOptions::RECTILINEAR); } else { opts.setProjection(PanoramaOptions::CYLINDRICAL); } } // downscale pano a little double sizeFactor = 0.7; pano.setOptions(opts); double w = CalculateOptimalScale::calcOptimalScale(pano); opts.setWidth(roundi(opts.getWidth()*w*sizeFactor), true); pano.setOptions(opts); } if(doPhotometric) { // photometric estimation PanoramaOptions opts = pano.getOptions(); int nPoints = 200; int pyrLevel=3; bool randomPoints = true; nPoints = nPoints * pano.getNrOfImages(); std::vector<vigra_ext::PointPairRGB> points; ProgressDisplay *progressDisplay; if(!quiet) progressDisplay=new StreamProgressDisplay(std::cout); else progressDisplay=new DummyProgressDisplay(); try { loadImgsAndExtractPoints(pano, nPoints, pyrLevel, randomPoints, *progressDisplay, points, !quiet); } catch (std::exception & e) { cerr << "caught exception: " << e.what() << endl; return 1; }; if(!quiet) cout << "\rSelected " << points.size() << " points" << endl; if (points.size() == 0) { cerr << "Error: no overlapping points found, exiting" << endl; return 1; } progressDisplay->startSubtask("Photometric Optimization", 0.0); // first, ensure that vignetting and response coefficients are linked const HuginBase::ImageVariableGroup::ImageVariableEnum vars[] = { HuginBase::ImageVariableGroup::IVE_EMoRParams, HuginBase::ImageVariableGroup::IVE_ResponseType, HuginBase::ImageVariableGroup::IVE_VigCorrMode, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift }; HuginBase::StandardImageVariableGroups variable_groups(pano); HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses(); for (size_t i = 0; i < lenses.getNumberOfParts(); i++) { std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed; links_needed.clear(); for (int v = 0; v < 5; v++) { if (!lenses.getVarLinkedInPart(vars[v], i)) { links_needed.insert(vars[v]); } }; if (!links_needed.empty()) { std::set<HuginBase::ImageVariableGroup::ImageVariableEnum>::iterator it; for (it = links_needed.begin(); it != links_needed.end(); it++) { lenses.linkVariablePart(*it, i); } } } HuginBase::SmartPhotometricOptimizer::PhotometricOptimizeMode optmode = HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_LDR; if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) { optmode = HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_HDR; } SmartPhotometricOptimizer photoOpt(pano, progressDisplay, pano.getOptimizeVector(), points, optmode); photoOpt.run(); // calculate the mean exposure. opts.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano); pano.setOptions(opts); progressDisplay->finishSubtask(); delete progressDisplay; }; // write result OptimizeVector optvec = pano.getOptimizeVector(); UIntSet imgs; fill_set(imgs,0, pano.getNrOfImages()-1); if (output != "") { ofstream of(output.c_str()); pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile)); } else { pano.printPanoramaScript(cout, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile)); } return 0; }
int main(int argc, char *argv[]) { // parse arguments const char * optstring = "o:hn:pws"; int c; string output; bool onlyPair = false; bool wholePano = false; bool skipOptimisation = false; double n = 2.0; while ((c = getopt (argc, argv, optstring)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'n': n = atof(optarg); if(n==0) { cerr <<"Invalid parameter: " << optarg << " is not valid real number" << endl; return 1; }; if (n<1.0) { cerr << "Invalid parameter: n must be at least 1" << endl; return 1; }; break; case 'p': onlyPair= true; break; case 'w': wholePano = true; break; case 's': skipOptimisation = true; break; case ':': cerr <<"Option -n requires a number" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind != 1) { usage(argv[0]); return 1; }; if (onlyPair && wholePano) { cerr << "Options -p and -w can't used together" << endl; return 1; }; string input=argv[optind]; Panorama pano; ifstream prjfile(input.c_str()); if (!prjfile.good()) { cerr << "could not open script : " << input << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(input)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "error while parsing panos tool script: " << input << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } size_t nrImg=pano.getNrOfImages(); if (nrImg < 2) { cerr << "Panorama should consist of at least two images" << endl; return 1; } if (pano.getNrOfCtrlPoints() < 3) { cerr << "Panorama should contain at least 3 control point" << endl; }; size_t cpremoved1=0; UIntSet CPtoRemove; // step 1 with pairwise optimisation if(!wholePano) { CPtoRemove=getCPoutsideLimit_pair(pano,n); if (CPtoRemove.size()>0) for(UIntSet::reverse_iterator it = CPtoRemove.rbegin(); it != CPtoRemove.rend(); ++it) pano.removeCtrlPoint(*it); cpremoved1=CPtoRemove.size(); }; // step 2 with optimisation of whole panorama bool unconnected=false; if(!onlyPair) { //check for unconnected images CPGraph graph; createCPGraph(pano, graph); CPComponents comps; int parts=findCPComponents(graph, comps); if (parts > 1) { unconnected=true; } else { CPtoRemove.clear(); if(skipOptimisation) { std::cout << endl << "Skipping optimisation, current image positions will be used." << endl; }; CPtoRemove=getCPoutsideLimit(pano,n,skipOptimisation); if (CPtoRemove.size()>0) for(UIntSet::reverse_iterator it = CPtoRemove.rbegin(); it != CPtoRemove.rend(); ++it) pano.removeCtrlPoint(*it); }; }; cout << endl; if(!wholePano) cout << "Removed " << cpremoved1 << " control points in step 1" << endl; if(!onlyPair) if(unconnected) cout <<"Skipped step 2 because of unconnected image pairs" << endl; else cout << "Removed " << CPtoRemove.size() << " control points in step 2" << endl; //write output OptimizeVector optvec = pano.getOptimizeVector(); UIntSet imgs; fill_set(imgs,0, pano.getNrOfImages()-1); // Set output .pto filename if not given if (output=="") { output=input.substr(0,input.length()-4).append("_clean.pto"); } ofstream of(output.c_str()); pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input)); cout << endl << "Written output to " << output << endl; return 0; }
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:i:l:h"; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"image", required_argument, NULL, 'i' }, {"lines", required_argument, NULL, 'l' }, {"help", no_argument, NULL, 'h' }, 0 }; UIntSet cmdlineImages; int c; int optionIndex = 0; int nrLines = 5; string output; while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'i': { int imgNr=atoi(optarg); if((imgNr==0) && (strcmp(optarg,"0")!=0)) { cerr << "Could not parse image number."; return 1; }; cmdlineImages.insert(imgNr); }; break; case 'l': nrLines=atoi(optarg); if(nrLines<1) { cerr << "Could not parse number of lines."; return 1; }; break; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind != 1) { cout << "Warning: " << argv[0] << " can only work on one project file at one time" << endl << endl; usage(argv[0]); return 1; }; string input=argv[optind]; // read panorama Panorama pano; ifstream prjfile(input.c_str()); if (!prjfile.good()) { cerr << "could not open script : " << input << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(input)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "error while parsing panos tool script: " << input << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } if(pano.getNrOfImages()==0) { cerr << "error: project file does not contains any image" << endl; cerr << "aborting processing" << endl; return 1; }; std::vector<size_t> imagesToProcess; if(cmdlineImages.size()==0) { //no image given, process all for(size_t i=0;i<pano.getNrOfImages();i++) { imagesToProcess.push_back(i); }; } else { //check, if given image numbers are valid for(UIntSet::const_iterator it=cmdlineImages.begin();it!=cmdlineImages.end();it++) { if((*it)>=0 && (*it)<pano.getNrOfImages()) { imagesToProcess.push_back(*it); }; }; }; if(imagesToProcess.size()==0) { cerr << "No image to process found" << endl << "Stopping processing" << endl; return 1; }; PT_setProgressFcn(ptProgress); PT_setInfoDlgFcn(ptinfoDlg); cout << argv[0] << " is searching for vertical lines" << endl; #if _WINDOWS //multi threading of image loading results sometime in a race condition //try to prevent this by initialisation of codecManager before //running multi threading part std::string s=vigra::impexListExtensions(); #endif #ifdef HAS_PPL size_t nrCPS=pano.getNrOfCtrlPoints(); Concurrency::parallel_for<size_t>(0,imagesToProcess.size(),[&pano,imagesToProcess,nrLines](size_t i) #else for(size_t i=0;i<imagesToProcess.size();i++) #endif { unsigned int imgNr=imagesToProcess[i]; cout << "Working on image " << pano.getImage(imgNr).getFilename() << endl; // now load and process all images vigra::ImageImportInfo info(pano.getImage(imgNr).getFilename().c_str()); HuginBase::CPVector foundLines; if(info.isGrayscale()) { foundLines=LoadGrayImageAndFindLines(info, pano, imgNr, nrLines); } else { if(info.isColor()) { //colour images foundLines=LoadImageAndFindLines(info, pano, imgNr, nrLines); } else { std::cerr << "Image " << pano.getImage(imgNr).getFilename().c_str() << " has " << info.numBands() << " channels." << std::endl << "Linefind works only with grayscale or color images." << std::endl << "Skipping image." << std::endl; }; }; #ifndef HAS_PPL cout << "Found " << foundLines.size() << " vertical lines" << endl; #endif if(foundLines.size()>0) { for(CPVector::const_iterator cpIt=foundLines.begin(); cpIt!=foundLines.end(); cpIt++) { pano.addCtrlPoint(*cpIt); }; }; } #ifdef HAS_PPL );
void OptimizePhotometricPanel::runOptimizer(const UIntSet & imgs) { DEBUG_TRACE(""); int mode = m_mode_cb->GetSelection(); // check if vignetting and response are linked, display a warning if they are not // The variables to check: const HuginBase::ImageVariableGroup::ImageVariableEnum vars[] = { HuginBase::ImageVariableGroup::IVE_EMoRParams, HuginBase::ImageVariableGroup::IVE_ResponseType, HuginBase::ImageVariableGroup::IVE_VigCorrMode, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift }; // keep a list of commands needed to fix it: std::vector<PT::PanoCommand *> commands; HuginBase::ConstImageVariableGroup & lenses = variable_groups->getLenses(); for (size_t i = 0; i < lenses.getNumberOfParts(); i++) { std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed; links_needed.clear(); for (int v = 0; v < 5; v++) { if (!lenses.getVarLinkedInPart(vars[v], i)) { links_needed.insert(vars[v]); } }; if (!links_needed.empty()) { commands.push_back(new PT::LinkLensVarsCmd(*m_pano, i, links_needed)); } } // if the list of commands is empty, all is good and we don't need a warning. if (!commands.empty()) { int ok = wxMessageBox(_("The same vignetting and response parameters should\nbe applied for all images of a lens.\nCurrently each image can have different parameters.\nLink parameters?"), _("Link parameters"), wxYES_NO | wxICON_INFORMATION); if (ok == wxYES) { // perform all the commands we stocked up earilier. for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++) { GlobalCmdHist::getInstance().addCommand(*it); } } else { // free all the commands, the user doesn't want them used. for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++) { delete *it; } } } Panorama optPano = m_pano->getSubset(imgs); PanoramaOptions opts = optPano.getOptions(); OptimizeVector optvars; if(mode==OPT_CUSTOM) { optvars = getOptimizeVector(); if (optPano.getNrOfImages() != m_pano->getNrOfImages()) { OptimizeVector o = optvars; optvars.clear(); for (UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it) { optvars.push_back(o[*it]); } } unsigned int countVar=0; for(unsigned int i=0;i<optvars.size();i++) { countVar+=optvars[i].size(); }; if(countVar==0) { wxMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Exposure optimization"), wxOK | wxICON_INFORMATION); return; }; }; std::vector<vigra_ext::PointPairRGB> m_points; // extract points only if not done previously long nPoints = 200; wxConfigBase::Get()->Read(wxT("/OptimizePhotometric/nRandomPointsPerImage"), & nPoints); // get parameters for estimation. nPoints = wxGetNumberFromUser(_("The vignetting and exposure correction is determined by analysing color values in the overlapping areas.\nTo speed up the computation, only a random subset of points is used."), _("Number of points per image"), _("Photometric optimization"), nPoints, 0, 32000, this); if (nPoints < 0) { return; } wxConfigBase::Get()->Write(wxT("/OptimizePhotometric/nRandomPointsPerImage"),nPoints); ProgressReporterDialog progress(5.0, _("Photometric alignment"), _("Loading images")); progress.Show(); nPoints = nPoints * optPano.getNrOfImages(); // get the small images std::vector<vigra::FRGBImage *> srcImgs; for (size_t i=0; i < optPano.getNrOfImages(); i++) { ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename()); vigra::FRGBImage * img = new FRGBImage; if (!e) { wxMessageBox(_("Error: could not load all images"), _("Error")); return; } if (e->image8 && e->image8->width() > 0) { reduceToNextLevel(*(e->image8), *img); transformImage(vigra::srcImageRange(*img), vigra::destImage(*img), vigra::functor::Arg1()/vigra::functor::Param(255.0)); } else if (e->image16 && e->image16->width() > 0) { reduceToNextLevel(*(e->image16), *img); transformImage(vigra::srcImageRange(*img), vigra::destImage(*img), vigra::functor::Arg1()/vigra::functor::Param(65535.0)); } else { reduceToNextLevel(*(e->imageFloat), *img); } srcImgs.push_back(img); } bool randomPoints = true; extractPoints(optPano, srcImgs, nPoints, randomPoints, progress, m_points); if (m_points.size() == 0) { wxMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Error")); return; } double error = 0; try { //wxBusyCursor busyc; if (mode != OPT_CUSTOM) { // run automatic optimisation // ensure that we have a valid anchor. PanoramaOptions opts = optPano.getOptions(); if (opts.colorReferenceImage >= optPano.getNrOfImages()) { opts.colorReferenceImage = 0; optPano.setOptions(opts); } smartOptimizePhotometric(optPano, PhotometricOptimizeMode(mode), m_points, progress, error); } else { // optimize selected parameters optimizePhotometric(optPano, optvars, m_points, progress, error); } } catch (std::exception & error) { wxMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Internal error")); } progress.Close(); // display information about the estimation process: int ret = wxMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error*255), _("Photometric optimization finished"), wxYES_NO | wxICON_INFORMATION,this); if (ret == wxYES) { DEBUG_DEBUG("Applying vignetting corr"); // TODO: merge into a single update command const VariableMapVector & vars = optPano.getVariables(); GlobalCmdHist::getInstance().addCommand( new PT::UpdateImagesVariablesCmd(*m_pano, imgs, vars) ); //now update panorama exposure value PanoramaOptions opts = m_pano->getOptions(); opts.outputExposureValue = calcMeanExposure(*m_pano); GlobalCmdHist::getInstance().addCommand( new PT::SetPanoOptionsCmd(*m_pano, opts) ); } }
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; };
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:t:h"; enum { MINOVERLAP=1000 }; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"template", required_argument, NULL, 't'}, {"help", no_argument, NULL, 'h' }, 0 }; int c; int optionIndex = 0; string output; string templateFile; while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1) { switch (c) { case 'o': output = optarg; break; case 't': templateFile = optarg; if(!hugin_utils::FileExists(templateFile)) { cerr << "Error: Template \"" << templateFile << "\" not found." << endl; return 1; }; break; case 'h': usage(argv[0]); return 0; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a parameter" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind == 0) { cout << "Error: No project file given." << endl; return 1; }; if (argc - optind != 1) { cout << "Error: pto_template can only work on one project file at one time" << endl; return 1; }; if (templateFile.length()==0) { cerr << "Error: No template given." << endl; return 1; }; string input=argv[optind]; // read panorama Panorama pano; ifstream prjfile(input.c_str()); if (!prjfile.good()) { cerr << "Error: could not open script : " << input << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(input)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "Error while parsing panos tool script: " << input << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } if(pano.getNrOfImages()==0) { cerr << "Error: project file does not contains any image" << endl; cerr << "aborting processing" << endl; return 1; }; Panorama newPano; ifstream templateStream(templateFile.c_str()); if (!templateStream.good()) { cerr << "Error: could not open template script : " << templateFile << endl; return 1; } newPano.setFilePrefix(hugin_utils::getPathPrefix(templateFile)); err = newPano.readData(templateStream); if (err != DocumentData::SUCCESSFUL) { cerr << "Error while parsing template script: " << templateFile << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } if (pano.getNrOfImages() != newPano.getNrOfImages()) { cerr << "Error: template expects " << newPano.getNrOfImages() << " images," << endl << " current project contains " << pano.getNrOfImages() << " images" << endl << " Could not apply template" << endl; return false; } // check image sizes, and correct parameters if required. for (unsigned int i = 0; i < newPano.getNrOfImages(); i++) { // check if image size is correct const SrcPanoImage & oldSrcImg = pano.getImage(i); SrcPanoImage newSrcImg = newPano.getSrcImage(i); // just keep the file name newSrcImg.setFilename(oldSrcImg.getFilename()); if (oldSrcImg.getSize() != newSrcImg.getSize()) { // adjust size properly. newSrcImg.resize(oldSrcImg.getSize()); } newPano.setSrcImage(i, newSrcImg); } // keep old control points. newPano.setCtrlPoints(pano.getCtrlPoints()); //write output UIntSet imgs; fill_set(imgs, 0, newPano.getNrOfImages()-1); // Set output .pto filename if not given if (output=="") { output=input.substr(0,input.length()-4).append("_template.pto"); } ofstream of(output.c_str()); newPano.printPanoramaScript(of, newPano.getOptimizeVector(), newPano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input)); cout << endl << "Written output to " << output << endl; return 0; }
CPVector AutoPanoKolor::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; wxString autopanoExe = setting.GetProg(); // write default autopano.kolor.com flags wxString autopanoArgs = setting.GetArgs(); string imgFiles; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename())); } wxString ptofilepath = wxFileName::CreateTempFileName(wxT("ap_res")); wxFileName ptofn(ptofilepath); wxString ptofile = ptofn.GetFullName(); autopanoArgs.Replace(wxT("%o"), ptofile); wxString tmp; tmp.Printf(wxT("%d"), nFeatures); autopanoArgs.Replace(wxT("%p"), tmp); SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin()); tmp.Printf(wxT("%f"), firstImg.getHFOV()); autopanoArgs.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) firstImg.getProjection()); autopanoArgs.Replace(wxT("%f"), tmp); autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME)); wxString tempdir = ptofn.GetPath(); autopanoArgs.Replace(wxT("%d"), ptofn.GetPath()); wxString cmd; cmd.Printf(wxT("%s %s"), wxQuoteFilename(autopanoExe).c_str(), autopanoArgs.c_str()); #ifdef __WXMSW__ if (cmd.size() > 32766) { CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"), _("Too many images selected"), parent); return cps; } #endif DEBUG_DEBUG("Executing: " << cmd.c_str()); wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(cmd); if (arguments.GetCount() > 127) { DEBUG_ERROR("Too many arguments for call to wxExecute()"); DEBUG_ERROR("Try using the %s parameter in preferences"); CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent); return cps; } ret_value = 0; // use MyExternalCmdExecDialog ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent); if (ret_value == HUGIN_EXIT_CODE_CANCELLED) { return cps; } else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; } ptofile = ptofn.GetFullPath(); ptofile.append(wxT("0.oto")); if (! wxFileExists(ptofile.c_str()) ) { CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()), _("Control point detector failure"), parent ); return cps; } // read and update control points cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano); if (!wxRemoveFile(ptofile)) { DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str()); } return cps; }
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() == 0) { return cps; } // create suitable command line.. wxString autopanoExe = GetProgPath(setting.GetProg()); if(setting.IsTwoStepDetector()) { std::vector<wxString> keyFiles(pano.getNrOfImages()); cps=automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent); Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; wxString autopanoArgs = setting.GetArgs(); // TODO: create a secure temporary filename here wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res")); autopanoArgs.Replace(wxT("%o"), ptofile); wxString tmp; tmp.Printf(wxT("%d"), nFeatures); autopanoArgs.Replace(wxT("%p"), tmp); SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin()); tmp.Printf(wxT("%f"), firstImg.getHFOV()); autopanoArgs.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) firstImg.getProjection()); autopanoArgs.Replace(wxT("%f"), tmp); long idx = autopanoArgs.Find(wxT("%namefile")) ; DEBUG_DEBUG("find %namefile in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx); bool use_namefile = idx >=0; idx = autopanoArgs.Find(wxT("%i")); DEBUG_DEBUG("find %i in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx); bool use_params = idx >=0; idx = autopanoArgs.Find(wxT("%s")); bool use_inputscript = idx >=0; if (! (use_namefile || use_params || use_inputscript)) { CPMessage(_("Please use %namefile, %i or %s to specify the input files for the control point detector"), _("Error in control point detector command"), parent); return cps; } wxFile namefile; wxString namefile_name; if (use_namefile) { // create temporary file with image names. namefile_name = wxFileName::CreateTempFileName(wxT("ap_imgnames"), &namefile); DEBUG_DEBUG("before replace %namefile: " << autopanoArgs.mb_str(wxConvLocal)); autopanoArgs.Replace(wxT("%namefile"), namefile_name); DEBUG_DEBUG("after replace %namefile: " << autopanoArgs.mb_str(wxConvLocal)); for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME)); namefile.Write(wxT("\r\n")); } // close namefile if (namefile_name != wxString(wxT(""))) { namefile.Close(); } } else { string imgFiles; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename())); } autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME)); } wxString ptoinfile_name; if (use_inputscript) { wxFile ptoinfile; ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj")); autopanoArgs.Replace(wxT("%s"), ptoinfile_name); ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile)); //delete all existing control points in temp project //otherwise the existing control points will be loaded again Panorama tempPano=pano.duplicate(); CPVector emptyCPV; tempPano.setCtrlPoints(emptyCPV); tempPano.printPanoramaScript(ptoinstream, tempPano.getOptimizeVector(), tempPano.getOptions(), imgs, false); } #ifdef __WXMSW__ if (autopanoArgs.size() > 32000) { CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"), _("Too many images selected"), parent ); return cps; } #endif wxString cmd = autopanoExe + wxT(" ") + autopanoArgs; DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal)); wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(autopanoArgs); if (arguments.GetCount() > 127) { DEBUG_ERROR("Too many arguments for call to wxExecute()"); DEBUG_ERROR("Try using the %%s parameter in preferences"); CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent); return cps; } ret_value = 0; // use MyExternalCmdExecDialog ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent); if (ret_value == HUGIN_EXIT_CODE_CANCELLED) { return cps; } else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; } if (! wxFileExists(ptofile.c_str())) { CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()), _("Control point detector failure"), parent ); return cps; } // read and update control points if(use_inputscript) { cps = readUpdatedControlPoints((const char*)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs); } else { cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano); }; if (namefile_name != wxString(wxT(""))) { namefile.Close(); wxRemoveFile(namefile_name); } if (ptoinfile_name != wxString(wxT(""))) { wxRemoveFile(ptoinfile_name); } if (!wxRemoveFile(ptofile)) { DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str()); } return cps; }
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size()<2) return cps; DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages()); vector<UIntSet> usedImages; usedImages.resize(pano.getNrOfImages()); if(setting.GetOption()) { //only work on not connected image pairs CPVector oldCps=pano.getCtrlPoints(); for(unsigned i=0;i<oldCps.size();i++) { if(oldCps[i].mode==ControlPoint::X_Y) { usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr); usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr); }; }; }; HuginBase::CalculateImageOverlap overlap(&pano); overlap.calculate(10); for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++) { UIntSet images; images.clear(); images.insert(*it); UIntSet::const_iterator it2=it; for(++it2;it2!=imgs.end();it2++) { //check if this image pair was yet used if(set_contains(usedImages[*it2],*it)) continue; //now check position if(overlap.getOverlap(*it,*it2)>0) { images.insert(*it2); }; }; if(images.size()<2) continue; //remember image pairs for later for(UIntSet::const_iterator img_it=images.begin();img_it!=images.end();img_it++) for(UIntSet::const_iterator img_it2=images.begin();img_it2!=images.end();img_it2++) usedImages[*img_it].insert(*img_it2); AutoPanoSift matcher; CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, pano, images, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, pano, images, 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; }; }; Cleanup(setting, pano, imgs, keyFiles, parent); return cps; };
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { std::vector<wxString> keyFiles(pano.getNrOfImages()); return automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent); };
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:p:f:c:s:lh"; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"projection", required_argument, NULL, 'p' }, {"fov", required_argument, NULL, 'f' }, {"crop", required_argument, NULL, 'c' }, {"stacklength", required_argument, NULL, 's' }, {"linkstacks", no_argument, NULL, 'l' }, {"distortion", no_argument, NULL, 300 }, {"vignetting", no_argument, NULL, 301 }, {"help", no_argument, NULL, 'h' }, 0 }; int c; int optionIndex = 0; string output; int projection=-1; float fov=-1; int stackLength=1; bool linkStacks=false; vigra::Rect2D cropRect(0,0,0,0); bool loadDistortion=false; bool loadVignetting=false; while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'p': { projection=atoi(optarg); if((projection==0) && (strcmp(optarg,"0")!=0)) { cerr << "Could not parse image number."; return 1; }; if(projection<0) { cerr << "Invalid projection number." << endl; return 1; }; }; break; case 'f': fov=atof(optarg); if(fov<1 || fov>360) { cerr << "Invalid field of view"; return 1; }; break; case 'c': { int left, right, top, bottom; int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom); if (n==4) { if(right>left && bottom>top) { cropRect.setUpperLeft(vigra::Point2D(left,top)); cropRect.setLowerRight(vigra::Point2D(right,bottom)); } else { cerr << "Invalid crop area" << endl; return 1; }; } else { cerr << "Could not parse crop values" << endl; return 1; }; }; break; case 's': stackLength=atoi(optarg); if(stackLength<1) { cerr << "Could not parse stack length." << endl; return 1; }; break; case 'l': linkStacks=true; break; case 300: loadDistortion=true; break; case 301: loadVignetting=true; break; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind < 1) { usage(argv[0]); return 1; }; cout << "Generating pto file..." << endl; cout.flush(); std::vector<string> filelist; while(optind<argc) { string input; #ifdef _WINDOWS //do globbing input=GetAbsoluteFilename(argv[optind]); char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; char newFile[_MAX_PATH]; _splitpath(input.c_str(), drive, dir, NULL, NULL); struct _finddata_t finddata; intptr_t findhandle = _findfirst(input.c_str(), &finddata); if (findhandle != -1) { do { //ignore folder, can be happen when using *.* if((finddata.attrib & _A_SUBDIR)==0) { _splitpath(finddata.name, NULL, NULL, fname, ext); _makepath(newFile, drive, dir, fname, ext); //check if valid image file if(vigra::isImage(newFile)) { filelist.push_back(std::string(newFile)); }; }; } while (_findnext(findhandle, &finddata) == 0); _findclose(findhandle); } #else input=argv[optind]; if(hugin_utils::FileExists(input)) { if(vigra::isImage(input.c_str())) { filelist.push_back(GetAbsoluteFilename(input)); }; }; #endif optind++; }; if(filelist.size()==0) { cerr << "No valid image files given." << endl; return 1; }; //sort filenames sort(filelist.begin(),filelist.end(),doj::alphanum_less()); if(projection<0) { InitLensDB(); }; Panorama pano; for(size_t i=0; i<filelist.size();i++) { SrcPanoImage srcImage; cout << "Reading " << filelist[i] << "..." << endl; srcImage.setFilename(filelist[i]); try { vigra::ImageImportInfo info(filelist[i].c_str()); if(info.width()==0 || info.height()==0) { cerr << "ERROR: Could not decode image " << filelist[i] << endl << "Skipping this image." << endl << endl; continue; } srcImage.setSize(info.size()); std::string pixelType=info.getPixelType(); if((pixelType=="UINT8") || (pixelType=="UINT16") || (pixelType=="INT16")) { srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR); } else { srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR); }; } catch(std::exception & e) { cerr << "ERROR: caught exception: " << e.what() << endl; cerr << "Could not read image information for file " << filelist[i] << endl; cerr << "Skipping this image." << endl << endl; continue; }; srcImage.readEXIF(); srcImage.applyEXIFValues(); if(projection>=0) { srcImage.setProjection((HuginBase::BaseSrcPanoImage::Projection)projection); } else { srcImage.readProjectionFromDB(); }; if(fov>0) { srcImage.setHFOV(fov); if(srcImage.getCropFactor()==0) { srcImage.setCropFactor(1.0); }; } else { //set plausible default value if they could not read from exif if(srcImage.getExifFocalLength()==0 || srcImage.getCropFactor()==0) { cout << "\tNo value for field of view found in EXIF data. " << endl << "\tAssuming a HFOV of 50 degrees. " << endl; srcImage.setHFOV(50); srcImage.setCropFactor(1.0); }; }; if(cropRect.width()>0 && cropRect.height()>0) { if(srcImage.isCircularCrop()) { srcImage.setCropMode(SrcPanoImage::CROP_CIRCLE); } else { srcImage.setCropMode(SrcPanoImage::CROP_RECTANGLE); }; srcImage.setAutoCenterCrop(false); srcImage.setCropRect(cropRect); }; if(loadDistortion) { if(srcImage.readDistortionFromDB()) { cout << "\tRead distortion data from lensfun database." << endl; } else { cout << "\tNo valid distortion data found in lensfun database." << endl; }; }; if(loadVignetting) { if(srcImage.readVignettingFromDB()) { cout << "\tRead vignetting data from lensfun database." << endl; } else { cout << "\tNo valid vignetting data found in lensfun database." << endl; }; }; pano.addImage(srcImage); }; if(pano.getNrOfImages()==0) { cerr << "Adding images to project files failed." << endl; HuginBase::LensDB::LensDB::Clean(); return 1; }; //link lenses if(pano.getNrOfImages()>1) { double redBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifRedBalance(); double blueBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifBlueBalance(); if(fabs(redBalanceAnchor)<1e-2) { redBalanceAnchor=1; }; if(fabs(blueBalanceAnchor)<1e-2) { blueBalanceAnchor=1; }; StandardImageVariableGroups variable_groups(pano); ImageVariableGroup& lenses = variable_groups.getLenses(); for(size_t i=1;i<pano.getNrOfImages();i++) { int image=-1; const SrcPanoImage & srcImg=pano.getImage(i); for(size_t j=0;j<i;j++) { const SrcPanoImage & compareImg=pano.getImage(j); if(srcImg.getHFOV()==compareImg.getHFOV() && srcImg.getProjection()==compareImg.getProjection() && srcImg.getExifModel()==compareImg.getExifModel() && srcImg.getExifMake()==compareImg.getExifMake() && srcImg.getSize()==compareImg.getSize()) { image=j; break; }; }; if(image!=-1) { SrcPanoImage img=pano.getSrcImage(i); double ev=img.getExposureValue(); lenses.switchParts(i,lenses.getPartNumber(image)); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i); img.setExposureValue(ev); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i); img.setWhiteBalanceRed(img.getExifRedBalance()/redBalanceAnchor); img.setWhiteBalanceBlue(img.getExifBlueBalance()/blueBalanceAnchor); pano.setSrcImage(i, img); }; }; cout << endl << "Assigned " << lenses.getNumberOfParts() << " lenses." << endl; if(lenses.getNumberOfParts()>1 && stackLength>1) { cout << "Project contains more than one lens, but you requested to assign" << endl << "stacks. This is not supported. Therefore stacks will not be" << endl << "assigned." << endl << endl; stackLength=1; }; }; //link stacks if(pano.getNrOfImages()>1 && stackLength>1) { stackLength=std::min<int>(stackLength,pano.getNrOfImages()); int stackCount=pano.getNrOfImages() / stackLength; if(pano.getNrOfImages() % stackLength > 0) { stackCount++; }; if(stackCount<pano.getNrOfImages()) { for(size_t stackNr=0;stackNr<stackCount;stackNr++) { size_t firstImgStack=stackNr*stackLength; for(size_t i=0;i<stackLength;i++) { if(firstImgStack+i<pano.getNrOfImages()) { pano.linkImageVariableStack(firstImgStack,firstImgStack+i); if(linkStacks) { pano.linkImageVariableYaw(firstImgStack,firstImgStack+i); pano.linkImageVariablePitch(firstImgStack,firstImgStack+i); pano.linkImageVariableRoll(firstImgStack,firstImgStack+i); }; }; }; }; cout << "Assigned " << stackCount << " stacks." << endl; }; }; //set output exposure value PanoramaOptions opt = pano.getOptions(); opt.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano); pano.setOptions(opt); // set optimizer switches pano.setOptimizerSwitch(HuginBase::OPT_PAIR); pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE); //output if(output=="") { output=hugin_utils::stripExtension(pano.getImage(0).getFilename()); if(pano.getNrOfImages()>1) { output.append("-"); output.append(hugin_utils::stripExtension(hugin_utils::stripPath(pano.getImage(pano.getNrOfImages()-1).getFilename()))); }; output=output.append(".pto"); }; output=GetAbsoluteFilename(output); //write output UIntSet imgs; fill_set(imgs,0, pano.getNrOfImages()-1); ofstream of(output.c_str()); pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(output)); cout << endl << "Written output to " << output << endl; HuginBase::LensDB::LensDB::Clean(); return 0; }
int main() { FeaturesService featuresService = FeaturesService(); string imagename = "0"; vector<string> imagenames; vector<Mat> images, imagesnocolor; vector<vector<Matches>> imagesmatches; vector<vector<int>> relatedImages; vector<set<int>> panoramas; vector<vector<Matches>> panoramasmatches; unsigned int numImages; while (imagename.compare("") != 0 && imagename.compare("-1") != 0) { cout << "Insert image path to load (insert -1 to start loading predetermined images or just ENTER to finish the list of images): "; cin >> imagename; imagenames.push_back(imagename); } if (imagename.compare("-1") == 0) { imagenames.push_back("./yosemite2.jpg"); imagenames.push_back("./yosemite1.jpg"); imagenames.push_back("./b.JPG"); imagenames.push_back("./yosemite3.jpg"); imagenames.push_back("./a.JPG"); imagenames.push_back("./yosemite4.jpg"); imagenames.push_back("./yosemite5.jpg"); imagenames.push_back("./raufusskauz.JPG"); imagenames.push_back("./yosemite6.jpg"); imagenames.push_back("./yosemite7.jpg"); imagenames.push_back("./c.JPG"); } cout << "Loading images" << endl; imagenames = featuresService.loadImagesArray(imagenames, images, imagesnocolor); numImages = imagenames.size(); cout << "Computing homographies" << endl; featuresService.computeMatchesAndHomography(imagesnocolor, imagesmatches); featuresService.computeRelatedImages(imagesmatches, relatedImages); featuresService.computePanoramas(relatedImages, panoramasmatches, imagesmatches); cout << "Related images" << endl; vector<Panorama> panoramasfinales; int lastadded; cout << "Creating panoramas" << endl; for (int itout = 0; itout < panoramasmatches.size(); itout++) { Panorama newpanorama; newpanorama.addImage(panoramasmatches[itout][0].getImage2(), images[panoramasmatches[itout][0].getImage2().getImgNumber()]); lastadded = panoramasmatches[itout][0].getImage2().getImgNumber(); panoramasmatches[itout].erase(panoramasmatches[itout].begin()); int size = panoramasmatches[itout].size(); for (int i = 0; i < size; i++) { for (int itin = 0; itin < panoramasmatches[itout].size(); itin++) { if (panoramasmatches[itout][itin].getImage1().getImgNumber() == lastadded) { newpanorama.addImage(panoramasmatches[itout][itin].getImage2(), images[panoramasmatches[itout][itin].getImage2().getImgNumber()]); lastadded = panoramasmatches[itout][itin].getImage2().getImgNumber(); break; } } } Mat destiny; bilateralFilter(newpanorama.getPanorama(), destiny, 5, 20,20); newpanorama.setPanorama(destiny); panoramasfinales.insert(panoramasfinales.end(), newpanorama); } cout << "Showing panoramas" << endl; for (unsigned int i = 0; i < panoramasfinales.size(); i++) { string nombre = "Resultado"; nombre.append(to_string(i)); imshow(nombre, panoramasfinales[i].getPanorama()); } waitKey(0); system("pause"); }
int main(int argc, char* argv[]) { // Exit with usage unless filename given as argument if (argc < 2) { usage(); } unsigned int i = 1, mask = 0; double threshold = 0.5; vector<string> images_to_mask; string pto_file = (""),output_pto = (""); string mask_format = ("PNG"); string model_file = ("celeste.model"); int course_fine = 0; int resize_dimension=800; // Deal with arguments // parse arguments int c; const char * optstring = "i:o:d:s:t:m:f:r:h"; while ((c = getopt (argc, argv, optstring)) != -1) { switch(c) { case 'h': usage(); break; case 'i': pto_file=optarg; break; case 'o': output_pto=optarg; break; case 't': threshold = atof(optarg); if(threshold<=0 || threshold>1) { cerr << "Invalid parameter: threshold (-t) should be between 0 and 1" << std::endl; return 1; }; break; case 'm': mask = atoi(optarg); if(mask<0 || mask>1) { cerr << "Invalid parameter: mask parameter (-m) can only be 0 or 1" << std::endl; return 1; }; break; case 'f': mask_format = optarg; break; case 'd': model_file = optarg; break; case 'r': course_fine = atoi(optarg); break; case 's': resize_dimension = atoi(optarg); if(resize_dimension<100) { cerr << "Invalid parameter: maximum dimension (-s) should be bigger than 100" << std::endl; return 1; }; break; case ':': cerr <<"Missing parameter for parameter " << argv[optind] << endl; return 1; break; case '?': /* invalid parameter */ return 1; break; default: /* unknown */ usage(); }; }; while(optind<argc) { images_to_mask.push_back(argv[optind]); optind++; }; if(images_to_mask.size()==0 && pto_file.empty()) { cout << "No project file or image files given."<< endl; return 1; }; // Check model file if (!fileexists(model_file)){ #if _WINDOWS char buffer[MAX_PATH];//always use MAX_PATH for filepaths GetModuleFileName(NULL,buffer,sizeof(buffer)); string working_path=(buffer); string install_path_model=""; //remove filename std::string::size_type pos=working_path.rfind("\\"); if(pos!=std::string::npos) { working_path.erase(pos); //remove last dir: should be bin pos=working_path.rfind("\\"); if(pos!=std::string::npos) { working_path.erase(pos); //append path delimiter and path working_path.append("\\share\\hugin\\data\\"); install_path_model=working_path; } } #elif defined MAC_SELF_CONTAINED_BUNDLE char path[PATH_MAX + 1]; uint32_t size = sizeof(path); string install_path_model(""); if (_NSGetExecutablePath(path, &size) == 0) { install_path_model=dirname(path); install_path_model.append("/../Resources/xrc/"); } #else string install_path_model = (INSTALL_DATA_DIR); #endif install_path_model.append(model_file); if (!fileexists(install_path_model)){ cout << endl << "Couldn't open SVM model file " << model_file << endl; cout << "Also tried " << install_path_model << endl << endl; exit(1); }else{ model_file = install_path_model; } } // Set output .pto filename if not given if (output_pto == ("") && pto_file != ("")){ output_pto = pto_file.substr(0,pto_file.length()-4).append("_celeste.pto"); } // Convert mask format to upper case transform(mask_format.begin(), mask_format.end(), mask_format.begin(),(int(*)(int)) toupper); if (mask_format == ("JPG")){ mask_format = ("JPEG"); } if (mask_format != ("PNG") &&mask_format != ("BMP") && mask_format != ("GIF") && mask_format != ("JPEG") && mask_format != ("TIFF")){ mask_format = ("TIFF"); } // Print some stuff out cout << endl << "Celeste: Removes cloud-like control points from Hugin project files and creates image masks" << endl; cout << "using Support Vector Machines." << endl; cout << endl << "Version " << DISPLAY_VERSION << endl << endl; cout << "Arguments:" << endl; cout << "Input Hugin file:\t" << pto_file << endl; cout << "Output Hugin file:\t" << output_pto << endl; cout << "SVM model file:\t\t" << model_file << endl; cout << "Max dimension:\t\t" << resize_dimension << endl; cout << "SVM threshold:\t\t" << threshold << endl; cout << "Create PTO masks:\t"; if (mask){ cout << "Yes" << endl; }else{ cout << "No" << endl; } cout << "Mask format:\t\t" << mask_format << endl; cout << "Filter radius:\t\t"; // Mask resolution int radius; if (course_fine) { radius = 10; cout << "Small" << endl << endl; } else { radius=20; cout << "Large" << endl << endl; } // Convert mask format to lower case cout << "Converting mask format to lower case..." << endl; transform(mask_format.begin(), mask_format.end(), mask_format.begin(),(int(*)(int)) tolower); // Vectors to store SVM responses and PTO file info etc vector<string> images,pto_file_top,pto_file_cps,pto_file_end; vector<double> svm_responses; cout << "Loading SVMmodel..." << endl; struct celeste::svm_model* model; if(!celeste::loadSVMmodel(model,model_file)) { cerr << "Could not load SVMmodel" << endl; return 1; }; // Mask images if (images_to_mask.size()) { cout << "Masking images..." << endl << endl; for (unsigned int l = 0; l < images_to_mask.size(); l++) { std::string imagefile=images_to_mask[l]; try { cout << "Opening image file:\t" << imagefile << endl; // Read image given and convert to UInt16 vigra::UInt16RGBImage in=loadAndConvertImage(imagefile); if(in.width()==0 || in.height()==0) { continue; }; // Create mask file name string mask_name = generateMaskName(imagefile,mask_format); cout << "Generating mask:\t" << mask_name << endl; // Create mask vigra::BImage mask=celeste::getCelesteMask(model,in,radius,threshold,resize_dimension); exportImage(srcImageRange(mask), vigra::ImageExportInfo(mask_name.c_str()).setPixelType("UINT8")); } catch (vigra::StdException & e) { // catch any errors that might have occured and print their reason cout << "Unable to open file:\t" << imagefile << endl << endl; cout << e.what() << endl << endl; }; }; }; // Process PTO file if (pto_file != ("")) { cout << "Parsing Hugin project file " << pto_file << endl << endl; Panorama pano; ifstream prjfile(pto_file.c_str()); if (!prjfile.good()) { cerr << "could not open script : " << pto_file << endl; celeste::destroySVMmodel(model); return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(pto_file)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "error while parsing panos tool script: " << pto_file << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; celeste::destroySVMmodel(model); return 1; } cout << "Done parsing Hugin step 1" << endl; for(unsigned int i=0;i<pano.getNrOfImages();i++) { CPointVector cps=pano.getCtrlPointsVectorForImage(i); if(cps.size()>0 || mask) { try { string imagefile=pano.getImage(i).getFilename(); vigra::UInt16RGBImage in=loadAndConvertImage(imagefile); if(in.width()==0 || in.height()==0) { continue; }; if(cps.size()>0) { UIntSet cloudCP=celeste::getCelesteControlPoints(model,in,cps,radius,threshold,resize_dimension); if(cloudCP.size()>0) { for(UIntSet::reverse_iterator it=cloudCP.rbegin();it!=cloudCP.rend();++it) { pano.removeCtrlPoint(*it); }; }; }; if(mask) { string mask_name = generateMaskName(imagefile,mask_format); // Create mask vigra::BImage mask=celeste::getCelesteMask(model,in,radius,threshold,resize_dimension); exportImage(srcImageRange(mask), vigra::ImageExportInfo(mask_name.c_str()).setPixelType("UINT8")); }; } catch (vigra::StdException & e) { // catch any errors that might have occured and print their reason cout << "Unable to open file:\t" << pano.getImage(i).getFilename() << endl << endl; cout << e.what() << endl << endl; }; }; }; cout << "about to write new pto file" << endl; // write new pto file ofstream of(output_pto.c_str()); UIntSet imgs; cout << "fill_set..." << endl; fill_set(imgs,0, pano.getNrOfImages()-1); cout << "printing..." << endl; pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(pto_file)); cout << endl << "Written file " << output_pto << endl << endl; } celeste::destroySVMmodel(model); return(0); }
CPVector AutoPanoSiftStack::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); }; //generate cp for median exposure ret_value=0; if(images_layer.size()>1) { AutoPanoSift matcher; cps=matcher.automatch(setting, pano, images_layer, nFeatures, ret_value, parent); if(ret_value!=0) return cps; }; //now 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) return cps; }; }; } return cps; };