nona.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00026 #include <hugin_config.h>
00027 #include <fstream>
00028 #include <sstream>
00029 
00030 #include <algorithm>
00031 #include <cctype>
00032 #include <string>
00033 
00034 #include <vigra/error.hxx>
00035 
00036 #include <getopt.h>
00037 #ifndef WIN32
00038 #include <unistd.h>
00039 #endif
00040 
00041 #include <hugin_basic.h>
00042 #include "hugin_base/algorithms/basic/LayerStacks.h"
00043 #include <hugin_utils/platform.h>
00044 #include <algorithms/nona/NonaFileStitcher.h>
00045 #include <vigra_ext/ImageTransformsGPU.h>
00046 #include "hugin_utils/stl_utils.h"
00047 #include "nona/StitcherOptions.h"
00048 
00049 #include <tiffio.h>
00050 
00051 using namespace vigra;
00052 using namespace HuginBase;
00053 using namespace hugin_utils;
00054 using namespace std;
00055 
00056 static void usage(const char* name)
00057 {
00058     cerr << name << ": stitch a panorama image" << std::endl
00059          << std::endl
00060          << "nona version " << hugin_utils::GetHuginVersion() << std::endl
00061          << std::endl
00062          << " It uses the transform function from PanoTools, the stitching itself" << std::endl
00063          << " is quite simple, no seam feathering is done." << std::endl
00064          << " only the non-antialiasing interpolators of panotools are supported" << std::endl
00065          << std::endl
00066          << " The following output formats (n option of panotools p script line)" << std::endl
00067          << " are supported:"<< std::endl
00068          << std::endl
00069          << "  JPEG, TIFF, PNG  : Single image formats with internal blender"<< std::endl
00070          << "  JPEG_m, TIFF_m, PNG_m : multiple image files"<< std::endl
00071          << "  TIFF_multilayer : Multilayer tiff files, readable by The Gimp 2.0" << std::endl
00072          << std::endl
00073          << "Usage: " << name  << " [options] -o output project_file (image files)" << std::endl
00074          << "  Options: " << std::endl
00075          << "      -c         create coordinate images (only TIFF_m output)" << std::endl
00076          << "      -v         verbose output" << std::endl
00077          << "      -d         print detailed output for gpu processing" << std::endl
00078          << "      -g         perform image remapping on the GPU" << std::endl
00079          << std::endl
00080          << "  The following options can be used to override settings in the project file:" << std::endl
00081          << "      -i num     remap only image with number num" << std::endl
00082          << "                   (can be specified multiple times)" << std::endl
00083          << "      -m str     set output file format (TIFF, TIFF_m, TIFF_multilayer," << std::endl
00084          << "                    EXR, EXR_m, JPEG, JPEG_m, PNG, PNG_m)" << std::endl
00085          << "      -r ldr/hdr set output mode." << std::endl
00086          << "                   ldr  keep original bit depth and response" << std::endl
00087          << "                   hdr  merge to hdr" << std::endl
00088          << "      -e exposure set exposure for ldr mode" << std::endl
00089          << "      -p TYPE    pixel type of the output. Can be one of:" << std::endl
00090          << "                  UINT8   8 bit unsigned integer" << std::endl
00091          << "                  UINT16  16 bit unsigned integer" << std::endl
00092          << "                  INT16   16 bit signed integer" << std::endl
00093          << "                  UINT32  32 bit unsigned integer" << std::endl
00094          << "                  INT32   32 bit signed integer" << std::endl
00095          << "                  FLOAT   32 bit floating point" << std::endl
00096          << "      -z|--compression set compression type." << std::endl
00097          << "                  Possible options for tiff output:" << std::endl
00098          << "                   NONE      no compression" << std::endl
00099          << "                   PACKBITS  packbits compression" << std::endl
00100          << "                   LZW       lzw compression" << std::endl
00101          << "                   DEFLATE   deflate compression" << std::endl
00102          << "                  For jpeg output set quality number" << std::endl
00103          << "      --ignore-exposure  don't correct exposure" << std::endl
00104          << "                   (this does not work with -e switch together)" << std::endl
00105          << "      --save-intermediate-images  saves also the intermediate" << std::endl
00106          << "                   images (only when output is TIFF, PNG or JPEG)" << std::endl
00107          << "      --intermediate-suffix=SUFFIX  suffix for intermediate images" << std::endl
00108          << "      --create-exposure-layers  create all exposure layers" << std::endl
00109          << "                   (this will always use TIFF)" << std::endl
00110          << "      --clip-exposure  mask automatically all dark and bright pixels" << std::endl
00111          << std::endl;
00112 }
00113 
00114 int main(int argc, char* argv[])
00115 {
00116 
00117     // parse arguments
00118     const char* optstring = "z:cho:i:t:m:p:r:e:vgd";
00119     int c;
00120 
00121     opterr = 0;
00122 
00123     bool doCoord = false;
00124     UIntSet outputImages;
00125     string basename;
00126     string outputFormat;
00127     bool overrideOutputMode = false;
00128     std::string compression;
00129     PanoramaOptions::OutputMode outputMode = PanoramaOptions::OUTPUT_LDR;
00130     bool overrideExposure = false;
00131     double exposure=0;
00132     HuginBase::Nona::AdvancedOptions advOptions;
00133     int verbose = 0;
00134     bool useGPU = false;
00135     string outputPixelType;
00136     bool createExposureLayers = false;
00137 
00138     enum
00139     {
00140         IGNOREEXPOSURE=1000,
00141         SAVEINTERMEDIATEIMAGES,
00142         INTERMEDIATESUFFIX,
00143         EXPOSURELAYERS,
00144         MASKCLIPEXPOSURE
00145     };
00146     static struct option longOptions[] =
00147     {
00148         { "ignore-exposure", no_argument, NULL, IGNOREEXPOSURE },
00149         { "save-intermediate-images", no_argument, NULL, SAVEINTERMEDIATEIMAGES },
00150         { "intermediate-suffix", required_argument, NULL, INTERMEDIATESUFFIX },
00151         { "compression", required_argument, NULL, 'z' },
00152         { "create-exposure-layers", no_argument, NULL, EXPOSURELAYERS },
00153         { "clip-exposure", no_argument, NULL, MASKCLIPEXPOSURE },
00154         0
00155     };
00156     
00157     int optionIndex = 0;
00158     while ((c = getopt_long(argc, argv, optstring, longOptions, &optionIndex)) != -1)
00159     {
00160         switch (c)
00161         {
00162             case 'o':
00163                 basename = optarg;
00164                 break;
00165             case 'c':
00166                 doCoord = true;
00167                 break;
00168             case 'i':
00169                 outputImages.insert(atoi(optarg));
00170                 break;
00171             case 'm':
00172                 outputFormat = optarg;
00173                 break;
00174             case 'p':
00175                 outputPixelType = optarg;
00176                 break;
00177             case 'r':
00178                 if (string(optarg) == "ldr")
00179                 {
00180                     overrideOutputMode = true;
00181                     outputMode = PanoramaOptions::OUTPUT_LDR;
00182                 }
00183                 else if (string(optarg) == "hdr")
00184                 {
00185                     overrideOutputMode = true;
00186                     outputMode = PanoramaOptions::OUTPUT_HDR;
00187                 }
00188                 else
00189                 {
00190                     usage(hugin_utils::stripPath(argv[0]).c_str());
00191                     return 1;
00192                 }
00193                 break;
00194             case 'e':
00195                 overrideExposure = true;
00196                 exposure = atof(optarg);
00197                 break;
00198             case IGNOREEXPOSURE:
00199                 HuginBase::Nona::SetAdvancedOption(advOptions, "ignoreExposure", true);
00200                 break;
00201             case SAVEINTERMEDIATEIMAGES:
00202                 HuginBase::Nona::SetAdvancedOption(advOptions, "saveIntermediateImages", true);
00203                 break;
00204             case INTERMEDIATESUFFIX:
00205                 HuginBase::Nona::SetAdvancedOption(advOptions, "saveIntermediateImagesSuffix", std::string(optarg));
00206                 break;
00207             case EXPOSURELAYERS:
00208                 createExposureLayers = true;
00209                 break;
00210             case MASKCLIPEXPOSURE:
00211                 HuginBase::Nona::SetAdvancedOption(advOptions, "maskClipExposure", true);
00212                 break;
00213             case '?':
00214             case 'h':
00215                 usage(hugin_utils::stripPath(argv[0]).c_str());
00216                 return 0;
00217             case 't':
00218                 std::cout << "WARNING: Switch -t is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
00219                 break;
00220             case 'v':
00221                 ++verbose;
00222                 break;
00223             case 'z':
00224                 compression = optarg;
00225                 compression=hugin_utils::toupper(compression);
00226                 break;
00227             case 'g':
00228                 useGPU = true;
00229                 break;
00230             case 'd':
00231                 vigra_ext::SetGPUDebugMessages(true);
00232                 break;
00233             default:
00234                 usage(hugin_utils::stripPath(argv[0]).c_str());
00235                 abort ();
00236         }
00237     }
00238 
00239     if (basename == "" || argc - optind <1)
00240     {
00241         usage(hugin_utils::stripPath(argv[0]).c_str());
00242         return 1;
00243     }
00244     unsigned nCmdLineImgs = argc -optind -1;
00245 
00246     const char* scriptFile = argv[optind];
00247 
00248     // suppress tiff warnings
00249     TIFFSetWarningHandler(0);
00250 
00251     AppBase::ProgressDisplay* pdisp = NULL;
00252     if(verbose > 0)
00253     {
00254         pdisp = new AppBase::StreamProgressDisplay(cout);
00255     }
00256     else
00257     {
00258         pdisp = new AppBase::DummyProgressDisplay;
00259     }
00260 
00261     Panorama pano;
00262     ifstream prjfile(scriptFile);
00263     if (prjfile.bad())
00264     {
00265         cerr << "could not open script : " << scriptFile << std::endl;
00266         exit(1);
00267     }
00268     pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile));
00269     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
00270     if (err != AppBase::DocumentData::SUCCESSFUL)
00271     {
00272         cerr << "error while parsing panos tool script: " << scriptFile << std::endl;
00273         exit(1);
00274     }
00275 
00276     if ( nCmdLineImgs > 0)
00277     {
00278         if (nCmdLineImgs != pano.getNrOfImages())
00279         {
00280             cerr << "Incorrect number of images specified on command line\nProject required " << pano.getNrOfImages() << " but " << nCmdLineImgs << " where given" << std::endl;
00281             exit(1);
00282         }
00283         for (unsigned i=0; i < pano.getNrOfImages(); i++)
00284         {
00285             pano.setImageFilename(i, argv[optind+i+1]);
00286         }
00287 
00288     }
00289     PanoramaOptions  opts = pano.getOptions();
00290 
00291     // save coordinate images, if requested
00292     opts.saveCoordImgs = doCoord;
00293     if (createExposureLayers)
00294     {
00295         if (!outputFormat.empty())
00296         {
00297             std::cout << "Warning: Ignoring output format " << outputFormat << std::endl
00298                 << "         Switch --create-exposure-layers will enforce TIFF_m output." << std::endl;
00299         };
00300         outputFormat = "TIFF";
00301         if (!outputImages.empty())
00302         {
00303             std::cout << "Warning: Ignoring specified output images." << std::endl
00304                 << "         Switch --create-exposure-layers will always work on all active images." << std::endl;
00305             outputImages.clear();
00306         };
00307     };
00308     if (outputFormat == "TIFF_m")
00309     {
00310         opts.outputFormat = PanoramaOptions::TIFF_m;
00311         opts.outputImageType = "tif";
00312     }
00313     else if (outputFormat == "JPEG_m")
00314     {
00315         opts.outputFormat = PanoramaOptions::JPEG_m;
00316         opts.tiff_saveROI = false;
00317         opts.outputImageType = "jpg";
00318     }
00319     else if (outputFormat == "JPEG")
00320     {
00321         opts.outputFormat = PanoramaOptions::JPEG;
00322         opts.tiff_saveROI = false;
00323         opts.outputImageType = "jpg";
00324     }
00325     else if (outputFormat == "PNG_m")
00326     {
00327         opts.outputFormat = PanoramaOptions::PNG_m;
00328         opts.tiff_saveROI = false;
00329         opts.outputImageType = "png";
00330     }
00331     else if (outputFormat == "PNG")
00332     {
00333         opts.outputFormat = PanoramaOptions::PNG;
00334         opts.tiff_saveROI = false;
00335         opts.outputImageType = "png";
00336     }
00337     else if (outputFormat == "TIFF")
00338     {
00339         opts.outputFormat = PanoramaOptions::TIFF;
00340         opts.outputImageType = "tif";
00341     }
00342     else if (outputFormat == "TIFF_multilayer")
00343     {
00344         opts.outputFormat = PanoramaOptions::TIFF_multilayer;
00345         opts.outputImageType = "tif";
00346     }
00347     else if (outputFormat == "EXR_m")
00348     {
00349         opts.outputFormat = PanoramaOptions::EXR_m;
00350         opts.outputImageType = "exr";
00351     }
00352     else if (outputFormat == "EXR")
00353     {
00354         opts.outputFormat = PanoramaOptions::EXR;
00355         opts.outputImageType = "exr";
00356     }
00357     else if (outputFormat != "")
00358     {
00359         cerr << "Error: unknown output format: " << outputFormat << endl;
00360         return 1;
00361     }
00362 
00363     if (!compression.empty())
00364     {
00365         if (opts.outputImageType == "tif")
00366         {
00367             opts.tiffCompression = compression;
00368         }
00369         else
00370         {
00371             if (opts.outputImageType == "jpg")
00372             {
00373                 int q = atoi(compression.c_str());
00374                 if (q > 0 && q <= 100)
00375                 {
00376                     opts.quality = q;
00377                 }
00378                 else
00379                 {
00380                     std::cerr << "WARNING: \"" << compression << "\" is not valid compression value for jpeg images." << std::endl
00381                         << "         Using value " << opts.quality << " found in pto file." << std::endl;
00382                 };
00383             };
00384         };
00385     };
00386 
00387     if (outputPixelType.size() > 0)
00388     {
00389         opts.outputPixelType = outputPixelType;
00390     }
00391 
00392     if (overrideOutputMode)
00393     {
00394         opts.outputMode = outputMode;
00395     }
00396 
00397     if (overrideExposure)
00398     {
00399         opts.outputExposureValue = exposure;
00400         if (HuginBase::Nona::GetAdvancedOption(advOptions, "ignoreExosure", false))
00401         {
00402             HuginBase::Nona::SetAdvancedOption(advOptions, "ignoreExposure", false);
00403             std::cout << "WARNING: Switches --ignore-exposure and -e can't to used together." << std::endl
00404                 << "         Ignore switch --ignore-exposure." << std::endl;
00405         }
00406     }
00407 
00408     if (outputImages.empty())
00409     {
00410         outputImages = HuginBase::getImagesinROI(pano, pano.getActiveImages());
00411     }
00412     else
00413     {
00414         UIntSet activeImages = HuginBase::getImagesinROI(pano, pano.getActiveImages());
00415         for(UIntSet::const_iterator it=outputImages.begin(); it!=outputImages.end(); ++it)
00416         {
00417             if(!set_contains(activeImages,*it))
00418             {
00419                 std::cerr << "The project file does not contains an image with number " << *it << std::endl;
00420                 return 1;
00421             };
00422         };
00423     };
00424     if(outputImages.empty())
00425     {
00426         std::cout << "Project does not contain active images." << std::endl
00427                   << "Nothing to do for nona." << std::endl;
00428         return 0;
00429     };
00430     if(useGPU)
00431     {
00432         switch(opts.getProjection())
00433         {
00434             // the following projections are not supported by nona-gpu
00435             case HuginBase::PanoramaOptions::BIPLANE:
00436             case HuginBase::PanoramaOptions::TRIPLANE:
00437             case HuginBase::PanoramaOptions::PANINI:
00438             case HuginBase::PanoramaOptions::EQUI_PANINI:
00439             case HuginBase::PanoramaOptions::GENERAL_PANINI:
00440                 useGPU=false;
00441                 std::cout << "Nona-GPU does not support this projection. Switch to CPU calculation."<<std::endl;
00442                 break;
00443         };
00444     };
00445 
00446     DEBUG_DEBUG("output basename: " << basename);
00447 
00448     try
00449     {
00450         if (useGPU)
00451         {
00452             useGPU = initGPU(&argc, argv);
00453         }
00454         opts.remapUsingGPU = useGPU;
00455         pano.setOptions(opts);
00456 
00457         if (createExposureLayers)
00458         {
00459             HuginBase::UIntSetVector exposureLayers = getExposureLayers(pano, outputImages, opts);
00460             if (exposureLayers.empty())
00461             {
00462                 std::cerr << "ERROR: Could not determine exposure layers. Cancel execution." << std::endl;
00463             }
00464             else
00465             {
00466                 // we need to pass the basename to the stitcher
00467                 // because NonaFileOutputStitcher get already filename with numbers added
00468                 HuginBase::Nona::SetAdvancedOption(advOptions, "basename", basename);
00469                 for (size_t i = 0; i < exposureLayers.size(); ++i)
00470                 {
00471                     HuginBase::PanoramaOptions modOptions(opts);
00472                     // set output exposure to exposure value of first image of layers
00473                     // normaly this this invoked with --ignore-exposure, so this has no effect
00474                     modOptions.outputExposureValue = pano.getImage(*(exposureLayers[i].begin())).getExposureValue();
00475                     // build filename
00476                     std::ostringstream filename;
00477                     filename << basename << std::setfill('0') << std::setw(4) << i;
00478                     NonaFileOutputStitcher(pano, pdisp, modOptions, exposureLayers[i], filename.str(), advOptions).run();
00479                 }
00480             }
00481         }
00482         else
00483         {
00484             // stitch panorama
00485             NonaFileOutputStitcher(pano, pdisp, opts, outputImages, basename, advOptions).run();
00486         };
00487         // add a final newline, after the last progress message
00488         if (verbose > 0)
00489         {
00490             cout << std::endl;
00491         }
00492 
00493         if (useGPU)
00494         {
00495             wrapupGPU();
00496         }
00497 
00498     }
00499     catch (std::exception& e)
00500     {
00501         cerr << "caught exception: " << e.what() << std::endl;
00502         return 1;
00503     }
00504 
00505     if(pdisp != NULL)
00506     {
00507         delete pdisp;
00508     }
00509 
00510     return 0;
00511 }

Generated on 4 Sep 2015 for Hugintrunk by  doxygen 1.4.7