Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OptimizePhotometricPanel.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "hugin_config.h"
28 #include "panoinc_WX.h"
29 
30 #include "panoinc.h"
31 
35 
36 #include <vigra_ext/Pyramid.h>
37 #include <vigra_ext/openmp_vigra.h>
39 #include "base_wx/CommandHistory.h"
40 #include "base_wx/PanoCommand.h"
41 #include "hugin/MainFrame.h"
43 #include "hugin/config_defaults.h"
44 #include "base_wx/wxImageCache.h"
45 #include "hugin/ImagesTree.h"
47 #include "hugin/PanoOperation.h"
48 
49 //============================================================================
50 //============================================================================
51 //============================================================================
52 
54 {
55 };
56 
57 bool OptimizePhotometricPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
58  long style, const wxString& name)
59 {
60  DEBUG_TRACE("");
61  if (! wxPanel::Create(parent, id, pos, size, style, name))
62  {
63  return false;
64  }
65 
66  wxXmlResource::Get()->LoadPanel(this, wxT("optimize_photo_panel"));
67  wxPanel * panel = XRCCTRL(*this, "optimize_photo_panel", wxPanel);
68 
69  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
70  topsizer->Add(panel, 1, wxEXPAND, 0);
71  SetSizer(topsizer);
72 
73  m_only_active_images_cb = XRCCTRL(*this, "optimize_photo_panel_only_active_images", wxCheckBox);
76 
77  m_images_tree = XRCCTRL(*this, "optimize_photo_panel_images", ImagesTreeCtrl);
79  m_lens_tree = XRCCTRL(*this, "optimize_photo_panel_lens", ImagesTreeCtrl);
81 
82  XRCCTRL(*this, "optimize_photo_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
83  // bind other events
84  Bind(wxEVT_CLOSE_WINDOW, &OptimizePhotometricPanel::OnClose, this);
85  Bind(wxEVT_BUTTON, &OptimizePhotometricPanel::OnOptimizeButton, this, XRCID("optimize_photo_panel_optimize"));
86  Bind(wxEVT_BUTTON, &OptimizePhotometricPanel::OnReset, this, XRCID("optimize_photo_panel_reset"));
87 
88  return true;
89 }
90 
92 {
93  m_pano = panorama;
94  // observe the panorama
95  m_pano->addObserver(this);
99 
104 
105 }
106 
108 {
109  m_images_tree->SetGuiLevel(newGuiLevel);
110  m_lens_tree->SetGuiLevel(newGuiLevel);
111 };
112 
114 {
115  DEBUG_TRACE("dtor, writing config");
116 
117  m_pano->removeObserver(this);
118  DEBUG_TRACE("dtor end");
119 }
120 
122 {
124 };
125 
127 {
128  m_only_active_images_cb->SetValue(onlyActive);
129  m_images_tree->MarkActiveImages(onlyActive);
130  m_lens_tree->MarkActiveImages(onlyActive);
131 };
132 
134 {
135  DEBUG_TRACE("");
136  // disable window so that user can't click optimize button twice
137  wxWindowDisabler winDisable;
138  // run optimizer
139 
140  HuginBase::UIntSet imgs;
142  {
143  // use only selected images.
144  imgs = m_pano->getActiveImages();
145  if (imgs.size() < 2)
146  {
147  wxMessageBox(_("The project does not contain any active images.\nPlease activate at least 2 images in the (fast) preview window.\nOptimization canceled."),
148 #ifdef _WIN32
149  _("Hugin"),
150 #else
151  wxT(""),
152 #endif
153  wxICON_ERROR | wxOK);
154  return;
155  }
156  }
157  else
158  {
159  fill_set(imgs, 0, m_pano->getNrOfImages()-1);
160  }
161  runOptimizer(imgs);
162 }
163 
165 {
168 }
169 
171  const HuginBase::UIntSet & imgNr)
172 {
173  XRCCTRL(*this, "optimize_photo_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>1);
174  XRCCTRL(*this, "optimize_photo_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);
175 }
176 
178 {
179  DEBUG_TRACE("");
181 
182  // check if vignetting and response are linked, display a warning if they are not
183  // The variables to check:
185  HuginBase::ImageVariableGroup::IVE_EMoRParams,
186  HuginBase::ImageVariableGroup::IVE_ResponseType,
187  HuginBase::ImageVariableGroup::IVE_VigCorrMode,
188  HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
189  HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
190  };
191  // keep a list of commands needed to fix it:
192  std::vector<PanoCommand::PanoCommand *> commands;
194  HuginBase::ConstImageVariableGroup & lenses = variable_groups.getLenses();
195  for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
196  {
197  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
198  links_needed.clear();
199  for (int v = 0; v < 5; v++)
200  {
201  if (!lenses.getVarLinkedInPart(vars[v], i))
202  {
203  links_needed.insert(vars[v]);
204  }
205  };
206  if (!links_needed.empty())
207  {
208  commands.push_back(new PanoCommand::LinkLensVarsCmd(*m_pano, i, links_needed));
209  }
210  }
211  // if the list of commands is empty, all is good and we don't need a warning.
212  if (!commands.empty()) {
213  int ok = wxMessageBox(_("The same vignetting and response parameters should\nbe applied for all images of a lens.\nCurrently each image can have different parameters.\nLink parameters?"), _("Link parameters"), wxYES_NO | wxICON_INFORMATION);
214  if (ok == wxYES)
215  {
216  // perform all the commands we stocked up earilier using a CombinedPanoCommand, so only
217  // one command is in the history stack.
219  }
220  else
221  {
222  // free all the commands, the user doesn't want them used.
223  for (std::vector<PanoCommand::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); ++it)
224  {
225  delete *it;
226  }
227  }
228  }
229 
230  HuginBase::Panorama optPano = m_pano->getSubset(imgs);
231  HuginBase::PanoramaOptions opts = optPano.getOptions();
232 
234  if(mode==0)
235  {
236  optvars = optPano.getOptimizeVector();
237  bool valid=false;
238  for(unsigned int i=0;i<optvars.size() && !valid;i++)
239  {
240  if(set_contains(optvars[i], "Eev") || set_contains(optvars[i], "Er") || set_contains(optvars[i], "Eb") ||
241  set_contains(optvars[i], "Vb") || set_contains(optvars[i], "Vx") || set_contains(optvars[i], "Ra"))
242  {
243  valid=true;
244  };
245  };
246  if(!valid)
247  {
248  wxMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Exposure optimization"), wxOK | wxICON_INFORMATION);
249  return;
250  };
251  };
252 
253  double error = 0;
254  {
255  std::vector<vigra_ext::PointPairRGB> points;
256  long nPoints = 200;
257  wxConfigBase::Get()->Read(wxT("/OptimizePhotometric/nRandomPointsPerImage"), &nPoints , HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS);
258 
259  ProgressReporterDialog progress(optPano.getNrOfImages()+2, _("Photometric alignment"), _("Loading images"), this);
260  progress.Show();
261 
262  nPoints = nPoints * optPano.getNrOfImages();
263  // get the small images
264  std::vector<vigra::FRGBImage *> srcImgs;
266  float imageStepSize = 1 / 255.0f;
267  for (size_t i=0; i < optPano.getNrOfImages(); i++)
268  {
269  ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename());
270  if (!e)
271  {
272  wxMessageBox(_("Error: could not load all images"), _("Error"));
273  return;
274  }
276  vigra::FRGBImage * img = new vigra::FRGBImage;
277  if (e->imageFloat && e->imageFloat->size().area() > 0)
278  {
279  if (e->mask->size().area() > 0)
280  {
281  vigra::BImage maskSmall;
282  vigra_ext::reduceToNextLevel(*(e->imageFloat), *(e->mask), *img, maskSmall);
284  vigra::inspectImageIf(srcImageRange(*img), srcImage(maskSmall), minmax);
285  imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
286  }
287  else
288  {
289  vigra_ext::reduceToNextLevel(*(e->imageFloat), *img);
291  vigra::inspectImage(srcImageRange(*img), minmax);
292  imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
293  };
295  }
296  else
297  {
298  if (e->image16 && e->image16->size().area() > 0)
299  {
300  vigra_ext::reduceToNextLevel(*(e->image16), *img);
302  vigra::functor::Arg1() / vigra::functor::Param(65535.0));
304  imageStepSize = std::min(imageStepSize, 1 / 65536.0f);
305  }
306  else
307  {
308  vigra_ext::reduceToNextLevel(*(e->get8BitImage()), *img);
310  vigra::functor::Arg1() / vigra::functor::Param(255.0));
312  imageStepSize = std::min(imageStepSize, 1 / 255.0f);
313  };
314  };
315  srcImgs.push_back(img);
316  limits.push_back(limit);
317  if (!progress.updateDisplayValue())
318  {
319  // check if user pressed cancel
320  return;
321  };
322  }
323  points= HuginBase::RandomPointSampler(optPano, &progress, srcImgs, limits, nPoints).execute().getResultPoints();
324 
325  if (!progress.updateDisplayValue())
326  {
327  return;
328  };
329  if (points.empty())
330  {
331  wxMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Error"));
332  return;
333  }
334 
335  progress.setMaximum(0);
336  progress.updateDisplay(_("Optimize..."));
337  try
338  {
339  if (mode != 0)
340  {
341  // run automatic optimisation
342  // ensure that we have a valid anchor.
343  HuginBase::PanoramaOptions opts = optPano.getOptions();
344  if (opts.colorReferenceImage >= optPano.getNrOfImages())
345  {
346  opts.colorReferenceImage = 0;
347  optPano.setOptions(opts);
348  }
350  switch(mode)
351  {
354  break;
357  break;
360  break;
363  break;
364  default:
365  //invalid combination
366  return;
367  };
368  HuginBase::SmartPhotometricOptimizer::smartOptimizePhotometric(optPano, optMode, points, imageStepSize, &progress, error);
369  }
370  else
371  {
372  // optimize selected parameters
373  HuginBase::PhotometricOptimizer::optimizePhotometric(optPano, optvars, points, imageStepSize, &progress, error);
374  }
375  if (progress.wasCancelled())
376  {
377  return;
378  }
379  }
380  catch (std::exception & error)
381  {
382  wxMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Internal error"));
383  return;
384  }
385  }
386  wxYield();
387 
388  // display information about the estimation process:
389  int ret = wxMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error*255),
390  _("Photometric optimization finished"), wxYES_NO | wxICON_INFORMATION,this);
391 
392  if (ret == wxYES)
393  {
394  DEBUG_DEBUG("Applying vignetting corr");
395  // TODO: merge into a single update command
396  const HuginBase::VariableMapVector & vars = optPano.getVariables();
397  std::vector<PanoCommand::PanoCommand*> optCommands;
398  optCommands.push_back(new PanoCommand::UpdateImagesVariablesCmd(*m_pano, imgs, vars));
399  //now update panorama exposure value
402  optCommands.push_back(new PanoCommand::SetPanoOptionsCmd(*m_pano, opts));
404  }
405 }
406 
407 void OptimizePhotometricPanel::OnClose(wxCloseEvent& event)
408 {
409  DEBUG_TRACE("OnClose");
410  // do not close, just hide if we're not forced
411  if (event.CanVeto())
412  {
413  event.Veto();
414  Hide();
415  DEBUG_DEBUG("Hiding");
416  }
417  else
418  {
419  DEBUG_DEBUG("Closing");
420  Destroy();
421  }
422 }
423 
424 void OptimizePhotometricPanel::OnReset(wxCommandEvent& e)
425 {
428  if(cmd!=NULL)
429  {
431  };
432 };
433 
435 
437  : wxXmlResourceHandler()
438 {
439  AddWindowStyles();
440 }
441 
443 {
444  XRC_MAKE_INSTANCE(cp, OptimizePhotometricPanel)
445 
446  cp->Create(m_parentAsWindow,
447  GetID(),
448  GetPosition(), GetSize(),
449  GetStyle(wxT("style")),
450  GetName());
451 
452  SetupWindow( cp);
453 
454  return cp;
455 }
456 
458 {
459  return IsOfClass(node, wxT("OptimizePhotometricPanel"));
460 }
461 
Base class for all panorama commands.
Definition: Command.h:38
void reduceToNextLevel(ImageIn &in, ImageOut &out)
Definition: Pyramid.h:136
bool getVarLinkedInPart(ImageVariableEnum variable, std::size_t part) const
Get the linked status of a particular variable for a given part number.
An ImageVariableGroup is a collection of image variables that can have some shared variable values...
void OnCheckOnlyActiveImages(wxCommandEvent &e)
handle &quot;only active images&quot; checkbox
update variables of a group of images
Definition: PanoCommand.h:174
void SetGroupMode(GroupMode newMode)
sets the group mode to given mode
class for storing the limits of an image used by the sampler to exclude too dark or too bright pixel ...
Definition: PointSampler.h:44
virtual PanoCommand::PanoCommand * GetCommand(wxWindow *parent, HuginBase::Panorama &pano, HuginBase::UIntSet images, GuiLevel guiLevel)
returns the appropriate PanoCommand::PanoCommand to be inserted into GlobalCmdHistory, checks if operation is enabled
void SetGuiLevel(GuiLevel newGuiLevel)
static double calcMeanExposure(const PanoramaData &pano)
declaration of main image tree control
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
#define DEBUG_TRACE(msg)
Definition: utils.h:67
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
void SetOptimizeOnlyActiveImages(const bool onlyActive)
sets the status of the &quot;optimize only active images&quot; menu item
Definition: MainFrame.cpp:1625
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
include file for the hugin project
PhotometricOptimizeMode
local optimize definition.
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
Definition: ROIImage.h:300
Definition of PanoOperation class.
void Init(HuginBase::Panorama *pano)
initialization, connects all control with Panorama, register observer
Definition: ImagesTree.cpp:204
PanoCommand to combine other PanoCommands.
Definition: PanoCommand.h:39
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
set the panorama options
Definition: PanoCommand.h:418
std::vector< VariableMap > VariableMapVector
PointPairs getResultPoints()
Definition: PointSampler.h:130
Model for a panorama.
Definition: Panorama.h:152
void MarkActiveImages(const bool markActive)
sets the flag, if active/disabled image should be marked with different colour
Definition: ImagesTree.cpp:928
ConstImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition: Panorama.h:454
some definitions to work with optimizer master switches
void SetDisplayMode(DisplayMode newMode)
sets the display mode to given mode
VariableMapVector getVariables() const
get variables of this panorama
Definition: Panorama.cpp:118
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2153
Link a set of lens variables for some lens.
Definition: PanoCommand.h:554
void SetOnlyActiveImages(const bool onlyActive)
for external setting of &quot;only active image&quot; checkbox
static void smartOptimizePhotometric(PanoramaData &pano, PhotometricOptimizeMode mode, const std::vector< vigra_ext::PointPairRGB > &correspondences, const float imageStepSize, AppBase::ProgressDisplay *progress, double &error)
use various heuristics to decide what to optimize.
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
virtual void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
receives notification about panorama changes
Make an ImageVariableGroup for lenses and other common concepts.
static GlobalCmdHist & getInstance()
virtual void panoramaChanged(HuginBase::Panorama &pano)
receives notification about panorama changes
void runOptimizer(const HuginBase::UIntSet &img)
void OnOptimizeButton(wxCommandEvent &e)
run the optimizer
static void optimizePhotometric(PanoramaData &pano, const OptimizeVector &vars, const PointPairs &correspondences, const float imageStepSize, AppBase::ProgressDisplay *progress, double &error)
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
void SetGuiLevel(GuiLevel newSetting)
sets the GuiLevel of the control
Definition: ImagesTree.cpp:943
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
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
VALUETYPE min
the current min
Definition: utils.h:362
HuginBase::UIntSet GetSelectedImages()
returns the selected images
Definition: ImagesTree.cpp:899
void addObserver(PanoramaObserver *o)
add a panorama observer.
Definition: Panorama.cpp:1546
include file for the hugin project
const GuiLevel GetGuiLevel() const
Definition: MainFrame.h:185
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
the main images tree control, used on images and optimizer tabs
Definition: ImagesTree.h:36
const int getPhotometricOptimizerSwitch() const
return the photometric optimizer master switch
Definition: Panorama.h:467
PanoOperation to reset image variables.
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
void Init(HuginBase::Panorama *pano)
VALUETYPE max
the current max
Definition: utils.h:364
std::vector< LimitIntensity > LimitIntensityVector
Definition: PointSampler.h:65
void transformImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
Definition: openmp_vigra.h:330
std::vector< std::set< std::string > > OptimizeVector
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
GuiLevel
Definition: GuiLevel.h:31
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
PointSampler & execute()
Definition: PointSampler.h:119
std::size_t getNumberOfParts() const
get the number of parts.
Panorama image options.
#define HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS
static T min(T x, T y)
Definition: svm.cpp:62
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxT("panel"))
void SetOptimizerMode()
sets to control into optimizer mode
Definition: ImagesTree.cpp:985