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