Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
wxPanoCommand.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
27 #include "hugin_config.h"
28 
29 #include "panoinc_WX.h"
30 #include "panoinc.h"
31 #include <wx/window.h>
32 #include "wxPlatform.h"
33 #include "LensTools.h"
34 
35 #include "wxImageCache.h"
36 #include "platform.h"
37 #include "wxPanoCommand.h"
38 #include "HFOVDialog.h"
39 #include "wxutils.h"
41 
42 #include <vigra/cornerdetection.hxx>
43 #include <vigra/localminmax.hxx>
45 
46 #include <hugin_utils/alphanum.h>
47 
48 #ifdef HUGIN_HSI
50 #endif
51 
52 namespace PanoCommand
53 {
54 
56 {
57  // TODO: rewrite, and use same function for modular image creation.
58  const HuginBase::SrcPanoImage & i1 = pano.getImage(img1);
59  const HuginBase::SrcPanoImage & i2 = pano.getImage(img1);
60 
61  // run both images through the harris corner detector
62  ImageCache::EntryPtr eptr = ImageCache::getInstance().getSmallImage(i1.getFilename());
63 
64  vigra::BImage leftImg(eptr->get8BitImage()->size());
65 
66  vigra::GreenAccessor<vigra::RGBValue<vigra::UInt8> > ga;
67  vigra::copyImage(srcImageRange(*(eptr->get8BitImage()), ga ),
68  destImage(leftImg));
69 
70  double scale = i1.getSize().width() / (double) leftImg.width();
71 
72  //const vigra::BImage & leftImg = ImageCache::getInstance().getPyramidImage(
73  // i1.getFilename(),1);
74 
75  vigra::BImage leftCorners(leftImg.size());
76  vigra::FImage leftCornerResponse(leftImg.size());
77 
78  // empty corner image
79  leftCorners.init(0);
80 
81  DEBUG_DEBUG("running corner detector threshold: " << cornerThreshold << " scale: " << scale );
82 
83  // find corner response at scale scale
84  vigra::cornerResponseFunction(srcImageRange(leftImg),
85  destImage(leftCornerResponse),
86  scale);
87 
88  // saveScaledImage(leftCornerResponse,"corner_response.png");
89  DEBUG_DEBUG("finding local maxima");
90  // find local maxima of corner response, mark with 1
91  vigra::localMaxima(vigra::srcImageRange(leftCornerResponse), vigra::destImage(leftCorners), 255);
92 
93 // exportImage(srcImageRange(leftCorners), vigra::ImageExportInfo("c:/corner_response_maxima.png"));
94 
95  DEBUG_DEBUG("thresholding corner response");
96  // threshold corner response to keep only strong corners (above 400.0)
97  vigra::transformImage(vigra::srcImageRange(leftCornerResponse), vigra::destImage(leftCornerResponse),
98  vigra::Threshold<double, double>(
99  cornerThreshold, DBL_MAX, 0.0, 1.0));
100 
101  vigra::combineTwoImages(srcImageRange(leftCorners), srcImage(leftCornerResponse),
102  destImage(leftCorners), std::multiplies<float>());
103 
104 // exportImage(srcImageRange(leftCorners), vigra::ImageExportInfo("c:/corner_response_threshold.png"));
105 
106  // create transform from img1 -> sphere
107  HuginBase::PTools::Transform img1ToSphere;
108  HuginBase::PTools::Transform sphereToImg2;
109 
112  opts.setHFOV(360);
113  opts.setWidth(360);
114  opts.setVFOV(180);
115 
116  img1ToSphere.createInvTransform(pano, img1, opts);
117  sphereToImg2.createTransform(pano, img2, opts);
118 
119 
120  int border = 5;
121  double sphx, sphy;
122  double img2x, img2y;
123  // need to scale the images.
124  // sample grid on img1 and try to add ctrl points
125  for (unsigned int x=0; x < (unsigned int)leftImg.width(); x++ ) {
126  for (unsigned int y=0; y < (unsigned int)leftImg.height(); y++) {
127  if (leftCorners(x,y) > 0) {
128  img1ToSphere.transformImgCoord(sphx, sphy, scale*x, scale*y);
129  sphereToImg2.transformImgCoord(img2x, img2y, sphx, sphy);
130  // check if it is inside..
131  if ( img2x > border && img2x < i2.getWidth() - border
132  && img2y > border && img2y < i2.getHeight() - border )
133  {
134  // add control point
135  HuginBase::ControlPoint p(img1, scale*x, scale*y, img2, img2x, img2y);
136  pano.addCtrlPoint(p);
137  }
138  }
139  }
140  }
142  return true;
143 }
144 
146 {
147  double redBal=1;
148  double blueBal=1;
149  if(pano.getNrOfImages()>=1)
150  {
151  const HuginBase::SrcPanoImage &anchor = pano.getImage(pano.getOptions().colorReferenceImage);
152  // use EXIF Red/BlueBalance data only if image and anchor image are from the same camera
153  if(srcImg.getExifMake() == anchor.getExifMake() &&
154  srcImg.getExifModel() == anchor.getExifModel())
155  {
156  double redBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifRedBalance();
157  double blueBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifBlueBalance();
158  if(fabs(redBalanceAnchor)<1e-2)
159  {
160  redBalanceAnchor=1;
161  };
162  if(fabs(blueBalanceAnchor)<1e-2)
163  {
164  blueBalanceAnchor=1;
165  };
166  redBal=fabs(srcImg.getExifRedBalance()/redBalanceAnchor);
167  blueBal=fabs(srcImg.getExifBlueBalance()/blueBalanceAnchor);
168  if(redBal<1e-2)
169  {
170  redBal=1;
171  };
172  if(blueBal<1e-2)
173  {
174  blueBal=1;
175  };
176  };
177  }
178  srcImg.setWhiteBalanceRed(redBal);
179  srcImg.setWhiteBalanceBlue(blueBal);
180 };
181 
182 bool getLensDataFromUser(wxWindow * parent, HuginBase::SrcPanoImage & srcImg)
183 {
184  // display lens dialog
185  HFOVDialog dlg(parent, srcImg);
186  dlg.CenterOnParent();
187  int ret = dlg.ShowModal();
188  if (ret == wxID_OK)
189  {
190  // assume a cancel dialog.
191  srcImg = dlg.GetSrcImage();
192  if (dlg.GetCropFactor() <= 0)
193  {
194  srcImg.setCropFactor(1);
195  }
196  return true;
197  }
198  else {
199  return false;
200  }
201 }
202 
204 std::string GetICCProfileNameChecked(const std::string& iccName)
205 {
206  // if no icc profile given assume sRGB profile
207  if (iccName.empty())
208  {
209  return "sRGB";
210  };
211  // all profiles starting with sRGB are assumed the same
212  // even if there small? differences between them
213  if (iccName.compare(0, 4, "sRGB") == 0)
214  {
215  return "sRGB";
216  };
217  // otherwise return full name
218  return iccName;
219 }
221 {
222  // check if the files should be sorted by date
223  const long sort = wxConfigBase::Get()->Read("General/SortNewImgOnAdd", HUGIN_GUI_SORT_NEW_IMG_ON_ADD);
224 
225  switch (sort) {
226  case 1:
227  // sort by filename
228  std::sort(files.begin(), files.end(), doj::alphanum_less());
229  break;
230  case 2:
231  // sort by date
232  std::sort(files.begin(), files.end(), FileIsNewer());
233  break;
234  default:
235  // no or unknown sort method
236  break;
237  }
238 
239  HuginBase::StandardImageVariableGroups variable_groups(pano);
240  HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
241  const size_t oldImgCount = pano.getNrOfImages();
242 
243  // load additional images...
244  for (const auto& filename: files)
245  {
247  wxString fname(filename.c_str(), HUGIN_CONV_FILENAME);
248 
249  // try to read settings automatically.
250  srcImg.setFilename(filename);
251  try
252  {
253  vigra::ImageImportInfo info(filename.c_str());
254  if(info.width()==0 || info.height()==0)
255  {
256  hugin_utils::HuginMessageBox(wxString::Format(_("Could not decode image:\n%s\nAbort"), fname.c_str()), _("Hugin"), wxOK | wxICON_HAND, wxGetActiveWindow());
257  return false;
258  };
259  srcImg.setSize(info.size());
260  const std::string pixelType=info.getPixelType();
261  // refuse black/white images
262  if (pixelType == "BILEVEL")
263  {
264  hugin_utils::HuginMessageBox(wxString::Format(_("File \"%s\" is a black/white image.\nHugin does not support this image type. Skipping this image.\nConvert image to grayscale image and try loading again."), fname.c_str()),
265  _("Hugin"), wxOK|wxICON_EXCLAMATION, wxGetActiveWindow());
266  continue;
267  }
268  // check if images is grayscale or RGB image, maybe with alpha channel
269  // reject CMYK or other images
270  const int bands = info.numBands();
271  const int extraBands = info.numExtraBands();
272  if (bands != 1 && bands != 3 && !(bands == 2 && extraBands == 1) && !(bands == 4 && extraBands == 1))
273  {
274  hugin_utils::HuginMessageBox(wxString::Format(_("Hugin supports only grayscale and RGB images (without and with alpha channel).\nBut file \"%s\" has %d channels and %d extra channels (probably alpha channels).\nHugin does not support this image type. Skipping this image.\nConvert this image to grayscale or RGB image and try loading again."), fname.c_str(), bands, extraBands),
275  _("Hugin"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
276  continue;
277  };
278  if (pano.getNrOfImages() == 0)
279  {
280  pano.setNrOfBands(bands - extraBands);
281  };
282  if (pano.getNrOfBands() != bands - extraBands)
283  {
284  wxString s(_("Hugin supports only grayscale or RGB images (without and with alpha channel)."));
285  s.Append("\n");
286  if (pano.getNrOfBands() == 3)
287  {
288  s.Append(wxString::Format(_("File \"%s\" is a grayscale image, but other images in project are color images."), fname.c_str()));
289  }
290  else
291  {
292  s.Append(wxString::Format(_("File \"%s\" is a color image, but other images in project are grayscale images."), fname.c_str()));
293  };
294  s.Append("\n");
295  s.Append(_("Hugin does not support this mixing. Skipping this image.\nConvert this image to grayscale or RGB image respectively and try loading again."));
296  hugin_utils::HuginMessageBox(s, _("Warning"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
297  continue;
298  };
299  if ((pixelType == "UINT8") || (pixelType == "UINT16") || (pixelType == "INT16"))
300  {
301  if (hugin_utils::IsLinearICCProfile(info.getICCProfile()))
302  {
303  srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
304  }
305  else
306  {
307  srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR);
308  }
309  }
310  else
311  srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
312  if (pano.getNrOfImages() > 0)
313  {
314  const std::string newICCProfileDesc = hugin_utils::GetICCDesc(info.getICCProfile());
315  if (GetICCProfileNameChecked(newICCProfileDesc) != GetICCProfileNameChecked(pano.getICCProfileDesc()))
316  {
317  // icc profiles does not match
318  wxString warning;
319  if (newICCProfileDesc.empty())
320  {
321  warning = wxString::Format(_("File \"%s\" has no embedded icc profile, but other images in project have profile \"%s\" embedded."), fname.c_str(), wxString(pano.getICCProfileDesc().c_str(), wxConvLocal).c_str());
322  }
323  else
324  {
325  if (pano.getICCProfileDesc().empty())
326  {
327  warning = wxString::Format(_("File \"%s\" has icc profile \"%s\" embedded, but other images in project have no embedded color profile."), fname.c_str(), wxString(newICCProfileDesc.c_str(), wxConvLocal).c_str());
328  }
329  else
330  {
331  warning = wxString::Format(_("File \"%s\" has icc profile \"%s\" embedded, but other images in project have color profile \"%s\" embedded."), fname.c_str(), wxString(newICCProfileDesc.c_str(), wxConvLocal).c_str(), wxString(pano.getICCProfileDesc().c_str(), wxConvLocal).c_str());
332  }
333  }
334  warning.Append("\n");
335  warning.Append(_("Hugin expects all images in the same color profile.\nPlease convert all images to same color profile and try again."));
336  hugin_utils::HuginMessageBox(warning, _("Hugin"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
337  continue;
338  }
339  }
340  else
341  {
342  // remember icc profile name
343  if (!info.getICCProfile().empty())
344  {
345  pano.setICCProfileDesc(hugin_utils::GetICCDesc(info.getICCProfile()));
346  }
347  else
348  {
349  pano.setICCProfileDesc("");
350  };
351  }
352  }
353  catch(std::exception & e)
354  {
355  std::cerr << "ERROR: caught exception: " << e.what() << std::endl;
356  std::cerr << "Could not get pixel type for file " << filename << std::endl;
357  hugin_utils::HuginMessageBox(wxString::Format(_("Could not decode image:\n%s\nAbort"), fname.c_str()), _("Hugin"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
358  return false;
359  };
360  bool ok = srcImg.readEXIF();
361  if(ok)
362  {
363  ok = srcImg.applyEXIFValues();
364  // load crop factor from database if unknown
365  if (srcImg.getCropFactor()<0.1)
366  {
367  srcImg.readCropfactorFromDB();
368  ok=(srcImg.getExifFocalLength()>0 && srcImg.getCropFactor()>0.1);
369  };
370  if (srcImg.getProjection() != HuginBase::BaseSrcPanoImage::EQUIRECTANGULAR)
371  {
372  // if projection is equirectangular, we loaded info from gpano tags
373  // in this case we don't need to look up the database
374  const bool ignoreFovRectilinear = wxConfigBase::Get()->Read("/General/IgnoreFovRectilinearOnAdd", 1l) == 1l;
375  srcImg.readProjectionFromDB(ignoreFovRectilinear);
376  };
377  };
378  // set preferred projection if requested
379  if (m_preferredLensType != -1)
380  {
381  srcImg.setProjection(static_cast<HuginBase::BaseSrcPanoImage::Projection>(m_preferredLensType));
382  };
383  // save EXIF data for later to prevent double loading of EXIF data
384  applyColorBalanceValue(srcImg, pano);
385  if (! ok ) {
386  // search for image with matching size and exif data
387  // and re-use it.
388  bool added = false;
389  for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
390  HuginBase::SrcPanoImage other = pano.getSrcImage(i);
391  if ( other.getSize() == srcImg.getSize() &&
392  other.getExifModel() == srcImg.getExifModel() &&
393  other.getExifMake() == srcImg.getExifMake() &&
394  other.getExifFocalLength() == srcImg.getExifFocalLength()
395  )
396  {
397  // add image
398  if (srcImg.getCropFactor() <= 0.1)
399  {
400  // set crop factor to 1 if not set
401  srcImg.setCropFactor(other.getCropFactor());
402  };
403  int imgNr = pano.addImage(srcImg);
404  variable_groups.update();
405  lenses.switchParts(imgNr, lenses.getPartNumber(i));
406  added=true;
407  break;
408  }
409  }
410  if (added) continue;
411  }
412  int matchingLensNr=-1;
413  // if no similar image found, ask user
414  if (! ok) {
415  if (!getLensDataFromUser(wxGetActiveWindow(), srcImg)) {
416  // assume a standard lens
417  srcImg.setHFOV(50);
418  srcImg.setCropFactor(1);
419  }
420  }
421 
422  // check the image hasn't disappeared on us since the HFOV dialog was
423  // opened
424  wxString fn(srcImg.getFilename().c_str(),HUGIN_CONV_FILENAME);
425  if (!wxFileName::FileExists(fn)) {
426  DEBUG_INFO("Image: " << fn.mb_str() << " has disappeared, skipping...");
427  continue;
428  }
429 
430  // FIXME: check if the exif information
431  // indicates this image matches a already used lens
432  variable_groups.update();
433  double ev = 0;
434  bool set_exposure = false;
435  for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
436  HuginBase::SrcPanoImage other = pano.getSrcImage(i);
437  if (other.getExifFocalLength()>0) {
438  if (other.getSize() == srcImg.getSize()
439  && other.getExifModel() == srcImg.getExifModel()
440  && other.getExifMake() == srcImg.getExifMake()
441  && other.getExifFocalLength() == srcImg.getExifFocalLength()
442  // Smartphone cameras can have different crop factors, take also this case into account
443  && other.getCropFactor() == srcImg.getCropFactor()
444  )
445  {
446  matchingLensNr = lenses.getPartNumber(i);
447  break;
448  }
449  }
450  else
451  {
452  // no exiv information, just check image size.
453  if (other.getSize() == srcImg.getSize() )
454  {
455  matchingLensNr = lenses.getPartNumber(i);
456  break;
457  }
458  }
459  }
460 
461  // If matchingLensNr == -1 still, we haven't found a good lens to use.
462  // We shouldn't attach the image to a lens in this case, it will have
463  // its own new lens.
464  int imgNr = pano.addImage(srcImg);
465  variable_groups.update();
466  if (matchingLensNr != -1)
467  {
468  lenses.switchParts(imgNr, matchingLensNr);
469  }
470  if (imgNr == 0) {
471  // get initial value for output exposure
473  opts.outputExposureValue = srcImg.getExposureValue();
474  pano.setOptions(opts);
475  }
476  }
477  if (pano.hasPossibleStacks())
478  {
479  wxString message;
480  if (oldImgCount == 0)
481  {
482  // all images added
483  message = _("Hugin has image stacks detected in the added images and will assign corresponding stack numbers to the images.");
484  }
485  else
486  {
487  message = _("Hugin has image stacks detected in the whole project. Stack numbers will be re-assigned on base of this detection. Existing stack assignments will be overwritten.");
488  };
489  message.append("\n");
490  message.append(_("Should the position of images in each stack be linked?"));
491  hugin_utils::MessageDialog dialog = hugin_utils::GetMessageDialog(message, _("Hugin"), wxICON_EXCLAMATION | wxYES_NO | wxCANCEL, wxGetActiveWindow());
492  dialog->SetExtendedMessage(_("When shooting bracketed image stacks from a sturdy tripod the position of the images in each stack can be linked to help Hugin to process the panorama. But if the images in each stack require a fine tune of the position (e. g. when shooting hand held), then don't link the position."));
493  if (oldImgCount == 0)
494  {
495  dialog->SetYesNoCancelLabels(_("Link position"), _("Don't link position"), _("Don't assign stacks"));
496  }
497  else
498  {
499  dialog->SetYesNoCancelLabels(_("Link position"), _("Don't link position"), _("Keep existing stacks"));
500  };
501  switch (dialog->ShowModal())
502  {
503  case wxID_OK:
504  case wxID_YES:
505  pano.linkPossibleStacks(true);
506  break;
507  case wxID_NO:
508  pano.linkPossibleStacks(false);
509  break;
510  };
511  }
512  else
513  {
514  bool hasStacks = false;
515  for (size_t i = 0; i<pano.getNrOfImages(); i++)
516  {
517  if (pano.getImage(i).StackisLinked())
518  {
519  hasStacks = true;
520  break;
521  };
522  };
523  wxConfigBase* config = wxConfigBase::Get();
524  bool showExposureWarning = config->Read("/ShowExposureWarning", 1l) == 1l;
525  if (!hasStacks && pano.getMaxExposureDifference() > 2 && showExposureWarning)
526  {
527  wxDialog dlg;
528  wxXmlResource::Get()->LoadDialog(&dlg, NULL, "warning_exposure_dlg");
529  if (dlg.ShowModal() == wxID_OK)
530  {
531  if (XRCCTRL(dlg, "dont_show_again_checkbox", wxCheckBox)->GetValue())
532  {
533  config->Write("/ShowExposureWarning", 0l);
534  }
535  else
536  {
537  config->Write("/ShowExposureWarning", 1l);
538  };
539  config->Flush();
540  }
541  };
542  };
543  return true;
544 }
545 
546 
548 {
550  int ptoVersion = 0;
551  std::ifstream in(filename.c_str());
552  if (newPano.loadPTScript(in, ptoVersion, prefix))
553  {
554  pano.setMemento(newPano);
556  // always reset to TIFF_m ...
558  // get enblend and enfuse options from preferences
559  if (ptoVersion < 2)
560  {
561  // no options stored in file, use default arguments in config file
562  opts.enblendOptions = wxConfigBase::Get()->Read("/Enblend/Args", HUGIN_ENBLEND_ARGS).mb_str(wxConvLocal);
563  opts.enfuseOptions = wxConfigBase::Get()->Read("/Enfuse/Args", HUGIN_ENFUSE_ARGS).mb_str(wxConvLocal);
564  }
565  // Set the nona gpu flag base on what is in preferences as it is not
566  // stored in the file.
567  opts.remapUsingGPU = wxConfigBase::Get()->Read("/Nona/UseGPU",HUGIN_NONA_USEGPU) == 1;
568  pano.setOptions(opts);
569 
570  HuginBase::StandardImageVariableGroups variableGroups(pano);
571  HuginBase::ImageVariableGroup & lenses = variableGroups.getLenses();
572 
573  unsigned int nImg = pano.getNrOfImages();
574  wxString basedir;
575  bool autopanoSiftFile=false;
576  HuginBase::SrcPanoImage autopanoSiftRefImg;
577  HuginBase::VariableMapVector vars(nImg);
578  for (unsigned int i = 0; i < nImg; i++) {
579  wxFileName fname(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
580  while (! fname.FileExists()){
581  // Is file in the new path
582  if (basedir != wxEmptyString) {
583  DEBUG_DEBUG("Old filename: " << pano.getImage(i).getFilename());
584  std::string fn = hugin_utils::stripPath(pano.getImage(i).getFilename());
585  DEBUG_DEBUG("Old filename, without path): " << fn);
586  wxString newname(fn.c_str(), HUGIN_CONV_FILENAME);
587  // GetFullName does only work with local paths (not compatible across platforms)
588 // wxString newname = fname.GetFullName();
589  fname.AssignDir(basedir);
590  fname.SetFullName(newname);
591  DEBUG_TRACE("filename with new path: " << fname.GetFullPath().mb_str(wxConvLocal));
592  if (fname.FileExists()) {
593  pano.setImageFilename(i, (const char *)fname.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
594  DEBUG_TRACE("New filename set: " << fname.GetFullPath().mb_str(wxConvLocal));
595  // TODO - set pano dirty flag so that new paths are saved
596  continue;
597  }
598  }
599 
600  hugin_utils::HuginMessageBox(wxString::Format(_("The project file \"%s\" refers to image \"%s\" which was not found.\nPlease manually select the correct image."), filename, fname.GetFullPath()), _("Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
601 
602  if (basedir == wxEmptyString) {
603  basedir = fname.GetPath();
604  }
605 
606  // open file dialog
607  wxFileDialog dlg(wxGetActiveWindow(), wxString::Format(_("Select image %s"), fname.GetFullName()),
608  basedir, fname.GetFullName(),
609  GetFileDialogImageFilters(), wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_PREVIEW, wxDefaultPosition);
610  dlg.SetDirectory(basedir);
611  if (dlg.ShowModal() == wxID_OK) {
612  pano.setImageFilename(i, (const char *)dlg.GetPath().mb_str(HUGIN_CONV_FILENAME));
613  // save used path
614  basedir = dlg.GetDirectory();
615  DEBUG_INFO("basedir is: " << basedir.mb_str(wxConvLocal));
616  } else {
617  HuginBase::PanoramaMemento emptyPano;
618  pano.setMemento(emptyPano);
619  // set an empty panorama
620  return true;
621  }
622  fname.Assign(dlg.GetPath());
623  }
624  // check if image size is correct
625  HuginBase::SrcPanoImage srcImg = pano.getSrcImage(i);
626  //
627  vigra::ImageImportInfo imginfo(srcImg.getFilename().c_str());
628  if (srcImg.getSize() != imginfo.size()) {
629  // adjust size properly.
630  srcImg.resize(imginfo.size(), &vars[i]);
631  }
632  // check if script contains invalid HFOV
633  double hfov = pano.getImage(i).getHFOV();
634  if (pano.getImage(i).getProjection() == HuginBase::SrcPanoImage::RECTILINEAR
635  && hfov >= 180 && autopanoSiftFile == false)
636  {
637  autopanoSiftFile = true;
638  // something is wrong here, try to read from exif data (all images)
639  bool ok = srcImg.readEXIF();
640  if(ok) {
641  ok = srcImg.applyEXIFValues();
642  };
643  if (! ok) {
644  getLensDataFromUser(wxGetActiveWindow(), srcImg);
645  }
646  autopanoSiftRefImg = srcImg;
647  }
648  else
649  {
650  // load exif data
651  srcImg.readEXIF();
652  if (autopanoSiftFile)
653  {
654  // need to copy the lens parameters from the first lens.
655  srcImg.setHFOV(autopanoSiftRefImg.getHFOV());
656  };
657  };
658  // remember icc profile, only from first image
659  if (i == 0)
660  {
661  pano.setNrOfBands(imginfo.numBands() - imginfo.numExtraBands());
662  pano.setICCProfileDesc(hugin_utils::GetICCDesc(imginfo.getICCProfile()));
663  }
664  pano.setSrcImage(i, srcImg);
665  }
666  // special update routine, when images size changed
667  // and some linked variables needs update after rescaling
668  for (unsigned i = 0; i < nImg; ++i)
669  {
670  if (!vars[i].empty())
671  {
672  pano.updateVariables(i, vars[i]);
673  };
674  };
675  // Link image projection across each lens, since it is not saved.
676  const HuginBase::UIntSetVector imgSetLens = lenses.getPartsSet();
677  for (size_t i = 0; i < imgSetLens.size(); ++i)
678  {
679  const HuginBase::UIntSet imgLens = imgSetLens[i];
680  if (imgLens.size()>1)
681  {
682  HuginBase::UIntSet::const_iterator it = imgLens.begin();
683  const size_t img1 = *it;
684  ++it;
685  do
686  {
687  pano.linkImageVariableProjection(img1, *it);
688  ++it;
689  } while (it != imgLens.end());
690  };
691  };
692  } else {
693  DEBUG_ERROR("could not load panotools script");
694  in.close();
695  return false;
696  };
697  in.close();
698 
699  // Verify control points are valid
700  // loop through entire list of points, confirming they are inside the
701  // bounding box of their images
702  const HuginBase::CPVector & oldCPs = pano.getCtrlPoints();
703  HuginBase::CPVector goodCPs;
704  int bad_cp_count = 0;
705  for (HuginBase::CPVector::const_iterator it = oldCPs.begin();
706  it != oldCPs.end(); ++it)
707  {
708  HuginBase::ControlPoint point = *it;
709  const HuginBase::SrcPanoImage & img1 = pano.getImage(point.image1Nr);
710  const HuginBase::SrcPanoImage & img2 = pano.getImage(point.image2Nr);
711  if (0 > point.x1 || point.x1 > img1.getSize().x ||
712  0 > point.y1 || point.y1 > img1.getSize().y ||
713  0 > point.x2 || point.x2 > img2.getSize().x ||
714  0 > point.y2 || point.y2 > img2.getSize().y)
715  {
716  bad_cp_count++;
717  } else
718  {
719  goodCPs.push_back(point);
720  }
721  }
722 
723  if (bad_cp_count > 0)
724  {
725  wxString errMsg = wxString::Format(_("%d invalid control point(s) found.\n\nPress OK to remove."), bad_cp_count);
726  hugin_utils::HuginMessageBox(errMsg, _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
727  pano.setCtrlPoints(goodCPs);
728  }
729 
730  // check stacks and warn users in case
731  CheckLensStacks(&pano, false);
732  // Update control point error values
734  if(markAsOptimized)
735  {
736  pano.markAsOptimized();
737  };
738  return true;
739 }
740 
742 {
743  pano.reset();
744 
745  // Setup pano with options from preferences
747  wxConfigBase* config = wxConfigBase::Get();
748  opts.quality = config->Read("/output/jpeg_quality",HUGIN_JPEG_QUALITY);
749  switch(config->Read("/output/tiff_compression", HUGIN_TIFF_COMPRESSION))
750  {
751  case 0:
752  default:
753  opts.outputImageTypeCompression = "NONE";
754  opts.tiffCompression = "NONE";
755  break;
756  case 1:
757  opts.outputImageTypeCompression = "PACKBITS";
758  opts.tiffCompression = "PACKBITS";
759  break;
760  case 2:
761  opts.outputImageTypeCompression = "LZW";
762  opts.tiffCompression = "LZW";
763  break;
764  case 3:
765  opts.outputImageTypeCompression = "DEFLATE";
766  opts.tiffCompression = "DEFLATE";
767  break;
768  }
769  switch (config->Read("/output/ldr_format", HUGIN_LDR_OUTPUT_FORMAT)) {
770  case 1:
771  opts.outputImageType ="jpg";
772  break;
773  case 2:
774  opts.outputImageType ="png";
775  break;
776  case 3:
777  opts.outputImageType ="exr";
778  break;
779  default:
780  case 0:
781  opts.outputImageType ="tif";
782  break;
783  }
784  // HDR disabled because there is no real choice at the moment: HDR TIFF is broken and there is only EXR
785  // opts.outputImageTypeHDR = config->Read("/output/hdr_format", HUGIN_HDR_OUTPUT_FORMAT);
787  opts.blendMode = static_cast<HuginBase::PanoramaOptions::BlendingMechanism>(config->Read("/default_blender", HUGIN_DEFAULT_BLENDER));
788  opts.enblendOptions = config->Read("Enblend/Args",HUGIN_ENBLEND_ARGS).mb_str(wxConvLocal);
789  opts.enfuseOptions = config->Read("Enfuse/Args",HUGIN_ENFUSE_ARGS).mb_str(wxConvLocal);
790  opts.verdandiOptions = config->Read("/VerdandiDefaultArgs", wxEmptyString).mb_str(wxConvLocal);
791  opts.interpolator = (vigra_ext::Interpolator)config->Read("Nona/Interpolator",HUGIN_NONA_INTERPOLATOR);
792  opts.remapUsingGPU = config->Read("Nona/useGPU",HUGIN_NONA_USEGPU)!=0;
793  opts.tiff_saveROI = config->Read("Nona/CroppedImages",HUGIN_NONA_CROPPEDIMAGES)!=0;
796  pano.setOptions(opts);
797 
800  return true;
801 }
802 
803 
805 {
806  wxConfigBase* config = wxConfigBase::Get();
807 
808  if (pano.getNrOfImages() == 0) {
809  // TODO: prompt for images!
810  wxString path = config->Read("actualPath", wxEmptyString);
811  wxFileDialog dlg(wxGetActiveWindow(), _("Add images"),
812  path, wxEmptyString,
813  GetFileDialogImageFilters(), wxFD_OPEN|wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST | wxFD_PREVIEW , wxDefaultPosition);
814  dlg.SetDirectory(path);
815 
816  // remember the image extension
817  wxString img_ext;
818  if (config->HasEntry("lastImageType")){
819  img_ext = config->Read("lastImageType").c_str();
820  }
821  if (img_ext == "all images")
822  dlg.SetFilterIndex(0);
823  else if (img_ext == "jpg")
824  dlg.SetFilterIndex(1);
825  else if (img_ext == "tiff")
826  dlg.SetFilterIndex(2);
827  else if (img_ext == "png")
828  dlg.SetFilterIndex(3);
829  else if (img_ext == "hdr")
830  dlg.SetFilterIndex(4);
831  else if (img_ext == "exr")
832  dlg.SetFilterIndex(5);
833  else if (img_ext == "all files")
834  dlg.SetFilterIndex(6);
835  DEBUG_INFO ( "Image extention: " << img_ext.mb_str(wxConvLocal) );
836 
837  // call the file dialog
838  if (dlg.ShowModal() == wxID_OK) {
839  // get the selections
840  wxArrayString Pathnames;
841  dlg.GetPaths(Pathnames);
842 
843  // save the current path to config
844 #ifdef __WXGTK__
845  //workaround a bug in GTK, see https://bugzilla.redhat.com/show_bug.cgi?id=849692 and http://trac.wxwidgets.org/ticket/14525
846  config->Write("/actualPath", wxPathOnly(Pathnames[0]));
847 #else
848  config->Write("/actualPath", dlg.GetDirectory());
849 #endif
850  DEBUG_INFO ( wxString::Format("img_ext: %d", dlg.GetFilterIndex()).mb_str(wxConvLocal) );
851  // save the image extension
852  switch ( dlg.GetFilterIndex() ) {
853  case 0: config->Write("lastImageType", "all images"); break;
854  case 1: config->Write("lastImageType", "jpg"); break;
855  case 2: config->Write("lastImageType", "tiff"); break;
856  case 3: config->Write("lastImageType", "png"); break;
857  case 4: config->Write("lastImageType", "hdr"); break;
858  case 5: config->Write("lastImageType", "exr"); break;
859  case 6: config->Write("lastImageType", "all files"); break;
860  }
861 
862  HuginBase::StandardImageVariableGroups variable_groups(pano);
863  HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
864  // add images.
865  for (unsigned int i=0; i< Pathnames.GetCount(); i++) {
866  std::string filename = (const char *)Pathnames[i].mb_str(HUGIN_CONV_FILENAME);
867  vigra::ImageImportInfo inf(filename.c_str());
869  img.setFilename(filename);
870  img.setSize(inf.size());
871  img.readEXIF();
872  img.applyEXIFValues();
873  int imgNr = pano.addImage(img);
874  lenses.updatePartNumbers();
875  if (i > 0) lenses.switchParts(imgNr, 0);
876  }
877 
878  }
879  }
880 
881  unsigned int nOldImg = pano.getNrOfImages();
882  HuginBase::PanoramaMemento newPanoMem;
883 
884  int ptoVersion = 0;
885  if (newPanoMem.loadPTScript(in, ptoVersion, "")) {
886  HuginBase::Panorama newPano;
887  newPano.setMemento(newPanoMem);
888 
889  unsigned int nNewImg = newPano.getNrOfImages();
890  if (nOldImg != nNewImg) {
891  wxString errMsg = wxString::Format(_("Error, template expects %d images,\ncurrent project contains %d images\n"), nNewImg, nOldImg);
892  hugin_utils::HuginMessageBox(errMsg, _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
893  return false;
894  }
895 
896  // check image sizes, and correct parameters if required.
897  HuginBase::VariableMapVector vars(nNewImg);
898  for (unsigned int i = 0; i < nNewImg; i++) {
899 
900  // check if image size is correct
901  const HuginBase::SrcPanoImage & oldSrcImg = pano.getImage(i);
902  HuginBase::SrcPanoImage newSrcImg = newPano.getSrcImage(i);
903 
904  // just keep the file name
905  DEBUG_DEBUG("apply template fn:" << newSrcImg.getFilename() << " real fn: " << oldSrcImg.getFilename());
906  newSrcImg.setFilename(oldSrcImg.getFilename());
907  if (oldSrcImg.getSize() != newSrcImg.getSize()) {
908  // adjust size properly.
909  newSrcImg.resize(oldSrcImg.getSize(), &(vars[i]));
910  }
911  newPano.setSrcImage(i, newSrcImg);
912  }
913  // now update all possible linked variables
914  // this has to be done separately, otherwise the linked variables
915  // would be updated several times
916  for (unsigned int i = 0; i < nNewImg; ++i)
917  {
918  if (!vars[i].empty())
919  {
920  newPano.updateVariables(i, vars[i]);
921  };
922  };
923  // keep old control points.
924  newPano.setCtrlPoints(pano.getCtrlPoints());
925  newPanoMem = newPano.getMemento();
926  // remmember setting of image type and icc profile
927  const int bands = pano.getNrOfBands();
928  const std::string iccProfile = pano.getICCProfileDesc();
929  pano.setMemento(newPanoMem);
930  pano.setNrOfBands(bands);
931  pano.setICCProfileDesc(iccProfile);
932  } else {
933  hugin_utils::HuginMessageBox(_("Error loading project file"), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
934  }
936  return true;
937 }
938 
939 #ifdef HUGIN_HSI
940 bool PythonScriptPanoCmd::processPanorama(HuginBase::Panorama& pano)
941 {
942  std::cout << "run python script: " << m_scriptFile.c_str() << std::endl;
943 
944  int success = hpi::callhpi ( m_scriptFile.c_str() , 1 ,
945  "HuginBase::Panorama*" , &pano ) ;
946 
947  if(success!=0)
948  hugin_utils::HuginMessageBox(wxString::Format("Script returned %d",success),_("Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
949  std::cout << "Python interface returned " << success << endl ;
950  // notify other of change in panorama
951  if(pano.getNrOfImages()>0)
952  {
953  for(unsigned int i=0;i<pano.getNrOfImages();i++)
954  {
955  pano.imageChanged(i);
956  };
957  };
959  return true;
960 }
961 #endif
962 
963 } // namespace
964 
#define DEBUG_INFO(msg)
Definition: utils.h:69
std::string GetICCDesc(const vigra::ImageImportInfo::ICCProfile &iccProfile)
returns description of given icc profile
Definition: utils.cpp:912
implementation of huginApp Class
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
void imageChanged(unsigned int imgNr)
mark image for change notification.
Definition: Panorama.cpp:1568
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
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
#define HUGIN_NONA_CROPPEDIMAGES
bool applyEXIFValues(bool applyEVValue=true)
apply values found in EXIF data to SrcPanoImage class, call readEXIF() before to initialize some valu...
void setMemento(const PanoramaMemento &memento)
set the internal state
Definition: Panorama.cpp:1507
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
std::vector< std::string > files
Definition: wxPanoCommand.h:57
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
bool IsLinearICCProfile(const vigra::ImageImportInfo::ICCProfile &iccProfile)
return true if icc profile is linear one, otherwise return false
Definition: utils.cpp:940
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
A dialog for HFOV.
Definition: HFOVDialog.h:37
std::unique_ptr< wxMessageDialogBase > MessageDialog
Definition: wxutils.h:90
#define DEBUG_TRACE(msg)
Definition: utils.h:67
#define HUGIN_JPEG_QUALITY
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Definition: Panorama.cpp:311
Somewhere to specify what variables belong to what.
std::string GetICCProfileNameChecked(const std::string &iccName)
return name of icc profile with same checks for comparision
some helper classes for graphes
Functor class to compare two objects with the &quot;Alphanum Algorithm&quot;.
Definition: alphanum.h:65
include file for the hugin project
#define HUGIN_GUI_SORT_NEW_IMG_ON_ADD
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
int getHeight() const
Get the height of the image in pixels.
Definition: SrcPanoImage.h:276
std::string outputImageTypeCompression
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
represents a control point
Definition: ControlPoint.h:38
virtual void updateVariables(const VariableMapVector &vars)
Set the variables.
Definition: Panorama.cpp:171
MessageDialog GetMessageDialog(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:212
bool readProjectionFromDB(const bool ignoreFovRectilinear=true)
tries to read projection and crop area from lens database you need to call SrcPanoImage::readEXIF bef...
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
std::vector< VariableMap > VariableMapVector
void calcCtrlPointErrors(PanoramaData &pano)
Update the Ctrl Point errors without optimizing.
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
Definition: Panorama.cpp:2181
Model for a panorama.
Definition: Panorama.h:152
empirical model of response
Definition: SrcPanoImage.h:100
C++ call interface to hpi.
UIntSetVector getPartsSet() const
return a vector which contains a HuginBase::UIntSet for each group with the corresponding images numb...
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition: Panorama.cpp:381
bool loadPTScript(std::istream &i, int &ptoVersion, const std::string &prefix="")
load a Hugin file
some definitions to work with optimizer master switches
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
void combineTwoImages(SrcImageIterator1 src1_upperleft, SrcImageIterator1 src1_lowerright, SrcAccessor1 src1_acc, SrcImageIterator2 src2_upperleft, SrcAccessor2 src2_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
Definition: openmp_vigra.h:249
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
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
vigra_ext::Interpolator interpolator
int callhpi(const char *plugin_name, int argc,...)
simplified call interface to the Python Plugin facility.
Definition: hpi.cpp:55
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
int getWidth() const
Get the width of the image in pixels.
Definition: SrcPanoImage.h:266
bool getLensDataFromUser(wxWindow *parent, HuginBase::SrcPanoImage &srcImg)
void resize(const vigra::Size2D &size, VariableMap *potentialLinkedVars)
&quot;resize&quot; image, adjusts all distortion coefficients for usage with a source image of size size potent...
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
#define HUGIN_NONA_INTERPOLATOR
#define HUGIN_TIFF_COMPRESSION
wxwindows specific panorama commands
void setImageFilename(unsigned int img, const std::string &fname)
set a new image filename
Definition: Panorama.cpp:373
#define HUGIN_NONA_USEGPU
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
#define DEBUG_ERROR(msg)
Definition: utils.h:76
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
#define HUGIN_HDRMERGE_ARGS
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
#define HUGIN_LDR_OUTPUT_FORMAT
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition: Panorama.cpp:319
const std::string getICCProfileDesc() const
return description of icc profile used for pano
Definition: Panorama.cpp:1598
Same as above, but use a non const panorama.
PanoramaMemento getMemento() const
get the internal state
Definition: Panorama.h:602
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
include file for the hugin project
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
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
void markAsOptimized(bool optimized=true)
Definition: Panorama.h:618
Memento class for a Panorama object.
Definition: Panorama.h:49
double GetCropFactor()
Definition: HFOVDialog.cpp:353
void updatePartNumbers()
Update the part numbers, call this when the panorama changes.
Holds transformations for Image -&gt; Pano and the other way.
#define HUGIN_ENFUSE_ARGS
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
bool readEXIF()
try to fill out information about the image, by examining the exif data
void setSize(vigra::Size2D val)
Set the image size in pixels.
void update()
Update part numbers for each variable group.
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
platform/compiler specific stuff.
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
Definition: openmp_vigra.h:305
void applyColorBalanceValue(HuginBase::SrcPanoImage &srcImg, HuginBase::Panorama &pano)
static void info(const char *fmt,...)
Definition: svm.cpp:95
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
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
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
bool CheckLensStacks(HuginBase::Panorama *pano, bool allowCancel)
check, if lens and stacks are correctly linked shows message box with short information if not ...
Definition: LensTools.cpp:447
void setNrOfBands(const int nrBands)
sets the number of bands
Definition: Panorama.cpp:1613
Interpolator
enum with all interpolation methods
Definition: Interpolators.h:78
HuginBase::SrcPanoImage GetSrcImage()
Definition: HFOVDialog.cpp:346
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
wxString GetFileDialogImageFilters()
return filter for image files, needed by file open dialog it contains all image format vigra can read...
Definition: platform.cpp:69
Panorama image options.
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
Definition: Panorama.cpp:2137
#define HUGIN_ENBLEND_ARGS
const double getMaxExposureDifference() const
returns the maximum exposure value difference of all images in the project
Definition: Panorama.cpp:2120
#define HUGIN_DEFAULT_BLENDER
bool readCropfactorFromDB()
tries to read cropfactor from lens database you need to call SrcPanoImage::readEXIF before to fill so...
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:176
void reset()
clear the internal state.
Definition: Panorama.cpp:69
BlendingMechanism blendMode
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
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
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition: utils.cpp:160
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().