Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pano_modify.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
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>
43 #include "hugin_utils/utils.h"
44 #include "PanoOptionsFromIni.h"
45 
46 static void usage(const char* name)
47 {
48  std::cout << name << ": change output parameters of project file" << std::endl
49  << "pano_modify version " << hugin_utils::GetHuginVersion() << std::endl
50  << std::endl
51  << "Usage: " << name << " [options] input.pto" << std::endl
52  << std::endl
53  << " Options:" << std::endl
54  << " -o, --output=file.pto Output Hugin PTO file. Default: <filename>_mod.pto" << std::endl
55  << " -p, --projection=x Sets the output projection to number x" << std::endl
56  << " --projection-parameter=x Sets the parameter of the projection" << std::endl
57  << " (Several parameters are separated by"<<std::endl
58  << " space or comma)" << std::endl
59  << " --fov=AUTO|HFOV|HFOVxVFOV Sets field of view" << std::endl
60  << " AUTO: calculates optimal fov" << std::endl
61  << " HFOV|HFOVxVFOV: set to given fov" << std::endl
62  << " -s, --straighten Straightens the panorama" << std::endl
63  << " -c, --center Centers the panorama" << std::endl
64  << " --canvas=AUTO|num%|WIDTHxHEIGHT Sets the output canvas size" << std::endl
65  << " AUTO: calculate optimal canvas size" << std::endl
66  << " num%: scales the optimal size by given percent" << std::endl
67  << " WIDTHxHEIGHT: set to given size" << std::endl
68  << " --crop=AUTO|AUTOHDR|AUTOOUTSIDE|left,right,top,bottom|left,right,top,bottom%" << std::endl
69  << " Sets the crop rectangle" << std::endl
70  << " AUTO: autocrop panorama" << std::endl
71  << " AUTOHDR: autocrop HDR panorama" << std::endl
72  << " AUTOOUTSIDE: autocrop outside of all images" << std::endl
73  << " left,right,top,bottom: to given size" << std::endl
74  << " left,right,top,bottom%: to size relative to canvas" << std::endl
75  << " --output-exposure=AUTO|num Sets the output exposure value to mean" << std::endl
76  << " exposure (AUTO) or to given value" << std::endl
77  << " Prefix number with r for relativ change" << std::endl
78  << " --output-range-compression=num Set range compression" << std::endl
79  << " Value should be a real in range 0..20" << std::endl
80  << " --output-cropped-tiff Output cropped tiffs as intermediate images" << std::endl
81  << " --output-uncropped-tiff Output uncropped tiffs as intermediate images" << std::endl
82  << " --output-type=str Sets the type of output" << std::endl
83  << " Valid items are" << std::endl
84  << " NORMAL|N: normal panorama" << std::endl
85  << " STACKSFUSEDBLENDED|BF: LDR panorama with" << std::endl
86  << " blended stacks" << std::endl
87  << " EXPOSURELAYERSFUSED|FB: LDR panorama with" << std::endl
88  << " fused exposure layers (any arrangement)" << std::endl
89  << " HDR: HDR panorama" << std::endl
90  << " REMAP: remapped images with corrected exposure" << std::endl
91  << " REMAPORIG: remapped images with" << std::endl
92  << " uncorrected exposure" << std::endl
93  << " HDRREMAP: remapped images in linear color space" << std::endl
94  << " FUSEDSTACKS: exposure fused stacks" << std::endl
95  << " HDRSTACKS: HDR stacks" << std::endl
96  << " EXPOSURELAYERS: blended exposure layers" << std::endl
97  << " and separated by a comma." << std::endl
98  << " --ldr-file=JPG|TIF|PNG Sets the filetype for LDR panorama output" << std::endl
99  << " --ldr-compression=str Sets the compression for LDR panorama output" << std::endl
100  << " For TIF: NONE|PACKBITS|LZW|DEFLATE" << std::endl
101  << " For JPEG: quality as number" << std::endl
102  << " --hdr-file=EXR|TIF Sets the filetype for HDR panorama output" << std::endl
103  << " --hdr-compression=str Sets the compression for HDR panorama output" << std::endl
104  << " For TIF: NONE|PACKBITS|LZW|DEFLATE" << std::endl
105  << " --blender=ENBLEND|INTERNAL Sets the blender to be used at stitching" << std::endl
106  << " stage." << std::endl
107  << " --blender-args=str Sets the arguments for the blender" << std::endl
108  << " --fusion-args=str Sets the arguments for the fusion program" << std::endl
109  << " --hdrmerge-args=str Setst the arguments for hdrmerge" << std::endl
110  << " --rotate=yaw,pitch,roll Rotates the whole panorama with the given angles" << std::endl
111  << " --translate=x,y,z Translate the whole panorama with the given values" << std::endl
112  << " --interpolation=int Sets the interpolation method" << std::endl
113  << " --ini=FILE Read the settings from the given FILE and apply it" << std::endl
114  << " --template=TEMPLATE Read the panorama options from the given TEMPLATE" << std::endl
115  << " and apply it" << std::endl
116  << " -h, --help Shows this help" << std::endl
117  << std::endl;
118 }
119 
120 int main(int argc, char* argv[])
121 {
122  // parse arguments
123  const char* optstring = "o:p:sch";
124 
125  enum
126  {
127  SWITCH_FOV=1000,
128  SWITCH_CANVAS,
129  SWITCH_CROP,
130  SWITCH_ROTATE,
131  SWITCH_TRANSLATE,
132  SWITCH_EXPOSURE,
133  SWITCH_RANGE_COMPRESSION,
134  SWITCH_OUTPUT_TYPE,
135  SWITCH_BLENDER,
136  SWITCH_LDRFILETYPE,
137  SWITCH_LDRCOMPRESSION,
138  SWITCH_HDRFILETYPE,
139  SWITCH_HDRCOMPRESSION,
140  SWITCH_CROPPED_TIFF,
141  SWITCH_UNCROPPED_TIFF,
142  SWITCH_BLENDER_ARGS,
143  SWITCH_FUSION_ARGS,
144  SWITCH_HDRMERGE_ARGS,
145  SWITCH_PROJECTION_PARAMETER,
146  SWITCH_INTERPOLATION,
147  SWITCH_INI_FILE,
148  SWITCH_TEMPLATE
149  };
150  static struct option longOptions[] =
151  {
152  {"output", required_argument, NULL, 'o' },
153  {"projection", required_argument, NULL, 'p' },
154  {"projection-parameter", required_argument, NULL, SWITCH_PROJECTION_PARAMETER },
155  {"fov", required_argument, NULL, SWITCH_FOV },
156  {"straighten", no_argument, NULL, 's' },
157  {"center", no_argument, NULL, 'c' },
158  {"canvas", required_argument, NULL, SWITCH_CANVAS },
159  {"crop", required_argument, NULL, SWITCH_CROP },
160  {"output-cropped-tiff", no_argument, NULL, SWITCH_CROPPED_TIFF },
161  {"output-uncropped-tiff", no_argument, NULL, SWITCH_UNCROPPED_TIFF },
162  {"output-exposure", required_argument, NULL, SWITCH_EXPOSURE },
163  {"output-range-compression", required_argument, NULL, SWITCH_RANGE_COMPRESSION },
164  {"output-type", required_argument, NULL, SWITCH_OUTPUT_TYPE },
165  {"blender", required_argument, NULL, SWITCH_BLENDER },
166  {"blender-args", required_argument, NULL, SWITCH_BLENDER_ARGS },
167  {"fusion-args", required_argument, NULL, SWITCH_FUSION_ARGS },
168  {"hdrmerge-args", required_argument, NULL, SWITCH_HDRMERGE_ARGS },
169  {"ldr-file", required_argument,NULL, SWITCH_LDRFILETYPE },
170  {"ldr-compression", required_argument, NULL, SWITCH_LDRCOMPRESSION },
171  {"hdr-file", required_argument, NULL, SWITCH_HDRFILETYPE },
172  {"hdr-compression", required_argument, NULL, SWITCH_HDRCOMPRESSION },
173  {"rotate", required_argument, NULL, SWITCH_ROTATE },
174  {"translate", required_argument, NULL, SWITCH_TRANSLATE },
175  {"interpolation", required_argument, NULL, SWITCH_INTERPOLATION},
176  {"ini", required_argument, NULL, SWITCH_INI_FILE },
177  {"template", required_argument, NULL, SWITCH_TEMPLATE },
178  {"help", no_argument, NULL, 'h' },
179  0
180  };
181 
182  int projection=-1;
183  std::vector<double> projParameter;
184  double newHFOV=-1;
185  double newVFOV=-1;
186  int scale=100;
187  int newWidth=-1;
188  int newHeight=-1;
189  int outputCroppedTiff=-1;
190  vigra::Rect2D newROI(0,0,0,0);
191  hugin_utils::FDiff2D newRoiRelativeLeftTop(-1.0, -1.0);
192  hugin_utils::FDiff2D newRoiRelativeRightBottom(-1.0, -1.0);
193  bool doFit=false;
194  bool doStraighten=false;
195  bool doCenter=false;
196  bool doOptimalSize=false;
197  enum AutoCropMode
198  { NONE, AUTO, AUTOHDR, AUTOOUTSIDE};
199  AutoCropMode doAutocrop=AutoCropMode::NONE;
200  int c;
201  double yaw = 0;
202  double pitch = 0;
203  double roll = 0;
204  double x = 0;
205  double y = 0;
206  double z = 0;
207  double outputExposure = -1000;
208  double outputRangeCompression = -1;
209  bool relativeExposure = false;
210  bool calcMeanExposure = false;
211  std::string outputType;
212  std::string ldrfiletype;
213  std::string ldrcompression;
214  std::string hdrfiletype;
215  std::string hdrcompression;
216  std::string output;
217  std::string param;
218  std::string blender;
219 #define EMPTYARG "(empty)"
220  std::string blenderArgs(EMPTYARG);
221  std::string fusionArgs(EMPTYARG);
222  std::string hdrMergeArgs(EMPTYARG);
223  std::string iniFile;
224  std::string templateFile;
225  int interpolation = -1;
226  while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
227  {
228  switch (c)
229  {
230  case 'o':
231  output = optarg;
232  break;
233  case 'h':
234  usage(hugin_utils::stripPath(argv[0]).c_str());
235  return 0;
236  case 'p':
237  //projection
238  projection=atoi(optarg);
239  if((projection==0) && (strcmp(optarg,"0")!=0))
240  {
241  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse projection number." << std::endl;
242  return 1;
243  };
244  if(projection>=panoProjectionFormatCount())
245  {
246  std::cerr << hugin_utils::stripPath(argv[0]) << ": projection " << projection << " is an invalid projection number." << std::endl;
247  return 1;
248  };
249  break;
250  case SWITCH_PROJECTION_PARAMETER:
251  // projection parameters
252  {
253  // split at space or comma
254  std::vector<std::string> parameter = hugin_utils::SplitString(optarg, ", ");
255  for(const auto& p: parameter)
256  {
257  double d;
258  if (hugin_utils::stringToDouble(p, d))
259  {
260  projParameter.push_back(d);
261  }
262  else
263  {
264  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse projection parameters \"" << optarg << "\"." << std::endl;
265  return 1;
266  };
267  };
268  }
269  break;
270  case SWITCH_FOV:
271  //field of view
272  param=optarg;
273  param=hugin_utils::toupper(param);
274  if(param=="AUTO")
275  {
276  doFit=true;
277  }
278  else
279  {
280  double hfov, vfov;
281  int n=sscanf(optarg, "%lfx%lf", &hfov, &vfov);
282  if(n==1)
283  {
284  if(hfov>0)
285  {
286  newHFOV=hfov;
287  }
288  else
289  {
290  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid field of view" << std::endl;
291  return 1;
292  };
293  }
294  else
295  {
296  if (n==2)
297  {
298  if(hfov>0 && vfov>0)
299  {
300  newHFOV=hfov;
301  newVFOV=vfov;
302  }
303  else
304  {
305  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid field of view" << std::endl;
306  return 1;
307  };
308  }
309  else
310  {
311  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse field of view" << std::endl;
312  return 1;
313  };
314  };
315  };
316  break;
317  case 's':
318  doStraighten=true;
319  break;
320  case 'c':
321  doCenter=true;
322  break;
323  case SWITCH_CANVAS:
324  //canvas size
325  param=optarg;
326  param=hugin_utils::toupper(param);
327  if(param=="AUTO")
328  {
329  doOptimalSize=true;
330  }
331  else
332  {
333  int pos=param.find("%");
334  if(pos!=std::string::npos)
335  {
336  param=param.substr(0,pos);
337  scale=atoi(param.c_str());
338  if(scale==0)
339  {
340  std::cerr << hugin_utils::stripPath(argv[0]) << ": No valid scale factor given." << std::endl;
341  return 1;
342  };
343  doOptimalSize=true;
344  }
345  else
346  {
347  int width, height;
348  int n=sscanf(optarg, "%dx%d", &width, &height);
349  if (n==2)
350  {
351  if(width>0 && height>0)
352  {
353  newWidth=width;
354  newHeight=height;
355  }
356  else
357  {
358  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid canvas size" << std::endl;
359  return 1;
360  };
361  }
362  else
363  {
364  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse canvas size" << std::endl;
365  return 1;
366  };
367  };
368  };
369  break;
370  case SWITCH_CROP:
371  //crop
372  param=optarg;
373  param=hugin_utils::toupper(param);
374  if (param == "AUTO")
375  {
376  doAutocrop = AutoCropMode::AUTO;
377  }
378  else
379  {
380  if (param == "AUTOHDR")
381  {
382  doAutocrop = AutoCropMode::AUTOHDR;
383  }
384  else
385  {
386  if (param == "AUTOOUTSIDE")
387  {
388  doAutocrop = AutoCropMode::AUTOOUTSIDE;
389  }
390  else
391  {
392  const int pos = param.find("%");
393  if (pos != std::string::npos)
394  {
395  // parse relative values
396  param = param.substr(0, pos);
397  double left, right, top, bottom;
398  const int n = sscanf(param.c_str(), "%lf,%lf,%lf,%lf", &left, &right, &top, &bottom);
399  if (n == 4)
400  {
401  if (right > left && bottom > top && left >= 0.0 && top >= 0.0 && right <= 100.0 && bottom <= 100.0)
402  {
403  // check values, 0..100 %
404  newRoiRelativeLeftTop = hugin_utils::FDiff2D(left, top);
405  newRoiRelativeRightBottom = hugin_utils::FDiff2D(right, bottom);
406  }
407  else
408  {
409  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid crop area" << std::endl;
410  return 1;
411  };
412  }
413  else
414  {
415  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse crop values" << std::endl;
416  return 1;
417  };
418  }
419  else
420  {
421  int left, right, top, bottom;
422  int n = sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
423  if (n == 4)
424  {
425  if (right > left && bottom > top && left >= 0 && top >= 0)
426  {
427  newROI.setUpperLeft(vigra::Point2D(left, top));
428  newROI.setLowerRight(vigra::Point2D(right, bottom));
429  }
430  else
431  {
432  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid crop area" << std::endl;
433  return 1;
434  };
435  }
436  else
437  {
438  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse crop values" << std::endl;
439  return 1;
440  };
441  };
442  };
443  };
444  };
445  break;
446  case SWITCH_CROPPED_TIFF:
447  outputCroppedTiff = 1;
448  break;
449  case SWITCH_UNCROPPED_TIFF:
450  outputCroppedTiff = 0;
451  break;
452  case SWITCH_EXPOSURE:
453  param = optarg;
454  param = hugin_utils::toupper(param);
455  if (param == "AUTO")
456  {
457  calcMeanExposure = true;
458  }
459  else
460  {
461  if (!param.empty())
462  {
463  // if first character is r assume relative exposure values
464  relativeExposure = (param[0] == 'R');
465  if (relativeExposure)
466  {
467  param.erase(0, 1);
468  };
469  int n = sscanf(param.c_str(), "%lf", &outputExposure);
470  if (n != 1)
471  {
472  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output exposure value." << std::endl;
473  return 1;
474  };
475  }
476  else
477  {
478  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output exposure value." << std::endl;
479  return 1;
480  };
481  };
482  break;
483  case SWITCH_RANGE_COMPRESSION:
484  if(!hugin_utils::stringToDouble(std::string(optarg), outputRangeCompression))
485  {
486  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse output range compression (" << optarg << ")." << std::endl;
487  return 1;
488  };
489  if (outputRangeCompression < 0.0 || outputRangeCompression > 20.0)
490  {
491  std::cerr << hugin_utils::stripPath(argv[0]) << ": range compression must be a real between 0 and 20." << std::endl;
492  return 1;
493  };
494  break;
495  case SWITCH_OUTPUT_TYPE:
496  if (!outputType.empty())
497  {
498  outputType.append(",");
499  };
500  outputType.append(optarg);
501  break;
502  case SWITCH_BLENDER:
503  blender = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
504  break;
505  case SWITCH_LDRFILETYPE:
506  ldrfiletype = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
507  break;
508  case SWITCH_LDRCOMPRESSION:
509  ldrcompression = hugin_utils::toupper(hugin_utils::StrTrim(optarg));
510  break;
511  case SWITCH_HDRFILETYPE:
512  hdrfiletype = hugin_utils::tolower(hugin_utils::StrTrim(optarg));
513  break;
514  case SWITCH_HDRCOMPRESSION:
515  hdrcompression = hugin_utils::toupper(hugin_utils::StrTrim(optarg));
516  break;
517  case SWITCH_BLENDER_ARGS:
518  blenderArgs = optarg;
519  break;
520  case SWITCH_FUSION_ARGS:
521  fusionArgs = optarg;
522  break;
523  case SWITCH_HDRMERGE_ARGS:
524  hdrMergeArgs = optarg;
525  break;
526  case SWITCH_ROTATE:
527  {
528  int n=sscanf(optarg, "%lf,%lf,%lf", &yaw, &pitch, &roll);
529  if(n!=3)
530  {
531  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse rotate angles values. Given: \"" << optarg << "\"" << std::endl;
532  return 1;
533  };
534  };
535  break;
536  case SWITCH_TRANSLATE:
537  {
538  int n=sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z);
539  if(n!=3)
540  {
541  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse translation values. Given: \"" << optarg << "\"" << std::endl;
542  return 1;
543  };
544  };
545  break;
546  case SWITCH_INTERPOLATION:
547  if (!hugin_utils::stringToInt(optarg, interpolation))
548  {
549  std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse interpolation value. Given: \"" << optarg << "\"" << std::endl;
550  return 1;
551  };
552  if (interpolation<0 || interpolation>vigra_ext::INTERP_SINC_1024)
553  {
554  std::cerr << hugin_utils::stripPath(argv[0]) << ": Interpolator " << interpolation << " is not valid." << std::endl;
555  return 1;
556  }
557  break;
558  case SWITCH_INI_FILE:
559  iniFile = optarg;
560  if (!hugin_utils::FileExists(iniFile))
561  {
562  std::cerr << hugin_utils::stripPath(argv[0]) << ": INI file " << iniFile << " not found." << std::endl;
563  return 1;
564  };
565  break;
566  case SWITCH_TEMPLATE:
567  templateFile = optarg;
568  if (!hugin_utils::FileExists(templateFile))
569  {
570  std::cerr << hugin_utils::stripPath(argv[0]) << ": Template file " << templateFile << " not found." << std::endl;
571  return 1;
572  };
573  break;
574  case ':':
575  case '?':
576  // missing argument or invalid switch
577  return 1;
578  break;
579  default:
580  // this should not happen
581  abort();
582 
583  }
584  }
585 
586  if (argc - optind != 1)
587  {
588  if (argc - optind < 1)
589  {
590  std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
591  }
592  else
593  {
594  std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
595  };
596  return 1;
597  };
598 
599  // set some options which depends on each other
600  if(doStraighten)
601  {
602  doCenter=false;
603  doFit=true;
604  };
605  if(doCenter)
606  {
607  doFit=true;
608  };
609 
610  std::string input=argv[optind];
611  // read panorama
612  HuginBase::Panorama pano;
613  if (!pano.ReadPTOFile(input, hugin_utils::getPathPrefix(input)))
614  {
615  return 1;
616  };
617 
618  // sets the projection
619  if(projection!=-1)
620  {
623  pano_projection_features proj;
624  if (panoProjectionFeaturesQuery(projection, &proj))
625  {
626  std::cout << "Setting projection to " << proj.name << std::endl;
627  }
628  pano.setOptions(opt);
629  };
630  // set projection parameters
631  if (!projParameter.empty())
632  {
634  if (projParameter.size() > opt.m_projFeatures.numberOfParameters)
635  {
636  std::cout << "Warning: Given " << projParameter.size() << " projection parameters, but projection supports" << std::endl
637  << " only " << opt.m_projFeatures.numberOfParameters << ". Ignoring surplus parameters." << std::endl;
638  while (projParameter.size() > opt.m_projFeatures.numberOfParameters)
639  {
640  projParameter.pop_back();
641  }
642  }
643  if (!projParameter.empty())
644  {
645  std::vector<double> newProjParameters = opt.getProjectionParameters();
646  std::copy(projParameter.begin(), projParameter.end(), newProjParameters.begin());
647  opt.setProjectionParameters(newProjParameters);
648  // read back, new the limits have been applied
649  newProjParameters = opt.getProjectionParameters();
650  auto it = newProjParameters.begin();
651  std::cout << "Setting projection parameters to: " << *it;
652  ++it;
653  while (it != newProjParameters.end())
654  {
655  std::cout << ", " << *it;
656  ++it;
657  }
658  std::cout << std::endl;
659  pano.setOptions(opt);
660  }
661  else
662  {
663  std::cout << "Warning: Current projection does not support projection parameters." << std::endl;
664  }
665  }
666  // output exposure value
667  if (outputExposure > -1000 || calcMeanExposure)
668  {
670  if (calcMeanExposure)
671  {
673  }
674  else
675  {
676  if (relativeExposure)
677  {
678  opt.outputExposureValue += outputExposure;
679  }
680  else
681  {
682  opt.outputExposureValue = outputExposure;
683  };
684  };
685  std::cout << "Setting output exposure value to " << opt.outputExposureValue << std::endl;
686  pano.setOptions(opt);
687  };
688  // output range compression
689  if (outputRangeCompression >= 0.0)
690  {
692  opt.outputRangeCompression = outputRangeCompression;
693  std::cout << "Setting output range compression to " << opt.outputRangeCompression << std::endl;
694  pano.setOptions(opt);
695  };
696  // output type: normal, fused, hdr pano..
697  if (!outputType.empty())
698  {
700  // reset all output
701  // final pano
702  opt.outputLDRBlended = false;
703  opt.outputLDRExposureBlended = false;
704  opt.outputLDRExposureLayersFused = false;
705  opt.outputHDRBlended = false;
706  // remapped images
707  opt.outputLDRLayers = false;
708  opt.outputLDRExposureRemapped = false;
709  opt.outputHDRLayers = false;
710  // stacks
711  opt.outputLDRStacks = false;
712  opt.outputHDRStacks = false;
713  // exposure layers
714  opt.outputLDRExposureLayers = false;
715  // now parse string and set corresponding options
716  std::vector<std::string> tokens = hugin_utils::SplitString(outputType, ",");
717  size_t counter = 0;
718  for (size_t i = 0; i < tokens.size(); i++)
719  {
720  std::string s = hugin_utils::toupper(hugin_utils::StrTrim(tokens[i]));
721  if (s == "NORMAL" || s=="N")
722  {
723  opt.outputLDRBlended = true;
724  std::cout << "Activate output of normal panorama." << std::endl;
725  counter++;
726  continue;
727  };
728  if (s == "STACKSFUSEDBLENDED" || s == "FB")
729  {
730  opt.outputLDRExposureBlended = true;
731  std::cout << "Activate output of LDR panorama: Exposure fused from stacks." << std::endl;
732  counter++;
733  continue;
734  };
735  if (s == "EXPOSURELAYERSFUSED" || s == "BF")
736  {
737  opt.outputLDRExposureLayersFused = true;
738  std::cout << "Activate output of LDR panorama: Exposure fused from any arrangement." << std::endl;
739  counter++;
740  continue;
741  };
742  if (s == "HDR")
743  {
744  opt.outputHDRBlended = true;
745  std::cout << "Activate output of hdr panorama." << std::endl;
746  counter++;
747  continue;
748  };
749  // single remapped images
750  if (s == "REMAP")
751  {
752  opt.outputLDRLayers = true;
753  std::cout << "Activate output of remapped, exposure corrected images." << std::endl;
754  counter++;
755  continue;
756  };
757  if (s == "REMAPORIG")
758  {
759  opt.outputLDRExposureRemapped = true;
760  std::cout << "Activate output of remapped images with unmodified exposure." << std::endl;
761  counter++;
762  continue;
763  };
764  if (s == "HDRREMAP")
765  {
766  opt.outputHDRLayers = true;
767  std::cout << "Activate output of remapped hdr images." << std::endl;
768  counter++;
769  continue;
770  };
771  //stacks
772  if (s == "FUSEDSTACKS")
773  {
774  opt.outputLDRStacks = true;
775  std::cout << "Activate output of exposure fused stacks." << std::endl;
776  counter++;
777  continue;
778  };
779  if (s == "HDRSTACKS")
780  {
781  opt.outputHDRStacks = true;
782  std::cout << "Activate output of HDR stacks." << std::endl;
783  counter++;
784  continue;
785  };
786  //exposure layers
787  if (s == "EXPOSURELAYERS")
788  {
789  opt.outputLDRExposureLayers = true;
790  std::cout << "Activate output of exposure layers." << std::endl;
791  counter++;
792  continue;
793  };
794  std::cout << "Unknown parameter \"" << s << "\" found in --output-type." << std::endl
795  << "Ignoring this parameter." << std::endl;
796  }
797  if (counter > 0)
798  {
799  pano.setOptions(opt);
800  }
801  else
802  {
803  std::cout << "No matching output type given. The whole output-type is ignored." << std::endl;
804  };
805  };
806  // cropped or uncropped tiff output
807  if (outputCroppedTiff != -1)
808  {
810  opts.tiff_saveROI = (outputCroppedTiff == 1);
811  std::cout << "Setting support for cropped images: " << ((outputCroppedTiff == 1) ? "yes" : "no") << std::endl;
812  pano.setOptions(opts);
813  }
814  // blender type
815  if (!blender.empty())
816  {
818  if (blender == "enblend")
819  {
821  std::cout << "Setting blender type to \"ENBLEND\"." << std::endl;
822  }
823  else
824  {
825  if (blender == "internal" || blender == "verdandi")
826  {
828  std::cout << "Setting blender type to \"INTERNAL\"." << std::endl;
829  }
830  else
831  {
832  std::cout << "Blender \"" << blender << "\" is not a valid blender ." << std::endl
833  << "Ignoring parameter." << std::endl;
834  };
835  };
836  pano.setOptions(opt);
837  }
838  if (blenderArgs != EMPTYARG)
839  {
841  switch (opt.blendMode)
842  {
844  opt.enblendOptions = blenderArgs;
845  std::cout << "Setting enblend arguments to " << blenderArgs << std::endl;
846  break;
848  opt.verdandiOptions = blenderArgs;
849  std::cout << "Setting verdandi arguments to " << blenderArgs << std::endl;
850  break;
851  default:
852  std::cout << "Unknown blender in pto file." << std::endl;
853  break;
854  };
855  pano.setOptions(opt);
856  };
857  if (fusionArgs != EMPTYARG)
858  {
860  opt.enfuseOptions = fusionArgs;
861  std::cout << "Setting enfuse arguments to " << fusionArgs << std::endl;
862  pano.setOptions(opt);
863  };
864  if (hdrMergeArgs != EMPTYARG)
865  {
867  opt.hdrmergeOptions = hdrMergeArgs;
868  std::cout << "Setting hugin_hdrdmerge arguments to " << hdrMergeArgs << std::endl;
869  pano.setOptions(opt);
870  };
871  // ldr output file type
872  if (!ldrfiletype.empty())
873  {
875  if (ldrfiletype == "jpg" || ldrfiletype == "png" || ldrfiletype == "tif")
876  {
877  opt.outputImageType = ldrfiletype;
878  std::cout << "Setting ldr output to filetype \"" << ldrfiletype << "\"." << std::endl;
879  pano.setOptions(opt);
880  }
881  else
882  {
883  std::cout << "LDR file format \"" << ldrfiletype << "\" is not a valid LDR output filetype." << std::endl
884  << "Ignoring parameter." << std::endl;
885  };
886  };
887  // ldr compression
888  if (!ldrcompression.empty())
889  {
891  if (opt.outputImageType == "tif")
892  {
893  if (ldrcompression == "NONE" || ldrcompression == "PACKBITS" || ldrcompression == "LZW" || ldrcompression == "DEFLATE")
894  {
895  opt.outputImageTypeCompression = ldrcompression;
896  std::cout << "Setting TIF compression to \"" << ldrcompression << "\"." << std::endl;
897  opt.tiffCompression = ldrcompression;
898  }
899  else
900  {
901  std::cout << "LDR compression \"" << ldrcompression << "\" is not a valid compression value for TIF files." << std::endl
902  << "Ignoring compression." << std::endl;
903  }
904  }
905  else
906  {
907  if (opt.outputImageType == "jpg")
908  {
909  int quality = 0;
910  quality = atoi(ldrcompression.c_str());
911  if (quality != 0)
912  {
913  if (quality>0 && quality <=100)
914  {
915  opt.quality = quality;
916  std::cout << "Setting JPEG quality to " << quality << "." << std::endl;
917  }
918  else
919  {
920  std::cout << "Given value for JPEG quality is outside the valid range 1..100." << std::endl
921  << "Ignoring value." << std::endl;
922  };
923  }
924  else
925  {
926  std::cout << "Could not parse \"" << ldrcompression << "\" as a valid JPEG quality number." << std::endl
927  << "Ignoring value." << std::endl;
928  };
929  }
930  else
931  {
932  if (opt.outputImageType == "png")
933  {
934  std::cout << "Setting compression for PNG images is not supported." << std::endl;
935  }
936  else
937  {
938  // this should never happen
939  std::cout << "Unknown image format" << std::endl;
940  };
941  };
942  };
943  pano.setOptions(opt);
944  };
945  // hdr output file type
946  if (!hdrfiletype.empty())
947  {
949  if (hdrfiletype == "exr" || hdrfiletype == "tif")
950  {
951  opt.outputImageTypeHDR = hdrfiletype;
952  std::cout << "Setting hdr output to filetype \"" << hdrfiletype << "\"." << std::endl;
953  pano.setOptions(opt);
954  }
955  else
956  {
957  std::cout << "HDR file format \"" << hdrfiletype << "\" is not a valid HDR output filetype." << std::endl
958  << "Ignoring parameter." << std::endl;
959  };
960  };
961  // hdr compression
962  if (!hdrcompression.empty())
963  {
965  if (opt.outputImageTypeHDR == "tif")
966  {
967  if (hdrcompression == "NONE" || hdrcompression == "PACKBITS" || hdrcompression == "LZW" || hdrcompression == "DEFLATE")
968  {
969  opt.outputImageTypeHDRCompression = hdrcompression;
970  std::cout << "Setting HDR-TIF compression to \"" << hdrcompression << "\"." << std::endl;
971  }
972  else
973  {
974  std::cout << "HDR compression \"" << hdrcompression << "\" is not a valid compression value for TIF files." << std::endl
975  << "Ignoring compression." << std::endl;
976  }
977  }
978  else
979  {
980  if (opt.outputImageTypeHDR == "exr")
981  {
982  std::cout << "Setting compression for EXR images is not supported." << std::endl;
983  }
984  else
985  {
986  // this should never happen
987  std::cout << "Unknown HDR image format" << std::endl;
988  };
989  };
990  pano.setOptions(opt);
991  };
992  // rotate complete pano
993  if (std::abs(yaw) + std::abs(pitch) + std::abs(roll) > 0.0)
994  {
995  std::cout << "Rotate panorama (yaw=" << yaw << ", pitch= " << pitch << ", roll=" << roll << ")" << std::endl;
996  HuginBase::RotatePanorama(pano, yaw, pitch, roll).run();
997  };
998  // translate complete pano
999  if(std::abs(x) + std::abs(y) + std::abs(z) > 0.0)
1000  {
1001  std::cout << "Translate panorama (x=" << x << ", y=" << y << ", z=" << z << ")" << std::endl;
1002  HuginBase::TranslatePanorama(pano, x, y, z).run();
1003  };
1004  // straighten
1005  if(doStraighten)
1006  {
1007  std::cout << "Straighten panorama" << std::endl;
1010  };
1011  // center
1012  if(doCenter)
1013  {
1014  std::cout << "Center panorama" << std::endl;
1016  }
1017  //fit fov
1018  if(doFit)
1019  {
1020  std::cout << "Fit panorama field of view to best size" << std::endl;
1022  HuginBase::CalculateFitPanorama fitPano(pano);
1023  fitPano.run();
1024  opt.setHFOV(fitPano.getResultHorizontalFOV());
1026  std::cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << std::endl;
1027  pano.setOptions(opt);
1028  };
1029  //set field of view manually
1030  if(newHFOV>0)
1031  {
1033  opt.setHFOV(newHFOV);
1034  if(opt.fovCalcSupported(opt.getProjection()) && newVFOV>0)
1035  {
1036  opt.setVFOV(newVFOV);
1037  }
1038  std::cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << std::endl;
1039  pano.setOptions(opt);
1040  };
1041  // calc optimal size
1042  if(doOptimalSize)
1043  {
1044  std::cout << "Calculate optimal size of panorama" << std::endl;
1047  opt.setWidth(hugin_utils::roundi(opt.getWidth()*s*scale/100), true);
1048  std::cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << std::endl;
1049  pano.setOptions(opt);
1050  };
1051  // set canvas size
1052  if(newWidth>0 && newHeight>0)
1053  {
1055  opt.setWidth(newWidth);
1056  opt.setHeight(newHeight);
1057  std::cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << std::endl;
1058  pano.setOptions(opt);
1059  };
1060  // auto crop
1061  if (doAutocrop != AutoCropMode::NONE)
1062  {
1063  std::cout << "Searching for best crop rectangle" << std::endl;
1065  vigra::Rect2D roi;
1066  if (doAutocrop == AutoCropMode::AUTOOUTSIDE)
1067  {
1068  HuginBase::CalculateOptimalROIOutside cropPano(pano, &dummy);
1069  cropPano.run();
1070  roi = cropPano.getResultOptimalROI();
1071  }
1072  else
1073  {
1074  HuginBase::CalculateOptimalROI cropPano(pano, &dummy);
1075  if (doAutocrop == AutoCropMode::AUTOHDR)
1076  {
1077  cropPano.setStacks(getHDRStacks(pano, pano.getActiveImages(), pano.getOptions()));
1078  }
1079  cropPano.run();
1080  roi = cropPano.getResultOptimalROI();
1081  };
1083  //set the ROI - fail if the right/bottom is zero, meaning all zero
1084  if(!roi.isEmpty())
1085  {
1086  opt.setROI(roi);
1087  std::cout << "Set crop size to " << roi.left() << "," << roi.top() << "," << roi.right() << "," << roi.bottom() << std::endl;
1088  pano.setOptions(opt);
1089  }
1090  else
1091  {
1092  std::cout << "Could not find best crop rectangle" << std::endl;
1093  }
1094  };
1095  //setting crop rectangle manually
1096  if(newROI.right() != 0 && newROI.bottom() != 0)
1097  {
1099  opt.setROI(newROI);
1100  std::cout << "Set crop size to " << opt.getROI().left() << "," << opt.getROI().right() << "," << opt.getROI().top() << "," << opt.getROI().bottom() << std::endl;
1101  pano.setOptions(opt);
1102  };
1103  if (newRoiRelativeLeftTop.x > -1 && newRoiRelativeRightBottom.x > -1)
1104  {
1106  opt.setROI(vigra::Rect2D(
1107  opt.getWidth() * newRoiRelativeLeftTop.x / 100.0,
1108  opt.getHeight() * newRoiRelativeLeftTop.y / 100.0,
1109  opt.getWidth() * newRoiRelativeRightBottom.x / 100.0,
1110  opt.getHeight() * newRoiRelativeRightBottom.y / 100.0
1111  ));
1112  std::cout << "Set crop size to " << opt.getROI().left() << "," << opt.getROI().right() << "," << opt.getROI().top() << "," << opt.getROI().bottom() << std::endl;
1113  pano.setOptions(opt);
1114  }
1115  //setting interpolation method
1116  if (interpolation>=0)
1117  {
1119  opt.interpolator = static_cast<vigra_ext::Interpolator>(interpolation);
1120  std::cout << "Set interpolation method to " << interpolation << std::endl;
1121  pano.setOptions(opt);
1122  };
1123  // read settings from ini file and apply it
1124  if (!iniFile.empty())
1125  {
1126  std::cout << "Reading panorama options from " << iniFile << std::endl;
1127  const HuginBase::PanoramaOptions options = ReadPanoramaOptionsFromIni(iniFile, pano);
1128  pano.setOptions(options);
1129  };
1130  // read settings from other pto file and apply only PanoramaOptions
1131  if (!templateFile.empty())
1132  {
1133  // read template panorama
1134  HuginBase::Panorama templatePano;
1135  if (!pano.ReadPTOFile(templateFile, hugin_utils::getPathPrefix(templateFile)))
1136  {
1137  return 1;
1138  };
1139  std::cout << "Applying settings from " << templateFile << std::endl;
1140  pano.setOptions(templatePano.getOptions());
1141  };
1142  //write output
1143  // Set output .pto filename if not given
1144  output = hugin_utils::GetOutputFilename(output, input, "mod");
1145  if (pano.WritePTOFile(output, hugin_utils::getPathPrefix(output)))
1146  {
1147  std::cout << std::endl << "Written output to " << output << std::endl;
1148  };
1149 
1150  return 0;
1151 }
PanoramaOptions::ProjectionFormat getProjection() const
std::vector< UIntSet > getHDRStacks(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output stacks
Definition: LayerStacks.cpp:35
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
Dummy progress display, without output.
declaration of functions to handle stacks and layers
#define EMPTYARG
void setHeight(unsigned int h)
set panorama height
pano_projection_features m_projFeatures
int roundi(T x)
Definition: hugin_math.h:73
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
Definition: utils.cpp:208
static double calcMeanExposure(const PanoramaData &pano)
std::string GetOutputFilename(const std::string &out, const std::string &in, const std::string &suffix)
construct output filename, if ouput is known return this value otherwise use the input filename and a...
Definition: utils.cpp:420
bool outputLDRLayers
save remapped layers (LDR)
bool fovCalcSupported(ProjectionFormat f) const
true, if FOV calcuations are supported for projection f
std::string outputImageTypeHDRCompression
bool outputHDRLayers
save remapped layers (HDR)
unsigned int getHeight() const
get panorama height
HuginBase::PanoramaOptions ReadPanoramaOptionsFromIni(const std::string &iniFile, HuginBase::Panorama &pano)
read settings from given ini file and apply wished settings if they are applicable ...
void setProjectionParameters(const std::vector< double > &params)
set the optional parameters (they need to be of the correct size)
virtual void run()
runs the algorithm.
std::string outputImageTypeCompression
std::string toupper(const std::string &s)
Definition: stl_utils.h:59
bool outputLDRExposureBlended
&lt; save exposure fused stacks (no exposure adjustment)
void setStacks(std::vector< UIntSet > hdr_stacks)
sets the stack vector
const vigra::Rect2D & getROI() const
Model for a panorama.
Definition: Panorama.h:152
bool outputLDRBlended
save blended panorama (LDR)
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
vigra_ext::Interpolator interpolator
static double calcOptimalScale(PanoramaData &panorama)
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...
Definition: Panorama.cpp:2023
virtual vigra::Rect2D getResultOptimalROI()
return the ROI structure?, for now area
virtual double getResultHeight()
Definition: FitPanorama.h:75
bool outputHDRBlended
save blended panorama (HDR)
TDiff2D< double > FDiff2D
Definition: hugin_math.h:150
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
Definition: utils.cpp:264
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
void setROI(const vigra::Rect2D &val)
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
bool outputLDRExposureLayers
save blended exposure layers, do not perform fusion (no exposure adjustment)
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
unsigned int getWidth() const
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
virtual double getResultHorizontalFOV()
Definition: FitPanorama.h:68
virtual vigra::Rect2D getResultOptimalROI()
returns the found crop rect
bool outputLDRExposureRemapped
save remapped layers (no exposure adjustment)
const std::vector< double > & getProjectionParameters() const
Get the optional projection parameters.
bool outputLDRExposureLayersFused
save blended exposure layers which are then fused (no exposure adjustment)
static void usage()
Definition: Main.cpp:32
std::string GetHuginVersion()
return a string with version numbers
Definition: utils.cpp:920
read settings from ini file and apply only applicable values
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
Definition: Panorama.cpp:1531
ProjectionFormat
Projection of final panorama.
Interpolator
enum with all interpolation methods
Definition: Interpolators.h:78
std::vector< std::string > SplitString(const std::string &s, const std::string &sep)
split string s at given sep, returns vector of strings
Definition: utils.cpp:294
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
Panorama image options.
bool outputHDRStacks
save image stacks (HDR)
BlendingMechanism blendMode
std::string tolower(const std::string &s)
convert a string to lowercase
Definition: stl_utils.h:49
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition: utils.cpp:160
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
int main(int argc, char *argv[])
Definition: Main.cpp:167