Hugin trunk 0.1
Loading...
Searching...
No Matches
autooptimiser.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
28#include <hugin_config.h>
29
30#include <fstream>
31#include <sstream>
32#include <getopt.h>
33
34#include <hugin_basic.h>
46#include "ExtractPoints.h"
47
48static void usage(const char* name)
49{
50 std::cout << name << ": optimize image positions" << std::endl
51 << "autooptimiser version " << hugin_utils::GetHuginVersion() << std::endl
52 << std::endl
53 << "Usage: " << name << " [options] input.pto" << std::endl
54 << " To read a project from stdio, specify - as input file." << std::endl
55 << std::endl
56 << " Options:" << std::endl
57 << " -o file.pto output file. If omitted, stdout is used." << std::endl
58 << std::endl
59 << " Optimisation options (if not specified, no optimisation takes place)" << std::endl
60 << " -a auto align mode, includes various optimisation stages, depending" << std::endl
61 << " on the amount and distribution of the control points" << std::endl
62 << " -p pairwise optimisation of yaw, pitch and roll, starting from" << std::endl
63 << " first image" << std::endl
64 << " -m Optimise photometric parameters" << std::endl
65 << " -n Optimize parameters specified in script file (like PTOptimizer)" << std::endl
66 << std::endl
67 << " Postprocessing options:" << std::endl
68 << " -l level horizon (works best for horizontal panos)" << std::endl
69 << " -s automatically select a suitable output projection and size" << std::endl
70 << " Other options:" << std::endl
71 << " -q quiet operation (no progress is reported)" << std::endl
72 << " -v HFOV specify horizontal field of view of input images." << std::endl
73 << " Used if the .pto file contains invalid HFOV values" << std::endl
74 << " (autopano-SIFT writes .pto files with invalid HFOV)" << std::endl
75 << std::endl
76 << " --only-active-images take only active images into account when" << std::endl
77 << " optimising (only valid with -n switch)" << std::endl
78 << std::endl
79 << " When using -a -l -m and -s options together, a similar operation to the" << std::endl
80 << " \"Align\" button in hugin is performed." << std::endl
81 << std::endl;
82}
83
84int main(int argc, char* argv[])
85{
86 // parse arguments
87 const char* optstring = "alho:npqsv:m";
88 int c;
89 enum
90 {
92 };
93 static struct option longOptions[] =
94 {
95 { "output", required_argument, NULL, 'o'},
96 { "help", no_argument, NULL, 'h' },
97 { "only-active-images", no_argument, NULL, SWITCH_ONLY_ACTIVE},
98 0
99 };
100 std::string output;
101 bool doPairwise = false;
102 bool doAutoOpt = false;
103 bool doNormalOpt = false;
104 bool optOnlyActive = false;
105 bool doLevel = false;
106 bool chooseProj = false;
107 bool quiet = false;
108 bool doPhotometric = false;
109 double hfov = 0.0;
110 while ((c = getopt_long(argc, argv, optstring, longOptions, nullptr)) != -1)
111 {
112 switch (c)
113 {
114 case 'o':
115 output = optarg;
116 break;
117 case 'h':
119 return 0;
120 case 'p':
121 doPairwise = true;
122 break;
123 case 'a':
124 doAutoOpt = true;
125 break;
126 case 'n':
127 doNormalOpt = true;
128 break;
129 case 'l':
130 doLevel = true;
131 break;
132 case 's':
133 chooseProj = true;
134 break;
135 case 'q':
136 quiet = true;
137 break;
138 case 'v':
139 hfov = atof(optarg);
140 break;
141 case 'm':
142 doPhotometric = true;
143 break;
145 optOnlyActive = true;
146 break;
147 case ':':
148 case '?':
149 // missing argument or invalid switch
150 return 1;
151 break;
152 default:
153 // this should not happen
154 abort ();
155 }
156 }
157
158 if (argc - optind != 1)
159 {
160 if (argc - optind < 1)
161 {
162 std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
163 }
164 else
165 {
166 std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
167 };
168 return 1;
169 }
170
171 const char* scriptFile = argv[optind];
172
175 {
176 return 1;
177 };
178
179 if (pano.getNrOfImages() == 0)
180 {
181 std::cerr << "Panorama should consist of at least one image" << std::endl;
182 return 1;
183 }
184
185 // for bad HFOV (from autopano-SIFT)
186 for (unsigned i=0; i < pano.getNrOfImages(); i++)
187 {
189 if (img.getProjection() == HuginBase::SrcPanoImage::RECTILINEAR
190 && img.getHFOV() >= 180)
191 {
192 // something is wrong here, try to read from exif data
193 std::cerr << "HFOV of image " << img.getFilename() << " invalid, trying to read EXIF tags" << std::endl;
194 img.readEXIF();
195 bool ok = img.applyEXIFValues(false);
196 if (! ok)
197 {
198 if (hfov)
199 {
200 img.setHFOV(hfov);
201 }
202 else
203 {
204 std::cerr << "EXIF reading failed, please specify HFOV with -v" << std::endl;
205 return 1;
206 }
207 }
208 pano.setSrcImage(i, img);
209 }
210 }
211 // update optimize vector, if switch is set to manual nothing is done
213
214 if(pano.getNrOfCtrlPoints()==0 && (doPairwise || doAutoOpt || doNormalOpt))
215 {
216 std::cerr << "Panorama have to have control points to optimise positions" << std::endl;
217 return 1;
218 };
219 if (doPairwise && ! doAutoOpt)
220 {
221 // do pairwise optimisation
223
224 // do global optimisation
225 if (!quiet)
226 {
227 std::cerr << "*** Pairwise position optimisation" << std::endl;
228 }
230 }
231 else if (doAutoOpt)
232 {
233 if (!quiet)
234 {
235 std::cerr << "*** Adaptive geometric optimisation" << std::endl;
236 }
238 }
239 else if (doNormalOpt)
240 {
241 if (optOnlyActive)
242 {
243 if (!quiet)
244 {
245 std::cerr << "*** Optimising parameters specified in PTO file (active images only)" << std::endl;
246 }
247 //optimise only active images
248 const HuginBase::UIntSet activeImages = pano.getActiveImages();
249 if (activeImages.empty())
250 {
251 std::cerr << "*** Image contains no active images. Nothing to do." << std::endl;
252 }
253 else
254 {
255 HuginBase::Panorama optPano = pano.getSubset(activeImages);
257 // write result back into initial pano
258 pano.updateVariables(activeImages, optPano.getVariables());
259 };
260 }
261 else
262 {
263 // optimise all images, independend of active state of individual images
264 if (!quiet)
265 {
266 std::cerr << "*** Optimising parameters specified in PTO file" << std::endl;
267 }
269 };
270 }
271 else
272 {
273 if (!quiet)
274 {
275 std::cerr << "*** Geometric parameters not optimized" << std::endl;
276 }
277 }
278
279 if (doLevel)
280 {
281 bool hasVerticalLines=false;
283 if(!allCP.empty() && (doPairwise || doAutoOpt || doNormalOpt))
284 {
285 for(size_t i=0; i<allCP.size() && !hasVerticalLines; i++)
286 {
288 };
289 };
290 // straighten only if there are no vertical control points
292 {
293 std::cout << "Skipping automatic leveling because of existing vertical control points." << std::endl;
294 // center pano, ignore step for single image project files or when using rectilinear projection
295 // where vertical control points can be used for correction of perspective
297 {
299 }
300 }
301 else
302 {
305 };
306 }
307
308 if (chooseProj)
309 {
312 fitPano.run();
313 opts.setHFOV(fitPano.getResultHorizontalFOV());
315 const double vfov = opts.getVFOV();
316 const double hfov = opts.getHFOV();
317 // avoid perspective projection if field of view > 100 deg
318 const double mf = 100;
319 bool changedProjection=false;
320 if (pano.getNrOfImages() == 1)
321 {
322 // special case for single image projects
323 switch (pano.getImage(0).getProjection())
324 {
326 // single rectilinear image, keep rectilinear projection
328 {
330 changedProjection = true;
331 };
332 break;
333 default:
334 if (vfov < mf)
335 {
336 // small vfov, use cylindrical
338 {
340 changedProjection = true;
341 };
342 }
343 else
344 {
345 // otherwise go to equirectangular
347 {
349 changedProjection = true;
350 };
351 };
352 break;
353 };
354 }
355 else
356 {
357 if (vfov < mf)
358 {
359 // cylindrical or rectilinear
360 if (hfov < mf)
361 {
363 {
365 changedProjection = true;
366 };
367 }
368 else
369 {
371 {
373 changedProjection = true;
374 };
375 };
376 }
377 else
378 {
379 // vfov > 100, use equirectangular projection
381 {
383 changedProjection = true;
384 };
385 };
386 };
387 pano.setOptions(opts);
388 // the projection could be changed, calculate fit again
390 {
392 fitPano2.run();
393 opts.setHFOV(fitPano2.getResultHorizontalFOV());
394 opts.setHeight(hugin_utils::roundi(fitPano2.getResultHeight()));
395 pano.setOptions(opts);
396 };
397
398 // downscale pano a little
399 const double sizeFactor = 0.7;
402 pano.setOptions(opts);
403 }
404
405 if(doPhotometric)
406 {
407 // photometric estimation
409 int nPoints = 200;
410 nPoints = nPoints * pano.getNrOfImages();
411
412 std::vector<vigra_ext::PointPairRGB> points;
414 if(!quiet)
415 {
417 }
418 else
419 {
421 }
422 float imageStepSize;
423 try
424 {
426 }
427 catch (std::exception& e)
428 {
429 std::cerr << "caught exception: " << e.what() << std::endl;
430 return 1;
431 };
432 if(!quiet)
433 {
434 std::cout << "\rSelected " << points.size() << " points" << std::endl;
435 }
436
437 if (points.empty())
438 {
439 std::cerr << "Error: no overlapping points found, exiting" << std::endl;
440 return 1;
441 }
442
443 progressDisplay->setMessage("Photometric Optimization");
444 // first, ensure that vignetting and response coefficients are linked
446 {
447 HuginBase::ImageVariableGroup::IVE_EMoRParams,
448 HuginBase::ImageVariableGroup::IVE_ResponseType,
449 HuginBase::ImageVariableGroup::IVE_VigCorrMode,
450 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
451 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
452 };
455 for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
456 {
457 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
458 links_needed.clear();
459 for (int v = 0; v < 5; v++)
460 {
461 if (!lenses.getVarLinkedInPart(vars[v], i))
462 {
463 links_needed.insert(vars[v]);
464 }
465 };
466 if (!links_needed.empty())
467 {
468 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum>::iterator it;
469 for (it = links_needed.begin(); it != links_needed.end(); ++it)
470 {
472 }
473 }
474 }
475
478 if (opts.outputMode == HuginBase::PanoramaOptions::OUTPUT_HDR || variable_groups.getStacks().getNumberOfParts() < pano.getNrOfImages())
479 {
480 // use HDR algorithm is HDR mode is selected or the project contains stacks
482 }
484 photoOpt.run();
485
486 // calculate the mean exposure.
488 pano.setOptions(opts);
489 progressDisplay->taskFinished();
490 delete progressDisplay;
491 };
492
493 // write result
496 {
497 std::cout << "Written output to " << output << std::endl;
498 };
499 return 0;
500}
helper procedure for photometric optimizer on command line
void loadImgsAndExtractPoints(HuginBase::Panorama pano, int nPoints, int pyrLevel, bool randomPoints, AppBase::ProgressDisplay &progress, std::vector< vigra_ext::PointPairRGB > &points, int verbose, float &imageStepSize)
Declare the ImageVariableGroup and ImageVariableGroupObserver classes.
static void usage()
Definition Main.cpp:32
!! from PTOptimise.h 1951
Somewhere to specify what variables belong to what.
int main(int argc, char *argv[])
Dummy progress display, without output.
a progress display to print progress reports to a stream
static void autoOptimise(PanoramaData &pano, bool optRoll=true)
virtual double getResultHorizontalFOV()
Definition FitPanorama.h:68
virtual double getResultHeight()
Definition FitPanorama.h:75
static double calcMeanExposure(const PanoramaData &pano)
static double calcOptimalScale(PanoramaData &panorama)
@ X
evaluate x, points are on a vertical line
Same as above, but use a non const panorama.
void linkVariablePart(ImageVariableEnum variable, unsigned int partNr)
link one of the variables across a given part
virtual void run()
runs the algorithm.
Panorama image options.
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void setHeight(unsigned int h)
set panorama height
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
unsigned int getWidth() const
PanoramaOptions::ProjectionFormat getProjection() const
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
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...
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
std::size_t getNrOfCtrlPoints() const
number of control points
Definition Panorama.h:306
void updateOptimizeVector()
updates the optimize vector according to master switches
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition Panorama.h:319
virtual void updateVariables(const VariableMapVector &vars)
Set the variables.
Definition Panorama.cpp:171
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition Panorama.h:454
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
static void smartOptimize(PanoramaData &pano)
PhotometricOptimizeMode
local optimize definition.
All variables of a source image.
bool applyEXIFValues(bool applyEVValue=true)
apply values found in EXIF data to SrcPanoImage class, call readEXIF() before to initialize some valu...
bool readEXIF()
try to fill out information about the image, by examining the exif data
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
std::vector< ControlPoint > CPVector
std::set< unsigned int > UIntSet
int roundi(T x)
Definition hugin_math.h:73
std::string GetHuginVersion()
return a string with version numbers
Definition utils.cpp:907
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
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition utils.cpp:160
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition utils.cpp:184
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41