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