00001
00021 #include <iostream>
00022 #include <string>
00023 #include <cstring>
00024
00025 #include <hugin_config.h>
00026 #include <hugin_version.h>
00027
00028 #include <hugin_utils/utils.h>
00029
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
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
00053 static const uint16_t SAVE_GENWEIGHTS = 1;
00054 static const uint16_t OTHER_GRAY = 2;
00055
00056
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
00126 << " -t, --threshold=THRESH threshold; default: " << thresholdLim << endl
00127 << " -c, --contrast=CONTR change constrast 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 weigths" << endl
00139 << " w save generated weigths" << 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 constrastID,
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
00192
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 constrastID:
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
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
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
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
00362
00363
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
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
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 }