Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panorama.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
26 #include "Panorama.h"
27 
28 #include "PTScriptParsing.h"
29 #include "ImageVariableTranslate.h"
35 
36 #include <fstream>
37 #include <typeinfo>
38 
39 namespace HuginBase {
40 
41 Panorama::Panorama() : dirty(false), m_forceImagesUpdate(false)
42 {
43  // init map with ptoptimizer variables.
44  m_ptoptimizerVarNames.insert("a");
45  m_ptoptimizerVarNames.insert("b");
46  m_ptoptimizerVarNames.insert("c");
47  m_ptoptimizerVarNames.insert("d");
48  m_ptoptimizerVarNames.insert("e");
49  m_ptoptimizerVarNames.insert("g");
50  m_ptoptimizerVarNames.insert("t");
51  m_ptoptimizerVarNames.insert("v");
52  m_ptoptimizerVarNames.insert("r");
53  m_ptoptimizerVarNames.insert("p");
54  m_ptoptimizerVarNames.insert("y");
55  m_ptoptimizerVarNames.insert("TrX");
56  m_ptoptimizerVarNames.insert("TrY");
57  m_ptoptimizerVarNames.insert("TrZ");
58  m_ptoptimizerVarNames.insert("Tpy");
59  m_ptoptimizerVarNames.insert("Tpp");
60 }
61 
63 {
64  DEBUG_TRACE("dtor");
65  reset();
66  DEBUG_TRACE("dtor about to finish");
67 }
68 
70 {
71  // delete all images and control points.
72  state.ctrlPoints.clear();
75  state.optvec.clear();
76  state.optSwitch=0;
78  state.needsOptimization = false;
80  dirty=false;
81 }
82 
83 std::vector<unsigned int> Panorama::getCtrlPointsForImage(unsigned int imgNr) const
84 {
85  std::vector<unsigned int> result;
86  unsigned int i = 0;
87  for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
88  if ((it->image1Nr == imgNr) || (it->image2Nr == imgNr)) {
89  result.push_back(i);
90  }
91  i++;
92  }
93  return result;
94 }
95 
97 {
98  CPointVector result;
99  for(unsigned int i=0;i<state.ctrlPoints.size();i++)
100  {
101  ControlPoint point=state.ctrlPoints[i];
102  if(point.image1Nr==imgNr)
103  {
104  result.push_back(std::make_pair(i,point));
105  }
106  else
107  {
108  if(point.image2Nr==imgNr)
109  {
110  point.mirror();
111  result.push_back(std::make_pair(i,point));
112  };
113  };
114  };
115  return result;
116 };
117 
119 {
120  VariableMapVector map;
121  for (size_t i = 0; i < state.images.size(); i++)
122  {
123  map.push_back(state.images[i]->getVariableMap());
124  }
125  return map;
126 }
127 
128 const VariableMap Panorama::getImageVariables(unsigned int imgNr) const
129 {
130  assert(imgNr < state.images.size());
131  return state.images[imgNr]->getVariableMap();
132 }
133 
134 
135 void Panorama::updateCtrlPointErrors(const UIntSet & imgs, const CPVector & cps)
136 {
137  unsigned sc = 0;
138  unsigned ic = 0;
139  std::map<unsigned int, unsigned int> script2CPMap;
140  for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
141  if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
142  script2CPMap[sc] = ic;
143  sc++;
144  }
145  ic++;
146  }
147 
148  // need to have same number of control points!
149  assert(cps.size() == script2CPMap.size());
150  unsigned i=0;
151  for (CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it) {
152  imageChanged(script2CPMap[it->image1Nr]);
153  imageChanged(script2CPMap[it->image2Nr]);
154  state.ctrlPoints[script2CPMap[i]].error = it->error;
155  i++;
156  }
157 }
158 
159 
161 {
162  assert(cps.size() == state.ctrlPoints.size());
163  unsigned int nrp = cps.size();
164  for (unsigned int i = 0; i < nrp ; i++) {
165  imageChanged(state.ctrlPoints[i].image1Nr);
166  imageChanged(state.ctrlPoints[i].image2Nr);
167  state.ctrlPoints[i].error = cps[i].error;
168  }
169 }
170 
172 {
173  assert(vars.size() == state.images.size());
174  unsigned int i = 0;
175  for (VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it) {
176  updateVariables(i, *it);
177  i++;
178  }
179 }
180 
181 void Panorama::updateVariables(const UIntSet & imgs, const VariableMapVector & vars)
182 {
183  VariableMapVector::const_iterator v_it = vars.begin();
184  for (UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it) {
185  assert(*it < state.images.size());
186  updateVariables(*it, *v_it);
187  ++v_it;
188  }
189 }
190 
191 void Panorama::updateVariables(unsigned int imgNr, const VariableMap & var)
192 {
193  if (imgNr > state.images.size())
194  return;
195  for (VariableMap::const_iterator it = var.begin(); it != var.end() ; ++it) {
196  updateVariable(imgNr,it->second);
197  }
198 }
199 
200 void Panorama::updateVariable(unsigned int imgNr, const Variable &var)
201 {
202  if (imgNr > state.images.size())
203  return;
204  // update a single variable, and everything linked to it.
205  state.images[imgNr]->setVar(var.getName(), var.getValue());
206  // call imageChanged for the images affected by this.
207 #define image_variable( name, type, default_value ) \
208  if (PTOVariableConverterFor##name::checkApplicability(var.getName())) \
209  {\
210  for (std::size_t i = 0; i < getNrOfImages(); i++)\
211  {\
212  if (state.images[imgNr]->name##isLinkedWith(*state.images[i]))\
213  {\
214  imageChanged(i);\
215  }\
216  }\
217  }\
218  else
219 #include "image_variables.h"
220 #undef image_variable
221  {// this is for the final else.
222  DEBUG_ERROR("Unknown variable " << var.getName());
223  }
224  state.needsOptimization = true;
225 }
226 
227 void Panorama::UpdateFocalLength(UIntSet imgs, double newFocalLength)
228 {
229  for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();++it)
230  {
231  state.images[*it]->updateFocalLength(newFocalLength);
232  imageChanged(*it);
233  };
234  //search for images with linked HFOV and mark these also as changed
235  for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();++it)
236  {
237  SrcPanoImage *img=state.images[*it];
238  if(state.images[*it]->HFOVisLinked())
239  {
240  for(unsigned int j=0;j<getNrOfImages();j++)
241  {
242  if(*it!=j)
243  {
244  if(state.images[*it]->HFOVisLinkedWith(*img))
245  {
246  imageChanged(j);
247  };
248  };
249  };
250  };
251  };
252 };
253 
254 void Panorama::UpdateCropFactor(UIntSet imgs, double newCropFactor)
255 {
256  //store list of focal length, so we can keep the focal length unchanged and change hfov instead
257  std::vector<double> focalLengthVector(getNrOfImages(),0.0);
258  for(unsigned i=0;i<getNrOfImages();i++)
259  {
260  focalLengthVector[i]=state.images[i]->calcFocalLength(state.images[i]->getProjection(),
261  state.images[i]->getHFOV(),state.images[i]->getCropFactor(),state.images[i]->getSize());
262  };
263  for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();++it)
264  {
265  state.images[*it]->updateCropFactor(focalLengthVector[*it],newCropFactor);
266  imageChanged(*it);
267  };
268 };
269 
270 // What counts as changed in terms of the image variable links?
271 // Should I call imageChanged on every image linked to sourceImg and destImg?
272 // destImg's variable will change value to sourceImg's, so the images linked to
273 // destImg should be linked.
275 #define image_variable( name, type, default_value )\
276 void Panorama::linkImageVariable##name(unsigned int sourceImgNr, unsigned int destImgNr)\
277 {\
278  state.images[destImgNr]->link##name(state.images[sourceImgNr]);\
279  imageChanged(destImgNr);\
280  imageChanged(sourceImgNr);\
281  state.needsOptimization = true;\
282 }
283 #include "image_variables.h"
284 #undef image_variable
285 
287 #define image_variable( name, type, default_value )\
288 void Panorama::unlinkImageVariable##name(unsigned int imgNr)\
289 {\
290  state.images[imgNr]->unlink##name();\
291  imageChanged(imgNr);\
292  state.needsOptimization = true;\
293 }
294 #include "image_variables.h"
295 #undef image_variable
296 
298 {
299  DEBUG_ASSERT(optvec.size() == state.images.size());
300  state.optvec = optvec;
301 }
302 
303 void Panorama::setOptimizerSwitch(const int newSwitch)
304 {
305  if(state.optSwitch!=newSwitch)
306  {
307  state.optSwitch=newSwitch;
308  };
309 };
310 
312 {
313  if(state.optPhotoSwitch!=newSwitch)
314  {
315  state.optPhotoSwitch=newSwitch;
316  };
317 };
318 
319 unsigned int Panorama::addImage(const SrcPanoImage &img)
320 {
321  unsigned int nr = state.images.size();
322  state.images.push_back(new SrcPanoImage(img));
323  // create empty optimisation vector
324  state.optvec.push_back(std::set<std::string>());
325  imageChanged(nr);
326  return nr;
327 }
328 
329 void Panorama::removeImage(unsigned int imgNr)
330 {
331  DEBUG_DEBUG("Panorama::removeImage(" << imgNr << ")");
332  assert(imgNr < state.images.size());
333 
334  // remove control points
335  CPVector::iterator it = state.ctrlPoints.begin();
336  while (it != state.ctrlPoints.end()) {
337  if ((it->image1Nr == imgNr) || (it->image2Nr == imgNr)) {
338  // remove point that refernce to imgNr
339  it = state.ctrlPoints.erase(it);
340  } else {
341  // correct point references
342  if (it->image1Nr > imgNr) it->image1Nr--;
343  if (it->image2Nr > imgNr) it->image2Nr--;
344  ++it;
345  }
346  }
347 
348  DEBUG_TRACE("Remove variables and image from panorama state")
349  delete state.images[imgNr];
350  state.images.erase(state.images.begin() + imgNr);
351  state.optvec.erase(state.optvec.begin() + imgNr);
352 
353  // check if reference image has been moved
357  }
358 
359  if (state.options.colorReferenceImage >= state.images.size()) {
362  }
363 
364  // change all other (moved) images
365  DEBUG_TRACE("flag moved images as dirty");
366  for (unsigned int i=imgNr; i < state.images.size(); i++) {
367  imageChanged(i);
368  }
369  m_forceImagesUpdate = true;
370 }
371 
372 
373 void Panorama::setImageFilename(unsigned int i, const std::string & fname)
374 {
375  DEBUG_ASSERT(i < state.images.size());
376  state.images[i]->setFilename(fname);
377  imageChanged(i);
378  m_forceImagesUpdate = true;
379 }
380 
381 unsigned int Panorama::addCtrlPoint(const ControlPoint & point )
382 {
383  unsigned int nr = state.ctrlPoints.size();
384  state.ctrlPoints.push_back(point);
385  imageChanged(point.image1Nr);
386  imageChanged(point.image2Nr);
387  state.needsOptimization = true;
388  return nr;
389 }
390 
391 void Panorama::removeCtrlPoint(unsigned int pNr)
392 {
393  DEBUG_ASSERT(pNr < state.ctrlPoints.size());
394  ControlPoint & point = state.ctrlPoints[pNr];
395  unsigned int i1 = point.image1Nr;
396  unsigned int i2 = point.image2Nr;
397  state.ctrlPoints.erase(state.ctrlPoints.begin() + pNr);
398 
399  // update line control points
401  imageChanged(i1);
402  imageChanged(i2);
403  state.needsOptimization = true;
404 }
405 
407 {
408  std::set<std::string> listOfCPs;
409  std::set<unsigned int> duplicateCPs;
410  for(unsigned int i=0; i<state.ctrlPoints.size();i++)
411  {
412  std::string s=state.ctrlPoints[i].getCPString();
413  std::pair<std::set<std::string>::iterator,bool> it=listOfCPs.insert(s);
414  if(it.second==false)
415  {
416  duplicateCPs.insert(i);
417  };
418  }
419  //now remove duplicate control points, mark affected images as changed
420  if(!duplicateCPs.empty())
421  {
422  for(std::set<unsigned int>::reverse_iterator it=duplicateCPs.rbegin();it!=duplicateCPs.rend();++it)
423  {
424  ControlPoint cp=state.ctrlPoints[*it];
427  removeCtrlPoint(*it);
428  };
429  };
431 }
432 
433 
434 void Panorama::changeControlPoint(unsigned int pNr, const ControlPoint & point)
435 {
436  assert(pNr < state.ctrlPoints.size());
437 
438  // change notify for all involved images
439  imageChanged(state.ctrlPoints[pNr].image1Nr);
440  imageChanged(state.ctrlPoints[pNr].image2Nr);
441  imageChanged(point.image1Nr);
442  imageChanged(point.image2Nr);
443  state.needsOptimization = true;
444 
445  state.ctrlPoints[pNr] = point;
447 }
448 
449 void Panorama::setCtrlPoints(const CPVector & points)
450 {
451  for (CPVector::const_iterator it = state.ctrlPoints.begin();
452  it != state.ctrlPoints.end(); ++it)
453  {
454  imageChanged(it->image1Nr);
455  imageChanged(it->image2Nr);
456  }
457 
458  state.ctrlPoints = points;
459 
460  for (CPVector::const_iterator it = state.ctrlPoints.begin();
461  it != state.ctrlPoints.end(); ++it)
462  {
463  imageChanged(it->image1Nr);
464  imageChanged(it->image2Nr);
465  }
466  state.needsOptimization = true;
468 }
469 
470 // close holes in line control points
472 {
473  // sort all line control points
474  std::map<int, int> lines;
475  for (CPVector::const_iterator it = state.ctrlPoints.begin();
476  it != state.ctrlPoints.end(); ++it)
477  {
478  if (it->mode > 2)
479  lines[it->mode] = 0;
480  }
481  int i=3;
482  for (std::map<int,int >::iterator it = lines.begin(); it != lines.end(); ++it)
483  {
484  (*it).second = i;
485  i++;
486  }
487 
488  for (CPVector::iterator it = state.ctrlPoints.begin();
489  it != state.ctrlPoints.end(); ++it)
490  {
491  if (it->mode > 2) {
492  int newmode = lines[it->mode];
493  if (it->mode != newmode) {
494  it->mode = newmode;
495  imageChanged(it->image1Nr);
496  imageChanged(it->image2Nr);
497  }
498  }
499  }
500 }
501 
502 
503 void Panorama::printPanoramaScript(std::ostream & o,
504  const OptimizeVector & optvars,
505  const PanoramaOptions & output,
506  const UIntSet & imgs,
507  bool forPTOptimizer,
508  const std::string & stripPrefix) const
509 {
510  // set numeric locale to C, for correct number output
511  char * old_locale = strdup(setlocale(LC_NUMERIC, NULL));
512  setlocale(LC_NUMERIC,"C");
513 
514  if (forPTOptimizer) {
515  o << "# PTOptimizer script, written by hugin" << std::endl
516  << std::endl;
517  } else {
518  o << "# hugin project file" << std::endl;
519  o << "#hugin_ptoversion 2" << std::endl;
520  }
521  // output options..
522 
523  output.printScriptLine(o, forPTOptimizer);
524 
525  // map from script img nr -> pano image nr
526  std::map<unsigned int, unsigned int> imageNrMap;
527  o << std::endl
528  << "# image lines" << std::endl;
529 
530  // somewhere to store the v lines, which give the variables to be optimised.
531  std::stringstream vlines;
532  std::stringstream masklines;
533  unsigned int ic = 0;
534  for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end();
535  ++imgNrIt)
536  {
537  unsigned int imgNr = *imgNrIt;
538  imageNrMap[imgNr] = ic;
539  const SrcPanoImage & img = *state.images[imgNr];
540  VariableMap vars;
541 
542  // print special comment line with hugin GUI data
543  o << "#-hugin ";
544  if (img.getCropMode() != BaseSrcPanoImage::NO_CROP) {
545  if (img.getAutoCenterCrop())
546  o << " autoCenterCrop=1";
547  }
548  o << " cropFactor=" << img.getCropFactor() ;
549  if (! img.getActive()) {
550  o << " disabled";
551  }
552  o << std::endl;
553 
554  o << "i w" << img.getSize().width() << " h" << img.getSize().height()
555  <<" f" << img.getProjection() << " ";
556 
557  // print variables with links
558 /* Individually do all the variables specified by each SrcPanoImg variable.
559  * Clear the list after each SrcPanoImg variable.
560  * If there is any links to previous images, write that in the script.
561  * If there are no links to previous images, write the value instead.
562  * Each variable in SrcPanoImg may produce any number of variables in the map,
563  * but the linking properties are shared.
564  * Additionally, when we are writing variables by value which are set to be
565  * optimised, we should remember them so we can write them later as 'v' lines.
566  */
567 #define image_variable( name, type, default_value )\
568  PTOVariableConverterFor##name::addToVariableMap(state.images[imgNr]->get##name##IV(), vars);\
569  if (!vars.empty())\
570  {\
571  bool linking = false;\
572  std::size_t link_target;\
573  if (ic!=0)\
574  {\
575  if (state.images[imgNr]->name##isLinked())\
576  {\
577  for (link_target = 0; link_target < imgNr; link_target++)\
578  {\
579  if (set_contains(imgs,link_target) && state.images[imgNr]->name##isLinkedWith(*state.images[link_target]))\
580  {\
581  linking = true;\
582  break;\
583  }\
584  }\
585  }\
586  }\
587  for (VariableMap::const_iterator vit = vars.begin();\
588  vit != vars.end(); ++vit)\
589  {\
590  if (forPTOptimizer && !set_contains(m_ptoptimizerVarNames,vit->first))\
591  continue;\
592  else if (linking)\
593  {\
594  o << vit->first << "=" << imageNrMap[link_target] << " ";\
595  } else {\
596  if (set_contains(optvars[imgNr], vit->first))\
597  {\
598  vlines << "v " << vit->first << imageNrMap[imgNr] << std::endl;\
599  }\
600  if (((vit->first == "a" && set_contains(optvars[imgNr], "a") )|| \
601  (vit->first == "b" && set_contains(optvars[imgNr], "b") )|| \
602  (vit->first == "c" && set_contains(optvars[imgNr], "c") )|| \
603  (vit->first == "TrX" && set_contains(optvars[imgNr], "TrX") )|| \
604  (vit->first == "TrY" && set_contains(optvars[imgNr], "TrY") )|| \
605  (vit->first == "TrZ" && set_contains(optvars[imgNr], "TrZ") )\
606  )\
607  && forPTOptimizer && vit->second.getValue() == 0.0) \
608  {\
609  o << vit->first << 1e-5 << " ";\
610  } else if (( (vit->first == "r" && set_contains(optvars[imgNr], "r") ) || \
611  (vit->first == "p" && set_contains(optvars[imgNr], "p") ) || \
612  (vit->first == "y" && set_contains(optvars[imgNr], "y") ) \
613  )\
614  && forPTOptimizer && fabs(vit->second.getValue()) < 1e-13)\
615  {\
616  o << vit->first << 0 << " ";\
617  } else {\
618  vit->second.print(o) << " ";\
619  }\
620  }\
621  }\
622  }\
623  vars.clear();
624 #include "image_variables.h"
625 #undef image_variable
626 
627  if (img.getCropMode()!=SrcPanoImage::NO_CROP) {
628  // print crop parameters
629  vigra::Rect2D c = img.getCropRect();
630  o << " S" << c.left() << "," << c.right() << "," << c.top() << "," << c.bottom();
631  }
632 
633  if (!forPTOptimizer) {
634 
635  if (img.getVigCorrMode() != SrcPanoImage::VIGCORR_NONE) {
636  o << " Vm" << img.getVigCorrMode();
637  }
638 
639  if (!img.getFlatfieldFilename().empty()) {
640  o << " Vf\"" << img.getFlatfieldFilename() << "\"";
641  }
642  if (img.getResponseType() > 0) {
643  o << " Rt" << img.getResponseType();
644  }
645 
646  if(img.hasMasks())
647  img.printMaskLines(masklines,ic);
648  }
649 
650 #if 0
651 //panotools paramters, currently not used
652  o << " u" << output.featherWidth
653  << (img.getMorph() ? " o" : "");
654 #endif
655  std::string fname = img.getFilename();
656  if (!stripPrefix.empty()) {
657  // strip prefix from image names.
658  // check if the prefix is acutally the same
659  std::string tmp = fname.substr(0,stripPrefix.size());
660  if (tmp.compare(stripPrefix) == 0) {
661  DEBUG_DEBUG("striping " << stripPrefix << " from " << fname);
662  fname = fname.erase(0,stripPrefix.size());
663  DEBUG_DEBUG("after stripping: " << fname);
664  } else {
665  DEBUG_DEBUG(stripPrefix << " does not match " << fname);
666  }
667  }
668  o << " n\"" << fname << "\"" << std::endl;
669  ic++;
670  }
671 
672  o << std::endl << std::endl
673  << "# specify variables that should be optimized" << std::endl
674  << vlines.str()
675  << "v" << std::endl; // empty v line to work around libpano13 bug.
676 
677  o << std::endl << std::endl
678  << "# control points" << std::endl;
679  for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
680  if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
681  o << "c n" << imageNrMap[it->image1Nr]
682  << " N" << imageNrMap[it->image2Nr]
683  << " x" << it->x1 << " y" << it->y1
684  << " X" << it->x2 << " Y" << it->y2
685  << " t" << it->mode << std::endl;
686  }
687  }
688  o << std::endl;
689 
690  if(masklines.str().length()>0)
691  o << "# masks" << std::endl
692  << masklines.str()
693  << std::endl;
694 
695  // special line with hugins options.
696  o << "#hugin_optimizeReferenceImage " << output.optimizeReferenceImage << std::endl;
697  o << "#hugin_blender ";
698  switch (output.blendMode) {
700  o << "none" << endl;
701  break;
703  o << "PTblender" << endl;
704  break;
706  o << "smartblend" << endl;
707  break;
709  o << "PTmasker" << endl;
710  break;
712  o << "internal" << endl;
713  break;
714  default:
716  o << "enblend" << endl;
717  break;
718  }
719 
720  o << "#hugin_remapper ";
721  switch (output.remapper) {
723  o << "PTmender" << endl;
724  break;
725  default:
727  o << "nona" << endl;
728  break;
729  }
730 
731  o << "#hugin_enblendOptions " << output.enblendOptions << endl;
732  o << "#hugin_enfuseOptions " << output.enfuseOptions << endl;
733  o << "#hugin_hdrmergeOptions " << output.hdrmergeOptions << endl;
734  o << "#hugin_verdandiOptions " << output.verdandiOptions << endl;
735  o << "#hugin_edgeFillMode " << static_cast<int>(output.edgeFillMode) << endl;
736  o << "#hugin_edgeFillKeepInput " << (output.keepEdgeFillInput ? "true" : "false") << endl;
737 
738  o << "#hugin_outputLDRBlended " << (output.outputLDRBlended ? "true" : "false") << endl;
739  o << "#hugin_outputLDRLayers " << (output.outputLDRLayers ? "true" : "false") << endl;
740  o << "#hugin_outputLDRExposureRemapped " << (output.outputLDRExposureRemapped ? "true" : "false") << endl;
741  o << "#hugin_outputLDRExposureLayers " << (output.outputLDRExposureLayers ? "true" : "false") << endl;
742  o << "#hugin_outputLDRExposureBlended " << (output.outputLDRExposureBlended ? "true" : "false") << endl;
743  o << "#hugin_outputLDRStacks " << (output.outputLDRStacks ? "true" : "false") << endl;
744  o << "#hugin_outputLDRExposureLayersFused " << (output.outputLDRExposureLayersFused ? "true" : "false") << endl;
745  o << "#hugin_outputHDRBlended " << (output.outputHDRBlended ? "true" : "false") << endl;
746  o << "#hugin_outputHDRLayers " << (output.outputHDRLayers ? "true" : "false") << endl;
747  o << "#hugin_outputHDRStacks " << (output.outputHDRStacks ? "true" : "false") << endl;
748 
749  o << "#hugin_outputLayersCompression " << output.outputLayersCompression << endl;
750  o << "#hugin_outputImageType " << output.outputImageType << endl;
751  o << "#hugin_outputImageTypeCompression " << output.outputImageTypeCompression << endl;
752  o << "#hugin_outputJPEGQuality " << output.quality << endl;
753  o << "#hugin_outputImageTypeHDR " << output.outputImageTypeHDR << endl;
754  o << "#hugin_outputImageTypeHDRCompression " << output.outputImageTypeHDRCompression << endl;
755 
756  o << "#hugin_outputStacksMinOverlap " << std::setprecision(3) << output.outputStacksMinOverlap << endl;
757  o << "#hugin_outputLayersExposureDiff " << std::setprecision(2) << output.outputLayersExposureDiff << endl;
758 
759  o << "#hugin_outputRangeCompression " << std::setprecision(2) << output.outputRangeCompression << endl;
760 
761  if(optvars==getOptimizeVector())
762  {
763  o << "#hugin_optimizerMasterSwitch " << getOptimizerSwitch() << endl;
764  o << "#hugin_optimizerPhotoMasterSwitch " << getPhotometricOptimizerSwitch() << endl;
765  }
766  else
767  {
768  o << "#hugin_optimizerMasterSwitch 0" << endl;
769  o << "#hugin_optimizerPhotoMasterSwitch 0" << endl;
770  };
771 
772  // reset locale
773  setlocale(LC_NUMERIC,old_locale);
774  free(old_locale);
775 }
776 
777 
778 void Panorama::printStitcherScript(std::ostream & o,
779  const PanoramaOptions & target,
780  const UIntSet & imgs) const
781 {
782  // set numeric locale to C, for correct number output
783  char * old_locale = strdup(setlocale(LC_NUMERIC, NULL));
784  setlocale(LC_NUMERIC,"C");
785 
786  o << "# PTStitcher script, written by hugin" << std::endl
787  << std::endl;
788  // output options..
789  target.printScriptLine(o, true);
790  o << std::endl
791  << "# output image lines" << std::endl;
792  for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end(); ++imgNrIt) {
793  unsigned int imgNr = *imgNrIt;
794  const SrcPanoImage & img = *state.images[imgNr];
795 // DGSW FIXME - Unreferenced
796 // const Lens & lens = state.lenses[lensNr];
797  const VariableMap & vars = state.images[imgNr]->getVariableMap();
798 
799  o << "o w" << img.getSize().width() << " h" << img.getSize().height()
800  <<" f" << img.getProjection() << " ";
801  // print variables, without links
802  VariableMap::const_iterator vit;
803  for(vit = vars.begin(); vit != vars.end(); ++vit)
804  {
805  if (!set_contains(m_ptoptimizerVarNames,vit->first)) {
806  continue;
807  }
808  vit->second.print(o) << " ";
809  }
810 #if 0
811 // panotools parameters, currently not used
812  o << " u" << img.getFeatureWidth()
813  << (img.getMorph() ? " o" : "");
814 #endif
815  o << " n\"" << img.getFilename() << "\"";
816  if (img.getCropMode()!=SrcPanoImage::NO_CROP) {
817  // print crop parameters
818  vigra::Rect2D c = img.getCropRect();
819  o << " S" << c.left() << "," << c.right() << "," << c.top() << "," << c.bottom();
820  }
821  o << std::endl;
822  }
823  o << std::endl;
824 
825  // reset locale
826  setlocale(LC_NUMERIC,old_locale);
827  free(old_locale);
828 
829 }
830 
831 void Panorama::changeFinished(bool keepDirty)
832 {
833  if (state.images.empty()) {
834  // force an empty update if all images have been
835  // removed
836  DEBUG_DEBUG("forcing images update, with no images");
837  m_forceImagesUpdate = true;
838  }
839  // remove change notification for nonexisting images from set.
840  UIntSet::iterator uB = changedImages.lower_bound(state.images.size());
841  changedImages.erase(uB,changedImages.end());
842 
843  std::stringstream t;
844  copy(changedImages.begin(), changedImages.end(),
845  std::ostream_iterator<unsigned int>(t, " "));
846  DEBUG_TRACE("changed image(s) " << t.str() << " begin");
847  //force update of crops
848  if(!changedImages.empty())
849  {
850  for(UIntSet::iterator it=changedImages.begin();it!=changedImages.end();++it)
851  {
852  //if the projection was changed, we need to update the crop mode
853  updateCropMode(*it);
854  //now center the crop if user requested it
855  if(state.images[*it]->getAutoCenterCrop())
856  {
857  centerCrop(*it);
858  };
859  };
860  };
861  //update masks
862  updateMasks();
864  std::list<PanoramaObserver *>::iterator it;
865  for(it = observers.begin(); it != observers.end(); ++it) {
866  DEBUG_TRACE("notifying listener");
867  if (!changedImages.empty() || m_forceImagesUpdate) {
868  (*it)->panoramaImagesChanged(*this, changedImages);
869  }
870  (*it)->panoramaChanged(*this);
871  }
872  // reset changed images
873  changedImages.clear();
874  m_forceImagesUpdate = false;
875  if (!keepDirty) {
876  dirty = true;
878  }
879  DEBUG_TRACE("end");
880 }
881 
882 void Panorama::updateMasksForImage(unsigned int imgNr, MaskPolygonVector newMasks)
883 {
884  DEBUG_ASSERT(imgNr < state.images.size());
885  state.images[imgNr]->setMasks(newMasks);
886  imageChanged(imgNr);
887  m_forceImagesUpdate = true;
888 };
889 
890 void Panorama::transferMask(MaskPolygon mask,unsigned int imgNr, const UIntSet& targetImgs)
891 {
892  if(targetImgs.empty())
893  {
894  return;
895  };
896  MaskPolygon transformedMask=mask;
897  // clip positive mask to image boundaries or clip region
898  vigra::Rect2D clipRect=vigra::Rect2D(0,0,state.images[imgNr]->getWidth(),state.images[imgNr]->getHeight());
899  if(mask.isPositive())
900  {
901  //clip to crop region only positive masks
902  switch(state.images[imgNr]->getCropMode())
903  {
905  clipRect=clipRect & state.images[imgNr]->getCropRect();
906  if(clipRect.isEmpty())
907  {
908  return;
909  };
910  if(clipRect.width()>10 && clipRect.height()>10)
911  {
912  clipRect.addBorder(-2);
913  };
914  break;
916  {
917  vigra::Rect2D cropRect=state.images[imgNr]->getCropRect();
918  hugin_utils::FDiff2D center((cropRect.left()+cropRect.right())/2.0,(cropRect.top()+cropRect.bottom())/2.0);
919  double radius=((cropRect.width()<cropRect.height())?cropRect.width():cropRect.height())/2.0;
920  if(radius>10)
921  {
922  radius-=2;
923  };
924  if(!transformedMask.clipPolygon(center,radius))
925  {
926  return;
927  };
928  };
929  break;
930  default:
931  if(clipRect.width()>10 && clipRect.height()>10)
932  {
933  clipRect.addBorder(-2);
934  };
935  break;
936  };
937  };
938  int origWindingNumber=transformedMask.getTotalWindingNumber();
939  if(transformedMask.clipPolygon(clipRect))
940  {
941  //increase resolution of positive mask to get better transformation
942  //of vertices, especially for fisheye images
943  transformedMask.subSample(20);
944  //transform polygon to panorama space
946  trans.createInvTransform(getImage(imgNr),getOptions());
947  transformedMask.transformPolygon(trans);
948  for(UIntSet::const_iterator it=targetImgs.begin();it!=targetImgs.end();++it)
949  {
950  if(imgNr==(*it))
951  {
952  continue;
953  };
954  MaskPolygon targetMask;
955  if(state.images[imgNr]->YawisLinkedWith(*(state.images[*it])))
956  {
957  //if yaw is linked, we simply copy the mask
958  targetMask=mask;
959  }
960  else
961  {
962  targetMask=transformedMask;
963  PTools::Transform targetTrans;
964  targetTrans.createTransform(getImage(*it),getOptions());
965  targetMask.transformPolygon(targetTrans);
966  //check if transformation has produced invalid polygon
967  if(targetMask.getMaskPolygon().size()<3)
968  {
969  continue;
970  };
971  //check if mask was inverted - outside became inside and vice versa
972  //if so, invert mask
973  int newWindingNumber=targetMask.getTotalWindingNumber();
974  targetMask.setInverted(origWindingNumber * newWindingNumber < 0);
975  };
976  //now clip polygon to image rectangle, add mask only when polygon is inside image
977  if(targetMask.clipPolygon(vigra::Rect2D(-maskOffset,-maskOffset,
978  state.images[*it]->getWidth()+maskOffset,state.images[*it]->getHeight()+maskOffset)))
979  {
981  targetMask.setImgNr(*it);
982  state.images[*it]->addActiveMask(targetMask);
983  };
984  };
985  };
986 };
987 
988 void Panorama::updateMasks(bool convertPosMaskToNeg)
989 {
990  // update masks
991  UIntSet imgWithPosMasks;
992  for(unsigned int i=0;i<state.images.size();i++)
993  {
994  state.images[i]->clearActiveMasks();
995  if(state.images[i]->hasPositiveMasks())
996  {
997  imgWithPosMasks.insert(i);
998  };
999  };
1000  CalculateImageOverlap overlap(this);
1001  overlap.limitToImages(imgWithPosMasks);
1002  overlap.calculate(10);
1003  ConstStandardImageVariableGroups variable_groups(*this);
1004  ConstImageVariableGroup & lenses = variable_groups.getLenses();
1005  for(unsigned int i=0;i<state.images.size();i++)
1006  {
1007  if(state.images[i]->hasMasks())
1008  {
1009  MaskPolygonVector masks=state.images[i]->getMasks();
1010  for(unsigned int j=0;j<masks.size();j++)
1011  {
1012  if(convertPosMaskToNeg)
1013  {
1014  //this is used for masking in the cp finder, we are consider
1015  //all masks as negative masks, because at this moment
1016  //the final position of the images is not known
1017  switch(masks[j].getMaskType())
1018  {
1021  masks[j].setImgNr(i);
1022  masks[j].setMaskType(MaskPolygon::Mask_negative);
1023  state.images[i]->addActiveMask(masks[j]);
1024  break;
1027  {
1028  //copy mask to all images of the same stack
1029  UIntSet imgStack;
1030  for(unsigned int k=0;k<getNrOfImages();k++)
1031  {
1032  if(i!=k)
1033  {
1034  if(state.images[i]->StackisLinkedWith(*(state.images[k])))
1035  {
1036  imgStack.insert(k);
1037  };
1038  };
1039  };
1040  masks[j].setImgNr(i);
1041  masks[j].setMaskType(MaskPolygon::Mask_negative);
1042  state.images[i]->addActiveMask(masks[j]);
1043  transferMask(masks[j],i,imgStack);
1044  };
1045  break;
1047  {
1048  unsigned int lensNr=lenses.getPartNumber(i);
1049  //copy masks to all image of the same lens
1050  for(unsigned int k=0;k<getNrOfImages();k++)
1051  {
1052  if(lenses.getPartNumber(k)==lensNr)
1053  {
1054  masks[j].setImgNr(k);
1055  masks[j].setMaskType(MaskPolygon::Mask_negative_lens);
1056  state.images[k]->addActiveMask(masks[j]);
1057  };
1058  };
1059  };
1060  break;
1061  };
1062  }
1063  else
1064  {
1065  switch(masks[j].getMaskType())
1066  {
1068  //negative mask, simply copy mask to active mask
1069  masks[j].setImgNr(i);
1070  state.images[i]->addActiveMask(masks[j]);
1071  break;
1073  //propagate positive mask only if image is active
1074  if(state.images[i]->getActive())
1075  {
1076  UIntSet overlapImgs=overlap.getOverlapForImage(i);
1077  transferMask(masks[j],i,overlapImgs);
1078  };
1079  break;
1081  {
1082  //search all images of the stack
1083  UIntSet imgStack;
1084  for(unsigned int k=0;k<getNrOfImages();k++)
1085  {
1086  if(i!=k)
1087  {
1088  if(state.images[i]->StackisLinkedWith(*(state.images[k])))
1089  {
1090  imgStack.insert(k);
1091  };
1092  };
1093  };
1094  //copy mask also to the image which contains the mask
1095  masks[j].setImgNr(i);
1096  masks[j].setMaskType(MaskPolygon::Mask_negative);
1097  state.images[i]->addActiveMask(masks[j]);
1098  transferMask(masks[j],i,imgStack);
1099  };
1100  break;
1102  {
1103  //remove all images from the stack from the set
1104  UIntSet imgStack;
1105  fill_set(imgStack,0,getNrOfImages()-1);
1106  imgStack.erase(i);
1107  for(unsigned int k=0;k<getNrOfImages();k++)
1108  {
1109  if(i!=k)
1110  {
1111  if(state.images[i]->StackisLinkedWith(*(state.images[k])))
1112  {
1113  imgStack.erase(k);
1114  };
1115  };
1116  };
1117  //only leave overlapping images in set
1118  UIntSet imgOverlap=overlap.getOverlapForImage(i);
1119  UIntSet imgs;
1120  std::set_intersection(imgStack.begin(),imgStack.end(),imgOverlap.begin(),imgOverlap.end(),inserter(imgs,imgs.begin()));
1121  //now transfer mask
1122  transferMask(masks[j],i,imgs);
1123  };
1124  break;
1126  {
1127  unsigned int lensNr=lenses.getPartNumber(i);
1128  //copy masks to all image of the same lens
1129  for(unsigned int k=0;k<getNrOfImages();k++)
1130  {
1131  if(lenses.getPartNumber(k)==lensNr)
1132  {
1133  masks[j].setImgNr(k);
1134  masks[j].setMaskType(MaskPolygon::Mask_negative_lens);
1135  state.images[k]->addActiveMask(masks[j]);
1136  };
1137  };
1138  };
1139  break;
1140  };
1141  };
1142  };
1143  };
1144  };
1145 };
1146 
1147 void Panorama::updateCropMode(unsigned int imgNr)
1148 {
1149  vigra::Rect2D r=state.images[imgNr]->getCropRect();
1150  if(r.isEmpty() || r==vigra::Rect2D(state.images[imgNr]->getSize()))
1151  {
1152  state.images[imgNr]->setCropMode(SrcPanoImage::NO_CROP);
1153  }
1154  else
1155  {
1156  if (state.images[imgNr]->isCircularCrop())
1157  {
1158  state.images[imgNr]->setCropMode(SrcPanoImage::CROP_CIRCLE);
1159  }
1160  else
1161  {
1162  state.images[imgNr]->setCropMode(SrcPanoImage::CROP_RECTANGLE);
1163  };
1164  };
1165 };
1166 
1167 vigra::Rect2D Panorama::centerCropImage(unsigned int imgNr)
1168 {
1169  vigra::Rect2D cropRect;
1170  if(state.images[imgNr]->getCropMode()==SrcPanoImage::NO_CROP)
1171  {
1172  return cropRect;
1173  };
1174  int dx = hugin_utils::roundi(state.images[imgNr]->getRadialDistortionCenterShift().x);
1175  int dy = hugin_utils::roundi(state.images[imgNr]->getRadialDistortionCenterShift().y);
1176  vigra::Point2D center = vigra::Point2D(state.images[imgNr]->getSize().width()/2 + dx, state.images[imgNr]->getSize().height()/2 + dy);
1177 
1178  vigra::Diff2D d(state.images[imgNr]->getCropRect().width() / 2, state.images[imgNr]->getCropRect().height() / 2);
1179  cropRect.setUpperLeft( center - d);
1180  cropRect.setLowerRight( center + d);
1181  return cropRect;
1182 };
1183 
1184 void Panorama::centerCrop(unsigned int imgNr)
1185 {
1186  vigra::Rect2D cropRect;
1187  if( state.images[imgNr]->getCropMode()!=SrcPanoImage::NO_CROP &&
1188  state.images[imgNr]->getAutoCenterCrop() &&
1189  !(state.images[imgNr]->getCropRect().isEmpty())
1190  )
1191  {
1192  cropRect=centerCropImage(imgNr);
1193  if(!cropRect.isEmpty())
1194  {
1195  state.images[imgNr]->setCropRect(cropRect);
1196  imageChanged(imgNr);
1197  };
1198  };
1199  for (std::size_t i = 0; i < getNrOfImages(); i++)
1200  {
1201  if(i==imgNr)
1202  {
1203  continue;
1204  };
1205  if (state.images[imgNr]->RadialDistortionCenterShiftisLinkedWith(*state.images[i]))
1206  {
1207  if( state.images[i]->getCropMode()!=SrcPanoImage::NO_CROP &&
1208  state.images[i]->getAutoCenterCrop() &&
1209  !(state.images[i]->getCropRect().isEmpty())
1210  )
1211  {
1212  cropRect=centerCropImage(i);
1213  if(!cropRect.isEmpty())
1214  {
1215  state.images[i]->setCropRect(cropRect);
1216  imageChanged(i);
1217  };
1218  };
1219  };
1220  };
1221 };
1222 
1223 void UpdateOptVectorSet(std::set<std::string>& imgVar, const std::string& var, const bool opt)
1224 {
1225  if(opt)
1226  {
1227  imgVar.insert(var);
1228  }
1229  else
1230  {
1231  imgVar.erase(var);
1232  };
1233 };
1234 
1235 std::set<size_t> Panorama::getRefImages()
1236 {
1237  unsigned int refImg = getOptions().optimizeReferenceImage;
1238  std::set<size_t> refImgs;
1239  refImgs.insert(refImg);
1240  const HuginBase::SrcPanoImage & refImage = getImage(refImg);
1241  for (size_t imgNr = 0; imgNr < getNrOfImages(); imgNr++)
1242  {
1243  if(imgNr!=refImg)
1244  {
1245  const HuginBase::SrcPanoImage & compImage = getImage(imgNr);
1246  if (refImage.YawisLinkedWith(compImage))
1247  {
1248  refImgs.insert(imgNr);
1249  };
1250  };
1251  };
1252  return refImgs;
1253 };
1254 
1255 void Panorama::checkRefOptStatus(bool& linkRefImgsYaw, bool& linkRefImgsPitch, bool& linkRefImgsRoll)
1256 {
1257  // count number of vertical/horizontal control points
1258  int nHCP = 0;
1259  int nVCP = 0;
1260  const CPVector & cps = getCtrlPoints();
1261  for (CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
1262  {
1263  // control points
1264  if (it->mode == ControlPoint::X)
1265  {
1266  nVCP++;
1267  }
1268  else
1269  {
1270  if (it->mode == ControlPoint::Y)
1271  {
1272  nHCP++;
1273  }
1274  };
1275  };
1276 
1277  // try to select sensible position optimisation parameters,
1278  // dependent on output projection
1279  linkRefImgsYaw=false;
1280  linkRefImgsPitch=false;
1281  linkRefImgsRoll=false;
1282  switch (getOptions().getProjection())
1283  {
1285  linkRefImgsRoll = nVCP + nHCP >= 1;
1286  linkRefImgsYaw = nVCP + nHCP >= 3 && nVCP >= 1 && nHCP >= 1;
1287  linkRefImgsPitch = nVCP + nHCP >= 2;
1288  break;
1291  linkRefImgsPitch = nHCP + nVCP > 1;
1292  linkRefImgsRoll = nHCP + nVCP >= 1;
1293  break;
1294  default:
1295  break;
1296  };
1297 };
1298 
1300 {
1301  if(state.images.empty())
1302  {
1303  return;
1304  };
1305  if(state.optSwitch!=0)
1306  {
1307  std::set<size_t> refImgs=getRefImages();
1308  bool linkRefImgsYaw=false;
1309  bool linkRefImgsPitch=false;
1310  bool linkRefImgsRoll=false;
1311  checkRefOptStatus(linkRefImgsYaw, linkRefImgsPitch, linkRefImgsRoll);
1312 
1313  for(size_t i=0;i<getNrOfImages();i++)
1314  {
1316  {
1317  if(set_contains(refImgs,i))
1318  {
1319  UpdateOptVectorSet(state.optvec[i],"y",linkRefImgsYaw);
1320  UpdateOptVectorSet(state.optvec[i],"p",linkRefImgsPitch);
1321  UpdateOptVectorSet(state.optvec[i],"r",linkRefImgsRoll);
1322  //don't optimize translation parameters of anchor
1323  UpdateOptVectorSet(state.optvec[i],"TrX",false);
1324  UpdateOptVectorSet(state.optvec[i],"TrY",false);
1325  UpdateOptVectorSet(state.optvec[i],"TrZ",false);
1326  }
1327  else
1328  {
1329  UpdateOptVectorSet(state.optvec[i],"y",true);
1330  UpdateOptVectorSet(state.optvec[i],"p",true);
1331  UpdateOptVectorSet(state.optvec[i],"r",true);
1335  };
1336  }
1337  else
1338  {
1339  UpdateOptVectorSet(state.optvec[i],"y",false);
1340  UpdateOptVectorSet(state.optvec[i],"p",false);
1341  UpdateOptVectorSet(state.optvec[i],"r",false);
1342  UpdateOptVectorSet(state.optvec[i],"Trx",false);
1343  UpdateOptVectorSet(state.optvec[i],"Try",false);
1344  UpdateOptVectorSet(state.optvec[i],"Trz",false);
1345  };
1352  //shear and translation plane not include in master switches
1353  UpdateOptVectorSet(state.optvec[i],"g",false);
1354  UpdateOptVectorSet(state.optvec[i],"t",false);
1355  UpdateOptVectorSet(state.optvec[i],"Tpy", false);
1356  UpdateOptVectorSet(state.optvec[i],"Tpp", false);
1357  };
1358  };
1359  if(state.optPhotoSwitch!=0)
1360  {
1361  for(size_t i=0;i<getNrOfImages();i++)
1362  {
1376  };
1377  };
1378 };
1379 
1380 void Panorama::swapImages(unsigned int img1, unsigned int img2)
1381 {
1382  DEBUG_TRACE("swapping images " << img1 << ", " << img2);
1383  DEBUG_ASSERT(img1 < state.images.size());
1384  DEBUG_ASSERT(img2 < state.images.size());
1385 
1386  // first, swap image pointers in the list.
1387  SrcPanoImage * pimg1 = state.images[img1];
1388  state.images[img1] = state.images[img2];
1389  state.images[img2] = pimg1;
1390 
1391  // update control points
1392  for (CPVector::iterator it=state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
1393  int n1 = (*it).image1Nr;
1394  int n2 = (*it).image2Nr;
1395  if ((*it).image1Nr == img1) {
1396  n1 = img2;
1397  } else if ((*it).image1Nr == img2) {
1398  n1 = img1;
1399  }
1400  if ((*it).image2Nr == img1) {
1401  n2 = img2;
1402  } else if ((*it).image2Nr == img2) {
1403  n2 = img1;
1404  }
1405  (*it).image1Nr = n1;
1406  (*it).image2Nr = n2;
1407  }
1408 
1409  // update panorama options
1410  if (state.options.colorReferenceImage == img1) {
1412  } else if (state.options.colorReferenceImage == img2) {
1414  }
1415  if (state.options.optimizeReferenceImage == img1) {
1417  } else if (state.options.optimizeReferenceImage == img2) {
1419  }
1420  imageChanged(img1);
1421  imageChanged(img2);
1422 }
1423 
1424 void Panorama::moveImage(size_t img1, size_t img2)
1425 {
1426  //generate a vector with the translated image numbers
1427  std::vector<size_t> imgList(getNrOfImages(),-1);
1428  for(size_t i=0; i<getNrOfImages(); i++)
1429  {
1430  imgList[i]=i;
1431  };
1432  imgList.erase(imgList.begin()+img1);
1433  if(img2<imgList.size())
1434  {
1435  imgList.insert(imgList.begin()+img2, img1);
1436  }
1437  else
1438  {
1439  imgList.push_back(img1);
1440  };
1441  //generate map for translation of old -> new image numbers
1442  std::map<size_t,size_t> imgMap;
1443  for(size_t i=0; i<imgList.size(); i++)
1444  {
1445  imgMap[imgList[i]]=i;
1446  };
1447  // now generate the new images list
1448  std::vector<SrcPanoImage *> new_images(getNrOfImages());
1449  for(size_t i=0; i<imgList.size(); i++)
1450  {
1451  new_images[i]=state.images[imgList[i]];
1452  if(i!=imgList[i])
1453  {
1454  imageChanged(imgList[i]);
1455  };
1456  };
1457  state.images=new_images;
1458 
1459  // update optimize vector
1460  OptimizeVector newOptVec;
1461  for(size_t i=0; i<state.optvec.size(); i++)
1462  {
1463  newOptVec.push_back(state.optvec[imgList[i]]);
1464  };
1465  state.optvec=newOptVec;
1466 
1467  // update control points
1468  for (CPVector::iterator it=state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it)
1469  {
1470  (*it).image1Nr = imgMap[(*it).image1Nr];
1471  (*it).image2Nr = imgMap[(*it).image2Nr];
1472  // mirror points if first image number is higher than second
1473  if ((*it).image1Nr > (*it).image2Nr)
1474  {
1475  (*it).mirror();
1476  };
1477  }
1478 
1479  // update panorama options
1482 };
1483 
1485 {
1486  if(memento==NULL)
1487  return false;
1488 
1489  const PanoramaMemento* mymemento;
1490 
1491  try {
1492 
1493  mymemento = dynamic_cast<const PanoramaMemento*>(memento);
1494 
1495  } catch (std::bad_cast&) {
1496 // std::cerr << "Incompatible memento type." << std::endl;
1497  DEBUG_DEBUG("Incompatible memento type.");
1498  return false;
1499  }
1500 
1501  setMemento(PanoramaMemento(*mymemento));
1502  return true;
1503 }
1504 
1505 
1508 {
1509  DEBUG_TRACE("");
1510 
1511  // remove old content.
1512  reset();
1513  DEBUG_DEBUG("nr of images in memento:" << memento.images.size());
1514 
1515  state = memento;
1516  updateMasks();
1517  unsigned int nNewImages = state.images.size();
1518  DEBUG_DEBUG("nNewImages:" << nNewImages);
1519 
1520  // send changes for all images
1521  for (unsigned int i = 0; i < nNewImages; i++) {
1522  imageChanged(i);
1523  }
1524 }
1525 
1527 {
1528  return new PanoramaMemento(getMemento());
1529 }
1530 
1532 {
1536  }
1537 
1541  }
1542 
1543  state.options = opt;
1544 }
1545 
1547 {
1548  observers.push_back(o);
1549 }
1550 
1552 {
1553  size_t oldCount=observers.size();
1554  observers.remove(o);
1555  return observers.size()!=oldCount;
1556 }
1557 
1559 {
1560  observers.clear();
1561 }
1562 
1564 {
1565  return !changedImages.empty();
1566 }
1567 
1568 void Panorama::imageChanged(unsigned int imgNr)
1569 {
1570 // DEBUG_TRACE("adding image " << imgNr);
1571  changedImages.insert(imgNr);
1572  assert(changedImages.find(imgNr) != changedImages.end());
1573 }
1574 
1575 void Panorama::activateImage(unsigned int imgNr, bool active)
1576 {
1577  assert(imgNr < state.images.size());
1578  if (state.images[imgNr]->getActive() != active)
1579  {
1580  state.images[imgNr]->setActive(active);
1581  imageChanged(imgNr);
1582  }
1583 }
1584 
1586 {
1587  UIntSet activeImgs;
1588 
1589  for (unsigned int i = 0; i < state.images.size(); i++) {
1590  if (state.images[i]->getActive())
1591  {
1592  activeImgs.insert(i);
1593  }
1594  }
1595  return activeImgs;
1596 }
1597 
1598 const std::string Panorama::getICCProfileDesc() const
1599 {
1600  return state.iccProfileDesc;
1601 };
1602 
1603 void Panorama::setICCProfileDesc(const std::string& newDesc)
1604 {
1605  state.iccProfileDesc = newDesc;
1606 };
1607 
1608 const int Panorama::getNrOfBands() const
1609 {
1610  return state.bands;
1611 };
1612 
1613 void Panorama::setNrOfBands(const int nrBands)
1614 {
1615  state.bands = nrBands;
1616 };
1617 
1618 //==== internal function for variable management
1619 
1621 {
1622  DEBUG_ASSERT(imgNr < state.images.size());
1623  return *state.images[imgNr];
1624 }
1625 
1626 void Panorama::setSrcImage(unsigned int imgNr, const SrcPanoImage & img)
1627 {
1628  DEBUG_ASSERT(imgNr < state.images.size());
1629 
1630  /* Copy the variables. We don't assign directly so we can do the changes to
1631  * any linked variables.
1632  */
1633  SrcPanoImage *dest = state.images[imgNr];
1634  #define image_variable( name, type, default_value ) \
1635  dest->set##name (img.get##name());
1636  #include "image_variables.h"
1637  #undef image_variable
1638 
1639  // mark the potentially changed images.
1640 #define image_variable( name, type, default_value ) \
1641  for (std::size_t i = 0; i < getNrOfImages(); i++)\
1642  {\
1643  if(state.images[imgNr]->name##isLinkedWith(*state.images[i]))\
1644  {\
1645  imageChanged(i);\
1646  }\
1647  }
1648 #include "image_variables.h"
1649 #undef image_variable
1650 }
1651 
1652 
1654 {
1655  Panorama pano(*this);
1656  pano.observers.clear();
1657  return pano;
1658 }
1659 
1660 Panorama Panorama::getSubset(const UIntSet & imgs) const
1661 {
1662  Panorama subset;
1663  // copy data except for listners
1664 
1665  // bits that don't change in the subset.
1666  subset.imgFilePrefix = imgFilePrefix;
1667  subset.dirty = dirty;
1668  subset.state.options = state.options;
1669  subset.state.optSwitch=0;
1670  subset.state.optPhotoSwitch=0;
1672  subset.changedImages = changedImages;
1675 
1676  // check optimizer vector and update if necessary
1677  // optvec contains only the variables for the first image,
1678  // but if the first image is not in the subset then the variables is missing also for the next image
1679  // which can be in optvec
1680  OptimizeVector internalOptvec=state.optvec;
1681  UIntSet unusedImgs;
1682  {
1683  UIntSet allImgs;
1684  fill_set(allImgs, 0, getNrOfImages() - 1);
1685  std::set_difference(allImgs.begin(), allImgs.end(), imgs.begin(), imgs.end(), std::inserter(unusedImgs, unusedImgs.end()));
1686  };
1687  if (!unusedImgs.empty())
1688  {
1689  for (auto& i : unusedImgs)
1690  {
1691  for (auto& var : state.optvec[i])
1692  {
1693  for (auto& j : imgs)
1694  {
1695 #define image_variable(name, type, default_value)\
1696  if (PTOVariableConverterFor##name::checkApplicability(var))\
1697  {\
1698  if (state.images[i]->name##isLinkedWith(*state.images[j]))\
1699  {\
1700  internalOptvec[j].insert(var);\
1701  break;\
1702  }\
1703  }
1704 #include "image_variables.h"
1705 #undef image_variable
1706  };
1707  };
1708  };
1709  };
1710 
1711  // create image number map.
1712  std::map<unsigned int, unsigned int> imageNrMap;
1713 
1714  // copy image information
1715  unsigned int ic = 0;
1716  for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end();
1717  ++imgNrIt)
1718  {
1719  subset.state.images.push_back(new SrcPanoImage(*state.images[*imgNrIt]));
1720  subset.state.optvec.push_back(internalOptvec[*imgNrIt]);
1721  imageNrMap[*imgNrIt] = ic;
1722  ic++;
1723  }
1724 
1725  // recreate links between image variables.
1726  ic = 0;
1727  for (UIntSet::const_iterator i = imgs.begin(); i != imgs.end(); ++i)
1728  {
1729  unsigned int jc = ic + 1;
1730  UIntSet::const_iterator j = i;
1731  for (++j; j != imgs.end(); ++j)
1732  {
1737 #define image_variable( name, type, default_value )\
1738  if (state.images[*i]->name##isLinkedWith(*state.images[*j]))\
1739  {\
1740  subset.state.images[ic]->link##name(subset.state.images[jc]);\
1741  }
1742 #include "image_variables.h"
1743 #undef image_variable
1744  jc++;
1745  }
1746  ic++;
1747  }
1748 
1749  // select and translate control points.
1750  subset.state.ctrlPoints.clear();
1751  for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
1752  if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
1753  ControlPoint pnt = *it;
1754  pnt.image1Nr = imageNrMap[pnt.image1Nr];
1755  pnt.image2Nr = imageNrMap[pnt.image2Nr];
1756  subset.state.ctrlPoints.push_back(pnt);
1757  }
1758  }
1759 
1760  //update optimizeReferenceImage and colorReferenceImage number
1761  unsigned int newRefImg=0;
1762  std::map<unsigned int, unsigned int>::iterator it=imageNrMap.find(state.options.optimizeReferenceImage);
1763  if(it!=imageNrMap.end())
1764  {
1765  newRefImg=it->second;
1766  };
1767  it=imageNrMap.find(state.options.colorReferenceImage);
1768  subset.state.options.optimizeReferenceImage=newRefImg;
1769  newRefImg=0;
1770  if(it!=imageNrMap.end())
1771  {
1772  newRefImg=it->second;
1773  }
1774  subset.state.options.colorReferenceImage=newRefImg;
1775  return subset;
1776 }
1777 
1778 int FindStackNumberForImage(const std::vector<UIntSet>& imageGroups, const unsigned int imgNr)
1779 {
1780  for (size_t i = 0; i < imageGroups.size(); ++i)
1781  {
1782  if (set_contains(imageGroups[i], imgNr))
1783  {
1784  return i;
1785  };
1786  };
1787  return -1;
1788 };
1789 
1791 {
1792  const CPVector cps = getCtrlPoints();
1793  CPVector newCP;
1794 
1795  // remove all connected images, keep only a single image for each connected stack
1796  imageGroups.clear();
1797  std::vector<bool> visitedImages(getNrOfImages(), false);
1798  for (size_t i = 0; i < getNrOfImages(); ++i)
1799  {
1800  if (visitedImages[i])
1801  {
1802  continue;
1803  };
1804  const SrcPanoImage& img1 = getImage(i);
1805  UIntSet imgs;
1806  imgs.insert(i);
1807  visitedImages[i] = true;
1808  if (img1.YawisLinked())
1809  {
1810  for (size_t j = i + 1; j < getNrOfImages(); ++j)
1811  {
1812  if (img1.YawisLinkedWith(getImage(j)))
1813  {
1814  imgs.insert(j);
1815  visitedImages[j] = true;
1816  }
1817  }
1818  };
1819  imageGroups.push_back(imgs);
1820  };
1821  UIntSet singleStackImgs;
1822  for (size_t i = 0; i < imageGroups.size(); ++i)
1823  {
1824  singleStackImgs.insert(*imageGroups[i].begin());
1825  };
1826  // new generate subpano
1827  PanoramaData* subPano = getNewSubset(singleStackImgs);
1828  // translate now reference image
1829  int newRefImage = FindStackNumberForImage(imageGroups, getOptions().optimizeReferenceImage);
1830  if (newRefImage != -1)
1831  {
1832  PanoramaOptions opts = subPano->getOptions();
1833  opts.optimizeReferenceImage = newRefImage;
1834  subPano->setOptions(opts);
1835  };
1836  // remove all vertical and horizontal cp, also remap all cps to new subpano
1837  // all cps from removed images will be mapped to first image of corresponding stack
1838  for (CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
1839  {
1840  if (it->mode == ControlPoint::X_Y)
1841  {
1842  ControlPoint cp(*it);
1843  int newImg1 = FindStackNumberForImage(imageGroups, cp.image1Nr);
1844  int newImg2 = FindStackNumberForImage(imageGroups, cp.image2Nr);
1845  if (newImg1 != -1 && newImg2 != -1 && newImg1 != newImg2)
1846  {
1847  cp.image1Nr = newImg1;
1848  cp.image2Nr = newImg2;
1849  newCP.push_back(cp);
1850  };
1851  };
1852  };
1853  subPano->setCtrlPoints(newCP);
1854  return subPano;
1855 }
1856 
1857 void Panorama::mergePanorama(const Panorama &newPano)
1858 {
1859  if(newPano.getNrOfImages()>0)
1860  {
1861  std::vector<unsigned int> new_image_nr(newPano.getNrOfImages());
1863  HuginBase::OptimizeVector optVecNew=newPano.getOptimizeVector();
1864  const size_t oldImgNumber = getNrOfImages();
1865  HuginBase::UIntSet imgsAlreadyInPano;
1866  HuginBase::UIntSet imgsCheckLens;
1867  //add only new images
1868  for(unsigned int i=0;i<newPano.getNrOfImages();i++)
1869  {
1870  std::string filename=newPano.getImage(i).getFilename();
1871  bool found=false;
1872  for(unsigned int j=0;j<getNrOfImages();j++)
1873  {
1874  if(getImage(j).getFilename()==filename)
1875  {
1876  //image is already in panorama, we remember the image nr
1877  found=true;
1878  new_image_nr[i]=j;
1879  imgsAlreadyInPano.insert(i);
1880  // now check if we have to update the masks
1881  HuginBase::MaskPolygonVector masksOld=getImage(j).getMasks();
1882  HuginBase::MaskPolygonVector masksNew=newPano.getImage(i).getMasks();
1883  if(!masksNew.empty())
1884  {
1885  for(unsigned int k=0;k<masksNew.size();k++)
1886  {
1887  bool usedMasks=false;
1888  unsigned int l=0;
1889  while((!usedMasks) && l<masksOld.size())
1890  {
1891  usedMasks=(masksNew[k]==masksOld[l]);
1892  l++;
1893  };
1894  if(!usedMasks)
1895  masksOld.push_back(masksNew[k]);
1896  };
1897  updateMasksForImage(j,masksOld);
1898  };
1899  break;
1900  };
1901  };
1902  if(!found)
1903  {
1904  //new image found, read EXIF data and add it
1905  SrcPanoImage newImg(newPano.getImage(i));
1906  newImg.readEXIF();
1907  new_image_nr[i]=addImage(newImg);
1908  imgsCheckLens.insert(i);
1909  //copy also optimise vector
1910  optVec.push_back(optVecNew[i]);
1911  };
1912  };
1913  setOptimizeVector(optVec);
1914  // check and create lens for new added images
1917  HuginBase::UIntSetVector lensImgs = newLenses.getPartsSet();
1918  if (!imgsAlreadyInPano.empty())
1919  {
1920  for (auto img : imgsAlreadyInPano)
1921  {
1922  const size_t initialLensNumber = newLenses.getPartNumber(img);
1923  const size_t newLensNumber = oldLenses.getPartNumber(new_image_nr[img]);
1924  // create copy of UIntSet, because we can modifying the set in the for loop
1925  // and this invalidates the iterators
1926  const HuginBase::UIntSet imgs(imgsCheckLens);
1927  for (auto j : imgs)
1928  {
1929  if (set_contains(lensImgs[initialLensNumber], j))
1930  {
1931  oldLenses.switchParts(new_image_nr[j], newLensNumber);
1932  imgsCheckLens.erase(j);
1933  lensImgs[initialLensNumber].erase(j);
1934  };
1935  };
1936  lensImgs[initialLensNumber].erase(img);
1937  };
1938  };
1939  if (!imgsCheckLens.empty())
1940  {
1941  // find first lens not already handled
1942  size_t i = 0;
1943  while (i < lensImgs.size() && lensImgs[i].empty())
1944  {
1945  i++;
1946  };
1947  if (i < lensImgs.size())
1948  {
1949  const HuginBase::SrcPanoImage& srcImage = getImage(new_image_nr[*lensImgs[i].begin()]);
1950  size_t matchingLensNumber = -1;
1951  for (size_t j = 0; j < oldImgNumber; ++j)
1952  {
1953  const HuginBase::SrcPanoImage& compareImage = getImage(j);
1954  if (compareImage.getSize() == srcImage.getSize() &&
1955  compareImage.getExifModel() == srcImage.getExifModel() &&
1956  compareImage.getExifMake() == srcImage.getExifMake() &&
1957  compareImage.getExifFocalLength() == srcImage.getExifFocalLength())
1958  {
1959  matchingLensNumber = oldLenses.getPartNumber(j);
1960  break;
1961  };
1962  };
1963  // we found a matching lens
1964  if (matchingLensNumber >= 0)
1965  {
1966  for (size_t j : lensImgs[i])
1967  {
1968  oldLenses.switchParts(new_image_nr[j], matchingLensNumber);
1969  };
1970  };
1971  };
1972  };
1973  // recreate links between image variables.
1974  for (unsigned int i=0; i<newPano.getNrOfImages(); i++)
1975  {
1976  for(unsigned int j=i+1;j<newPano.getNrOfImages();j++)
1977  {
1978  const HuginBase::SrcPanoImage &img=newPano.getImage(i);
1979 #define image_variable( name, type, default_value )\
1980  if(img.name##isLinkedWith(newPano.getImage(j)))\
1981  {\
1982  linkImageVariable##name(new_image_nr[i],new_image_nr[j]);\
1983  };
1984 #include "panodata/image_variables.h"
1985 #undef image_variable
1986  }
1987  }
1988  //now translate cp
1989  CPVector cps=newPano.getCtrlPoints();
1990  const int nextLineCPOffset = getNextCPTypeLineNumber() - 3;
1991  for(unsigned int i=0;i<cps.size();i++)
1992  {
1993  // special treatment of line control points
1994  if (cps[i].mode > 2)
1995  {
1996  addCtrlPoint(HuginBase::ControlPoint(new_image_nr[cps[i].image1Nr], cps[i].x1, cps[i].y1,
1997  new_image_nr[cps[i].image2Nr], cps[i].x2, cps[i].y2, cps[i].mode + nextLineCPOffset));
1998  }
1999  else
2000  {
2001  // normal, horizontal and vertical cp keep their mode
2002  addCtrlPoint(HuginBase::ControlPoint(new_image_nr[cps[i].image1Nr], cps[i].x1, cps[i].y1,
2003  new_image_nr[cps[i].image2Nr], cps[i].x2, cps[i].y2, cps[i].mode));
2004  };
2005  };
2007  };
2008 };
2009 
2011 {
2012  int t=0;
2013  for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it)
2014  {
2015  t = std::max(t, it->mode);
2016  }
2017  if (t <= 2) {
2018  t=2;
2019  }
2020  return t+1;
2021 }
2022 
2023 bool Panorama::ReadPTOFile(const std::string& filename, const std::string& prefix)
2024 {
2025  // check if filename is an image file
2026  if (vigra::isImage(filename.c_str()))
2027  {
2028  std::cerr << "file \"" << filename << "\" seems to be an image file and not a PTO file." << std::endl;
2029  return false;
2030  };
2031  // open stream and check
2032  std::ifstream dataInput(filename.c_str());
2033  if (!dataInput.good() || dataInput.eof())
2034  {
2035  std::cerr << "could not open script : " << filename << std::endl;
2036  return false;
2037  };
2038  // finally read pto file
2039  PanoramaMemento newPano;
2040  int ptoVersion;
2041  const bool result = newPano.loadPTScript(dataInput, ptoVersion, prefix);
2042  // close stream
2043  dataInput.close();
2044  if (result)
2045  {
2046  // reading was sucessful, update current object
2047  this->setFilePrefix(prefix);
2048  this->setMemento(newPano);
2049  return true;
2050  }
2051  else
2052  {
2053  // failed to parse pto file
2054  std::cerr << "error while parsing panos tool script: " << filename << std::endl;
2055  return false;
2056  };
2057 }
2058 
2059 bool Panorama::WritePTOFile(const std::string& filename, const std::string& prefix)
2060 {
2061  std::ofstream outputStream(filename, std::ofstream::out | std::ofstream::trunc);
2062  if (outputStream.good())
2063  {
2064  UIntSet allImages;
2065  if (getNrOfImages() > 0)
2066  {
2067  fill_set(allImages, 0, getNrOfImages() - 1);
2068  };
2069  try
2070  {
2071  printPanoramaScript(outputStream, getOptimizeVector(), getOptions(), allImages, false, prefix);
2072  }
2073  catch (std::exception& e)
2074  {
2075  // error occured, return false
2076  outputStream.close();
2077  std::cerr << "Failed to write project file " << filename << " (error: " << e.what() << ")" << std::endl;
2078  return false;
2079  };
2080  outputStream.close();
2081  return true;
2082  }
2083  else
2084  {
2085  std::cerr << "Failed to write project file " << filename << " (Can not create file.)" << std::endl;
2086  return false;
2087  };
2088 }
2089 
2090 void Panorama::updateWhiteBalance(double redFactor, double blueFactor)
2091 {
2092  UIntSet modified_images;
2093  for(unsigned int i=0;i<getNrOfImages();i++)
2094  {
2095  if(!set_contains(modified_images,i))
2096  {
2097  state.images[i]->setWhiteBalanceRed(redFactor * state.images[i]->getWhiteBalanceRed());
2098  state.images[i]->setWhiteBalanceBlue(blueFactor * state.images[i]->getWhiteBalanceBlue());
2099  modified_images.insert(i);
2100  imageChanged(i);
2101  //check linked images and remember for later
2102  if(state.images[i]->WhiteBalanceRedisLinked())
2103  {
2104  if(i+1<getNrOfImages())
2105  {
2106  for(unsigned int j=i+1;j<getNrOfImages();j++)
2107  {
2108  if(state.images[i]->WhiteBalanceRedisLinkedWith(*(state.images[j])))
2109  {
2110  modified_images.insert(j);
2111  imageChanged(j);
2112  };
2113  };
2114  };
2115  };
2116  };
2117  };
2118 };
2119 
2121 {
2122  if (state.images.empty())
2123  {
2124  return 0;
2125  }
2126  double minEv = 1000;
2127  double maxEv = -1000;
2128  for (size_t i = 0; i < state.images.size(); i++)
2129  {
2130  const double ev = state.images[i]->getExposureValue();
2131  minEv = std::min(minEv, ev);
2132  maxEv = std::max(maxEv, ev);
2133  };
2134  return maxEv - minEv;
2135 };
2136 
2138 {
2139  if (state.images.empty())
2140  {
2141  return false;
2142  }
2143  // this algorithm is based on panostart by Bruno Postle
2144  // bracketed pano has at least a dynamic range of 1.2 ev values (corresponds to bracket with +-2/3)
2145  if (getMaxExposureDifference()<1.2)
2146  {
2147  return false;
2148  }
2149  //now get all exposure layers
2150  UIntSet allImg;
2151  fill_set(allImg, 0, state.images.size() - 1);
2152  UIntSetVector evValues = getExposureLayers(*this, allImg, 0.3);
2153  //if there is only one unique exposure value then there are no stacks
2154  if (evValues.size()<2)
2155  {
2156  return false;
2157  }
2158  //if number of unique exposure values is equal the number of images then there are no stacks
2159  if (evValues.size() == state.images.size())
2160  {
2161  return false;
2162  }
2163  //if number of images is not a multiple of number of unique exposure values
2164  //then the stacks are incomplete, skipping
2165  if (state.images.size() % evValues.size() != 0)
2166  {
2167  return false;
2168  }
2169  //check that all exposure layer have the same size indicating that all stacks are of the same size
2170  for (size_t layerNr = 1; layerNr < evValues.size(); ++layerNr)
2171  {
2172  if (evValues[0].size() != evValues[layerNr].size())
2173  {
2174  return false;
2175  };
2176  };
2177  return true;
2178 };
2179 
2181 void Panorama::linkPossibleStacks(bool linkPosition)
2182 {
2183  // we need at least 2 images
2184  if (state.images.size()<=1)
2185  {
2186  return;
2187  };
2188  // unlink all existing stacks
2189  for (size_t imgNr = 0; imgNr < state.images.size(); imgNr++)
2190  {
2191  if (state.images[imgNr]->YawisLinked())
2192  {
2193  unlinkImageVariableYaw(imgNr);
2194  unlinkImageVariablePitch(imgNr);
2195  unlinkImageVariableRoll(imgNr);
2196  unlinkImageVariableX(imgNr);
2197  unlinkImageVariableY(imgNr);
2198  unlinkImageVariableZ(imgNr);
2199  unlinkImageVariableTranslationPlaneYaw(imgNr);
2200  unlinkImageVariableTranslationPlanePitch(imgNr);
2201  };
2202  if (state.images[imgNr]->StackisLinked())
2203  {
2204  unlinkImageVariableStack(imgNr);
2205  };
2206  };
2207  // now link all possible stacks
2208  UIntSet allImg;
2209  fill_set(allImg, 0, state.images.size() - 1);
2210  UIntSetVector evValues = getExposureLayers(*this, allImg, 0.3);
2211  if (evValues.empty())
2212  {
2213  return;
2214  };
2215  unsigned int imgNr = 0;
2216  for (size_t i = 1; i<state.images.size(); i++)
2217  {
2218  if (set_contains(evValues[0], i))
2219  {
2220  imgNr = i;
2221  }
2222  else
2223  {
2224  linkImageVariableStack(imgNr, i);
2225  if (linkPosition)
2226  {
2227  linkImageVariableYaw(imgNr, i);
2228  linkImageVariablePitch(imgNr, i);
2229  linkImageVariableRoll(imgNr, i);
2230  linkImageVariableX(imgNr, i);
2231  linkImageVariableY(imgNr, i);
2232  linkImageVariableZ(imgNr, i);
2233  linkImageVariableTranslationPlaneYaw(imgNr, i);
2234  linkImageVariableTranslationPlanePitch(imgNr, i);
2235  };
2236  };
2237  };
2238 };
2239 
2241 {
2242  // Use the assignment operator to get the work done: see the next function.
2243  *this = data;
2244 }
2245 
2247 {
2248  // Copy the PanoramaMemento.
2249 
2250  // Don't do anything in the case of self assignment. This is important as we
2251  // are about to delete the image information.
2252  if (&data == this)
2253  {
2254  return *this;
2255  }
2256 
2257  // Remove any images we currently had.
2258  deleteAllImages();
2259  // copy image variables
2260  for (std::vector<SrcPanoImage *>::const_iterator it = data.images.begin();
2261  it != data.images.end(); ++it)
2262  {
2263  images.push_back(new SrcPanoImage(*(*it)));
2264  }
2265  // Copies of SrcPanoImage's variables aren't linked, so we have to create
2266  // new links in the same pattern.
2272  std::size_t num_imgs = images.size();
2273  for (std::size_t i = 0; i < num_imgs; i++)
2274  {
2275  // copy this image's links.
2276  // links to lower numbered images will have already been spotted, since
2277  // they are bi-directional.
2278  for (std::size_t j = i + 1; j < num_imgs; j++)
2279  {
2280 #define image_variable( name, type, default_value )\
2281  if (data.images[i]->name##isLinkedWith(*data.images[j]))\
2282  {\
2283  images[i]->link##name(images[j]);\
2284  }
2285 #include "image_variables.h"
2286 #undef image_variable
2287  }
2288  }
2289 
2290  ctrlPoints = data.ctrlPoints;
2292  bands = data.bands;
2293 
2294  options = data.options;
2295 
2296  optSwitch = data.optSwitch;
2298  optvec = data.optvec;
2299 
2301 
2302  return *this;
2303 }
2304 
2306 {
2307  deleteAllImages();
2308 }
2309 
2311 {
2312  // delete all the images pointed to by the images vector.
2313  for (std::vector<SrcPanoImage *>::iterator it = images.begin();
2314  it != images.end(); ++it)
2315  {
2316  delete *it;
2317  }
2318  // now clear the pointers themselves.
2319  images.clear();
2320 }
2321 
2322 bool PanoramaMemento::loadPTScript(std::istream &i, int & ptoVersion, const std::string &prefix)
2323 {
2324  DEBUG_TRACE("");
2325  // set numeric locale to C, for correct number output
2326  char * p = setlocale(LC_NUMERIC,NULL);
2327  char * old_locale = strdup(p);
2328  setlocale(LC_NUMERIC,"C");
2329  std::string line;
2330  // list of all control characters (char 0 .. 31), except tab stop 0x09 and carriage return 0x0d, otherwise pto files from Windows will be rejected
2331  const std::string controlCharacters { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
2332 
2333  // vector with the different information lines about images
2334  std::vector<PTScriptParsing::ImgInfo> oImgInfo;
2335  std::vector<PTScriptParsing::ImgInfo> iImgInfo;
2336  // strange comment information.
2337  std::vector<PTScriptParsing::ImgInfo> cImgInfo;
2338  // hugin additional information
2339  std::vector<PTScriptParsing::ImgInfo> huginImgInfo;
2340  // vector with readed masks
2341  MaskPolygonVector ImgMasks;
2342  CPVector loadedCp;
2343 
2344  // indicate lines that should be skipped for whatever reason
2345  bool skipNextLine = false;
2346 
2347  bool PTGUIScriptFile = false;
2348  int PTGUIScriptVersion = 0;
2349  // PTGui lens line detected
2350  int ctrlPointsImgNrOffset = 0;
2351  bool PTGUILensLine = false;
2352 
2353  bool PTGUILensLoaded = false;
2354  PTScriptParsing::ImgInfo PTGUILens;
2355 
2356  // set new options to some sensible default.
2357  options.reset();
2358  options.tiff_saveROI = false;
2359 
2360  ptoVersion = 1;
2361 
2362  bool firstOptVecParse = true;
2363  unsigned int lineNr = 0;
2364  while (i.good()) {
2365  std::getline(i, line);
2366  if (line.find_first_of(controlCharacters, 0) != std::string::npos)
2367  {
2368  // we found a binary character /control sequence in the text
2369  // this is not allowed in a pto file
2370  // reset locale
2371  setlocale(LC_NUMERIC, old_locale);
2372  free(old_locale);
2373  // stop processing
2374  return false;
2375  };
2376  lineNr++;
2377  DEBUG_DEBUG(lineNr << ": " << line);
2378  if (skipNextLine) {
2379  skipNextLine = false;
2380  continue;
2381  }
2382  //skip emtpy lines
2383  if(line.empty())
2384  continue;
2385  // check for a known line
2386  switch(line[0]) {
2387  case 'p':
2388  {
2389  DEBUG_DEBUG("p line: " << line);
2390  int i;
2391  if (PTScriptParsing::getIntParam(i, line, "f"))
2393  unsigned int w;
2394  if (PTScriptParsing::getIntParam(w, line, "w"))
2395  options.setWidth(w);
2396  double v;
2397  if (PTScriptParsing::getDoubleParam(v, line, "v"))
2398  options.setHFOV(v, false);
2399  int height;
2400  if (PTScriptParsing::getIntParam(height, line, "h"))
2401  options.setHeight(height);
2402 
2403  double newE;
2404  if (PTScriptParsing::getDoubleParam(newE, line, "E"))
2406  int ar=0;
2407  if (PTScriptParsing::getIntParam(ar, line, "R"))
2409 
2410  std::string format;
2411  if (PTScriptParsing::getPTParam(format, line, "T"))
2412  options.outputPixelType = format;
2413 
2414  if (PTScriptParsing::getPTParam(format, line, "S")) {
2415  int left, right, top, bottom;
2416  int n = sscanf(format.c_str(), "%d,%d,%d,%d", &left, &right, &top, &bottom);
2417  if (n == 4) {
2418  options.setROI(vigra::Rect2D(left, top, right, bottom));
2419  } else {
2420  DEBUG_WARN("Could not parse crop string: " << format);
2421  }
2422  }
2423 
2424  // parse projection parameters
2425  if (PTScriptParsing::getPTParam(format, line, "P")) {
2426  char * tstr = strdup(format.c_str());
2427  std::vector<double> projParam;
2428  char * b = strtok(tstr, " \"");
2429  if (b != NULL) {
2430  while (b != NULL) {
2431  double tempDbl;
2432  if (sscanf(b, "%lf", &tempDbl) == 1) {
2433  projParam.push_back(tempDbl);
2434  b = strtok(NULL, " \"");
2435  }
2436  }
2437  }
2438  free(tstr);
2439  // only set projection parameters, if the have the right size.
2440  if (projParam.size() == options.getProjectionParameters().size()) {
2441  options.setProjectionParameters(projParam);
2442  }
2443  }
2444 
2445  // this is fragile.. hope nobody adds additional whitespace
2446  // and other arguments than q...
2447  // n"JPEG q80"
2448  if (PTScriptParsing::getPTParam(format, line, "n")) {
2449  int t = format.find(' ');
2450  options.outputFormat = options.getFormatFromName(format.substr(0,t));
2451 
2452  // parse output format options.
2453  switch (options.outputFormat)
2454  {
2455  case PanoramaOptions::JPEG:
2457  {
2458  // "parse" jpg quality
2459  int q;
2460  if (PTScriptParsing::getIntParam(q, format, "q")) {
2461  options.quality = (int) q;
2462  }
2463  }
2464  break;
2466  {
2467  int coordImgs = 0;
2468  if (PTScriptParsing::getIntParam(coordImgs, format, "p"))
2469  if (coordImgs)
2470  options.saveCoordImgs = true;
2471  }
2472  case PanoramaOptions::TIFF:
2476  {
2477  // parse tiff compression mode
2478  std::string comp;
2479  if (PTScriptParsing::getPTParam(comp, format, "c:")) {
2480  if (comp == "NONE" || comp == "LZW" ||
2481  comp == "PACKBITS" || comp == "DEFLATE")
2482  {
2483  options.tiffCompression = comp;
2484  } else {
2485  DEBUG_WARN("No valid tiff compression found");
2486  }
2487  }
2488  // read tiff roi
2489  if (PTScriptParsing::getPTParam(comp, format, "r:")) {
2490  if (comp == "CROP") {
2491  options.tiff_saveROI = true;
2492  } else {
2493  options.tiff_saveROI = false;
2494  }
2495  }
2496  }
2497  break;
2498  default:
2499  break;
2500  }
2501  }
2502 
2503  int cRefImg = 0;
2504  if (PTScriptParsing::getIntParam(cRefImg, line, "k")) {
2505  options.colorReferenceImage = cRefImg;
2506  }
2507  break;
2508 
2509  }
2510  case 'm':
2511  {
2512  DEBUG_DEBUG("m line: " << line);
2513  // parse misc options
2514  int i;
2515  if (PTScriptParsing::getIntParam(i, line, "i"))
2517  break;
2518  }
2519  case 'v':
2520  {
2521  DEBUG_DEBUG("v line: " << line);
2522  if (!PTGUIScriptFile) {
2523  if (firstOptVecParse) {
2524  int nImg = std::max(iImgInfo.size(), oImgInfo.size());
2525  DEBUG_DEBUG("nImg: " << nImg);
2526  optvec = OptimizeVector(nImg);
2527  firstOptVecParse = false;
2528  }
2529  std::stringstream optstream;
2530  optstream << line.substr(1);
2531  std::string var;
2532  while (!(optstream >> std::ws).eof()) {
2533  optstream >> var;
2534  if (var.length() == 1) {
2535  // special case for PTGUI
2536  var += "0";
2537  }
2538  // find first numerical character
2539  std::string::size_type np = var.find_first_of("0123456789");
2540  if (np == std::string::npos) {
2541  // invalid, continue
2542  continue;
2543  }
2544  std::string name=var.substr(0,np);
2545  unsigned int nr;
2546  if (!hugin_utils::stringToUInt(var.substr(np), nr))
2547  {
2548  // invalid, continue
2549  continue;
2550  };
2551  DEBUG_ASSERT(nr < optvec.size());
2552  if(nr < optvec.size())
2553  {
2554  optvec[nr].insert(name);
2555  DEBUG_DEBUG("parsing opt: >" << var << "< : var:" << name << " image:" << nr);
2556  };
2557  }
2558  }
2559  break;
2560  }
2561  case 'c':
2562  {
2563  DEBUG_DEBUG("c line: " << line);
2564  int t;
2565  // read control points
2566  ControlPoint point;
2567  // TODO - should verify that line syntax is correct
2568  PTScriptParsing::getIntParam(point.image1Nr, line, "n");
2569  point.image1Nr += ctrlPointsImgNrOffset;
2570  PTScriptParsing::getIntParam(point.image2Nr, line, "N");
2571  point.image2Nr += ctrlPointsImgNrOffset;
2572  PTScriptParsing::getDoubleParam(point.x1, line, "x");
2573  PTScriptParsing::getDoubleParam(point.x2, line, "X");
2574  PTScriptParsing::getDoubleParam(point.y1, line, "y");
2575  PTScriptParsing::getDoubleParam(point.y2, line, "Y");
2576  if (!PTScriptParsing::getIntParam(t, line, "t")){
2577  t = 0;
2578  }
2579 
2580  point.mode = t;
2581  loadedCp.push_back(point);
2582  break;
2583  }
2584 
2585  // handle the complicated part.. the image & lens settings.
2586  // treat i and o lines the same.. however, o lines have priority
2587  // over i lines.(i lines often do not contain link information!)
2588  case 'i':
2589  {
2590  if (PTGUILensLine) {
2591  PTGUILensLine = false;
2592  PTGUILensLoaded = true;
2593  PTGUILens.parse(line);
2594  } else {
2595  iImgInfo.push_back(PTScriptParsing::ImgInfo(line));
2596  }
2597  break;
2598  }
2599  case 'o':
2600  {
2601  if (PTGUILensLine) {
2602  PTGUILensLine = false;
2603  PTGUILensLoaded = true;
2604  PTGUILens.parse(line);
2605  } else {
2606  oImgInfo.push_back(PTScriptParsing::ImgInfo(line));
2607  }
2608  break;
2609  }
2610 
2611  case 'k':
2612  {
2613  unsigned int param;
2614  if (PTScriptParsing::getIntParam(param, line, "i"))
2615  {
2616  MaskPolygon newPolygon;
2617  newPolygon.setImgNr(param);
2618  if (PTScriptParsing::getIntParam(param, line, "t"))
2619  newPolygon.setMaskType((HuginBase::MaskPolygon::MaskType)param);
2620  std::string format;
2621  if (PTScriptParsing::getPTParam(format, line, "p"))
2622  {
2623  if(newPolygon.parsePolygonString(format))
2624  ImgMasks.push_back(newPolygon);
2625  };
2626  };
2627  break;
2628  }
2629 
2630  case '#':
2631  {
2632  // parse special comments...
2633  if (line.substr(0,20) == std::string("# ptGui project file")) {
2634  PTGUIScriptFile = true;
2635  }
2636  if (line.substr(0,12) == "#-dummyimage") {
2637  PTGUILensLine = true;
2638  }
2639  if (PTGUIScriptFile) {
2640  // parse special PTGUI stuff.
2641  if (sscanf(line.c_str(), "#-fileversion %d", &PTGUIScriptVersion) > 0) {
2642  DEBUG_DEBUG("Detected PTGUI script version: " << PTGUIScriptVersion);
2643  switch (PTGUIScriptVersion) {
2644  case 0:
2645  break;
2646  case 1:
2647  break;
2648  case 2:
2649  break;
2650  case 3:
2651  break;
2652  case 4:
2653  break;
2654  case 5:
2655  break;
2656  case 6:
2657  break;
2658  case 7:
2659  break;
2660  default:
2661  ctrlPointsImgNrOffset = -1;
2662  // latest known version is 8
2663  break;
2664  }
2665  }
2666  }
2667 
2668  if (line.substr(0,8) == "#-hugin ") {
2669  // read hugin image line
2670  PTScriptParsing::ImgInfo info;
2671  info.autoCenterCrop = (line.find("autoCenterCrop=1") != std::string::npos);
2672  size_t pos = line.find("cropFactor=");
2673  if (pos > 0 && pos < line.length()) {
2674  double cropFactor=1;
2675  const char * s = line.c_str() + pos;
2676  sscanf(s,"cropFactor=%lf", & cropFactor);
2677  if(cropFactor<0.01 || cropFactor > 100)
2678  cropFactor=1;
2679  info.cropFactor = cropFactor;
2680  }
2681  pos = line.find("disabled");
2682  if (pos > 0 && pos < line.length()) {
2683  info.enabled = false;
2684  }
2685  huginImgInfo.push_back(info);
2686  }
2687 
2688  // PTGui and PTAssember project files:
2689  // #-imgfile 960 1280 "D:\data\bruno\074-098\087.jpg"
2690  if (line.substr(0,10) == "#-imgfile ") {
2691 
2692  // arghhh. I like string processing without regexps.
2693  int b = line.find_first_not_of(" ",9);
2694  int e = line.find_first_of(" ",b);
2695  DEBUG_DEBUG(" width:" << line.substr(b, e - b) << ":")
2696  int nextWidth;
2697  if (!hugin_utils::stringToInt(line.substr(b, e - b), nextWidth))
2698  {
2699  continue;
2700  };
2701  DEBUG_DEBUG("next width " << nextWidth);
2702  b = line.find_first_not_of(" ",e);
2703  e = line.find_first_of(" ",b);
2704  DEBUG_DEBUG(" height:" << line.substr(b, e - b) << ":")
2705  int nextHeight;
2706  if (!hugin_utils::stringToInt(line.substr(b, e - b), nextHeight))
2707  {
2708  continue;
2709  };
2710  DEBUG_DEBUG("next height " << nextHeight);
2711 
2712  std::string nextFilename;
2713  try {
2714  b = line.find_first_not_of(" \"",e);
2715  e = line.find_first_of("\"",b);
2716  nextFilename = line.substr(b,e-b);
2717  } catch (std::out_of_range& e) {
2718  DEBUG_ERROR("ERROR PARSING INPUT FILE" << e.what( ));
2719  return false;
2720  }
2721  DEBUG_DEBUG("next filename " << nextFilename);
2722 
2723  PTScriptParsing::ImgInfo info;
2724  info.width = nextWidth;
2725  info.height = nextHeight;
2726  info.filename = nextFilename;
2727  cImgInfo.push_back(info);
2728  }
2729 
2730 
2731  // parse hugin properties
2732  if (line.substr(0,7) == "#hugin_") {
2733  std::istringstream is(line);
2734  std::string var,value;
2735  is >> var >> value;
2736  if (!is.fail()) {
2737  if (var == "#hugin_ptoversion") {
2738  ptoVersion = atoi(value.c_str());
2739  }
2740 
2741  if (var == "#hugin_optimizeReferenceImage") {
2742  options.optimizeReferenceImage = atoi(value.c_str());
2743  } else if (var == "#hugin_remapper") {
2744  if (value == "nona") {
2746  } else if (value == "PTmender") {
2748  }
2749  } else if (var == "#hugin_blender") {
2750  if (value == "none") {
2752  } else if (value == "PTblender") {
2754  } else if (value == "enblend") {
2756  } else if (value == "PTmasker") {
2758  } else if (value == "smartblend") {
2760  } else if (value == "internal") {
2762  }
2763 
2764  } else if (var == "#hugin_enblendOptions") {
2765  options.enblendOptions = value;
2766  while (!is.eof()) {
2767  is >> value;
2768  if (!is.fail() && value.length() > 0) {
2769  options.enblendOptions += " ";
2770  options.enblendOptions += value;
2771  }
2772  }
2773  } else if (var == "#hugin_enfuseOptions") {
2774  options.enfuseOptions = value;
2775  while (!is.eof()) {
2776  is >> value;
2777  if (!is.fail() && value.length() > 0) {
2778  options.enfuseOptions += " ";
2779  options.enfuseOptions += value;
2780  }
2781  }
2782  } else if (var == "#hugin_hdrmergeOptions") {
2783  options.hdrmergeOptions = value;
2784  while (!is.eof()) {
2785  is >> value;
2786  if (!is.fail() && value.length() > 0) {
2787  options.hdrmergeOptions += " ";
2788  options.hdrmergeOptions += value;
2789  }
2790  }
2791  } else if (var == "#hugin_verdandiOptions") {
2792  options.verdandiOptions = value;
2793  while (!is.eof()) {
2794  is >> value;
2795  if (!is.fail() && value.length() > 0) {
2796  options.verdandiOptions += " ";
2797  options.verdandiOptions += value;
2798  }
2799  }
2800  } else if (var == "#hugin_edgeFillMode") {
2801  if (value == "0")
2802  {
2804  }
2805  else
2806  {
2807  if (value == "1")
2808  {
2810  };
2811  };
2812  } else if (var == "#hugin_edgeFillKeepInput") {
2813  options.keepEdgeFillInput = (value == "true");
2814  } else if (var == "#hugin_outputLDRBlended") {
2815  options.outputLDRBlended = (value == "true");
2816  } else if (var == "#hugin_outputLDRLayers") {
2817  options.outputLDRLayers = (value == "true");
2818  } else if (var == "#hugin_outputLDRExposureRemapped") {
2819  options.outputLDRExposureRemapped = (value == "true");
2820  } else if (var == "#hugin_outputLDRExposureLayers") {
2821  options.outputLDRExposureLayers = (value == "true");
2822  } else if (var == "#hugin_outputLDRExposureBlended") {
2823  options.outputLDRExposureBlended = (value == "true");
2824  } else if (var == "#hugin_outputLDRExposureLayersFused") {
2825  options.outputLDRExposureLayersFused = (value == "true");
2826  } else if (var == "#hugin_outputLDRStacks") {
2827  options.outputLDRStacks = (value == "true");
2828  } else if (var == "#hugin_outputHDRBlended") {
2829  options.outputHDRBlended = (value == "true");
2830  } else if (var == "#hugin_outputHDRLayers") {
2831  options.outputHDRLayers = (value == "true");
2832  } else if (var == "#hugin_outputHDRStacks") {
2833  options.outputHDRStacks = (value == "true");
2834 
2835  } else if (var == "#hugin_outputStacksMinOverlap") {
2836  double val=atof(value.c_str());
2837  if(val>0 && val <= 1)
2838  {
2840  };
2841  if (val < 0)
2842  {
2844  };
2845  } else if (var == "#hugin_outputLayersExposureDiff") {
2846  double val=atof(value.c_str());
2847  if(val>0.01)
2848  {
2850  }
2851 
2852  } else if (var == "#hugin_outputLayersCompression") {
2854  } else if (var == "#hugin_outputImageType") {
2855  options.outputImageType = value;
2856  } else if (var == "#hugin_outputImageTypeCompression") {
2858  } else if (var == "#hugin_outputJPEGQuality") {
2859  options.quality = atoi(value.c_str());
2860  } else if (var == "#hugin_outputImageTypeHDR") {
2861  options.outputImageTypeHDR = value;
2862  } else if (var == "#hugin_outputImageTypeHDRCompression") {
2864  } else if (var == "#hugin_outputRangeCompression") {
2865  options.outputRangeCompression = atof(value.c_str());
2867  } else if (var == "#hugin_optimizerMasterSwitch") {
2868  optSwitch = atoi(value.c_str());
2869  } else if (var == "#hugin_optimizerPhotoMasterSwitch") {
2870  optPhotoSwitch = atoi(value.c_str());
2871  };
2872 
2873  }
2874  }
2875  break;
2876  }
2877 
2878  } // case
2879  }
2880 
2881  // assemble images from the information read before..
2882 
2885 #if 0
2886  // handle PTGUI special case
2887  if (PTGUILensLoaded) {
2888  // create lens with dummy info
2889  Lens l;
2890  for (const char **v = Lens::variableNames; *v != 0; v++) {
2891  map_get(l.variables, *v).setValue(PTGUILens.vars[*v]);
2892  }
2893  l.setImageSize(vigra::Size2D(PTGUILens.width, PTGUILens.height));
2894  l.setCropFactor(1);
2895  l.setProjection((Lens::LensProjectionFormat) PTGUILens.f);
2896  lenses.push_back(l);
2897  }
2898 #endif
2899 
2900 /*
2901  // ugly hack to load PTGui script files
2902  if (ptGUIDummyImage) {
2903  DEBUG_DEBUG("loading default PTGUI line: " << line);
2904  Lens l;
2905  // skip ptgui's dummy image
2906  // load parameters into default lens...
2907  for (LensVarMap::iterator it = l.variables.begin();
2908  it != l.variables.end();
2909  ++it)
2910  {
2911  DEBUG_DEBUG("reading default lens variable " << it->first);
2912  int link;
2913  bool ok = readVar(it->second, link, line);
2914  DEBUG_ASSERT(ok);
2915  DEBUG_ASSERT(link == -1);
2916  }
2917  lenses.push_back(l);
2918 
2919  ptGUIDummyImage = false;
2920  break;
2921  }
2922 */
2923 
2924  // merge image info from the 3 different lines...
2925  // i lines are the main reference.
2926 
2927  int nImgs = iImgInfo.size();
2928  int nOLines = oImgInfo.size();
2929  int nCLines = cImgInfo.size();
2930 
2931  if (nImgs < nOLines) {
2932  // no, or less i lines found. scrap i lines.
2933  DEBUG_DEBUG("throwing away " << nImgs << " i lines");
2934  iImgInfo = oImgInfo;
2935  nImgs = nOLines;
2936  }
2937  if (nOLines < nImgs) {
2938  oImgInfo = iImgInfo;
2939  }
2940 
2941  // merge o lines and i lines into i lines.
2942  for (int i=0; i < nImgs; i++) {
2943 
2944  // move parameters from o lines -> i (only if it isn't given in the
2945  // i lines. or it is linked on the o lines)
2946 
2947  // ordinary variables
2948  for (const char ** v = PTScriptParsing::ImgInfo::varnames; *v; v++) {
2949 
2950  if ((iImgInfo[i].links[*v] == -2 && oImgInfo[i].links[*v] != -2) || (iImgInfo[i].links[*v] == -1 && oImgInfo[i].links[*v] >=0)) {
2951  DEBUG_DEBUG(*v << ": o -> i");
2952  iImgInfo[i].vars[*v] = oImgInfo[i].vars[*v];
2953  iImgInfo[i].links[*v] = oImgInfo[i].links[*v];
2954  }
2955  }
2956 
2957  if (iImgInfo[i].filename == "" && oImgInfo[i].filename != "") {
2958  DEBUG_DEBUG("filename: o -> i");
2959  iImgInfo[i].filename = oImgInfo[i].filename;
2960  }
2961 
2962  if (iImgInfo[i].crop.isEmpty() && !oImgInfo[i].crop.isEmpty()) {
2963  DEBUG_DEBUG("crop: o -> i");
2964  iImgInfo[i].crop = oImgInfo[i].crop;
2965  }
2966 
2967  if (iImgInfo[i].width <= 0 && oImgInfo[i].width > 0) {
2968  DEBUG_DEBUG("width: o -> i");
2969  iImgInfo[i].width = oImgInfo[i].width;
2970  }
2971 
2972  if (iImgInfo[i].height <= 0 && oImgInfo[i].height > 0) {
2973  DEBUG_DEBUG("height: o -> i");
2974  iImgInfo[i].height = oImgInfo[i].height;
2975  }
2976 
2977  if (iImgInfo[i].f < 0 && oImgInfo[i].f > 0) {
2978  DEBUG_DEBUG("f: o -> i");
2979  iImgInfo[i].f = oImgInfo[i].f;
2980  }
2981 
2982  if (nCLines == nImgs) {
2983  // img file & size in clines
2984  if (cImgInfo[i].filename != "" && cImgInfo[i].width > 0) {
2985  DEBUG_DEBUG("filename, width, height: c -> i");
2986  iImgInfo[i].filename = cImgInfo[i].filename;
2987  iImgInfo[i].width = cImgInfo[i].width;
2988  iImgInfo[i].height = cImgInfo[i].height;
2989  }
2990  }
2991  if (huginImgInfo.size() == (size_t)nImgs) {
2992  iImgInfo[i].cropFactor = huginImgInfo[i].cropFactor;
2993  iImgInfo[i].autoCenterCrop = huginImgInfo[i].autoCenterCrop;
2994  iImgInfo[i].enabled= huginImgInfo[i].enabled;
2995  }
2996  }
2997 
2998  // create images.
2999  for (int i=0; i < nImgs; i++) {
3000 
3001  DEBUG_DEBUG("i line: " << i);
3002  // read the variables
3003  VariableMap vars;
3004  int link = -2;
3005  fillVariableMap(vars);
3006 
3007  for (const char ** v = PTScriptParsing::ImgInfo::varnames; *v != 0; v++) {
3008  std::string name(*v);
3009  double val = iImgInfo[i].vars[*v];
3010  map_get(vars,name).setValue(val);
3011  if (iImgInfo[i].links[*v] >= 0) {
3012  link = iImgInfo[i].links[*v];
3013  }
3014  }
3015 
3016  std::string file = iImgInfo[i].filename;
3017  // add prefix if only a relative path.
3018 #ifdef _WIN32
3019  bool absPath = ( (file[1]==':' && file[2]=='\\') || (file[1]==':' && file[2]=='/') || (file[0] == '\\' && file[1] == '\\'));
3020 #else
3021  bool absPath = file[0] == '/';
3022 #endif
3023  if (!absPath) {
3024  file.insert(0, prefix);
3025  }
3026  DEBUG_DEBUG("filename: " << file);
3027 
3028  // Make a new SrcPanoImage in this list for expressing this one.
3029  SrcPanoImage * new_img_p = new SrcPanoImage();
3030  images.push_back(new_img_p);
3031  // and make a reference to it so we dont keep using images.back(),
3032  SrcPanoImage & new_img = *new_img_p;
3033  new_img.setFilename(file);
3034  new_img.setSize(vigra::Size2D(iImgInfo[i].width, iImgInfo[i].height));
3035  new_img.checkImageSizeKnown();
3036 
3037  // Panotools Script variables for the current SrcPanoImage variable.
3038  // We just need the names.
3039  VariableMap vars_for_name;
3040 
3041  // A dummy SrcPanoImage to use to fill vars_for_name.
3042  SrcPanoImage name_src;
3043 
3044 /* Set image variables in new_img using the PanoTools Script names, with
3045  * linking where specified in the file.
3046  *
3047  * We create a list of PanoTools script variable names for each variable in
3048  * SrcPanoImg (vars_for_name). It may have multiple variables or none at all.
3049  * If a link is found between any of the variables inside it we can link them up
3050  * in new_img.
3051  *
3052  * The Panorama Tools script format makes it possible to link parts of the same
3053  * SrcPanoImage variable differently (e.g. you can link the horizontal component
3054  * of shearing to a different target to the vertical component, not link the
3055  * vertical component at all). SrcPanoImage cannot handle this, so we end up
3056  * linking all components of the same variable to anything specified in the PTO
3057  * script for one of the components: most often we specify the same link
3058  * multiple times.
3059  */
3063 #define RESET_LOCALE setlocale(LC_NUMERIC,old_locale); free(old_locale);
3064 #define image_variable( name, type, default_value )\
3065  PTOVariableConverterFor##name::addToVariableMap(name_src.get##name##IV(), vars_for_name);\
3066  for (VariableMap::iterator vit = vars_for_name.begin();\
3067  vit != vars_for_name.end(); vit++)\
3068  {\
3069  if (link >= 0 && iImgInfo[i].links[vit->first] >= 0)\
3070  {\
3071  if ( !(PTGUILensLoaded && link == 0)\
3072  && (int) images.size() < link && (!PTGUILensLoaded))\
3073  {\
3074  DEBUG_ERROR("variables must be linked to an image with a lower number" << endl\
3075  << "number links: " << link << " images: " << images.size() << endl\
3076  << "error on line " << lineNr << ":" << endl\
3077  << line);\
3078  RESET_LOCALE\
3079  return false;\
3080  }\
3081  DEBUG_DEBUG("anchored to image " << iImgInfo[i].links[vit->first]);\
3082  new_img.link##name(images[iImgInfo[i].links[vit->first]]);\
3083  } else {\
3084  double val = map_get(vars, vit->first).getValue();\
3085  new_img.setVar(vit->first, val);\
3086  }\
3087  }\
3088  vars_for_name.clear();
3089 #include "image_variables.h"
3090 #undef image_variable
3091  new_img.setProjection((SrcPanoImage::Projection) iImgInfo[i].f);
3092 
3093  // check, if stacks are correctly linked
3094 #define check_stack_link(name) \
3095  if(!new_img.YawisLinked() && new_img.name##isLinked())\
3096  {\
3097  new_img.unlink##name();\
3098  };\
3099  if(new_img.YawisLinked() && !new_img.name##isLinked())\
3100  {\
3101  for(size_t j=0; j<i; j++)\
3102  {\
3103  if(new_img.YawisLinkedWith(*images[j]))\
3104  {\
3105  new_img.link##name(images[j]);\
3106  break;\
3107  };\
3108  };\
3109  }
3117 #undef check_stack_link
3118 
3119 #if 0
3120  new_img.setFeatherWidth((unsigned int) iImgInfo[i].blend_radius);
3121 #endif
3122 
3123  // is this right?
3124  new_img.setCropFactor(iImgInfo[i].cropFactor);
3125  new_img.setVigCorrMode(iImgInfo[i].vigcorrMode);
3126  new_img.setFlatfieldFilename(iImgInfo[i].flatfieldname);
3127  new_img.setResponseType((SrcPanoImage::ResponseType)iImgInfo[i].responseType);
3128  new_img.setAutoCenterCrop(iImgInfo[i].autoCenterCrop);
3129  new_img.setActive(iImgInfo[i].enabled);
3130 
3131  if (!iImgInfo[i].crop.isEmpty()) {
3132  if (new_img.isCircularCrop())
3133  {
3134  new_img.setCropMode(SrcPanoImage::CROP_CIRCLE);
3135  } else {
3136  new_img.setCropMode(SrcPanoImage::CROP_RECTANGLE);
3137  }
3138  new_img.setCropRect(iImgInfo[i].crop);
3139  }
3140 
3141  //now fill the mask
3142  for(unsigned int j=0;j<ImgMasks.size();j++)
3143  if(ImgMasks[j].getImgNr()==i)
3144  //now clip mask to image size + offset
3145  if(ImgMasks[j].clipPolygon(vigra::Rect2D(-0.9*maskOffset,-0.9*maskOffset,
3146  new_img.getWidth()+0.9*maskOffset,new_img.getHeight()+0.9*maskOffset)))
3147  {
3148  new_img.addMask(ImgMasks[j]);
3149  };
3150  }
3151 
3152  // if we haven't found a v line in the project file
3153  if (optvec.size() != images.size()) {
3154  optvec = OptimizeVector(images.size());
3155  }
3156 
3157  if (!loadedCp.empty())
3158  {
3159  // check if control points are linked with existing images
3160  const size_t nrImg = images.size();
3161  for (CPVector::const_iterator it = loadedCp.begin(); it != loadedCp.end(); ++it)
3162  {
3163  HuginBase::ControlPoint cp = *it;
3164  if (cp.image1Nr > cp.image2Nr)
3165  {
3166  // mirror control points if first images has a higher number than the second
3167  cp.mirror();
3168  };
3169  if (cp.image1Nr < nrImg && cp.image2Nr < nrImg)
3170  {
3171  ctrlPoints.push_back(cp);
3172  };
3173  };
3174  if (loadedCp.size() != ctrlPoints.size())
3175  {
3176  std::cout << "WARNING: Project file contains control points that are connected with" << std::endl
3177  << " non existing images. Ignoring these control points." << std::endl;
3178  };
3179  };
3180 
3181  if (images.empty())
3182  {
3183  std::cerr << "ERROR: Project file contains no images." << std::endl;
3184  }
3185  else
3186  {
3188  {
3189  // optimize reference images reference to non-existing image
3191  std::cout << "WARNING: Optimize reference image refers to non existing image. Reset to default value." << std::endl;
3192  };
3194  {
3195  // optimize reference images reference to non-existing image
3197  std::cout << "WARNING: Optimize photometric reference image refers to non existing image. Reset to default value." << std::endl;
3198  };
3199  };
3200  // reset locale
3201  setlocale(LC_NUMERIC,old_locale);
3202  free(old_locale);
3203 
3204  return !images.empty();
3205 }
3206 
3207 } // namespace
std::set< size_t > getRefImages()
returns set of reference image and images linked with reference images
Definition: Panorama.cpp:1235
static const char * variableNames[]
Definition: Lens.h:110
PanoramaOptions::ProjectionFormat getProjection() const
An ImageVariableGroup is a collection of image variables that can have some shared variable values...
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getLensVariables()
Get the set of lens image variables.
void imageChanged(unsigned int imgNr)
mark image for change notification.
Definition: Panorama.cpp:1568
declaration of functions to handle stacks and layers
void updateOptimizeVector()
updates the optimize vector according to master switches
Definition: Panorama.cpp:1299
std::vector< UIntSet > UIntSetVector
Definition: PanoramaData.h:56
const int getNrOfBands() const
return number of bands of first image (without alpha channel) so it can be 1 for grayscale or 3 for r...
Definition: Panorama.cpp:1608
std::vector< UIntSet > getExposureLayers(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output exposure layers
Definition: LayerStacks.cpp:96
void fillVariableMap(VariableMap &vars)
fill map with all image &amp; lens variables
void setMemento(const PanoramaMemento &memento)
set the internal state
Definition: Panorama.cpp:1507
void setHeight(unsigned int h)
set panorama height
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
int roundi(T x)
Definition: hugin_math.h:73
void moveImage(size_t img1, size_t img2)
moves images.
Definition: Panorama.cpp:1424
std::list< PanoramaObserver * > observers
Definition: Panorama.h:695
void checkRefOptStatus(bool &linkRefImgsYaw, bool &linkRefImgsPitch, bool &linkRefImgsRoll)
checks if yaw/pitch/roll of reference image can be check, it depends on number and type of control po...
Definition: Panorama.cpp:1255
void updateCtrlPointErrors(const CPVector &controlPoints)
update control points distances.
Definition: Panorama.cpp:160
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
virtual void setCtrlPoints(const CPVector &points)=0
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
void UpdateOptVectorSet(std::set< std::string > &imgVar, const std::string &var, const bool opt)
Definition: Panorama.cpp:1223
PanoramaData * getNewSubset(const UIntSet &imgs) const
Definition: Panorama.h:183
bool outputLDRLayers
save remapped layers (LDR)
const int maskOffset
polygon can exceed the image maximal maskOffset pixels in each direction bigger polygons will be clip...
Definition: Mask.h:44
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
virtual void updateWhiteBalance(double redFactor, double blueFactor)
update the global white balace of the panorama by multiplying the red and blue factor of each image w...
Definition: Panorama.cpp:2090
double X
std::string imgFilePrefix
Definition: Panorama.h:689
#define DEBUG_TRACE(msg)
Definition: utils.h:67
void setFilePrefix(std::string prefix)
sets the path prefix of the images reffered with relative paths
Definition: Panorama.h:664
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Definition: Panorama.cpp:311
std::string outputImageTypeHDRCompression
vigra::Rect2D centerCropImage(unsigned int imgNr)
return the centered crop for given image
Definition: Panorama.cpp:1167
bool outputHDRLayers
save remapped layers (HDR)
std::set< std::string > m_ptoptimizerVarNames
Definition: Panorama.h:701
Somewhere to specify what variables belong to what.
bool m_forceImagesUpdate
Definition: Panorama.h:699
const std::string & getName() const
void swapImages(unsigned int img1, unsigned int img2)
swap images.
Definition: Panorama.cpp:1380
bool getIntParam(T &value, const std::string &line, const std::string &name)
std::vector< SrcPanoImage * > images
The images inside the panorama.
Definition: Panorama.h:90
int getNextCPTypeLineNumber() const
get the number of a control point
Definition: Panorama.cpp:2010
a variable has a value and a name.
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
virtual bool setMementoToCopyOf(const PanoramaDataMemento *const memento)
set the internal state
Definition: Panorama.cpp:1484
void updateLineCtrlPoints()
assign new mode line numbers, if required
Definition: Panorama.cpp:471
void setProjectionParameters(const std::vector< double > &params)
set the optional parameters (they need to be of the correct size)
void calculate(unsigned int steps)
does the calculation, for each image steps*steps points are extracted and tested with all other image...
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
static char * line
Definition: svm.cpp:2784
double TranslationPlanePitch
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
int optSwitch
stores the optimizer switch, use OR of HuginBase::OptimizerSwitches
Definition: Panorama.h:103
std::string outputImageTypeCompression
PanoramaOptions options
Definition: Panorama.h:99
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
Definition: ROIImage.h:300
void setOptimizerSwitch(const int newSwitch)
set optimizer master switch
Definition: Panorama.cpp:303
bool getPTParam(std::string &output, const std::string &line, const std::string &parameter)
helper functions for parsing of a script line
represents a control point
Definition: ControlPoint.h:38
virtual void updateVariables(const VariableMapVector &vars)
Set the variables.
Definition: Panorama.cpp:171
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
Definition: Panorama.cpp:297
static FileFormat getFormatFromName(const std::string &name)
returns the FileFormat corrosponding to name.
bool outputLDRExposureBlended
&lt; save exposure fused stacks (no exposure adjustment)
int optPhotoSwitch
stores the photometric optimizer switch, use OR of HuginBase::OptimizerSwitches
Definition: Panorama.h:105
bool stringToUInt(const std::string &s, unsigned int &val)
convert string to unsigned integer value, returns true, if sucessful
Definition: utils.cpp:280
VectorPolygon getMaskPolygon() const
returns vector with coordinates of the polygon
Definition: Mask.h:81
Panorama duplicate() const
duplicate the panorama
Definition: Panorama.cpp:1653
#define check_stack_link(name)
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
virtual void UpdateCropFactor(UIntSet imgs, double newCropFactor)
updates the crop factor, try to keep focal length constant
Definition: Panorama.cpp:254
int FindStackNumberForImage(const std::vector< UIntSet > &imageGroups, const unsigned int imgNr)
Definition: Panorama.cpp:1778
std::vector< VariableMap > VariableMapVector
#define DEBUG_WARN(msg)
Definition: utils.h:74
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
Definition: Panorama.cpp:2181
Model for a panorama.
Definition: Panorama.h:152
virtual void setDirty(const bool &dirty=true)
Definition: DocumentData.h:57
void setInverted(const bool inverted)
set mask to normal or inverted
Definition: Mask.h:89
empirical model of response
Definition: SrcPanoImage.h:100
bool outputLDRBlended
save blended panorama (LDR)
ConstImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition: Panorama.cpp:381
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition: Panorama.h:454
bool loadPTScript(std::istream &i, int &ptoVersion, const std::string &prefix="")
load a Hugin file
some definitions to work with optimizer master switches
VariableMapVector getVariables() const
get variables of this panorama
Definition: Panorama.cpp:118
const VariableMap getImageVariables(unsigned int imgNr) const
Get the variables of an image.
Definition: Panorama.cpp:128
int getTotalWindingNumber() const
returns the total winding number of the polygon
Definition: Mask.cpp:84
void transformPolygon(const PTools::Transform &trans)
transforms the polygon coordinates by the given transformation
Definition: Mask.cpp:164
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
double TranslationPlaneYaw
void createInvTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
create image-&gt;pano transformation
std::vector< unsigned int > getCtrlPointsForImage(unsigned int imgNr) const
return all control points for a given image.
Definition: Panorama.cpp:83
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
Map::mapped_type & map_get(Map &m, const typename Map::key_type &key)
get a map element.
Definition: stl_utils.h:98
void centerCrop(unsigned int imgNr)
center the crop for given image and all linked images
Definition: Panorama.cpp:1184
vigra_ext::Interpolator interpolator
UIntSet getOverlapForImage(unsigned int i) const
returns a set of images which overlap with given image number
MaskType
enumeration with type of possible masks
Definition: Mask.h:56
virtual void setOptions(const PanoramaOptions &opt)=0
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
void changeControlPoint(unsigned int pNr, const ControlPoint &point)
change a control Point.
Definition: Panorama.cpp:434
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
void clearObservers()
remove all panorama observers.
Definition: Panorama.cpp:1558
virtual const PanoramaOptions & getOptions() const =0
returns the options for this panorama
int bands
number of bands of first image (without alpha channel), currently we can&#39;t mix grayscale and RGB imag...
Definition: Panorama.h:95
bool outputHDRBlended
save blended panorama (HDR)
void activateImage(unsigned int imgNr, bool active=true)
mark an image as active or inactive.
Definition: Panorama.cpp:1575
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
Make an ImageVariableGroup for lenses and other common concepts.
void setImageFilename(unsigned int img, const std::string &fname)
set a new image filename
Definition: Panorama.cpp:373
const bool hasPendingChanges() const
return if the panorama class has pending changes normally all controls listen to panoramaChanges noti...
Definition: Panorama.cpp:1563
Model for a panorama.
Definition: PanoramaData.h:81
bool clipPolygon(const vigra::Rect2D rect)
clips the polygon to the given rectangle
Definition: Mask.cpp:325
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
Definition: utils.cpp:264
void removeImage(unsigned int nr)
creates an image, from filename, and a Lens, if needed
Definition: Panorama.cpp:329
void printScriptLine(std::ostream &o, bool forPTOptimizer=false) const
double getValue() const
std::vector< MaskPolygon > MaskPolygonVector
Definition: Mask.h:147
CPointVector getCtrlPointsVectorForImage(unsigned int imgNr) const
return a vector of std::pairs with global ctrl point nr and ControlPoint In the class ControlPoint th...
Definition: Panorama.cpp:96
#define DEBUG_ERROR(msg)
Definition: utils.h:76
void setROI(const vigra::Rect2D &val)
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition: Panorama.cpp:319
OptimizeVector optvec
Definition: Panorama.h:101
void changeFinished()
notify observers about changes in this class
Definition: Panorama.h:564
virtual PanoramaDataMemento * getNewMemento() const
get the internal state
Definition: Panorama.cpp:1526
const std::string getICCProfileDesc() const
return description of icc profile used for pano
Definition: Panorama.cpp:1598
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
std::vector< CPoint > CPointVector
Definition: ControlPoint.h:102
std::map< std::string, Variable > VariableMap
void updateMasks(bool convertPosMaskToNeg=false)
updates all active masks
Definition: Panorama.cpp:988
void transferMask(MaskPolygon mask, unsigned int imgNr, const UIntSet &targetImgs)
transfers given mask from image imgNr to all targetImgs
Definition: Panorama.cpp:890
Same as above, but use a non const panorama.
bool outputLDRExposureLayers
save blended exposure layers, do not perform fusion (no exposure adjustment)
PanoramaMemento getMemento() const
get the internal state
Definition: Panorama.h:602
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
void setImgNr(const unsigned int newImgNr)
sets the associated image number, only used when loading a project, otherwise discarded ...
Definition: Mask.h:87
Convenience functions for SrcPanoImage to use on the image variables.
void setICCProfileDesc(const std::string &newDesc)
sets the icc profile description for check of same profile
Definition: Panorama.cpp:1603
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
this handler class will receive change events from the Panorama.
Definition: PanoramaData.h:401
const int getPhotometricOptimizerSwitch() const
return the photometric optimizer master switch
Definition: Panorama.h:467
void updateCropMode(unsigned int imgNr)
update the crop mode in dependence of crop rect and lens projection
Definition: Panorama.cpp:1147
double Y
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
bool outputLDRExposureRemapped
save remapped layers (no exposure adjustment)
definitions of classes to calculate overlap between different images
const std::vector< double > & getProjectionParameters() const
Get the optional projection parameters.
Memento class for a Panorama object.
Definition: Panorama.h:49
void removeDuplicateCtrlPoints()
removes duplicates control points
Definition: Panorama.cpp:406
bool outputLDRExposureLayersFused
save blended exposure layers which are then fused (no exposure adjustment)
static T max(T x, T y)
Definition: svm.cpp:65
const int getOptimizerSwitch() const
returns optimizer master switch
Definition: Panorama.h:461
double Z
Memento class for a PanoramaData object.
Definition: PanoramaData.h:443
void setMaskType(const MaskType newType)
sets mask type
Definition: Mask.h:77
Holds transformations for Image -&gt; Pano and the other way.
UIntSet changedImages
the images that have been changed since the last changeFinished()
Definition: Panorama.h:697
double Roll
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
bool isPositive() const
returns true, if mask type is positive
Definition: Mask.cpp:97
bool dirty
this indicates that there are unsaved changes
Definition: Panorama.h:692
void subSample(const double max_distance)
subsamples the polygon, so that the longest distance between 2 points is max_distance ...
Definition: Mask.cpp:179
void removeCtrlPoint(unsigned int pNr)
remove a control point.
Definition: Panorama.cpp:391
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
static void info(const char *fmt,...)
Definition: svm.cpp:95
std::vector< std::set< std::string > > OptimizeVector
class for calculating overlap of images
bool getDoubleParam(double &d, const std::string &line, const std::string &name)
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition: stl_utils.h:81
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.
void printPanoramaScript(std::ostream &o, const OptimizeVector &optvars, const PanoramaOptions &options, const UIntSet &imgs, bool forPTOptimizer, const std::string &stripPrefix="") const
create an optimizer script
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
PanoramaMemento & operator=(const PanoramaMemento &o)
assignment operator
void setNrOfBands(const int nrBands)
sets the number of bands
Definition: Panorama.cpp:1613
Interpolator
enum with all interpolation methods
Definition: Interpolators.h:78
void updateMasksForImage(unsigned int imgNr, MaskPolygonVector newMasks)
set complete mask list for image with number
Definition: Panorama.cpp:882
All variables of a source image.
Definition: SrcPanoImage.h:194
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
Panorama image options.
bool outputHDRStacks
save image stacks (HDR)
virtual void updateVariable(unsigned int imgNr, const Variable &var)
update a single variable
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
Definition: Panorama.cpp:2137
This file specifies what image variables SrcPanoImg should have.
const double getMaxExposureDifference() const
returns the maximum exposure value difference of all images in the project
Definition: Panorama.cpp:2120
evaluate y, points are on a horizontal line
Definition: ControlPoint.h:48
static T min(T x, T y)
Definition: svm.cpp:62
void reset()
clear the internal state.
Definition: Panorama.cpp:69
PanoramaMemento state
Definition: Panorama.h:694
BlendingMechanism blendMode
void mirror()
swap (image1Nr,x1,y1) with (image2Nr,x2,y2)
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano-&gt;image transformation
base class, which stores one mask polygon
Definition: Mask.h:52
std::string iccProfileDesc
description of the icc profile
Definition: Panorama.h:92
PanoramaData * getUnlinkedSubset(UIntSetVector &imageGroups) const
get a panorama, which does not contain images linked with positions, the cps are moved to the first i...
Definition: Panorama.cpp:1790
void mergePanorama(const Panorama &newPano)
merges the panorama with the given pano
void limitToImages(UIntSet img)
limits the calculation of the overlap to given image numbers
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
double Pitch
void printStitcherScript(std::ostream &o, const PanoramaOptions &target, const UIntSet &imgs) const
create the stitcher script
Definition: Panorama.cpp:778
BaseSrcPanoImage::Projection LensProjectionFormat
Definition: Lens.h:47
virtual void UpdateFocalLength(UIntSet imgs, double newFocalLength)
updates the focal length by changing hfov
Definition: Panorama.cpp:227