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[])