nona.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00026 #include <hugin_config.h>
00027 #include <hugin_version.h>
00028 #include <fstream>
00029 #include <sstream>
00030 
00031 #include <algorithm>
00032 #include <cctype>
00033 #include <string>
00034 
00035 #include <vigra/error.hxx>
00036 #include <vigra/impex.hxx>
00037 
00038 #ifdef WIN32
00039  #include <getopt.h>
00040 #else
00041  #include <unistd.h>
00042 #endif
00043 
00044 #include <hugin_basic.h>
00045 #include <hugin_utils/platform.h>
00046 #include <algorithms/nona/NonaFileStitcher.h>
00047 #include <vigra_ext/MultiThreadOperations.h>
00048 #include <vigra_ext/ImageTransformsGPU.h>
00049 
00050 #include <tiffio.h>
00051 
00052 #if !defined Hugin_shared || !defined _WINDOWS
00053 #define GLEW_STATIC
00054 #endif
00055 #include <GL/glew.h>
00056 #ifdef __APPLE__
00057   #include <GLUT/glut.h>
00058 #else
00059   #include <GL/glut.h>
00060 #endif
00061 
00062 using namespace vigra;
00063 using namespace HuginBase;
00064 using namespace hugin_utils;
00065 using namespace std;
00066 
00067 GLuint GlutWindowHandle;
00068 
00069 static void usage(const char * name)
00070 {
00071     cerr << name << ": stitch a panorama image" << std::endl
00072     << std::endl
00073     << "nona version " << DISPLAY_VERSION << std::endl
00074     << std::endl
00075     << " It uses the transform function from PanoTools, the stitching itself" << std::endl
00076     << " is quite simple, no seam feathering is done." << std::endl
00077     << " only the non-antialiasing interpolators of panotools are supported" << std::endl
00078     << std::endl
00079     << " The following output formats (n option of panotools p script line)" << std::endl
00080     << " are supported:"<< std::endl
00081     << std::endl
00082     << "  JPG, TIFF, PNG  : Single image formats without feathered blending:"<< std::endl
00083     << "  TIFF_m          : multiple tiff files"<< std::endl
00084     << "  TIFF_multilayer : Multilayer tiff files, readable by The Gimp 2.0" << std::endl
00085     << std::endl
00086     << "Usage: " << name  << " [options] -o output project_file (image files)" << std::endl
00087     << "  Options: " << std::endl
00088     << "      -c         create coordinate images (only TIFF_m output)" << std::endl
00089     << "      -v         quiet, do not output progress indicators" << std::endl
00090     << "      -d         print detailed output for gpu processing" << std::endl
00091     << "      -t num     number of threads to be used (default: nr of available cores)" << std::endl
00092     << "      -g         perform image remapping on the GPU" << std::endl
00093     << std::endl
00094     << "  The following options can be used to override settings in the project file:" << std::endl
00095     << "      -i num     remap only image with number num" << std::endl
00096     << "                   (can be specified multiple times)" << std::endl
00097     << "      -m str     set output file format (TIFF, TIFF_m, TIFF_multilayer, EXR, EXR_m)" << std::endl
00098     << "      -r ldr/hdr set output mode." << std::endl
00099     << "                   ldr  keep original bit depth and response" << std::endl
00100     << "                   hdr  merge to hdr" << std::endl
00101     << "      -e exposure set exposure for ldr mode" << std::endl
00102     << "      -p TYPE    pixel type of the output. Can be one of:" << std::endl
00103     << "                  UINT8   8 bit unsigned integer" << std::endl
00104     << "                  UINT16  16 bit unsigned integer" << std::endl
00105     << "                  INT16   16 bit signed integer" << std::endl
00106     << "                  UINT32  32 bit unsigned integer" << std::endl
00107     << "                  INT32   32 bit signed integer" << std::endl
00108     << "                  FLOAT   32 bit floating point" << std::endl
00109     << "      -z         set compression type." << std::endl
00110     << "                  Possible options for tiff output:" << std::endl
00111     << "                   NONE      no compression" << std::endl
00112     << "                   PACKBITS  packbits compression" << std::endl
00113     << "                   LZW       lzw compression" << std::endl
00114     << "                   DEFLATE   deflate compression" << std::endl
00115     << std::endl;
00116 }
00117 
00122 static bool initGPU(int *argcp,char **argv) {
00123     glutInit(argcp,argv);
00124     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_ALPHA);
00125     GlutWindowHandle = glutCreateWindow("nona");
00126 
00127     int err = glewInit();
00128     if (err != GLEW_OK) {
00129         cerr << "nona: an error occured while setting up the GPU:" << endl;
00130         cerr << glewGetErrorString(err) << endl;
00131         cerr << "nona: Switching to CPU calculation." << endl;
00132         glutDestroyWindow(GlutWindowHandle);
00133         return false;
00134     }
00135 
00136     cout << "nona: using graphics card: " << glGetString(GL_VENDOR) << " " << glGetString(GL_RENDERER) << endl;
00137 
00138     GLboolean has_arb_fragment_shader = glewGetExtension("GL_ARB_fragment_shader");
00139     GLboolean has_arb_vertex_shader = glewGetExtension("GL_ARB_vertex_shader");
00140     GLboolean has_arb_shader_objects = glewGetExtension("GL_ARB_shader_objects");
00141     GLboolean has_arb_shading_language = glewGetExtension("GL_ARB_shading_language_100");
00142     GLboolean has_arb_texture_rectangle = glewGetExtension("GL_ARB_texture_rectangle");
00143     GLboolean has_arb_texture_border_clamp = glewGetExtension("GL_ARB_texture_border_clamp");
00144     GLboolean has_arb_texture_float = glewGetExtension("GL_ARB_texture_float");
00145 
00146     if (!(has_arb_fragment_shader && has_arb_vertex_shader && has_arb_shader_objects && has_arb_shading_language && has_arb_texture_rectangle && has_arb_texture_border_clamp && has_arb_texture_float)) {
00147         const char * msg[] = {"false", "true"};
00148         cerr << "nona: extension GL_ARB_fragment_shader = " << msg[has_arb_fragment_shader] << endl;
00149         cerr << "nona: extension GL_ARB_vertex_shader = " << msg[has_arb_vertex_shader] << endl;
00150         cerr << "nona: extension GL_ARB_shader_objects = " << msg[has_arb_shader_objects] << endl;
00151         cerr << "nona: extension GL_ARB_shading_language_100 = " << msg[has_arb_shading_language] << endl;
00152         cerr << "nona: extension GL_ARB_texture_rectangle = " << msg[has_arb_texture_rectangle] << endl;
00153         cerr << "nona: extension GL_ARB_texture_border_clamp = " << msg[has_arb_texture_border_clamp] << endl;
00154         cerr << "nona: extension GL_ARB_texture_float = " << msg[has_arb_texture_float] << endl;
00155         cerr << "nona: This graphics system lacks the necessary extensions for -g." << endl;
00156         cerr << "nona: Switching to CPU calculation." << endl;
00157         glutDestroyWindow(GlutWindowHandle);
00158         return false;
00159     }
00160 
00161     return true;
00162 }
00163 
00164 static bool wrapupGPU() {
00165     glutDestroyWindow(GlutWindowHandle);
00166     return true;
00167 }
00168 
00169 int main(int argc, char *argv[])
00170 {
00171     
00172     // parse arguments
00173     const char * optstring = "z:cho:i:t:m:p:r:e:vgd";
00174     int c;
00175     
00176     opterr = 0;
00177     
00178     int nThread = getCPUCount();
00179     if (nThread < 0) nThread = 1;
00180     bool doCoord = false;
00181     UIntSet outputImages;
00182     string basename;
00183     string outputFormat;
00184     bool overrideOutputMode = false;
00185     std::string compression;
00186     PanoramaOptions::OutputMode outputMode = PanoramaOptions::OUTPUT_LDR;
00187     bool overrideExposure = false;
00188     double exposure=0;
00189     int verbose = 0;
00190     bool useGPU = false;
00191     string outputPixelType;
00192     
00193     while ((c = getopt (argc, argv, optstring)) != -1)
00194     {
00195         switch (c) {
00196             case 'o':
00197                 basename = optarg;
00198                 break;
00199             case 'c':
00200                 doCoord = true;
00201                 break;
00202             case 'i':
00203                 outputImages.insert(atoi(optarg));
00204                 break;
00205             case 'm':
00206                 outputFormat = optarg;
00207                 break;
00208             case 'p':
00209                 outputPixelType = optarg;
00210                 break;
00211             case 'r':
00212                 if (string(optarg) == "ldr") {
00213                     overrideOutputMode = true;
00214                     outputMode = PanoramaOptions::OUTPUT_LDR;
00215                 } else if (string(optarg) == "hdr") {
00216                     overrideOutputMode = true;
00217                     outputMode = PanoramaOptions::OUTPUT_HDR;
00218                 } else {
00219                     usage(argv[0]);
00220                     return 1;
00221                 }
00222                 break;
00223             case 'e':
00224                 overrideExposure = true;
00225                 exposure = atof(optarg);
00226                 break;
00227             case '?':
00228             case 'h':
00229                 usage(argv[0]);
00230                 return 0;
00231             case 't':
00232                 nThread = atoi(optarg);
00233                 break;
00234             case 'v':
00235                 ++verbose;
00236                 break;
00237             case 'z':
00238                 compression = optarg;
00239                 std::transform(compression.begin(), compression.end(), compression.begin(), (int(*)(int)) toupper);
00240                 break;
00241             case 'g':
00242                 useGPU = true;
00243                 break;
00244             case 'd':
00245                 vigra_ext::SetGPUDebugMessages(true);
00246                 break;
00247             default:
00248                 usage(argv[0]);
00249                 abort ();
00250         }
00251     }
00252 
00253     if (basename == "" || argc - optind <1) {
00254         usage(argv[0]);
00255         return 1;
00256     }
00257     unsigned nCmdLineImgs = argc -optind -1;
00258 
00259     if (nThread == 0) nThread = 1;
00260     vigra_ext::ThreadManager::get().setNThreads(nThread);
00261 
00262     const char * scriptFile = argv[optind];
00263 
00264     // suppress tiff warnings
00265     TIFFSetWarningHandler(0);
00266 
00267     AppBase::ProgressDisplay* pdisp = NULL;
00268     if(verbose > 0)
00269         pdisp = new AppBase::StreamProgressDisplay(cout);
00270     else
00271         pdisp = new AppBase::DummyProgressDisplay;
00272 
00273     Panorama pano;
00274     ifstream prjfile(scriptFile);
00275     if (prjfile.bad()) {
00276         cerr << "could not open script : " << scriptFile << std::endl;
00277         exit(1);
00278     }
00279     pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile));
00280     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
00281     if (err != AppBase::DocumentData::SUCCESSFUL) {
00282         cerr << "error while parsing panos tool script: " << scriptFile << std::endl;
00283         exit(1);
00284     }
00285 
00286     if ( nCmdLineImgs > 0) {
00287         if (nCmdLineImgs != pano.getNrOfImages()) {
00288             cerr << "Incorrect number of images specified on command line\nProject required " << pano.getNrOfImages() << " but " << nCmdLineImgs << " where given" << std::endl;
00289             exit(1);
00290         }
00291         for (unsigned i=0; i < pano.getNrOfImages(); i++) {
00292             pano.setImageFilename(i, argv[optind+i+1]);
00293         }
00294 
00295     }
00296     PanoramaOptions  opts = pano.getOptions();
00297 
00298     if (compression.size() > 0) {
00299         opts.tiffCompression=compression;
00300     }
00301 
00302     // save coordinate images, if requested
00303     opts.saveCoordImgs = doCoord;
00304     if (outputFormat == "TIFF_m") {
00305         opts.outputFormat = PanoramaOptions::TIFF_m;
00306     } else if (outputFormat == "TIFF") {
00307         opts.outputFormat = PanoramaOptions::TIFF;
00308     } else if (outputFormat == "TIFF_multilayer") {
00309         opts.outputFormat = PanoramaOptions::TIFF_multilayer;
00310     } else if (outputFormat == "EXR_m") {
00311         opts.outputFormat = PanoramaOptions::EXR_m;
00312     } else if (outputFormat == "EXR") {
00313         opts.outputFormat = PanoramaOptions::EXR;
00314     } else if (outputFormat != "") {
00315         cerr << "Error: unknown output format: " << outputFormat << endl;
00316         return 1;
00317     }
00318 
00319     if (outputPixelType.size() > 0) {
00320         opts.outputPixelType = outputPixelType;
00321     }
00322     
00323     if (overrideOutputMode) {
00324         opts.outputMode = outputMode;
00325     }
00326     
00327     if (overrideExposure) {
00328         opts.outputExposureValue = exposure;
00329     }
00330 
00331     if(outputImages.size()==0) 
00332     {
00333         outputImages = pano.getActiveImages();
00334     }
00335     else
00336     {
00337         UIntSet activeImages=pano.getActiveImages();
00338         for(UIntSet::const_iterator it=outputImages.begin(); it!=outputImages.end();it++)
00339         {
00340             if(!set_contains(activeImages,*it))
00341             {
00342                 std::cerr << "The project file does not contains an image with number " << *it << std::endl;
00343                 return 1;
00344             };
00345         };
00346     };
00347     if(outputImages.size()==0)
00348     {
00349         std::cout << "Project does not contain active images." << std::endl
00350             << "Nothing to do for nona." << std::endl;
00351         return 0;
00352     };
00353     if(useGPU)
00354     {
00355         switch(opts.getProjection())
00356         {
00357             // the following projections are not supported by nona-gpu
00358             case HuginBase::PanoramaOptions::BIPLANE:
00359             case HuginBase::PanoramaOptions::TRIPLANE:
00360             case HuginBase::PanoramaOptions::PANINI:
00361             case HuginBase::PanoramaOptions::EQUI_PANINI:
00362             case HuginBase::PanoramaOptions::GENERAL_PANINI:
00363                 useGPU=false;
00364                 std::cout << "Nona-GPU does not support this projection. Switch to CPU calculation."<<std::endl;
00365                 break;
00366         };
00367     };
00368     
00369     DEBUG_DEBUG("output basename: " << basename);
00370     
00371     try {
00372         if (useGPU) {
00373             useGPU = initGPU(&argc, argv);
00374         }
00375         opts.remapUsingGPU = useGPU;
00376         pano.setOptions(opts);
00377 
00378         // stitch panorama
00379         NonaFileOutputStitcher(pano, pdisp, opts, outputImages, basename).run();
00380         // add a final newline, after the last progress message
00381         if (verbose > 0) {
00382             cout << std::endl;
00383         }
00384 
00385         if (useGPU) {
00386             wrapupGPU();
00387         }
00388 
00389     } catch (std::exception & e) {
00390         cerr << "caught exception: " << e.what() << std::endl;
00391         return 1;
00392     }
00393     
00394     if(pdisp != NULL)
00395         delete pdisp;
00396 
00397     return 0;
00398 }

Generated on 26 Oct 2014 for Hugintrunk by  doxygen 1.4.7