autooptimiser.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00028 #include <hugin_config.h>
00029 #include <hugin_version.h>
00030 
00031 #include <fstream>
00032 #include <sstream>
00033 #ifdef WIN32
00034  #include <getopt.h>
00035 #else
00036  #include <unistd.h>
00037 #endif
00038 
00039 #include <hugin_basic.h>
00040 #include <hugin_utils/stl_utils.h>
00041 #include <appbase/ProgressDisplayOld.h>
00042 #include <algorithms/optimizer/PTOptimizer.h>
00043 #include <algorithms/nona/CenterHorizontally.h>
00044 #include <algorithms/basic/StraightenPanorama.h>
00045 #include <algorithms/basic/CalculateMeanExposure.h>
00046 #include <algorithms/nona/FitPanorama.h>
00047 #include <algorithms/basic/CalculateOptimalScale.h>
00048 #include <algorithms/optimizer/PhotometricOptimizer.h>
00049 #include <panodata/ImageVariableGroup.h>
00050 #include <panodata/StandardImageVariableGroups.h>
00051 #include "ExtractPoints.h"
00052 
00053 using namespace std;
00054 using namespace hugin_utils;
00055 using namespace HuginBase;
00056 using namespace AppBase;
00057 
00058 static void usage(const char * name)
00059 {
00060     cerr << name << ": optimize image positions" << endl
00061          << "autooptimiser version " << DISPLAY_VERSION << endl
00062          << endl
00063          << "Usage:  " << name << " [options] input.pto" << endl
00064          << "   To read a project from stdio, specify - as input file." << endl
00065          << endl
00066          << "  Options:" << endl
00067          << "     -o file.pto  output file. If omitted, stdout is used." << endl
00068          << endl
00069          << "    Optimisation options (if not specified, no optimisation takes place)" << std::endl
00070          << "     -a       auto align mode, includes various optimisation stages, depending" << endl
00071          << "               on the amount and distribution of the control points" << endl
00072          << "     -p       pairwise optimisation of yaw, pitch and roll, starting from" << endl
00073          << "              first image" << endl
00074          << "     -m       Optimise photometric parameters" << endl
00075          << "     -n       Optimize parameters specified in script file (like PTOptimizer)" << endl
00076          << endl
00077          << "    Postprocessing options:" << endl
00078          << "     -l       level horizon (works best for horizontal panos)" << endl
00079          << "     -s       automatically select a suitable output projection and size" << endl
00080          << "    Other options:" << endl
00081          << "     -q       quiet operation (no progress is reported)" << endl
00082          << "     -v HFOV  specify horizontal field of view of input images." << endl
00083          << "               Used if the .pto file contains invalid HFOV values" << endl
00084          << "               (autopano-SIFT writes .pto files with invalid HFOV)" << endl
00085          << endl
00086          << "   When using -a -l -m and -s options together, a similar operation to the \"Align\"" << endl
00087          << "    button in hugin is performed." << endl
00088          << endl;
00089 }
00090 
00091 int main(int argc, char *argv[])
00092 {
00093     // parse arguments
00094     const char * optstring = "alho:npqsv:m";
00095     int c;
00096     string output;
00097     bool doPairwise = false;
00098     bool doAutoOpt = false;
00099     bool doNormalOpt = false;
00100     bool doLevel = false;
00101     bool chooseProj = false;
00102     bool quiet = false;
00103     bool doPhotometric = false;
00104     double hfov = 0.0;
00105     while ((c = getopt (argc, argv, optstring)) != -1)
00106     {
00107         switch (c) {
00108         case 'o':
00109             output = optarg;
00110             break;
00111         case 'h':
00112             usage(argv[0]);
00113             return 0;
00114         case 'p':
00115             doPairwise = true;
00116             break;
00117         case 'a':
00118             doAutoOpt = true;
00119             break;
00120         case 'n':
00121             doNormalOpt = true;
00122             break;
00123         case 'l':
00124             doLevel = true;
00125             break;
00126         case 's':
00127             chooseProj = true;
00128             break;
00129         case 'q':
00130             quiet = true;
00131             break;
00132         case 'v':
00133             hfov = atof(optarg);
00134             break;
00135         case 'm':
00136             doPhotometric = true;
00137             break;
00138         default:
00139             abort ();
00140         }
00141     }
00142 
00143     if (argc - optind != 1) {
00144         usage(argv[0]);
00145         return 1;
00146     }
00147 
00148     const char * scriptFile = argv[optind];
00149 
00150     Panorama pano;
00151     if (scriptFile[0] == '-') {
00152         DocumentData::ReadWriteError err = pano.readData(std::cin);
00153         if (err != DocumentData::SUCCESSFUL) {
00154             cerr << "error while reading script file from stdin." << endl;
00155             cerr << "DocumentData::ReadWriteError code: " << err << endl;
00156             return 1;
00157         }
00158     } else {
00159         ifstream prjfile(scriptFile);
00160         if (!prjfile.good()) {
00161             cerr << "could not open script : " << scriptFile << endl;
00162             return 1;
00163         }
00164         pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile));
00165         DocumentData::ReadWriteError err = pano.readData(prjfile);
00166         if (err != DocumentData::SUCCESSFUL) {
00167             cerr << "error while parsing panos tool script: " << scriptFile << endl;
00168             cerr << "DocumentData::ReadWriteError code: " << err << endl;
00169             return 1;
00170         }
00171     }
00172 
00173     if (pano.getNrOfImages() == 0) {
00174         cerr << "Panorama should consist of at least one image" << endl;
00175         return 1;
00176     }
00177 
00178     // for bad HFOV (from autopano-SIFT)
00179     for (unsigned i=0; i < pano.getNrOfImages(); i++) {
00180         SrcPanoImage img = pano.getSrcImage(i);
00181         if (img.getProjection() == SrcPanoImage::RECTILINEAR
00182             && img.getHFOV() >= 180)
00183         {
00184             // something is wrong here, try to read from exif data
00185             double focalLength = 0;
00186             double cropFactor = 0;
00187             cerr << "HFOV of image " << img.getFilename() << " invalid, trying to read EXIF tags" << endl;
00188             bool ok = img.readEXIF(focalLength, cropFactor, true, false);
00189             if (! ok) {
00190                 if (hfov) {
00191                     img.setHFOV(hfov);
00192                 } else {
00193                     cerr << "EXIF reading failed, please specify HFOV with -v" << endl;
00194                     return 1;
00195                 }
00196             }
00197             pano.setSrcImage(i, img);
00198         }
00199     }
00200 
00201     if(pano.getNrOfCtrlPoints()==0 && (doPairwise || doAutoOpt || doNormalOpt))
00202     {
00203         cerr << "Panorama have to have control points to optimise positions" << endl;
00204         return 1;
00205     };
00206     if (doPairwise && ! doAutoOpt) {
00207         // do pairwise optimisation
00208         set<string> optvars;
00209         optvars.insert("r");
00210         optvars.insert("p");
00211         optvars.insert("y");
00212         AutoOptimise::autoOptimise(pano);
00213 
00214         // do global optimisation
00215         if (!quiet) std::cerr << "*** Pairwise position optimisation" << endl;
00216         PTools::optimize(pano);
00217     } else if (doAutoOpt) {
00218         if (!quiet) std::cerr << "*** Adaptive geometric optimisation" << endl;
00219         SmartOptimise::smartOptimize(pano);
00220     } else if (doNormalOpt) {
00221         if (!quiet) std::cerr << "*** Optimising parameters specified in PTO file" << endl;
00222         PTools::optimize(pano);
00223     } else {
00224         if (!quiet) std::cerr << "*** Geometric parameters not optimized" << endl;
00225     }
00226 
00227     if (doLevel)
00228     {
00229         bool hasVerticalLines=false;
00230         CPVector allCP=pano.getCtrlPoints();
00231         if(allCP.size()>0 && (doPairwise || doAutoOpt || doNormalOpt))
00232         {
00233             for(size_t i=0;i<allCP.size() && !hasVerticalLines;i++)
00234             {
00235                 hasVerticalLines=(allCP[i].mode==ControlPoint::X);
00236             };
00237         };
00238         // straighten only if there are no vertical control points
00239         if(hasVerticalLines)
00240         {
00241             cout << "Skipping automatic leveling because of existing vertical control points." << endl;
00242         }
00243         else
00244         {
00245             StraightenPanorama(pano).run();
00246             CenterHorizontally(pano).run();
00247         };
00248     }
00249 
00250     if (chooseProj) {
00251         PanoramaOptions opts = pano.getOptions();
00252         double hfov, vfov;
00253         CalculateFitPanorama fitPano = CalculateFitPanorama(pano);
00254         fitPano.run();
00255         opts.setHFOV(fitPano.getResultHorizontalFOV());
00256         opts.setHeight(roundi(fitPano.getResultHeight()));
00257         vfov = opts.getVFOV();
00258         hfov = opts.getHFOV();
00259         // avoid perspective projection if field of view > 100 deg
00260         double mf = 100;
00261         if (vfov < mf) {
00262             // cylindrical or rectilinear
00263             if (hfov < mf) {
00264                 opts.setProjection(PanoramaOptions::RECTILINEAR);
00265             } else {
00266                 opts.setProjection(PanoramaOptions::CYLINDRICAL);
00267             }
00268         }
00269 
00270         // downscale pano a little
00271         double sizeFactor = 0.7;
00272 
00273         pano.setOptions(opts);
00274         double w = CalculateOptimalScale::calcOptimalScale(pano);
00275         opts.setWidth(roundi(opts.getWidth()*w*sizeFactor), true);
00276         pano.setOptions(opts);
00277     }
00278 
00279     if(doPhotometric)
00280     {
00281         // photometric estimation
00282         PanoramaOptions opts = pano.getOptions();
00283         int nPoints = 200;
00284         int pyrLevel=3;
00285         bool randomPoints = true;
00286         nPoints = nPoints * pano.getNrOfImages();
00287  
00288         std::vector<vigra_ext::PointPairRGB> points;
00289         ProgressDisplay *progressDisplay;
00290         if(!quiet)
00291             progressDisplay=new StreamProgressDisplay(std::cout);
00292         else
00293             progressDisplay=new DummyProgressDisplay();
00294         try 
00295         {
00296             loadImgsAndExtractPoints(pano, nPoints, pyrLevel, randomPoints, *progressDisplay, points, !quiet);
00297         } 
00298         catch (std::exception & e)
00299         {
00300             cerr << "caught exception: " << e.what() << endl;
00301             return 1;
00302         };
00303         if(!quiet)
00304             cout << "\rSelected " << points.size() << " points" << endl;
00305 
00306         if (points.size() == 0)
00307         {
00308             cerr << "Error: no overlapping points found, exiting" << endl;
00309             return 1;
00310         }
00311 
00312         progressDisplay->startSubtask("Photometric Optimization", 0.0);
00313         // first, ensure that vignetting and response coefficients are linked
00314         const HuginBase::ImageVariableGroup::ImageVariableEnum vars[] = {
00315                 HuginBase::ImageVariableGroup::IVE_EMoRParams,
00316                 HuginBase::ImageVariableGroup::IVE_ResponseType,
00317                 HuginBase::ImageVariableGroup::IVE_VigCorrMode,
00318                 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
00319                 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
00320         };
00321         HuginBase::StandardImageVariableGroups variable_groups(pano);
00322         HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
00323         for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
00324         {
00325             std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
00326             links_needed.clear();
00327             for (int v = 0; v < 5; v++)
00328             {
00329                 if (!lenses.getVarLinkedInPart(vars[v], i))
00330                 {
00331                     links_needed.insert(vars[v]);
00332                 }
00333             };
00334             if (!links_needed.empty())
00335             {
00336                 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum>::iterator it;
00337                 for (it = links_needed.begin(); it != links_needed.end(); it++)
00338                 {
00339                     lenses.linkVariablePart(*it, i);
00340                 }
00341             }
00342         }
00343 
00344         HuginBase::SmartPhotometricOptimizer::PhotometricOptimizeMode optmode = 
00345             HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_LDR;
00346         if (opts.outputMode == PanoramaOptions::OUTPUT_HDR)
00347         {
00348             optmode = HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_HDR;
00349         }
00350         SmartPhotometricOptimizer photoOpt(pano, progressDisplay, pano.getOptimizeVector(), points, optmode);
00351         photoOpt.run();
00352 
00353         // calculate the mean exposure.
00354         opts.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano);
00355         pano.setOptions(opts);
00356         progressDisplay->finishSubtask();
00357         delete progressDisplay;
00358     };
00359 
00360     // write result
00361     OptimizeVector optvec = pano.getOptimizeVector();
00362     UIntSet imgs;
00363     fill_set(imgs,0, pano.getNrOfImages()-1);
00364     if (output != "") {
00365         ofstream of(output.c_str());
00366         pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile));
00367     } else {
00368         pano.printPanoramaScript(cout, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile));
00369     }
00370     return 0;
00371 }

Generated on 5 Dec 2014 for Hugintrunk by  doxygen 1.4.7