1 // -*- c-basic-offset: 4 -*-
2 
3 /** @file pano_modify.cpp
4  *
5  *  @brief program to modify some aspects of a project file on the command line
6  *
7  *  @author Thomas Modes
8  *
9  *  $Id$
10  *
11  */
12 
13 /*  This program is free software; you can redistribute it and/or
14  *  modify it under the terms of the GNU General Public
15  *  License as published by the Free Software Foundation; either
16  *  version 2 of the License, or (at your option) any later version.
17  *
18  *  This software is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *  General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public
24  *  License along with this software. If not, see
25  *  <http://www.gnu.org/licenses/>.
26  *
27  */
28 
29 #include <fstream>
30 #include <sstream>
31 #include <cmath>
32 #include <getopt.h>
33 #include <panodata/Panorama.h>
34 #include <algorithms/nona/CenterHorizontally.h>
35 #include <algorithms/basic/StraightenPanorama.h>
36 #include <algorithms/basic/RotatePanorama.h>
37 #include <algorithms/basic/TranslatePanorama.h>
38 #include <algorithms/nona/FitPanorama.h>
39 #include <algorithms/basic/CalculateOptimalScale.h>
40 #include <algorithms/basic/CalculateOptimalROI.h>
41 #include <algorithms/basic/LayerStacks.h>
42 #include <algorithms/basic/CalculateMeanExposure.h>
43 #include "hugin_utils/utils.h"
44 
usage(const char * name)45 static void usage(const char* name)
46 {
47     std::cout << name << ": change output parameters of project file" << std::endl
48          << "pano_modify version " << hugin_utils::GetHuginVersion() << std::endl
49          << std::endl
50          << "Usage:  " << name << " [options] input.pto" << std::endl
51          << std::endl
52          << "  Options:" << std::endl
53          << "    -o, --output=file.pto  Output Hugin PTO file. Default: <filename>_mod.pto" << std::endl
54          << "    -p, --projection=x     Sets the output projection to number x" << std::endl
55          << "    --projection-parameter=x    Sets the parameter of the projection" << std::endl
56          << "                                (Several parameters are separated by"<<std::endl
57          << "                                space or comma)" << std::endl
58          << "    --fov=AUTO|HFOV|HFOVxVFOV   Sets field of view" << std::endl
59          << "                                AUTO: calculates optimal fov" << std::endl
60          << "                                HFOV|HFOVxVFOV: set to given fov" << std::endl
61          << "    -s, --straighten       Straightens the panorama" << std::endl
62          << "    -c, --center           Centers the panorama" << std::endl
63          << "    --canvas=AUTO|num%|WIDTHxHEIGHT  Sets the output canvas size" << std::endl
64          << "                                AUTO: calculate optimal canvas size" << std::endl
65          << "                                num%: scales the optimal size by given percent" << std::endl
66          << "                                WIDTHxHEIGHT: set to given size" << std::endl
67          << "    --crop=AUTO|AUTOHDR|left,right,top,bottom  Sets the crop rectangle" << std::endl
68          << "                                AUTO: autocrop panorama" << std::endl
69          << "                                AUTOHDR: autocrop HDR panorama" << std::endl
70          << "                                left,right,top,bottom: to given size" << std::endl
71          << "    --output-exposure=AUTO|num  Sets the output exposure value to mean" << std::endl
72          << "                                exposure (AUTO) or to given value" << std::endl
73          << "                                Prefix number with r for relativ change" << std::endl
74          << "    --output-range-compression=num  Set range compression" << std::endl
75          << "                                    Value should be a real in range 0..20" << std::endl
76          << "    --output-cropped-tiff    Output cropped tiffs as intermediate images" << std::endl
77          << "    --output-uncropped-tiff  Output uncropped tiffs as intermediate images" << std::endl
78          << "    --output-type=str       Sets the type of output" << std::endl
79          << "                              Valid items are" << std::endl
80          << "                                NORMAL|N: normal panorama" << std::endl
81          << "                                STACKSFUSEDBLENDED|BF: LDR panorama with" << std::endl
82          << "                                    blended stacks" << std::endl
83          << "                                EXPOSURELAYERSFUSED|FB: LDR panorama with" << std::endl
84          << "                                    fused exposure layers (any arrangement)" << std::endl
85          << "                                HDR: HDR panorama" << std::endl
86          << "                                REMAP: remapped images with corrected exposure" << std::endl
87          << "                                REMAPORIG: remapped images with" << std::endl
88          << "                                    uncorrected exposure" << std::endl
89          << "                                HDRREMAP: remapped images in linear color space" << std::endl
90          << "                                FUSEDSTACKS: exposure fused stacks" << std::endl
91          << "                                HDRSTACKS: HDR stacks" << std::endl
92          << "                                EXPOSURELAYERS: blended exposure layers" << std::endl
93          << "                              and separated by a comma." << std::endl
94          << "    --ldr-file=JPG|TIF|PNG  Sets the filetype for LDR panorama output" << std::endl
95          << "    --ldr-compression=str   Sets the compression for LDR panorama output" << std::endl
96          << "                              For TIF: NONE|PACKBITS|LZW|DEFLATE" << std::endl
97          << "                              For JPEG: quality as number" << std::endl
98          << "    --hdr-file=EXR|TIF      Sets the filetype for HDR panorama output" << std::endl
99          << "    --hdr-compression=str   Sets the compression for HDR panorama output" << std::endl
100          << "                              For TIF: NONE|PACKBITS|LZW|DEFLATE" << std::endl
101          << "    --blender=ENBLEND|INTERNAL  Sets the blender to be used at stitching" << std::endl
102          << "                            stage." << std::endl
103          << "    --blender-args=str      Sets the arguments for the blender" << std::endl
104          << "    --fusion-args=str       Sets the arguments for the fusion program" << std::endl
105          << "    --hdrmerge-args=str     Setst the arguments for hdrmerge" << std::endl
106          << "    --rotate=yaw,pitch,roll Rotates the whole panorama with the given angles" << std::endl
107          << "    --translate=x,y,z       Translate the whole panorama with the given values" << std::endl
108          << "    --interpolation=int     Sets the interpolation method" << std::endl
109          << "    -h, --help             Shows this help" << std::endl
110          << std::endl;
111 }
112 
main(int argc,char * argv[])113 int main(int argc, char* argv[])
114 {
115     // parse arguments
116     const char* optstring = "o:p:sch";
117 
118     enum
119     {
120         SWITCH_FOV=1000,
121         SWITCH_CANVAS,
122         SWITCH_CROP,
123         SWITCH_ROTATE,
124         SWITCH_TRANSLATE,
125         SWITCH_EXPOSURE,
126         SWITCH_RANGE_COMPRESSION,
127         SWITCH_OUTPUT_TYPE,
128         SWITCH_BLENDER,
129         SWITCH_LDRFILETYPE,
130         SWITCH_LDRCOMPRESSION,
131         SWITCH_HDRFILETYPE,
132         SWITCH_HDRCOMPRESSION,
133         SWITCH_CROPPED_TIFF,
134         SWITCH_UNCROPPED_TIFF,
135         SWITCH_BLENDER_ARGS,
136         SWITCH_FUSION_ARGS,
137         SWITCH_HDRMERGE_ARGS,
138         SWITCH_PROJECTION_PARAMETER,
139         SWITCH_INTERPOLATION
140     };
141     static struct option longOptions[] =
142     {
143         {"output", required_argument, NULL, 'o' },
144         {"projection", required_argument, NULL, 'p' },
145         {"projection-parameter", required_argument, NULL, SWITCH_PROJECTION_PARAMETER },
146         {"fov", required_argument, NULL, SWITCH_FOV },
147         {"straighten", no_argument, NULL, 's' },
148         {"center", no_argument, NULL, 'c' },
149         {"canvas", required_argument, NULL, SWITCH_CANVAS },
150         {"crop", required_argument, NULL, SWITCH_CROP },
151         {"output-cropped-tiff", no_argument, NULL, SWITCH_CROPPED_TIFF },
152         {"output-uncropped-tiff", no_argument, NULL, SWITCH_UNCROPPED_TIFF },
153         {"output-exposure", required_argument, NULL, SWITCH_EXPOSURE },
154         {"output-range-compression", required_argument, NULL, SWITCH_RANGE_COMPRESSION },
155         {"output-type", required_argument, NULL, SWITCH_OUTPUT_TYPE },
156         {"blender", required_argument, NULL, SWITCH_BLENDER },
157         {"blender-args", required_argument, NULL, SWITCH_BLENDER_ARGS },
158         {"fusion-args", required_argument, NULL, SWITCH_FUSION_ARGS },
159         {"hdrmerge-args", required_argument, NULL, SWITCH_HDRMERGE_ARGS },
160         {"ldr-file", required_argument,NULL, SWITCH_LDRFILETYPE },
161         {"ldr-compression", required_argument, NULL, SWITCH_LDRCOMPRESSION },
162         {"hdr-file", required_argument, NULL, SWITCH_HDRFILETYPE },
163         {"hdr-compression", required_argument, NULL, SWITCH_HDRCOMPRESSION },
164         {"rotate", required_argument, NULL, SWITCH_ROTATE },
165         {"translate", required_argument, NULL, SWITCH_TRANSLATE },
166         {"interpolation", required_argument, NULL, SWITCH_INTERPOLATION},
167         {"help", no_argument, NULL, 'h' },
168         0
169     };
170 
171     int projection=-1;
172     std::vector<double> projParameter;
173     double newHFOV=-1;
174     double newVFOV=-1;
175     int scale=100;
176     int newWidth=-1;
177     int newHeight=-1;
178     int outputCroppedTiff=-1;
179     vigra::Rect2D newROI(0,0,0,0);
180     bool doFit=false;
181     bool doStraighten=false;
182     bool doCenter=false;
183     bool doOptimalSize=false;
184     bool doAutocrop=false;
185     bool autocropHDR=false;
186     int c;
187     double yaw = 0;
188     double pitch = 0;
189     double roll = 0;
190     double x = 0;
191     double y = 0;
192     double z = 0;
193     double outputExposure = -1000;
194     double outputRangeCompression = -1;
195     bool relativeExposure = false;
196     bool calcMeanExposure = false;
197     std::string outputType;
198     std::string ldrfiletype;
199     std::string ldrcompression;
200     std::string hdrfiletype;
201     std::string hdrcompression;
202     std::string output;
203     std::string param;
204     std::string blender;
205 #define EMPTYARG "(empty)"
206     std::string blenderArgs(EMPTYARG);
207     std::string fusionArgs(EMPTYARG);
208     std::string hdrMergeArgs(EMPTYARG);
209     int interpolation = -1;
210     while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
211     {
212         switch (c)
213         {
214             case 'o':
215                 output = optarg;
216                 break;
217             case 'h':
218                 usage(hugin_utils::stripPath(argv[0]).c_str());
219                 return 0;
220             case 'p':
221                 //projection
222                 projection=atoi(optarg);
223                 if((projection==0) && (strcmp(optarg,"0")!=0))
224                 {
225                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse projection number." << std::endl;
226                     return 1;
227                 };
228                 if(projection>=panoProjectionFormatCount())
229                 {
230                     std::cerr << hugin_utils::stripPath(argv[0]) << ": projection " << projection << " is an invalid projection number." << std::endl;
231                     return 1;
232                 };
233                 break;
234             case SWITCH_PROJECTION_PARAMETER:
235                 // projection parameters
236                 {
237                     // split at space or comma
238                     std::vector<std::string> parameter = hugin_utils::SplitString(optarg, ", ");
239                     for(const auto& p: parameter)
240                     {
241                         double d;
242                         if (hugin_utils::stringToDouble(p, d))
243                         {
244                             projParameter.push_back(d);
245                         }
246                         else
247                         {
248                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse projection parameters \"" << optarg << "\"." << std::endl;
249                             return 1;
250                         };
251                     };
252                 }
253                 break;
254             case SWITCH_FOV:
255                 //field of view
256                 param=optarg;
257                 param=hugin_utils::toupper(param);
258                 if(param=="AUTO")
259                 {
260                     doFit=true;
261                 }
262                 else
263                 {
264                     double hfov, vfov;
265                     int n=sscanf(optarg, "%lfx%lf", &hfov, &vfov);
266                     if(n==1)
267                     {
268                         if(hfov>0)
269                         {
270                             newHFOV=hfov;
271                         }
272                         else
273                         {
274                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid field of view" << std::endl;
275                             return 1;
276                         };
277                     }
278                     else
279                     {
280                         if (n==2)
281                         {
282                             if(hfov>0 && vfov>0)
283                             {
284                                 newHFOV=hfov;
285                                 newVFOV=vfov;
286                             }
287                             else
288                             {
289                                 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid field of view" << std::endl;
290                                 return 1;
291                             };
292                         }
293                         else
294                         {
295                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse field of view" << std::endl;
296                             return 1;
297                         };
298                     };
299                 };
300                 break;
301             case 's':
302                 doStraighten=true;
303                 break;
304             case 'c':
305                 doCenter=true;
306                 break;
307             case SWITCH_CANVAS:
308                 //canvas size
309                 param=optarg;
310                 param=hugin_utils::toupper(param);
311                 if(param=="AUTO")
312                 {
313                     doOptimalSize=true;
314                 }
315                 else
316                 {
317                     int pos=param.find("%");
318                     if(pos!=std::string::npos)
319                     {
320                         param=param.substr(0,pos);
321                         scale=atoi(param.c_str());
322                         if(scale==0)
323                         {
324                             std::cerr << hugin_utils::stripPath(argv[0]) << ": No valid scale factor given." << std::endl;
325                             return 1;
326                         };
327                         doOptimalSize=true;
328                     }
329                     else
330                     {
331                         int width, height;
332                         int n=sscanf(optarg, "%dx%d", &width, &height);
333                         if (n==2)
334                         {
335                             if(width>0 && height>0)
336                             {
337                                 newWidth=width;
338                                 newHeight=height;
339                             }
340                             else
341                             {
342                                 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid canvas size" << std::endl;
343                                 return 1;
344                             };
345                         }
346                         else
347                         {
348                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse canvas size" << std::endl;
349                             return 1;
350                         };
351                     };
352                 };
353                 break;
354             case SWITCH_CROP:
355                 //crop
356                 param=optarg;
357                 param=hugin_utils::toupper(param);
358                 if(param=="AUTO" || param=="AUTOHDR")
359                 {
360                     doAutocrop=true;
361                     if(param=="AUTOHDR")
362                     {
363                         autocropHDR=true;
364                     };
365                 }
366                 else
367                 {
368                     int left, right, top, bottom;
369                     int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
370                     if (n==4)
371                     {
372                         if(right>left && bottom>top && left>=0 && top>=0)
373                         {
374                             newROI.setUpperLeft(vigra::Point2D(left,top));
375                             newROI.setLowerRight(vigra::Point2D(right,bottom));
376                         }
377                         else
378                         {
379                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid crop area" << std::endl;
380                             return 1;
381                         };
382                     }
383                     else
384                     {
385                         std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse crop values" << std::endl;
386                         return 1;
387                     };
388                 };
389                 break;
390             case SWITCH_CROPPED_TIFF:
391                 outputCroppedTiff = 1;
392                 break;
393             case SWITCH_UNCROPPED_TIFF:
394                 outputCroppedTiff = 0;
395                 break;
396             case SWITCH_EXPOSURE:
397                 param = optarg;
398                 param = hugin_utils::toupper(param);
399                 if (param == "AUTO")
400                 {
401                     calcMeanExposure = true;
402                 }
403                 else
404                 {
405                     if (!param.empty())
406                     {
407                         // if first character is r assume relative exposure values
408                         relativeExposure = (param[0] == 'R');
409                         if (relativeExposure)
410                         {
411                             param.erase(0, 1);
412                         };
413                         int n = sscanf(param.c_str(), "%lf", &outputExposure);
414                         if (n != 1)
415                         {
416                             std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output exposure value." << std::endl;
417                             return 1;
418                         };
419                     }
420                     else
421                     {
422                         std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output exposure value." << std::endl;
423                         return 1;
424                     };
425                 };
426                 break;
427             case SWITCH_RANGE_COMPRESSION:
428                 if(!hugin_utils::stringToDouble(std::string(optarg), outputRangeCompression))
429                 {
430                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output range compression (" << optarg << ")." << std::endl;
431                     return 1;
432                 };
433                 if (outputRangeCompression < 0.0 || outputRangeCompression > 20.0)
434                 {
435                     std::cerr << hugin_utils::stripPath(argv[0]) << ": range compression must be a real between 0 and 20." << std::endl;
436                     return 1;
437                 };
438                 break;
439             case SWITCH_OUTPUT_TYPE:
440                 if (!outputType.empty())
441                 {
442                     outputType.append(",");
443                 };
444                 outputType.append(optarg);
445                 break;
446             case SWITCH_BLENDER:
447                 blender = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
448                 break;
449             case SWITCH_LDRFILETYPE:
450                 ldrfiletype = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
451                 break;
452             case SWITCH_LDRCOMPRESSION:
453                 ldrcompression = hugin_utils::toupper(hugin_utils::StrTrim(optarg));
454                 break;
455             case SWITCH_HDRFILETYPE:
456                 hdrfiletype = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
457                 break;
458             case SWITCH_HDRCOMPRESSION:
459                 hdrcompression = hugin_utils::toupper(hugin_utils::StrTrim(optarg));
460                 break;
461             case SWITCH_BLENDER_ARGS:
462                 blenderArgs = optarg;
463                 break;
464             case SWITCH_FUSION_ARGS:
465                 fusionArgs = optarg;
466                 break;
467             case SWITCH_HDRMERGE_ARGS:
468                 hdrMergeArgs = optarg;
469                 break;
470             case SWITCH_ROTATE:
471                 {
472                     int n=sscanf(optarg, "%lf,%lf,%lf", &yaw, &pitch, &roll);
473                     if(n!=3)
474                     {
475                         std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse rotate angles values. Given: \"" << optarg << "\"" << std::endl;
476                         return 1;
477                     };
478                 };
479                 break;
480             case SWITCH_TRANSLATE:
481                 {
482                     int n=sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z);
483                     if(n!=3)
484                     {
485                         std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse translation values. Given: \"" << optarg << "\"" << std::endl;
486                         return 1;
487                     };
488                 };
489                 break;
490             case SWITCH_INTERPOLATION:
491                 if (!hugin_utils::stringToInt(optarg, interpolation))
492                 {
493                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse interpolation value. Given: \"" << optarg << "\"" << std::endl;
494                     return 1;
495                 };
496                 if (interpolation<0 || interpolation>vigra_ext::INTERP_SINC_1024)
497                 {
498                     std::cerr << hugin_utils::stripPath(argv[0]) << ": Interpolator " << interpolation << " is not valid." << std::endl;
499                     return 1;
500                 }
501                 break;
502             case ':':
503             case '?':
504                 // missing argument or invalid switch
505                 return 1;
506                 break;
507             default:
508                 // this should not happen
509                 abort();
510 
511         }
512     }
513 
514     if (argc - optind != 1)
515     {
516         if (argc - optind < 1)
517         {
518             std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
519         }
520         else
521         {
522             std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
523         };
524         return 1;
525     };
526 
527     // set some options which depends on each other
528     if(doStraighten)
529     {
530         doCenter=false;
531         doFit=true;
532     };
533     if(doCenter)
534     {
535         doFit=true;
536     };
537 
538     std::string input=argv[optind];
539     // read panorama
540     HuginBase::Panorama pano;
541     std::ifstream prjfile(input.c_str());
542     if (!prjfile.good())
543     {
544         std::cerr << "could not open script : " << input << std::endl;
545         return 1;
546     }
547     pano.setFilePrefix(hugin_utils::getPathPrefix(input));
548     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
549     if (err != AppBase::DocumentData::SUCCESSFUL)
550     {
551         std::cerr << "error while parsing panos tool script: " << input << std::endl;
552         std::cerr << "DocumentData::ReadWriteError code: " << err << std::endl;
553         return 1;
554     }
555 
556     // sets the projection
557     if(projection!=-1)
558     {
559         HuginBase::PanoramaOptions opt = pano.getOptions();
560         opt.setProjection((HuginBase::PanoramaOptions::ProjectionFormat)projection);
561         pano_projection_features proj;
562         if (panoProjectionFeaturesQuery(projection, &proj))
563         {
564             std::cout << "Setting projection to " << proj.name << std::endl;
565         }
566         pano.setOptions(opt);
567     };
568     // set projection parameters
569     if (!projParameter.empty())
570     {
571         HuginBase::PanoramaOptions opt = pano.getOptions();
572         if (projParameter.size() > opt.m_projFeatures.numberOfParameters)
573         {
574             std::cout << "Warning: Given " << projParameter.size() << " projection parameters, but projection supports" << std::endl
575                 << "         only " << opt.m_projFeatures.numberOfParameters << ". Ignoring surplus parameters." << std::endl;
576             while (projParameter.size() > opt.m_projFeatures.numberOfParameters)
577             {
578                 projParameter.pop_back();
579             }
580         }
581         if (!projParameter.empty())
582         {
583             std::vector<double> newProjParameters = opt.getProjectionParameters();
584             std::copy(projParameter.begin(), projParameter.end(), newProjParameters.begin());
585             opt.setProjectionParameters(newProjParameters);
586             // read back, new the limits have been applied
587             newProjParameters = opt.getProjectionParameters();
588             auto it = newProjParameters.begin();
589             std::cout << "Setting projection parameters to: " << *it;
590             ++it;
591             while (it != newProjParameters.end())
592             {
593                 std::cout << ", " << *it;
594                 ++it;
595             }
596             std::cout << std::endl;
597             pano.setOptions(opt);
598         }
599         else
600         {
601             std::cout << "Warning: Current projection does not support projection parameters." << std::endl;
602         }
603     }
604     // output exposure value
605     if (outputExposure > -1000 || calcMeanExposure)
606     {
607         HuginBase::PanoramaOptions opt = pano.getOptions();
608         if (calcMeanExposure)
609         {
610             opt.outputExposureValue = HuginBase::CalculateMeanExposure::calcMeanExposure(pano);
611         }
612         else
613         {
614             if (relativeExposure)
615             {
616                 opt.outputExposureValue += outputExposure;
617             }
618             else
619             {
620                 opt.outputExposureValue = outputExposure;
621             };
622         };
623         std::cout << "Setting output exposure value to " << opt.outputExposureValue << std::endl;
624         pano.setOptions(opt);
625     };
626     // output range compression
627     if (outputRangeCompression >= 0.0)
628     {
629         HuginBase::PanoramaOptions opt = pano.getOptions();
630         opt.outputRangeCompression = outputRangeCompression;
631         std::cout << "Setting output range compression to " << opt.outputRangeCompression << std::endl;
632         pano.setOptions(opt);
633     };
634     // output type: normal, fused, hdr pano..
635     if (!outputType.empty())
636     {
637         HuginBase::PanoramaOptions opt = pano.getOptions();
638         // reset all output
639         // final pano
640         opt.outputLDRBlended = false;
641         opt.outputLDRExposureBlended = false;
642         opt.outputLDRExposureLayersFused = false;
643         opt.outputHDRBlended = false;
644         // remapped images
645         opt.outputLDRLayers = false;
646         opt.outputLDRExposureRemapped = false;
647         opt.outputHDRLayers = false;
648         // stacks
649         opt.outputLDRStacks = false;
650         opt.outputHDRStacks = false;
651         // exposure layers
652         opt.outputLDRExposureLayers = false;
653         // now parse string and set corresponding options
654         std::vector<std::string> tokens = hugin_utils::SplitString(outputType, ",");
655         size_t counter = 0;
656         for (size_t i = 0; i < tokens.size(); i++)
657         {
658             std::string s = hugin_utils::toupper(hugin_utils::StrTrim(tokens[i]));
659             if (s == "NORMAL" || s=="N")
660             {
661                 opt.outputLDRBlended = true;
662                 std::cout << "Activate output of normal panorama." << std::endl;
663                 counter++;
664                 continue;
665             };
666             if (s == "STACKSFUSEDBLENDED" || s == "FB")
667             {
668                 opt.outputLDRExposureBlended = true;
669                 std::cout << "Activate output of LDR panorama: Exposure fused from stacks." << std::endl;
670                 counter++;
671                 continue;
672             };
673             if (s == "EXPOSURELAYERSFUSED" || s == "BF")
674             {
675                 opt.outputLDRExposureLayersFused = true;
676                 std::cout << "Activate output of LDR panorama: Exposure fused from any arrangement." << std::endl;
677                 counter++;
678                 continue;
679             };
680             if (s == "HDR")
681             {
682                 opt.outputHDRBlended = true;
683                 std::cout << "Activate output of hdr panorama." << std::endl;
684                 counter++;
685                 continue;
686             };
687             // single remapped images
688             if (s == "REMAP")
689             {
690                 opt.outputLDRLayers = true;
691                 std::cout << "Activate output of remapped, exposure corrected images." << std::endl;
692                 counter++;
693                 continue;
694             };
695             if (s == "REMAPORIG")
696             {
697                 opt.outputLDRExposureRemapped = true;
698                 std::cout << "Activate output of remapped images with unmodified exposure." << std::endl;
699                 counter++;
700                 continue;
701             };
702             if (s == "HDRREMAP")
703             {
704                 opt.outputHDRLayers = true;
705                 std::cout << "Activate output of remapped hdr images." << std::endl;
706                 counter++;
707                 continue;
708             };
709             //stacks
710             if (s == "FUSEDSTACKS")
711             {
712                 opt.outputLDRStacks = true;
713                 std::cout << "Activate output of exposure fused stacks." << std::endl;
714                 counter++;
715                 continue;
716             };
717             if (s == "HDRSTACKS")
718             {
719                 opt.outputHDRStacks = true;
720                 std::cout << "Activate output of HDR stacks." << std::endl;
721                 counter++;
722                 continue;
723             };
724             //exposure layers
725             if (s == "EXPOSURELAYERS")
726             {
727                 opt.outputLDRExposureLayers = true;
728                 std::cout << "Activate output of exposure layers." << std::endl;
729                 counter++;
730                 continue;
731             };
732             std::cout << "Unknown parameter \"" << s << "\" found in --output-type." << std::endl
733                 << "Ignoring this parameter." << std::endl;
734         }
735         if (counter > 0)
736         {
737             pano.setOptions(opt);
738         }
739         else
740         {
741             std::cout << "No matching output type given. The whole output-type is ignored." << std::endl;
742         };
743     };
744     // cropped or uncropped tiff output
745     if (outputCroppedTiff != -1)
746     {
747         HuginBase::PanoramaOptions opts = pano.getOptions();
748         opts.tiff_saveROI = (outputCroppedTiff == 1);
749         std::cout << "Setting support for cropped images: " << ((outputCroppedTiff == 1) ? "yes" : "no") << std::endl;
750         pano.setOptions(opts);
751     }
752     // blender type
753     if (!blender.empty())
754     {
755         HuginBase::PanoramaOptions opt = pano.getOptions();
756         if (blender == "enblend")
757         {
758             opt.blendMode = HuginBase::PanoramaOptions::ENBLEND_BLEND;
759             std::cout << "Setting blender type to \"ENBLEND\"." << std::endl;
760         }
761         else
762         {
763             if (blender == "internal" || blender == "verdandi")
764             {
765                 opt.blendMode = HuginBase::PanoramaOptions::INTERNAL_BLEND;
766                 std::cout << "Setting blender type to \"INTERNAL\"." << std::endl;
767             }
768             else
769             {
770                 std::cout << "Blender \"" << blender << "\" is not a valid blender ." << std::endl
771                     << "Ignoring parameter." << std::endl;
772             };
773         };
774         pano.setOptions(opt);
775     }
776     if (blenderArgs != EMPTYARG)
777     {
778         HuginBase::PanoramaOptions opt = pano.getOptions();
779         switch (opt.blendMode)
780         {
781             case HuginBase::PanoramaOptions::ENBLEND_BLEND:
782                 opt.enblendOptions = blenderArgs;
783                 std::cout << "Setting enblend arguments to " << blenderArgs << std::endl;
784                 break;
785             case HuginBase::PanoramaOptions::INTERNAL_BLEND:
786                 opt.verdandiOptions = blenderArgs;
787                 std::cout << "Setting verdandi arguments to " << blenderArgs << std::endl;
788                 break;
789             default:
790                 std::cout << "Unknown blender in pto file." << std::endl;
791                 break;
792         };
793         pano.setOptions(opt);
794     };
795     if (fusionArgs != EMPTYARG)
796     {
797         HuginBase::PanoramaOptions opt = pano.getOptions();
798         opt.enfuseOptions = fusionArgs;
799         std::cout << "Setting enfuse arguments to " << fusionArgs << std::endl;
800         pano.setOptions(opt);
801     };
802     if (hdrMergeArgs != EMPTYARG)
803     {
804         HuginBase::PanoramaOptions opt = pano.getOptions();
805         opt.hdrmergeOptions = hdrMergeArgs;
806         std::cout << "Setting hugin_hdrdmerge arguments to " << hdrMergeArgs << std::endl;
807         pano.setOptions(opt);
808     };
809     // ldr output file type
810     if (!ldrfiletype.empty())
811     {
812         HuginBase::PanoramaOptions opt = pano.getOptions();
813         if (ldrfiletype == "jpg" || ldrfiletype == "png" || ldrfiletype == "tif")
814         {
815             opt.outputImageType = ldrfiletype;
816             std::cout << "Setting ldr output to filetype \"" << ldrfiletype << "\"." << std::endl;
817             pano.setOptions(opt);
818         }
819         else
820         {
821             std::cout << "LDR file format \"" << ldrfiletype << "\" is not a valid LDR output filetype." << std::endl
822                 << "Ignoring parameter." << std::endl;
823         };
824     };
825     // ldr compression
826     if (!ldrcompression.empty())
827     {
828         HuginBase::PanoramaOptions opt = pano.getOptions();
829         if (opt.outputImageType == "tif")
830         {
831             if (ldrcompression == "NONE" || ldrcompression == "PACKBITS" || ldrcompression == "LZW" || ldrcompression == "DEFLATE")
832             {
833                 opt.outputImageTypeCompression = ldrcompression;
834                 std::cout << "Setting TIF compression to \"" << ldrcompression << "\"." << std::endl;
835                 opt.tiffCompression = ldrcompression;
836             }
837             else
838             {
839                 std::cout << "LDR compression \"" << ldrcompression << "\" is not a valid compression value for TIF files." << std::endl
840                     << "Ignoring compression." << std::endl;
841             }
842         }
843         else
844         {
845             if (opt.outputImageType == "jpg")
846             {
847                 int quality = 0;
848                 quality = atoi(ldrcompression.c_str());
849                 if (quality != 0)
850                 {
851                     if (quality>0 && quality <=100)
852                     {
853                         opt.quality = quality;
854                         std::cout << "Setting JPEG quality to " << quality << "." << std::endl;
855                     }
856                     else
857                     {
858                         std::cout << "Given value for JPEG quality is outside the valid range 1..100." << std::endl
859                             << "Ignoring value." << std::endl;
860                     };
861                 }
862                 else
863                 {
864                     std::cout << "Could not parse \"" << ldrcompression << "\" as a valid JPEG quality number." << std::endl
865                         << "Ignoring value." << std::endl;
866                 };
867             }
868             else
869             {
870                 if (opt.outputImageType == "png")
871                 {
872                     std::cout << "Setting compression for PNG images is not supported." << std::endl;
873                 }
874                 else
875                 {
876                     // this should never happen
877                     std::cout << "Unknown image format" << std::endl;
878                 };
879             };
880         };
881         pano.setOptions(opt);
882     };
883     // hdr output file type
884     if (!hdrfiletype.empty())
885     {
886         HuginBase::PanoramaOptions opt = pano.getOptions();
887         if (hdrfiletype == "exr" || hdrfiletype == "tif")
888         {
889             opt.outputImageTypeHDR = hdrfiletype;
890             std::cout << "Setting hdr output to filetype \"" << ldrfiletype << "\"." << std::endl;
891             pano.setOptions(opt);
892         }
893         else
894         {
895             std::cout << "HDR file format \"" << ldrfiletype << "\" is not a valid HDR output filetype." << std::endl
896                 << "Ignoring parameter." << std::endl;
897         };
898     };
899     // hdr compression
900     if (!hdrcompression.empty())
901     {
902         HuginBase::PanoramaOptions opt = pano.getOptions();
903         if (opt.outputImageTypeHDR == "tif")
904         {
905             if (hdrcompression == "NONE" || hdrcompression == "PACKBITS" || hdrcompression == "LZW" || hdrcompression == "DEFLATE")
906             {
907                 opt.outputImageTypeHDRCompression = hdrcompression;
908                 std::cout << "Setting HDR-TIF compression to \"" << hdrcompression << "\"." << std::endl;
909             }
910             else
911             {
912                 std::cout << "HDR compression \"" << ldrcompression << "\" is not a valid compression value for TIF files." << std::endl
913                     << "Ignoring compression." << std::endl;
914             }
915         }
916         else
917         {
918             if (opt.outputImageTypeHDR == "exr")
919             {
920                 std::cout << "Setting compression for EXR images is not supported." << std::endl;
921             }
922             else
923             {
924                 // this should never happen
925                 std::cout << "Unknown HDR image format" << std::endl;
926             };
927         };
928         pano.setOptions(opt);
929     };
930     // rotate complete pano
931     if (std::abs(yaw) + std::abs(pitch) + std::abs(roll) > 0.0)
932     {
933         std::cout << "Rotate panorama (yaw=" << yaw << ", pitch= " << pitch << ", roll=" << roll << ")" << std::endl;
934         HuginBase::RotatePanorama(pano, yaw, pitch, roll).run();
935     };
936     // translate complete pano
937     if(std::abs(x) + std::abs(y) + std::abs(z) > 0.0)
938     {
939         std::cout << "Translate panorama (x=" << x << ", y=" << y << ", z=" << z << ")" << std::endl;
940         HuginBase::TranslatePanorama(pano, x, y, z).run();
941     };
942     // straighten
943     if(doStraighten)
944     {
945         std::cout << "Straighten panorama" << std::endl;
946         HuginBase::StraightenPanorama(pano).run();
947         HuginBase::CenterHorizontally(pano).run();
948     };
949     // center
950     if(doCenter)
951     {
952         std::cout << "Center panorama" << std::endl;
953         HuginBase::CenterHorizontally(pano).run();
954     }
955     //fit fov
956     if(doFit)
957     {
958         std::cout << "Fit panorama field of view to best size" << std::endl;
959         HuginBase::PanoramaOptions opt = pano.getOptions();
960         HuginBase::CalculateFitPanorama fitPano(pano);
961         fitPano.run();
962         opt.setHFOV(fitPano.getResultHorizontalFOV());
963         opt.setHeight(hugin_utils::roundi(fitPano.getResultHeight()));
964         std::cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << std::endl;
965         pano.setOptions(opt);
966     };
967     //set field of view manually
968     if(newHFOV>0)
969     {
970         HuginBase::PanoramaOptions opt = pano.getOptions();
971         opt.setHFOV(newHFOV);
972         if(opt.fovCalcSupported(opt.getProjection()) && newVFOV>0)
973         {
974             opt.setVFOV(newVFOV);
975         }
976         std::cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << std::endl;
977         pano.setOptions(opt);
978     };
979     // calc optimal size
980     if(doOptimalSize)
981     {
982         std::cout << "Calculate optimal size of panorama" << std::endl;
983         double s = HuginBase::CalculateOptimalScale::calcOptimalScale(pano);
984         HuginBase::PanoramaOptions opt = pano.getOptions();
985         opt.setWidth(hugin_utils::roundi(opt.getWidth()*s*scale/100), true);
986         std::cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << std::endl;
987         pano.setOptions(opt);
988     };
989     // set canvas size
990     if(newWidth>0 && newHeight>0)
991     {
992         HuginBase::PanoramaOptions opt = pano.getOptions();
993         opt.setWidth(newWidth);
994         opt.setHeight(newHeight);
995         std::cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << std::endl;
996         pano.setOptions(opt);
997     };
998     // auto crop
999     if(doAutocrop)
1000     {
1001         std::cout << "Searching for best crop rectangle" << std::endl;
1002         AppBase::DummyProgressDisplay dummy;
1003         HuginBase::CalculateOptimalROI cropPano(pano, &dummy);
1004         if(autocropHDR)
1005         {
1006             cropPano.setStacks(getHDRStacks(pano,pano.getActiveImages(), pano.getOptions()));
1007         }
1008         cropPano.run();
1009 
1010         vigra::Rect2D roi=cropPano.getResultOptimalROI();
1011         HuginBase::PanoramaOptions opt = pano.getOptions();
1012         //set the ROI - fail if the right/bottom is zero, meaning all zero
1013         if(!roi.isEmpty())
1014         {
1015             opt.setROI(roi);
1016             std::cout << "Set crop size to " << roi.left() << "," << roi.top() << "," << roi.right() << "," << roi.bottom() << std::endl;
1017             pano.setOptions(opt);
1018         }
1019         else
1020         {
1021             std::cout << "Could not find best crop rectangle" << std::endl;
1022         }
1023     };
1024     //setting crop rectangle manually
1025     if(newROI.right() != 0 && newROI.bottom() != 0)
1026     {
1027         HuginBase::PanoramaOptions opt = pano.getOptions();
1028         opt.setROI(newROI);
1029         std::cout << "Set crop size to " << newROI.left() << "," << newROI.right() << "," << newROI.top() << "," << newROI.bottom() << std::endl;
1030         pano.setOptions(opt);
1031     };
1032     //setting interpolation method
1033     if (interpolation>=0)
1034     {
1035         HuginBase::PanoramaOptions opt = pano.getOptions();
1036         opt.interpolator = static_cast<vigra_ext::Interpolator>(interpolation);
1037         std::cout << "Set interpolation method to " << interpolation << std::endl;
1038         pano.setOptions(opt);
1039     };
1040 
1041     //write output
1042     HuginBase::OptimizeVector optvec = pano.getOptimizeVector();
1043     HuginBase::UIntSet imgs;
1044     fill_set(imgs,0, pano.getNrOfImages()-1);
1045     // Set output .pto filename if not given
1046     if (output=="")
1047     {
1048         output=input.substr(0,input.length()-4).append("_mod.pto");
1049     }
1050     std::ofstream of(output.c_str());
1051     pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
1052 
1053     std::cout << std::endl << "Written output to " << output << std::endl;
1054     return 0;
1055 }
1056