26 #include <hugin_config.h> 
   34 #include <vigra/error.hxx> 
   48 static void usage(
const char* name)
 
   50     std::cout << name << 
": stitch a panorama image" << std::endl
 
   54          << 
" It uses the transform function from PanoTools, the stitching itself" << std::endl
 
   55          << 
" is quite simple, no seam feathering is done." << std::endl
 
   56          << 
" only the non-antialiasing interpolators of panotools are supported" << std::endl
 
   58          << 
" The following output formats (n option of panotools p script line)" << std::endl
 
   59          << 
" are supported:"<< std::endl
 
   61          << 
"  JPEG, TIFF, PNG  : Single image formats with internal blender"<< std::endl
 
   62          << 
"  JPEG_m, TIFF_m, PNG_m : multiple image files"<< std::endl
 
   63          << 
"  TIFF_multilayer : Multilayer tiff files, readable by The Gimp 2.0" << std::endl
 
   65          << 
"Usage: " << name  << 
" [options] -o output project_file (image files)" << std::endl
 
   66          << 
"  Options: " << std::endl
 
   67          << 
"      -c            create coordinate images (only TIFF_m output)" << std::endl
 
   68          << 
"      -v|--verbose  verbose output" << std::endl
 
   69          << 
"      -d|--debug    print detailed output for gpu processing" << std::endl
 
   70          << 
"      -g|--gpu      perform image remapping on the GPU" << std::endl
 
   72          << 
"  The following options can be used to override settings in the project file:" << std::endl
 
   73          << 
"      -i num     remap only image with number num" << std::endl
 
   74          << 
"                   (can be specified multiple times)" << std::endl
 
   75          << 
"      -m str     set output file format (TIFF, TIFF_m, TIFF_multilayer," << std::endl
 
   76          << 
"                    EXR, EXR_m, JPEG, JPEG_m, PNG, PNG_m)" << std::endl
 
   77          << 
"      -r ldr/hdr set output mode." << std::endl
 
   78          << 
"                   ldr  keep original bit depth and response" << std::endl
 
   79          << 
"                   hdr  merge to hdr" << std::endl
 
   80          << 
"      -e exposure set exposure for ldr mode" << std::endl
 
   81          << 
"      -p TYPE    pixel type of the output. Can be one of:" << std::endl
 
   82          << 
"                  UINT8   8 bit unsigned integer" << std::endl
 
   83          << 
"                  UINT16  16 bit unsigned integer" << std::endl
 
   84          << 
"                  INT16   16 bit signed integer" << std::endl
 
   85          << 
"                  UINT32  32 bit unsigned integer" << std::endl
 
   86          << 
"                  INT32   32 bit signed integer" << std::endl
 
   87          << 
"                  FLOAT   32 bit floating point" << std::endl
 
   88          << 
"      -z|--compression set compression type." << std::endl
 
   89          << 
"                  Possible options for tiff output:" << std::endl
 
   90          << 
"                   NONE      no compression" << std::endl
 
   91          << 
"                   PACKBITS  packbits compression" << std::endl
 
   92          << 
"                   LZW       lzw compression" << std::endl
 
   93          << 
"                   DEFLATE   deflate compression" << std::endl
 
   94          << 
"                  For jpeg output set quality number" << std::endl
 
   95          << 
"      --bigtiff   Use BigTIFF format for TIFF images" << std::endl
 
   96          << 
"      --ignore-exposure  don't correct exposure" << std::endl
 
   97          << 
"                   (this does not work with -e switch together)" << std::endl
 
   98          << 
"      --output-range-compression=value  set range compression" << std::endl
 
   99          << 
"                   value should be a real in range 0..20" << std::endl
 
  100          << 
"      --save-intermediate-images  saves also the intermediate" << std::endl
 
  101          << 
"                   images (only when output is TIFF, PNG or JPEG)" << std::endl
 
  102          << 
"      --intermediate-suffix=SUFFIX  suffix for intermediate images" << std::endl
 
  103          << 
