main.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 ; tab-width: 4 -*-
00002 /*
00003 * Copyright (C) 2007-2008 Anael Orlinski
00004 *
00005 * This file is part of Panomatic.
00006 *
00007 * Panomatic is free software; you can redistribute it and/or modify
00008 * it under the terms of the GNU General Public License as published by
00009 * the Free Software Foundation; either version 2 of the License, or
00010 * (at your option) any later version.
00011 *
00012 * Panomatic is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 * GNU General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU General Public License
00018 * along with Panomatic; if not, write to the Free Software
00019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 */
00021 
00022 #include <iostream>
00023 #include <vector>
00024 #include <string>
00025 #include <boost/foreach.hpp>
00026 #include "Utils.h"
00027 #include <getopt.h>
00028 
00029 using namespace std;
00030 
00031 #include "PanoDetector.h"
00032 
00033 void printVersion()
00034 {
00035     std::cout << "Hugin's cpfind " << DISPLAY_VERSION << endl;
00036     std::cout << "based on Pan-o-matic by Anael Orlinski" << endl;
00037 };
00038 
00039 void printUsage()
00040 {
00041     printVersion();
00042     cout << endl
00043         << "Basic usage: " << endl
00044         << "  cpfind -o output_project project.pto" << endl
00045         << "  cpfind -k i0 -k i1 ... -k in project.pto" << endl
00046         << "  cpfind --kall project.pto" << endl
00047         << endl << "The input project file is required." << endl
00048         << endl << "General options" << endl
00049         << "  -q|--quiet   Do not output progress" << endl
00050         << "  -v|--verbose  Verbose output" << endl
00051         << "  -h|--help     Shows this help screen" << endl
00052         << "  --version     Prints the version number and exits then" << endl
00053         << "  -o|--output=<string>  Sets the filename of the output file" << endl
00054         << "                        (default: default.pto)" << endl
00055         << endl << "Matching strategy (these options are mutually exclusive)" << endl
00056         << "  --linearmatch   Enable linear images matching" << endl
00057         << "                  Can be fine tuned with" << endl
00058         << "      --linearmatchlen=<int>  Number of images to match (default: 1)" << endl
00059         << "  --multirow      Enable heuristic multi row matching" << endl
00060         << "  --prealigned    Match only overlapping images," << endl
00061         << "                  requires a rough aligned panorama" << endl
00062         << endl << "Feature description options" << endl
00063         << "  --sieve1width=<int>    Sieve 1: Number of buckets on width (default: 10)" << endl
00064         << "  --sieve1height=<int>   Sieve 1: Number of buckets on height (default: 10)" << endl
00065         << "  --sieve1size=<int>     Sieve 1: Max points per bucket (default: 100)" << endl
00066         << "  --kdtreesteps=<int>          KDTree: search steps (default: 200)" << endl
00067         << "  --kdtreeseconddist=<double>  KDTree: distance of 2nd match (default: 0.25)" << endl
00068         << endl << "Feature matching options" << endl
00069         << "  --ransaciter=<int>     Ransac: iterations (default: 1000)" << endl
00070         << "  --ransacdist=<int>     Ransac: homography estimation distance threshold" << endl
00071         << "                                 (in pixels) (default: 25)" << endl
00072         << "  --ransacmode=<string>  Ransac: Select the mode used in the ransac step." << endl
00073         << "                                 Possible values: auto, hom, rpy, rpyv, rpyb" << endl
00074         << "                                 (default: auto)" << endl
00075         << "  --minmatches=<int>     Minimum matches (default: 6)" << endl
00076         << "  --sieve2width=<int>    Sieve 2: Number of buckets on width (default: 5)" << endl
00077         << "  --sieve2height=<int>   Sieve 2: Number of buckets on height (default: 5)" << endl
00078         << "  --sieve2size=<int>     Sieve 2: Max points per bucket (default: 1)" << endl
00079         << endl << "Caching options" << endl
00080         << "  -c|--cache    Caches automaticall keypoints to external file" << endl
00081         << "  --clean       Clean up cached keyfiles" << endl
00082         << "  -p|--keypath=<string>    Store keyfiles in given path" << endl
00083         << "  -k|--writekeyfile=<int>  Write a keyfile for this image number" << endl
00084         << "  --kall                   Write keyfiles for all images in the project" << endl
00085         << endl << "Advanced options" << endl
00086         << "  --celeste       Masks area with clouds before running feature descriptor" << endl
00087         << "                  Celeste can be fine tuned with the following parameters" << endl
00088         << "      --celestethreshold=<int>  Threshold for celeste (default 0.5)" << endl
00089         << "      --celesteradius=<int>     Radius for celeste (in pixels, default 20)" << endl
00090         << "  --ncores=<int>  Number of threads to use (default: autodetect number of cores)" << endl;
00091 };
00092 
00093 bool parseOptions(int argc, char** argv, PanoDetector& ioPanoDetector)
00094 {
00095     enum
00096     {
00097         SIEVE1WIDTH=256,
00098         SIEVE1HEIGHT,
00099         SIEVE1SIZE,
00100         LINEARMATCH,
00101         LINEARMATCHLEN,
00102         MULTIROW,
00103         PREALIGNED,
00104         KDTREESTEPS,
00105         KDTREESECONDDIST,
00106         MINMATCHES,
00107         RANSACMODE,
00108         RANSACITER,
00109         RANSACDIST,
00110         SIEVE2WIDTH,
00111         SIEVE2HEIGHT,
00112         SIEVE2SIZE,
00113         KALL,
00114         CLEAN,
00115         CELESTE,
00116         CELESTETHRESHOLD,
00117         CELESTERADIUS,
00118         CPFINDVERSION
00119     };
00120     const char* optstring = "qvftn:o:k:cp:h";
00121     static struct option longOptions[] =
00122     {
00123         {"quiet", no_argument, NULL, 'q' },
00124         {"verbose", no_argument, NULL, 'v'},
00125         {"fullscale", no_argument, NULL, 'f'},
00126         {"sieve1width", required_argument, NULL, SIEVE1WIDTH},
00127         {"sieve1height", required_argument, NULL, SIEVE1HEIGHT},
00128         {"sieve1size", required_argument, NULL, SIEVE1SIZE},
00129         {"linearmatch", no_argument, NULL, LINEARMATCH},
00130         {"linearmatchlen", required_argument, NULL, LINEARMATCHLEN},
00131         {"multirow", no_argument, NULL, MULTIROW},
00132         {"prealigned", no_argument, NULL, PREALIGNED},
00133         {"kdtreesteps", required_argument, NULL, KDTREESTEPS},
00134         {"kdtreeseconddist", required_argument, NULL, KDTREESECONDDIST},
00135         {"minmatches", required_argument, NULL, MINMATCHES},
00136         {"ransacmode", required_argument, NULL, RANSACMODE},
00137         {"ransaciter", required_argument, NULL, RANSACITER},
00138         {"ransacdist", required_argument, NULL, RANSACDIST},
00139         {"sieve2width", required_argument, NULL, SIEVE2WIDTH},
00140         {"sieve2height", required_argument, NULL, SIEVE2HEIGHT},
00141         {"sieve2size", required_argument, NULL, SIEVE2SIZE},
00142         {"test", no_argument, NULL, 't'},
00143         {"ncores", required_argument, NULL, 'n'},
00144         {"output", required_argument, NULL, 'o'},
00145         {"writekeyfile", required_argument, NULL, 'k'},
00146         {"kall", no_argument, NULL, KALL},
00147         {"cache", no_argument, NULL, 'c'},
00148         {"clean", no_argument, NULL, CLEAN},
00149         {"keypath", required_argument, NULL, 'p'},
00150         {"celeste", no_argument, NULL, CELESTE},
00151         {"celestethreshold", required_argument, NULL, CELESTETHRESHOLD},
00152         {"celesteradius", required_argument, NULL, CELESTERADIUS},
00153         {"version", no_argument, NULL, CPFINDVERSION},
00154         {"help", no_argument, NULL, 'h'},
00155         0
00156     };
00157 
00158     int c;
00159     int optionIndex = 0;
00160     int number;
00161     double floatNumber;
00162     string ransacMode;
00163     vector<int> keyfilesIndex;
00164     int doLinearMatch=0;
00165     int doMultirow=0;
00166     int doPrealign=0;
00167     while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00168     {
00169         switch (c)
00170         {
00171             case 'q':
00172                 ioPanoDetector.setVerbose(0);
00173                 break;
00174             case 'v':
00175                 ioPanoDetector.setVerbose(2);
00176                 break;
00177             case 'f':
00178                 ioPanoDetector.setDownscale(false);
00179                 break;
00180             case SIEVE1WIDTH:
00181                 number=atoi(optarg);
00182                 if(number>0)
00183                 {
00184                     ioPanoDetector.setSieve1Width(number);
00185                 };
00186                 break;
00187             case SIEVE1HEIGHT:
00188                 number=atoi(optarg);
00189                 if(number>0)
00190                 {
00191                     ioPanoDetector.setSieve1Height(number);
00192                 };
00193                 break;
00194             case SIEVE1SIZE:
00195                 number=atoi(optarg);
00196                 if(number>0)
00197                 {
00198                     ioPanoDetector.setSieve1Size(number);
00199                 };
00200                 break;
00201             case LINEARMATCH:
00202                 doLinearMatch=1;
00203                 break;
00204             case LINEARMATCHLEN:
00205                 number=atoi(optarg);
00206                 if(number>0)
00207                 {
00208                     ioPanoDetector.setLinearMatchLen(number);
00209                 };
00210                 break;
00211             case MULTIROW:
00212                 doMultirow=1;
00213                 break;
00214             case PREALIGNED:
00215                 doPrealign=1;
00216                 break;
00217             case KDTREESTEPS:
00218                 number=atoi(optarg);
00219                 if(number>0)
00220                 {
00221                     ioPanoDetector.setKDTreeSearchSteps(number);
00222                 };
00223                 break;
00224             case KDTREESECONDDIST:
00225                 floatNumber=atof(optarg);
00226                 if(floatNumber>0)
00227                 {
00228                     ioPanoDetector.setKDTreeSecondDistance(floatNumber);
00229                 };
00230                 break;
00231             case MINMATCHES:
00232                 number=atoi(optarg);
00233                 if(number>0)
00234                 {
00235                     ioPanoDetector.setMinimumMatches(number);
00236                 };
00237                 break;
00238             case RANSACMODE:
00239                 ransacMode=optarg;
00240                 cout << "Ransac: " << ransacMode << endl;
00241                 transform(ransacMode.begin(), ransacMode.end(), ransacMode.begin(),(int(*)(int)) tolower);
00242                 cout << "Ransac: " << ransacMode << endl;
00243                 if(ransacMode=="auto")
00244                 {
00245                     ioPanoDetector.setRansacMode(RANSACOptimizer::AUTO);
00246                 }
00247                 else
00248                 {
00249                     if(ransacMode=="hom")
00250                     {
00251                         ioPanoDetector.setRansacMode(RANSACOptimizer::HOMOGRAPHY);
00252                     }
00253                     else
00254                     {
00255                         if(ransacMode=="rpy")
00256                         {
00257                             ioPanoDetector.setRansacMode(RANSACOptimizer::RPY);
00258                         }
00259                         else
00260                         {
00261                             if(ransacMode=="rpyv")
00262                             {
00263                                 ioPanoDetector.setRansacMode(RANSACOptimizer::RPYV);
00264                             }
00265                             else
00266                             {
00267                                 if(ransacMode=="rpyvb")
00268                                 {
00269                                     ioPanoDetector.setRansacMode(RANSACOptimizer::RPYVB);
00270                                 }
00271                                 else
00272                                 {
00273                                     cout << "Warning: Invalid parameter in --ransacmode." << endl;
00274                                 };
00275                             };
00276                         };
00277                     };
00278                 };
00279                 break;
00280             case RANSACITER:
00281                 number=atoi(optarg);
00282                 if(number>0)
00283                 {
00284                     ioPanoDetector.setRansacIterations(number);
00285                 };
00286                 break;
00287             case RANSACDIST:
00288                 number=atoi(optarg);
00289                 if(number>0)
00290                 {
00291                     ioPanoDetector.setRansacDistanceThreshold(number);
00292                 };
00293                 break;
00294             case SIEVE2WIDTH:
00295                 number=atoi(optarg);
00296                 if(number>0)
00297                 {
00298                     ioPanoDetector.setSieve2Width(number);
00299                 };
00300                 break;
00301             case SIEVE2HEIGHT:
00302                 number=atoi(optarg);
00303                 if(number>0)
00304                 {
00305                     ioPanoDetector.setSieve2Height(number);
00306                 };
00307                 break;
00308             case SIEVE2SIZE:
00309                 number=atoi(optarg);
00310                 if(number>0)
00311                 {
00312                     ioPanoDetector.setSieve2Size(number);
00313                 };
00314                 break;
00315             case 't':
00316                 ioPanoDetector.setTest(true);
00317                 break;
00318             case 'n':
00319                 number=atoi(optarg);
00320                 if(number>0)
00321                 {
00322                     ioPanoDetector.setCores(number);
00323                 };
00324                 break;
00325             case 'o':
00326                 ioPanoDetector.setOutputFile(optarg);
00327                 break;
00328             case 'k':
00329                 number=atoi(optarg);
00330                 if((number==0) && (strcmp(optarg,"0")!=0))
00331                 {
00332                     cout << "Warning: " << optarg << " is not a valid image number of writekeyfile." << endl;
00333                 }
00334                 else
00335                 {
00336                     keyfilesIndex.push_back(number);
00337                 };
00338                 break;
00339             case KALL:
00340                 ioPanoDetector.setWriteAllKeyPoints();
00341                 break;
00342             case 'c':
00343                 ioPanoDetector.setCached(true);
00344                 break;
00345             case CLEAN:
00346                 ioPanoDetector.setCleanup(true);
00347                 break;
00348             case 'p':
00349                 ioPanoDetector.setKeyfilesPath(optarg);
00350                 break;
00351             case CELESTE:
00352                 ioPanoDetector.setCeleste(true);
00353                 break;
00354             case CELESTETHRESHOLD:
00355                 floatNumber=atof(optarg);
00356                 if(floatNumber>0.0)
00357                 {
00358                     ioPanoDetector.setCelesteThreshold(floatNumber);
00359                 };
00360                 break;
00361             case CELESTERADIUS:
00362                 number=atoi(optarg);
00363                 if(number>0)
00364                 {
00365                     ioPanoDetector.setCelesteRadius(number);
00366                 };
00367                 break;
00368             case CPFINDVERSION:
00369                 printVersion();
00370                 return false;
00371                 break;
00372             case 'h':
00373                 printUsage();
00374                 return false;
00375                 break;
00376             case ':':
00377                 cerr <<"Option " << longOptions[optionIndex].name << " requires an argument" << endl;
00378                 return false;
00379                 break;
00380             case '?':
00381             default:
00382                 break;
00383         };
00384     };
00385     
00386     if (argc - optind != 1)
00387     {
00388         cout << "Error: cpfind requires at least an input project file." << endl;
00389         return false;
00390     };
00391     ioPanoDetector.setInputFile(argv[optind]);
00392     if(doLinearMatch + doMultirow + doPrealign>1)
00393     {
00394         cout << "Error: The arguments --linearmatch, --multirow and --prealigned are" << endl
00395              << "       mutually exclusive. Use only one of them." << endl;
00396         return false;
00397     };
00398     if(doLinearMatch)
00399     {
00400         ioPanoDetector.setMatchingStrategy(PanoDetector::LINEAR);
00401     };
00402     if(doMultirow)
00403     {
00404         ioPanoDetector.setMatchingStrategy(PanoDetector::MULTIROW);
00405     };
00406     if(doPrealign)
00407     {
00408         ioPanoDetector.setMatchingStrategy(PanoDetector::PREALIGNED);
00409     };
00410     if(keyfilesIndex.size()>0)
00411     {
00412         ioPanoDetector.setKeyPointsIdx(keyfilesIndex);
00413     };
00414     return true;
00415 };
00416 
00417 int main(int argc, char** argv)
00418 {
00419     // create a panodetector object
00420     PanoDetector aPanoDetector;
00421     if(!parseOptions(argc, argv, aPanoDetector))
00422     {
00423         return 0;
00424     }
00425 
00426     if (!aPanoDetector.checkData())
00427     {
00428         return 0;
00429     }
00430 
00431     printVersion();
00432     if (aPanoDetector.getVerbose() > 1)
00433     {
00434         aPanoDetector.printDetails();
00435     }
00436 
00437     TIMETRACE("Detection",aPanoDetector.run());
00438 
00439     return 0;
00440 
00441 }

Generated on Mon Sep 22 01:25:43 2014 for Hugintrunk by  doxygen 1.3.9.1