deghosting_mask.cpp

Go to the documentation of this file.
00001 
00021 #include <iostream>
00022 #include <string>
00023 #include <cstring>
00024 
00025 #include <hugin_config.h>
00026 #include <hugin_version.h>
00027 // for stripExtension
00028 #include <hugin_utils/utils.h>
00029 // for exportImage
00030 #include <vigra_ext/impexalpha.hxx>
00031 
00032 #include "deghosting.h"
00033 #include "support.h"
00034 #include "threshold.h"
00035 #include "denoise.h"
00036 
00037 // deghosting algorithms
00038 #include "khan.h"
00039 
00040 #include <getopt.h>
00041 #ifdef WIN32
00042     #define snprintf _snprintf
00043 #endif
00044 
00045 using std::cout;
00046 using std::cerr;
00047 using std::endl;
00048 using std::string;
00049 
00050 using namespace deghosting;
00051 
00052 // options for otherFlags
00053 static const uint16_t SAVE_GENWEIGHTS = 1;
00054 static const uint16_t OTHER_GRAY = 2;
00055 
00056 // globals containing settings
00057 static int iterations = 4;
00058 static double sigma = 30;
00059 static uint16_t flags = ADV_ONLYP + ADV_MULTIRES;
00060 static uint16_t otherFlags = 0;
00061 static uint16_t otherThresholdFlags = 0;
00062 static uint16_t debugFlags = 0;
00063 static EMoR response(0.0f);
00064 static int verbosity = 0;
00065 static double thresholdLim = 150;
00066 static double contrast = 1.3;
00067 
00070 void parseOptions_advanced(char* optarg) {
00071     for(char *c = optarg; *c; c++) {
00072         switch(*c) {
00073             case 'f':
00074                 otherFlags += OTHER_GRAY;
00075                 break;
00076             case 'g':
00077                 flags += ADV_GAMMA;
00078                 break;
00079             case 'm':
00080                 flags -= ADV_MULTIRES;
00081                 break;
00082             case 't':
00083                 otherThresholdFlags += THRESHOLD_DONTCARE;
00084                 break;
00085             case 'w':
00086                 flags -= ADV_ONLYP;
00087                 break;
00088             default:
00089                 cerr<< "Error: unknown option" << endl;
00090                 exit(1);
00091         }
00092     }
00093 }
00094 
00097 void parseOptions_save(char* optarg) {
00098     for(char *c = optarg; *c; c++) {
00099         switch(*c) {
00100             case 'i':
00101                 debugFlags += SAVE_INITWEIGHTS;
00102                 break;
00103             case 'w':
00104                 otherFlags += SAVE_GENWEIGHTS;
00105                 break;
00106             default:
00107                 cerr<< "Error: unknown option" << endl;
00108                 exit(1);
00109         }
00110     }
00111 }
00112 
00113 static void usage()
00114 {
00115     cerr << "deghosting_mask: creates mask for removing ghosting in images" << endl
00116          << "deghosting_mask version " << DISPLAY_VERSION << endl
00117          << endl
00118          << "Usage: deghosting_mask [options] inputfile(s) " << endl
00119          << "   option are: " << endl
00120          << "     -o, --output=PREFIX       prefix for output masks" << endl
00121          << "     -i, --iterations=ITER     number of iterations, default is (ITER > 0)" << endl
00122          << "                               default: " << iterations << endl
00123          << "     -s, --sigma=SIGMA         standard deviation of Gaussian weighting" << endl
00124          << "                               function (SIGMA > 0); default: " << sigma << endl
00125          //<< "     -r, --response=E:M:o:R    use camera response specified in EMoR format" << endl
00126          << "     -t, --threshold=THRESH    threshold; default: " << thresholdLim << endl
00127          << "     -c, --contrast=CONTR      change contrast before applying threshold;" << endl
00128          << "                               default: " << contrast << endl
00129          << "     -a, --advanced=SET        advanced settings. Possible options are:" << endl
00130          << "                               f   use gray images for computation. It's about two times faster" << endl
00131          << "                                   but it usually returns worse results." << endl
00132          << "                                   You also have to change threshold to smaller value (around 100)" << endl
00133          << "                               g   use gamma 2.2 correction instead of logarithm if input images are HDR" << endl
00134          << "                               m   do not scale image, NOTE: slows down process" << endl
00135          << "                               t   use simple threshold, may result in holes in images" << endl
00136          << "                               w   compute \"complete\" weights, not only probabilities" << endl
00137          << "     -w, --save=SET            advanced save settings" << endl
00138          << "                               i   save initial weights" << endl
00139          << "                               w   save generated weights" << endl
00140          << "     -b BLOCKSIZE              image cache BLOCKSIZE in kilobytes; default: " <<
00141             (CachedFileImageDirector::v().getBlockSize() / 1024LL) << "KB" << endl
00142          << "     -m CACHESIZE              set image CACHESIZE in megabytes; default: " << 
00143             (CachedFileImageDirector::v().getAllocation() / 1048576LL) << "MB" << endl
00144          << "     -h, --help                display this help" << endl
00145          << "     -v, --verbose             verbose, repeat for more verbose output" << endl;
00146 }
00147 
00148 int main(int argc, char *argv[]) {
00149     try{
00150     const char * optstring = "o:i:s:r:t:c:a:w:b:m:hv";
00151     opterr = 0;
00152     int c;
00153     
00154     string outputPrefix = "weight";
00155     
00156     enum optionArgumentKind {
00157         NoArgument,
00158         StringArgument,
00159         DoubleArgument,
00160         IntegerArgument,
00161         ArrayArgument
00162     };
00163     
00164     enum optionId {
00165         outputID,
00166         iterationsID,
00167         sigmaID,
00168         responseID,
00169         thresholdID,
00170         contrastID,
00171         advancedID,
00172         saveID,
00173         helpID,
00174         verboseID
00175     };
00176       
00177     static struct option longOptions[] = {
00178         {"output", 1, 0, StringArgument},
00179         {"iterations", 1, 0, IntegerArgument},
00180         {"sigma", 1, 0, DoubleArgument},
00181         {"response", 1, 0, ArrayArgument},
00182         {"threshold", 1, 0, DoubleArgument},
00183         {"contrast", 1, 0, DoubleArgument},
00184         {"advanced", 1, 0, StringArgument},
00185         {"save", 1, 0, StringArgument},
00186         {"help", 0, 0, NoArgument},
00187         {"verbose", 0, 0, NoArgument},
00188         {0, 0, 0, 0}
00189     };
00190     
00191     // TEST
00192     // response for testing
00193     response.resize(5);
00194     response[0] = -3.59f;
00195     response[1] = -0.93f;
00196     response[2] =  0.11f;
00197     response[3] = -0.22f;
00198     response[4] =  0.34f;
00199        
00200     int optionIndex = 0;
00201     
00202     while ((c = getopt_long(argc, argv, optstring, longOptions, &optionIndex)) != -1) {
00203         switch (c) {
00204             case NoArgument: {
00205                 if (longOptions[optionIndex].flag != 0) break;
00206                 switch (optionIndex) {
00207                     case helpID:
00208                         usage();
00209                         return 0;
00210                     case verboseID:
00211                         verbosity++;
00212                         break;
00213                     default:
00214                         cerr << "There's a problem with parsing options" << endl;
00215                         return 1;
00216                 }
00217                 break;
00218             }
00219             
00220             case StringArgument: {
00221                 if (longOptions[optionIndex].flag != 0) break;
00222                 switch (optionIndex) {
00223                     case outputID:
00224                         outputPrefix = optarg;
00225                         break;
00226                     case advancedID:
00227                         parseOptions_advanced(optarg);
00228                         break;
00229                     case saveID:
00230                         parseOptions_save(optarg);
00231                         break;
00232                     default:
00233                         cerr << "There's a problem with parsing options" << endl;
00234                         return 1;
00235                 }
00236                 break;
00237             }
00238             
00239             case IntegerArgument: {
00240                 if (longOptions[optionIndex].flag != 0) break;
00241                 switch (optionIndex) {
00242                     case iterationsID:
00243                         iterations = atoi(optarg);
00244                         break;
00245                     default:
00246                         cerr << "There's a problem with parsing options" << endl;
00247                         return 1;
00248                 }
00249                 break;
00250             }
00251             
00252             case DoubleArgument: {
00253                 if (longOptions[optionIndex].flag != 0) break;
00254                 switch (optionIndex) {
00255                     case sigmaID:
00256                         sigma = atof(optarg);
00257                         break;
00258                     case thresholdID:
00259                         thresholdLim = atof(optarg);
00260                         break;
00261                     case contrastID:
00262                         contrast = atof(optarg);
00263                         break;
00264                 }
00265                 break;
00266             }
00267             
00268             case ArrayArgument: {
00269                 if (longOptions[optionIndex].flag != 0) break;
00270                 switch (optionIndex) {
00271                     case responseID:
00272                         // TODO
00273                         break;
00274                 }
00275                 break;
00276             }
00277             
00278             case 'o':
00279                 outputPrefix = optarg;
00280                 break;
00281             case 'i':
00282                 iterations = atoi(optarg);
00283                 break;
00284             case 's':
00285                 sigma = atof(optarg);
00286                 break;
00287             case 'r':
00288                 // TODO
00289                 break;
00290             case 't':
00291                 thresholdLim = atof(optarg);
00292                 break;
00293             case 'c':
00294                 contrast = atof(optarg);
00295                 break;
00296             case 'a':
00297                 parseOptions_advanced(optarg);
00298                 break;
00299             case 'w':
00300                 parseOptions_save(optarg);
00301                 break;
00302             case 'b': {
00303                 const int kilobytes = atoi(optarg);
00304                 if (kilobytes < 1) {
00305                     cerr << "cache block size must be 1 or more." << endl;
00306                     return 1;
00307                 }
00308                 CachedFileImageDirector::v().setBlockSize(static_cast<long long>(kilobytes) << 10);
00309                 break;
00310             }
00311             case 'm': {
00312                 const int megabytes = atoi(optarg);
00313                 if (megabytes < 1) {
00314                     cerr << "memory limit must be 1 or more." << endl;
00315                     return 1;
00316                 }
00317                 CachedFileImageDirector::v().setAllocation(static_cast<long long>(megabytes) << 20);
00318                 break;
00319             }
00320             case 'h':
00321                 usage();
00322                 return 0;
00323             case 'v':
00324                 verbosity++;
00325                 break;
00326         }
00327     }
00328     
00329     cout << endl;
00330     
00331     unsigned nFiles = argc - optind;
00332     if (nFiles == 0) {
00333         cerr << std::endl << "Error: at least three input images needed" << std::endl <<std::endl;
00334         usage();
00335         return 1;
00336     } else if (nFiles < 3) {
00337         std::cout << std::endl << "Error: You have to specify at least three images." << std::endl;
00338         return 1;
00339     }
00340     
00341     // load all images
00342     vector<string> inputFiles;
00343     for (size_t i=optind; i < (size_t)argc; i++)
00344     {
00345         inputFiles.push_back(argv[i]);
00346     }
00347     
00348     Deghosting* deghoster = NULL;
00349     
00350         vector<FImagePtr> weights;
00351         if (otherFlags & OTHER_GRAY) {
00352             Khan<float> khanDeghoster(inputFiles, flags, debugFlags, iterations, sigma, verbosity);
00353             deghoster = &khanDeghoster;
00354             weights = deghoster->createWeightMasks();
00355         } else {
00356             Khan<RGBValue<float> > khanDeghoster(inputFiles, flags, debugFlags, iterations, sigma, verbosity);
00357             deghoster = &khanDeghoster;
00358             weights = deghoster->createWeightMasks();
00359         }
00360         
00361         //deghoster->setCameraResponse(response);
00362                 
00363         // save weights
00364         if (otherFlags & SAVE_GENWEIGHTS) {
00365             for (unsigned int i=0; i<weights.size(); ++i) {
00366                 char tmpfn[100];
00367                 snprintf(tmpfn, 99, "%s_%d.tif", outputPrefix.c_str(), i);
00368                 ImageExportInfo exWeights(tmpfn);
00369                 exportImage(srcImageRange(*weights[i]), exWeights.setPixelType("UINT8"));
00370             }
00371         }
00372         
00373         // apply contrast functor
00374         for (unsigned int i=0; i < weights.size(); ++i) {
00375             transformImage(srcImageRange(*(weights[i])), destImage(*(weights[i])), BrightnessContrastFunctor<FImage::PixelType>(1, contrast, 0, 255));
00376         }
00377         
00378         vector<BImagePtr> thresholded = threshold(weights, thresholdLim, otherThresholdFlags);
00379         
00380         // save masks with treshold applied
00381         for (unsigned int i=0; i<weights.size(); ++i) {
00382             char tmpfn[100];
00383             string fileName = hugin_utils::stripExtension(inputFiles[i]);
00384             fileName = hugin_utils::stripPath(fileName);
00385             snprintf(tmpfn, 99, "%s_mask.tif", fileName.c_str());
00386             ImageExportInfo exWeights(tmpfn);
00387             BImage outImg = BImage((*thresholded[i]).size());
00388             simpleDenoise(srcImageRange(*thresholded[i]), destImage(outImg));
00389             exportImage(srcImageRange(outImg), exWeights.setPixelType("UINT8"));
00390         }
00391     } catch (const std::exception & e) {
00392         std::cerr << "caught exception: " << e.what() << std::endl;
00393         return 1;
00394     } catch (...) {
00395         std::cerr << "caught unknown exception" << std::endl;
00396         return 1;
00397     }
00398     return 0;
00399 }

Generated on Thu Apr 24 01:25:30 2014 for Hugintrunk by  doxygen 1.3.9.1