"      --final-suffix=SUFFIX  suffix for the final image" << std::endl
 
  104          << 
"      --create-exposure-layers  create all exposure layers" << std::endl
 
  105          << 
"                   (this will always use TIFF)" << std::endl
 
  106          << 
"      --clip-exposure[=lower cutoff:upper cutoff]" << std::endl
 
  107          << 
"                   mask automatically all dark and bright pixels" << std::endl
 
  108          << 
"                   optionally you can specify the limits for the" << std::endl
 
  109          << 
"                   lower and upper cutoff (specify in range 0...1," << std::endl
 
  110          << 
"                   relative the full range)" << std::endl
 
  111          << 
"      --seam=hard|blend   select the blend mode for the seam" << std::endl
 
  115 int main(
int argc, 
char* argv[])
 
  119     const char* optstring = 
"z:cho:i:t:m:p:r:e:vgd";
 
  122     bool doCoord = 
false;
 
  124     std::string basename;
 
  125     std::string outputFormat;
 
  126     bool overrideOutputMode = 
false;
 
  127     std::string compression;
 
  129     bool overrideExposure = 
false;
 
  131     double rangeCompression = -1;
 
  135     std::string outputPixelType;
 
  136     bool createExposureLayers = 
false;
 
  141         SAVEINTERMEDIATEIMAGES,
 
  150     static struct option longOptions[] =
 
  152         { 
"ignore-exposure", no_argument, NULL, IGNOREEXPOSURE },
 
  153         { 
"save-intermediate-images", no_argument, NULL, SAVEINTERMEDIATEIMAGES },
 
  154         { 
"intermediate-suffix", required_argument, NULL, INTERMEDIATESUFFIX },
 
  155         { 
"final-suffix", required_argument, NULL, FINALSUFFIX },
 
  156         { 
"compression", required_argument, NULL, 
'z' },
 
  157         { 
"create-exposure-layers", no_argument, NULL, EXPOSURELAYERS },
 
  158         { 
"clip-exposure", optional_argument, NULL, MASKCLIPEXPOSURE },
 
  159         { 
"seam", required_argument, NULL, SEAMMODE},
 
  160         { 
"gpu", no_argument, NULL, 
'g'},
 
  161         { 
"bigtiff", no_argument, NULL, USE_BIGTIFF },
 
  162         { 
"output-range-compression", required_argument, NULL, RANGECOMPRESSION },
 
  163         { 
"help", no_argument, NULL, 
'h'},
 
  164         { 
"debug", no_argument, NULL, 
'd'},
 
  165         { 
"verbose", no_argument, NULL, 
'v'},
 
  166         { 
"output", required_argument, NULL, 
'o'},
 
  170     while ((c = getopt_long(argc, argv, optstring, longOptions, 
nullptr)) != -1)
 
  181                 outputImages.insert(atoi(optarg));
 
  184                 outputFormat = optarg;
 
  187                 outputPixelType = optarg;
 
  190                 if (std::string(optarg) == 
"ldr")
 
  192                     overrideOutputMode = 
true;
 
  195                 else if (std::string(optarg) == 
"hdr")
 
  197                     overrideOutputMode = 
true;
 
  202                     std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": \"" << optarg << 
"\" is not a valid parameter for output mode (-r)." << std::endl;
 
  207                 overrideExposure = 
true;
 
  208                 exposure = atof(optarg);
 
  213             case SAVEINTERMEDIATEIMAGES:
 
  216             case INTERMEDIATESUFFIX:
 
  223                 createExposureLayers = 
true;
 
  225             case MASKCLIPEXPOSURE:
 
  227                 if (optarg != NULL && *optarg != 0)
 
  231                     if (tokens.size() == 2)
 
  237                             if (lowerCutoff < 0 || lowerCutoff>1)
 
  239                                 std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Argument \"" << tokens[0] << 
