cpclean.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00015 /*  This program is free software; you can redistribute it and/or
00016  *  modify it under the terms of the GNU General Public
00017  *  License as published by the Free Software Foundation; either
00018  *  version 2 of the License, or (at your option) any later version.
00019  *
00020  *  This software is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00023  *  General Public License for more details.
00024  *
00025  *  You should have received a copy of the GNU General Public
00026  *  License along with this software. If not, see
00027  *  <http://www.gnu.org/licenses/>.
00028  *
00029  */
00030 
00031 #include <fstream>
00032 #include <sstream>
00033 #include <getopt.h>
00034 
00035 #include <algorithms/optimizer/PTOptimizer.h>
00036 #include <algorithms/optimizer/ImageGraph.h>
00037 #include <algorithms/control_points/CleanCP.h>
00038 #include "panotools/PanoToolsInterface.h"
00039 
00040 static void usage(const char* name)
00041 {
00042     std::cout << name << ": remove wrong control points by statistic method" << std::endl
00043         << "cpclean version " << hugin_utils::GetHuginVersion() << std::endl
00044         << std::endl
00045         << "Usage:  " << name << " [options] input.pto" << std::endl
00046         << std::endl
00047         << "CPClean uses statistical methods to remove wrong control points" << std::endl << std::endl
00048         << "Step 1 optimises all images pairs, calculates for each pair mean " << std::endl
00049         << "       and standard deviation and removes all control points " << std::endl
00050         << "       with error bigger than mean+n*sigma" << std::endl
00051         << "Step 2 optimises the whole panorama, calculates mean and standard deviation" << std::endl
00052         << "       for all control points and removes all control points with error" << std::endl
00053         << "       bigger than mean+n*sigma" << std::endl << std::endl
00054         << "  Options:" << std::endl
00055         << "     --output|-o file.pto     Output Hugin PTO file." << std::endl
00056         << "                              Default: '<filename>_clean.pto'." << std::endl
00057         << "     --max-distance|-n num    distance factor for checking (default: 2)" << std::endl
00058         << "     --pairwise-checking|-p   do only pairwise optimisation (skip step 2)" << std::endl
00059         << "     --whole-pano-checking|-w do optimise whole panorama (skip step 1)" << std::endl
00060         << "     --dont-optimize|-s       skip optimisation step when optimisation the" << std::endl
00061         << "                              whole panorama" << std::endl
00062         << "     --check-line-cp|-l       also include line control points for calculation" << std::endl
00063         << "                              and filtering in step 2" << std::endl
00064         << "     --verbose|-v             verbose output during optimisation"<<std::endl
00065         << "     --help|-h                shows help" << std::endl
00066         << std::endl;
00067 }
00068 
00069 // dummy panotools progress functions
00070 static int ptProgress(int command, char* argument)
00071 {
00072     return 1;
00073 }
00074 
00075 static int ptinfoDlg(int command, char* argument)
00076 {
00077     return 1;
00078 }
00079 
00080 int main(int argc, char* argv[])
00081 {
00082     // parse arguments
00083     const char* optstring = "o:hn:pwslv";
00084     static struct option longOptions[] =
00085     {
00086         { "output", required_argument, NULL, 'o'},
00087         { "max-distance", required_argument, NULL, 'n'},
00088         { "pairwise-checking", no_argument, NULL, 'p'},
00089         { "whole-pano-checking", no_argument, NULL, 'w'},
00090         { "dont-optimize", no_argument, NULL, 's'},
00091         { "check-line-cp", no_argument, NULL, 'l' },
00092         { "verbose", no_argument, NULL, 'v'},
00093         { "help", no_argument, NULL, 'h' },
00094         0
00095     };
00096     int c;
00097     std::string output;
00098     bool onlyPair = false;
00099     bool wholePano = false;
00100     bool skipOptimisation = false;
00101     bool includeLineCp = false;
00102     bool verbose = false;
00103     double n = 2.0;
00104     while ((c = getopt_long(argc, argv, optstring, longOptions, nullptr)) != -1)
00105     {
00106         switch (c)
00107         {
00108             case 'o':
00109                 output = optarg;
00110                 break;
00111             case 'h':
00112                 usage(hugin_utils::stripPath(argv[0]).c_str());
00113                 return 0;
00114             case 'n':
00115                 n = atof(optarg);
00116                 if(n==0)
00117                 {
00118                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: " << optarg << " is not valid real number" << std::endl;
00119                     return 1;
00120                 };
00121                 if (n<1.0)
00122                 {
00123                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: n must be at least 1" << std::endl;
00124                     return 1;
00125                 };
00126                 break;
00127             case 'p':
00128                 onlyPair= true;
00129                 break;
00130             case 'w':
00131                 wholePano = true;
00132                 break;
00133             case 's':
00134                 skipOptimisation = true;
00135                 break;
00136             case 'l':
00137                 includeLineCp = true;
00138                 break;
00139             case 'v':
00140                 verbose = true;
00141                 break;
00142             case ':':
00143             case '?':
00144                 // missing argument or invalid switch
00145                 return 1;
00146                 break;
00147             default:
00148                 // this should not happen
00149                 abort ();
00150         }
00151     }
00152 
00153     if (argc - optind != 1)
00154     {
00155         if (argc - optind < 1)
00156         {
00157             std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
00158         }
00159         else
00160         {
00161             std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
00162         };
00163         return 1;
00164     };
00165 
00166     if (onlyPair && wholePano)
00167     {
00168         std::cerr << hugin_utils::stripPath(argv[0]) << ": Options -p and -w can't used together" << std::endl;
00169         return 1;
00170     };
00171 
00172     std::string input=argv[optind];
00173 
00174     HuginBase::Panorama pano;
00175     std::ifstream prjfile(input.c_str());
00176     if (!prjfile.good())
00177     {
00178         std::cerr << "could not open script : " << input << std::endl;
00179         return 1;
00180     }
00181     pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00182     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
00183     if (err != AppBase::DocumentData::SUCCESSFUL)
00184     {
00185         std::cerr << "error while parsing panos tool script: " << input << std::endl;
00186         std::cerr << "DocumentData::ReadWriteError code: " << err << std::endl;
00187         return 1;
00188     }
00189 
00190     const size_t nrImg=pano.getNrOfImages();
00191     if (nrImg < 2)
00192     {
00193         std::cerr << "Panorama should consist of at least two images" << std::endl;
00194         return 1;
00195     }
00196 
00197     if (pano.getNrOfCtrlPoints() < 3)
00198     {
00199         std::cerr << "Panorama should contain at least 3 control point" << std::endl;
00200     };
00201 
00202     if (!verbose)
00203     {
00204         PT_setProgressFcn(ptProgress);
00205         PT_setInfoDlgFcn(ptinfoDlg);
00206     };
00207 
00208     size_t cpremoved1 = 0;
00209     HuginBase::UIntSet CPtoRemove;
00210     // step 1 with pairwise optimisation
00211     if(!wholePano)
00212     {
00213         AppBase::DummyProgressDisplay dummy;
00214         CPtoRemove=getCPoutsideLimit_pair(pano, dummy, n);
00215         if (CPtoRemove.size()>0)
00216             for (HuginBase::UIntSet::reverse_iterator it = CPtoRemove.rbegin(); it != CPtoRemove.rend(); ++it)
00217             {
00218                 pano.removeCtrlPoint(*it);
00219             }
00220         cpremoved1=CPtoRemove.size();
00221     };
00222 
00223     // step 2 with optimisation of whole panorama
00224     bool unconnected=false;
00225     if(!onlyPair)
00226     {
00227         //check for unconnected images
00228         HuginGraph::ImageGraph graph(pano);
00229         unconnected = !graph.IsConnected();
00230         if (!unconnected)
00231         {
00232             CPtoRemove.clear();
00233             if(skipOptimisation)
00234             {
00235                 std::cout << std::endl << "Skipping optimisation, current image positions will be used." << std::endl;
00236             };
00237             CPtoRemove=getCPoutsideLimit(pano, n, skipOptimisation, includeLineCp);
00238             if (CPtoRemove.size()>0)
00239                 for (HuginBase::UIntSet::reverse_iterator it = CPtoRemove.rbegin(); it != CPtoRemove.rend(); ++it)
00240                 {
00241                     pano.removeCtrlPoint(*it);
00242                 }
00243         };
00244     };
00245 
00246     std::cout << std::endl;
00247     if(!wholePano)
00248     {
00249         std::cout << "Removed " << cpremoved1 << " control points in step 1" << std::endl;
00250     }
00251     if (!onlyPair)
00252     {
00253         if (unconnected)
00254         {
00255             std::cout << "Skipped step 2 because of unconnected image pairs" << std::endl;
00256         }
00257         else
00258         {
00259             std::cout << "Removed " << CPtoRemove.size() << " control points in step 2" << std::endl;
00260         };
00261     };
00262 
00263     //write output
00264     HuginBase::OptimizeVector optvec = pano.getOptimizeVector();
00265     HuginBase::UIntSet imgs;
00266     fill_set(imgs,0, pano.getNrOfImages()-1);
00267     // Set output .pto filename if not given
00268     if (output=="")
00269     {
00270         output=input.substr(0,input.length()-4).append("_clean.pto");
00271     }
00272     std::ofstream of(output.c_str());
00273     pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00274 
00275     std::cout << std::endl << "Written output to " << output << std::endl;
00276     return 0;
00277 }

Generated on 27 Apr 2017 for Hugintrunk by  doxygen 1.4.7