deghosting_mask.cpp

Go to the documentation of this file.
00001 
00021 #include <iostream>
00022 #include <string>
00023 #include <cstring>
00024 #include <cstdio>
00025 
00026 #include <hugin_config.h>
00027 // for stripExtension
00028 #include <hugin_utils/utils.h>
00029 // for exportImage
00030 #include <vigra/impex.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 " << hugin_utils::GetHuginVersion() << 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          << "     -h, --help                display this help" << endl
00141          << "     -v, --verbose             verbose, repeat for more verbose output" << endl;
00142 }
00143 
00144 int main(int argc, char *argv[]) {
00145     try{
00146     const char * optstring = "o:i:s:r:t:c:a:w:hv";
00147     opterr = 0;
00148     int c;
00149     
00150     string outputPrefix = "weight";
00151     
00152     enum optionArgumentKind {
00153         NoArgument,
00154         StringArgument,
00155         DoubleArgument,
00156         IntegerArgument,
00157         ArrayArgument
00158     };
00159     
00160     enum optionId {
00161         outputID,
00162         iterationsID,
00163         sigmaID,
00164         responseID,
00165         thresholdID,
00166         contrastID,
00167         advancedID,
00168         saveID,
00169         helpID,
00170         verboseID
00171     };
00172       
00173     static struct option longOptions[] = {
00174         {"output", 1, 0, StringArgument},
00175         {"iterations", 1, 0, IntegerArgument},
00176         {"sigma", 1, 0, DoubleArgument},
00177         {"response", 1, 0, ArrayArgument},
00178         {"threshold", 1, 0, DoubleArgument},
00179         {"contrast", 1, 0, DoubleArgument},
00180         {"advanced", 1, 0, StringArgument},
00181         {"save", 1, 0, StringArgument},
00182         {"help", 0, 0, NoArgument},
00183         {"verbose", 0, 0, NoArgument},
00184         {0, 0, 0, 0}
00185     };
00186     
00187     // TEST
00188     // response for testing
00189     response.resize(5);
00190     response[0] = -3.59f;
00191     response[1] = -0.93f;
00192     response[2] =  0.11f;
00193     response[3] = -0.22f;
00194     response[4] =  0.34f;
00195        
00196     int optionIndex = 0;
00197     
00198     while ((c = getopt_long(argc, argv, optstring, longOptions, &optionIndex)) != -1) {
00199         switch (c) {
00200             case NoArgument: {
00201                 if (longOptions[optionIndex].flag != 0) break;
00202                 switch (optionIndex) {
00203                     case helpID:
00204                         usage();
00205                         return 0;
00206                     case verboseID:
00207                         verbosity++;
00208                         break;
00209                     default:
00210                         cerr << "There's a problem with parsing options" << endl;
00211                         return 1;
00212                 }
00213                 break;
00214             }
00215             
00216             case StringArgument: {
00217                 if (longOptions[optionIndex].flag != 0) break;
00218                 switch (optionIndex) {
00219                     case outputID:
00220                         outputPrefix = optarg;
00221                         break;
00222                     case advancedID:
00223                         parseOptions_advanced(optarg);
00224                         break;
00225                     case saveID:
00226                         parseOptions_save(optarg);
00227                         break;
00228                     default:
00229                         cerr << "There's a problem with parsing options" << endl;
00230                         return 1;
00231                 }
00232                 break;
00233             }
00234             
00235             case IntegerArgument: {
00236                 if (longOptions[optionIndex].flag != 0) break;
00237                 switch (optionIndex) {
00238                     case iterationsID:
00239                         iterations = atoi(optarg);
00240                         break;
00241                     default:
00242                         cerr << "There's a problem with parsing options" << endl;
00243                         return 1;
00244                 }
00245                 break;
00246             }
00247             
00248             case DoubleArgument: {
00249                 if (longOptions[optionIndex].flag != 0) break;
00250                 switch (optionIndex) {
00251                     case sigmaID:
00252                         sigma = atof(optarg);
00253                         break;
00254                     case thresholdID:
00255                         thresholdLim = atof(optarg);
00256                         break;
00257                     case contrastID:
00258                         contrast = atof(optarg);
00259                         break;
00260                 }
00261                 break;
00262             }
00263             
00264             case ArrayArgument: {
00265                 if (longOptions[optionIndex].flag != 0) break;
00266                 switch (optionIndex) {
00267                     case responseID:
00268                         // TODO
00269                         break;
00270                 }
00271                 break;
00272             }
00273             
00274             case 'o':
00275                 outputPrefix = optarg;
00276                 break;
00277             case 'i':
00278                 iterations = atoi(optarg);
00279                 break;
00280             case 's':
00281                 sigma = atof(optarg);
00282                 break;
00283             case 'r':
00284                 // TODO
00285                 break;
00286             case 't':
00287                 thresholdLim = atof(optarg);
00288                 break;
00289             case 'c':
00290                 contrast = atof(optarg);
00291                 break;
00292             case 'a':
00293                 parseOptions_advanced(optarg);
00294                 break;
00295             case 'w':
00296                 parseOptions_save(optarg);
00297                 break;
00298             case 'h':
00299                 usage();
00300                 return 0;
00301             case 'v':
00302                 verbosity++;
00303                 break;
00304         }
00305     }
00306     
00307     cout << endl;
00308     
00309     unsigned nFiles = argc - optind;
00310     if (nFiles == 0) {
00311         cerr << std::endl << "Error: at least three input images needed" << std::endl <<std::endl;
00312         usage();
00313         return 1;
00314     } else if (nFiles < 3) {
00315         std::cout << std::endl << "Error: You have to specify at least three images." << std::endl;
00316         return 1;
00317     }
00318     
00319     // load all images
00320     vector<string> inputFiles;
00321     for (size_t i=optind; i < (size_t)argc; i++)
00322     {
00323         inputFiles.push_back(argv[i]);
00324     }
00325     
00326     Deghosting* deghoster = NULL;
00327     
00328         vector<FImagePtr> weights;
00329         if (otherFlags & OTHER_GRAY) {
00330             Khan<float> khanDeghoster(inputFiles, flags, debugFlags, iterations, sigma, verbosity);
00331             deghoster = &khanDeghoster;
00332             weights = deghoster->createWeightMasks();
00333         } else {
00334             Khan<RGBValue<float> > khanDeghoster(inputFiles, flags, debugFlags, iterations, sigma, verbosity);
00335             deghoster = &khanDeghoster;
00336             weights = deghoster->createWeightMasks();
00337         }
00338         
00339         //deghoster->setCameraResponse(response);
00340                 
00341         // save weights
00342         if (otherFlags & SAVE_GENWEIGHTS) {
00343             for (unsigned int i=0; i<weights.size(); ++i) {
00344                 char tmpfn[100];
00345                 snprintf(tmpfn, 99, "%s_%u.tif", outputPrefix.c_str(), i);
00346                 ImageExportInfo exWeights(tmpfn);
00347                 exportImage(srcImageRange(*weights[i]), exWeights.setPixelType("UINT8"));
00348             }
00349         }
00350         
00351         // apply contrast functor
00352         for (unsigned int i=0; i < weights.size(); ++i) {
00353             transformImage(srcImageRange(*(weights[i])), destImage(*(weights[i])), BrightnessContrastFunctor<FImage::PixelType>(1, contrast, 0, 255));
00354         }
00355         
00356         vector<BImagePtr> thresholded = threshold(weights, thresholdLim, otherThresholdFlags);
00357         
00358         // save masks with treshold applied
00359         for (unsigned int i=0; i<weights.size(); ++i) {
00360             char tmpfn[100];
00361             string fileName = hugin_utils::stripExtension(inputFiles[i]);
00362             fileName = hugin_utils::stripPath(fileName);
00363             snprintf(tmpfn, 99, "%s_mask.tif", fileName.c_str());
00364             ImageExportInfo exWeights(tmpfn);
00365             BImage outImg = BImage((*thresholded[i]).size());
00366             simpleDenoise(srcImageRange(*thresholded[i]), destImage(outImg));
00367             exportImage(srcImageRange(outImg), exWeights.setPixelType("UINT8"));
00368         }
00369     } catch (const std::exception & e) {
00370         std::cerr << "caught exception: " << e.what() << std::endl;
00371         return 1;
00372     } catch (...) {
00373         std::cerr << "caught unknown exception" << std::endl;
00374         return 1;
00375     }
00376     return 0;
00377 }

Generated on 3 Aug 2015 for Hugintrunk by  doxygen 1.4.7