"\" is not a valid number for lower cutoff." << std::endl;
 
  242                             if (upperCutoff < 0 || upperCutoff>1)
 
  244                                 std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Argument \"" << tokens[1] << 
"\" is not a valid number for upper cutoff." << std::endl;
 
  247                             if (lowerCutoff >= upperCutoff)
 
  249                                 std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Lower cutoff \"" << tokens[0] << 
"\" is higher than upper cutoff" << std::endl
 
  250                                     << 
"     \"" << tokens[1] << 
"\". This is no valid input." << std::endl;
 
  258                             std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Argument \"" << optarg << 
"\" is not valid number for --clip-exposure" << std::endl
 
  259                                 << 
"      Expected --clip-exposure=lower cutoff:upper cutoff" << std::endl
 
  260                                 << 
"      Both should be numbers between 0 and 1." << std::endl;
 
  266                         std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Argument \"" << optarg << 
"\" is not valid for --clip-exposure" << std::endl
 
  267                             << 
"      Expected --clip-exposure=lower cutoff:upper cutoff" << std::endl;
 
  274                     std::string text(optarg);
 
  288                             std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": String \"" << text << 
"\" is not a recognized seam blend mode." << std::endl;
 
  298                 std::cout << 
"WARNING: Switch -t is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
 
  304                 compression = optarg;
 
  308 #if defined __APPLE__ && defined __aarch64__ 
  311                 std::cout << 
"WARNING: GPU remapping is not supported on ARM Macs. Switching back to CPU remapping." << std::endl;
 
  322             case RANGECOMPRESSION:
 
  325                     std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": Could not parse output range compression (" << optarg << 
")." << std::endl;
 
  328                 if (rangeCompression < 0.0 || rangeCompression > 20.0)
 
  330                     std::cerr << 
hugin_utils::stripPath(argv[0]) << 
": range compression must be a real between 0 and 20." << std::endl;
 
  345     if (basename.empty())
 
  350     if(argc - optind < 1)
 
  355     unsigned nCmdLineImgs = argc -optind -1;
 
  357     const char* scriptFile = argv[optind];
 
  360     TIFFSetWarningHandler(0);
 
  368     if ( nCmdLineImgs > 0)
 
  372             std::cerr << 
"Incorrect number of images specified on command line\nProject required " << pano.
getNrOfImages() << 
" but " << nCmdLineImgs << 
" where given" << std::endl;
 
  385     if (createExposureLayers)
 
  387         if (!outputFormat.empty())
 
  389             std::cout << 
"Warning: Ignoring output format " << outputFormat << std::endl
 
  390                 << 
"         Switch --create-exposure-layers will enforce TIFF_m output." << std::endl;
 
  392         outputFormat = 
"TIFF";
 
  393         if (!outputImages.empty())
 
  395             std::cout << 
"Warning: Ignoring specified output images." << std::endl
 
  396                 << 
"         Switch --create-exposure-layers will always work on all active images." << std::endl;
 
  397             outputImages.clear();
 
  400     if (outputFormat == 
"TIFF_m")
 
  405     else if (outputFormat == 
"JPEG_m")
 
  411     else if (outputFormat == 
"JPEG")
 
  417     else if (outputFormat == 
"PNG_m")
 
  423     else if (outputFormat == 
"PNG")
 
  429     else if (outputFormat == 
"TIFF")
 
  434     else if (outputFormat == 
"TIFF_multilayer")
 
  439     else if (outputFormat == 
"EXR_m")
 
  444     else if (outputFormat == 
"EXR")
 
  449     else if (outputFormat != 
"")
 
  451         std::cerr << 
"Error: unknown output format: " << outputFormat << endl;
 
  455     if (!compression.empty())
 
  465                 int q = atoi(compression.c_str());
 
  466                 if (q > 0 && q <= 100)
 
  472                     std::cerr << 
"WARNING: \"" << compression << 
"\" is not valid compression value for jpeg images." << std::endl
 
  473                         << 
"         Using value " << opts.
quality << 
" found in pto file." << std::endl;
 
  479     if (!outputPixelType.empty())
 
  484     if (overrideOutputMode)
 
  489     if (overrideExposure)
 
  495             std::cout << 
"WARNING: Switches --ignore-exposure and -e can't to used together." << std::endl
 
  496                 << 
"         Ignore switch --ignore-exposure." << std::endl;
 
  499     if (rangeCompression >= 0.0)
 
  503             std::cout << 
"WARNING: Switch --ignore-exposure disables range compression." << std::endl
 
  504                 << 
"         --output-range-compression is therefore ignored." << std::endl;
 
  512     if (outputImages.empty())
 
  519         for (HuginBase::UIntSet::const_iterator it = outputImages.begin(); it != outputImages.end(); ++it)
 
  523                 std::cerr << 
"The project file does not contains an image with number " << *it << std::endl;
 
  528     if(outputImages.empty())
 
  530         std::cout << 
"Project does not contain active images." << std::endl
 
  531                   << 
"Nothing to do for nona." << std::endl;
 
  545                 std::cout << 
"Nona-GPU does not support this projection. Switch to CPU calculation."<<std::endl;
 
  572                 std::cout << 
"Could not initialize GPU. Switching back to CPU calculation." << std::endl;
 
  578         if (createExposureLayers)
 
  581             if (exposureLayers.empty())
 
  583                 std::cerr << 
"ERROR: Could not determine exposure layers. Cancel execution." << std::endl;
 
  590                 for (
size_t i = 0; i < exposureLayers.size(); ++i)
 
  597                     std::ostringstream filename;
 
  598                     filename << basename << std::setfill(
'0') << std::setw(4) << i;
 
  611             std::cout << std::endl;
 
  625     catch (std::exception& e)
 
  627         std::cerr << 
"caught exception: " << e.what() << std::endl;
 
bool wrapupGPU()
cleanup GPU settings 
PanoramaOptions::ProjectionFormat getProjection() const 
Dummy progress display, without output. 
declaration of functions to handle stacks and layers 
bool GetAdvancedOption(const AdvancedOptions &opts, const std::string &name, const bool defaultValue)
check if given option is saved and return its boolean value, otherwise return defaultValue ...
double outputRangeCompression
std::vector< UIntSet > UIntSetVector
std::vector< UIntSet > getExposureLayers(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output exposure layers 
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI 
bool set_contains(const _Container &c, const typename _Container::key_type &key)
This class will use the stitchPanorama function of nona. 
virtual void run()
runs the algorithm. 
std::string toupper(const std::string &s)
std::set< unsigned int > UIntSet
std::string getPathPrefix(const std::string &filename)
Get the path to a filename. 
void SetGPUDebugMessages(const bool doPrint)
std::size_t getNrOfImages() const 
number of images. 
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
Helper class for storing different options. 
void setImageFilename(unsigned int img, const std::string &fname)
set a new image filename 
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation. 
bool initGPU(int *argcp, char **argv)
Try to initalise GLUT and GLEW, and create an OpenGL context for GPU stitching. 
UIntSet getActiveImages() const 
get active images 
std::string tiffCompression
const PanoramaOptions & getOptions() const 
returns the options for this panorama 
std::string outputImageType
std::string GetHuginVersion()
return a string with version numbers 
std::map< std::string, std::string > AdvancedOptions
std::string outputPixelType
const SrcPanoImage & getImage(std::size_t nr) const 
get a panorama image, counting starts with 0 
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
std::vector< std::string > SplitString(const std::string &s, const std::string &sep)
split string s at given sep, returns vector of strings 
a progress display to print progress reports to a stream 
std::string tolower(const std::string &s)
convert a string to lowercase 
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames) 
void SetAdvancedOption(AdvancedOptions &opts, const std::string &name, const bool value)
store the option with name in AdvancedOptions 
double outputExposureValue
int main(int argc, char *argv[])