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 
53 BEGIN_EVENT_TABLE(OptimizePhotometricPanel, wxPanel)
54  EVT_CLOSE(OptimizePhotometricPanel::OnClose)
55  EVT_BUTTON(XRCID("optimize_photo_panel_optimize"), OptimizePhotometricPanel::OnOptimizeButton)
56  EVT_BUTTON(XRCID("optimize_photo_panel_reset"), OptimizePhotometricPanel::OnReset)
57  EVT_CHECKBOX(XRCID("optimize_photo_panel_only_active_images"), OptimizePhotometricPanel::OnCheckOnlyActiveImages)
59 
61 {
62 };
63 
64 bool OptimizePhotometricPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
65  long style, const wxString& name)
66 {
67  DEBUG_TRACE("");
68  if (! wxPanel::Create(parent, id, pos, size, style, name))
69  {
70  return false;
71  }
72 
73  wxXmlResource::Get()->LoadPanel(this, wxT("optimize_photo_panel"));
74  wxPanel * panel = XRCCTRL(*this, "optimize_photo_panel", wxPanel);
75 
76  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
77  topsizer->Add(panel, 1, wxEXPAND, 0);
78  SetSizer(topsizer);
79 
80  m_only_active_images_cb = XRCCTRL(*this, "optimize_photo_panel_only_active_images", wxCheckBox);
82 
83  m_images_tree = XRCCTRL(*this, "optimize_photo_panel_images", ImagesTreeCtrl);
85  m_lens_tree = XRCCTRL(*this, "optimize_photo_panel_lens", ImagesTreeCtrl);
87 
88  XRCCTRL(*this, "optimize_photo_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
89 
90  return true;
91 }
92 
94 {
95  m_pano = panorama;
96  // observe the panorama
97  m_pano->addObserver(this);
101 
106 
107 }
108 
110 {
111  m_images_tree->SetGuiLevel(newGuiLevel);
112  m_lens_tree->SetGuiLevel(newGuiLevel);
113 };
114 
116 {
117  DEBUG_TRACE("dtor, writing config");
118 
119  m_pano->removeObserver(this);
120  DEBUG_TRACE("dtor end");
121 }
122 
124 {
126 };
127 
129 {
130  m_only_active_images_cb->SetValue(onlyActive);
131  m_images_tree->MarkActiveImages(onlyActive);
132  m_lens_tree->MarkActiveImages(onlyActive);
133 };
134 
136 {
137  DEBUG_TRACE("");
138  // disable window so that user can't click optimize button twice
139  wxWindowDisabler winDisable;
140  // run optimizer
141 
142  HuginBase::UIntSet imgs;
144  {
145  // use only selected images.
146  imgs = m_pano->getActiveImages();
147  if (imgs.size() < 2)
148  {
149  wxMessageBox(_("The project does not contain any active images.\nPlease activate at least 2 images in the (fast) preview window.\nOptimization canceled."),
150 #ifdef _WIN32
151  _("Hugin"),
152 #else
153  wxT(""),
154 #endif
155  wxICON_ERROR | wxOK);
156  return;
157  }
158  }
159  else
160  {
161  fill_set(imgs, 0, m_pano->getNrOfImages()-1);
162  }
163  runOptimizer(imgs);
164 }
165 
167 {
170 }
171 
173  const HuginBase::UIntSet & imgNr)
174 {
175  XRCCTRL(*this, "optimize_photo_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>1);
176  XRCCTRL(*this, "optimize_photo_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);
177 }
178 
180 {
181  DEBUG_TRACE("");
183 
184  // check if vignetting and response are linked, display a warning if they are not
185  // The variables to check:
187  HuginBase::ImageVariableGroup::IVE_EMoRParams,
188  HuginBase::ImageVariableGroup::IVE_ResponseType,
189  HuginBase::ImageVariableGroup::IVE_VigCorrMode,
190  HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
191  HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
192  };
193  // keep a list of commands needed to fix it:
194  std::vector<PanoCommand::PanoCommand *> commands;
196  HuginBase::ConstImageVariableGroup & lenses = variable_groups.getLenses();
197  for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
198  {
199  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
200  links_needed.clear();
201  for (int v = 0; v < 5; v++)
202  {
203  if (!lenses.getVarLinkedInPart(vars[v], i))
204  {
205  links_needed.insert(vars[v]);
206  }
207  };
208  if (!links_needed.empty())
209  {
210  commands.push_back(new PanoCommand::LinkLensVarsCmd(*m_pano, i, links_needed));
211  }
212  }
213  // if the list of commands is empty, all is good and we don't need a warning.
214  if (!commands.empty()) {
215  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);
216  if (ok == wxYES)
217  {
218  // perform all the commands we stocked up earilier using a CombinedPanoCommand, so only
219  // one command is in the history stack.
221  }
222  else
223  {
224  // free all the commands, the user doesn't want them used.
225  for (std::vector<PanoCommand::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); ++it)
226  {
227  delete *it;
228  }
229  }
230  }
231 
232  HuginBase::Panorama optPano = m_pano->getSubset(imgs);
233  HuginBase::PanoramaOptions opts = optPano.getOptions();
234 
236  if(mode==0)
237  {
238  optvars = optPano.getOptimizeVector();
239  bool valid=false;
240  for(unsigned int i=0;i<optvars.size() && !valid;i++)
241  {
242  if(set_contains(optvars[i], "Eev") || set_contains(optvars[i], "Er") || set_contains(optvars[i], "Eb") ||
243  set_contains(optvars[i], "Vb") || set_contains(optvars[i], "Vx") || set_contains(optvars[i], "Ra"))
244  {
245  valid=true;
246  };
247  };
248  if(!valid)
249  {
250  wxMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Exposure optimization"), wxOK | wxICON_INFORMATION);
251  return;
252  };
253  };
254 
255  double error = 0;
256  {
257  std::vector<vigra_ext::PointPairRGB> points;
258  long nPoints = 200;
259  wxConfigBase::Get()->Read(wxT("/OptimizePhotometric/nRandomPointsPerImage"), &nPoints , HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS);
260 
261  ProgressReporterDialog progress(optPano.getNrOfImages()+2, _("Photometric alignment"), _("Loading images"), this);
262  progress.Show();
263 
264  nPoints = nPoints * optPano.getNrOfImages();
265  // get the small images
266  std::vector<vigra::FRGBImage *> srcImgs;
268  float imageStepSize = 1 / 255.0f;
269  for (size_t i=0; i < optPano.getNrOfImages(); i++)
270  {
271  ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename());
272  if (!e)
273  {
274  wxMessageBox(_("Error: could not load all images"), _("Error"));
275  return;
276  }
278  vigra::FRGBImage * img = new vigra::FRGBImage;
279  if (e->imageFloat && e->imageFloat->size().area() > 0)
280  {
281  if (e->mask->size().area() > 0)
282  {
283  vigra::BImage maskSmall;
284  vigra_ext::reduceToNextLevel(*(e->imageFloat), *(e->mask), *img, maskSmall);
286  vigra::inspectImageIf(srcImageRange(*img), srcImage(maskSmall), minmax);
287  imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
288  }
289  else
290  {
291  vigra_ext::reduceToNextLevel(*(e->imageFloat), *img);
293  vigra::inspectImage(srcImageRange(*img), minmax);
294  imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
295  };
297  }
298  else
299  {
300  if (e->image16 && e->image16->size().area() > 0)
301  {
302  vigra_ext::reduceToNextLevel(*(e->image16), *img);
304  vigra::functor::Arg1() / vigra::functor::Param(65535.0));
306  imageStepSize = std::min(imageStepSize, 1 / 65536.0f);
307  }
308  else
309  {
310  vigra_ext::reduceToNextLevel(*(e->get8BitImage()), *img);
312  vigra::functor::Arg1() / vigra::functor::Param(255.0));
314  imageStepSize = std::min(imageStepSize, 1 / 255.0f);
315  };
316  };
317  srcImgs.push_back(img);
318  limits.push_back(limit);
319  if (!progress.updateDisplayValue())
320  {
321  // check if user pressed cancel
322  return;
323  };
324  }
325  points= HuginBase::RandomPointSampler(optPano, &progress, srcImgs, limits, nPoints).execute().getResultPoints();
326 
327  if (!progress.updateDisplayValue())
328  {
329  return;
330  };
331  if (points.empty())
332  {
333  wxMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Error"));
334  return;
335  }
336 
337  progress.setMaximum(0);
338  progress.updateDisplay(_("Optimize..."));
339  try
340  {
341  if (mode != 0)
342  {
343  // run automatic optimisation
344  // ensure that we have a valid anchor.
345  HuginBase::PanoramaOptions opts = optPano.getOptions();
346  if (opts.colorReferenceImage >= optPano.getNrOfImages())
347  {
348  opts.colorReferenceImage = 0;
349  optPano.setOptions(opts);
350  }
352  switch(mode)
353  {
356  break;
359  break;
362  break;
365  break;
366  default:
367  //invalid combination
368  return;
369  };
370  HuginBase::SmartPhotometricOptimizer::smartOptimizePhotometric(optPano, optMode, points, imageStepSize, &progress, error);
371  }
372  else
373  {
374  // optimize selected parameters
375  HuginBase::PhotometricOptimizer::optimizePhotometric(optPano, optvars, points, imageStepSize, &progress, error);
376  }
377  if (progress.wasCancelled())
378  {
379  return;
380  }
381  }
382  catch (std::exception & error)
383  {
384  wxMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Internal error"));
385  return;
386  }
387  }
388  wxYield();
389 
390  // display information about the estimation process:
391  int ret = wxMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error*255),
392  _("Photometric optimization finished"), wxYES_NO | wxICON_INFORMATION,this);
393 
394  if (ret == wxYES)
395  {
396  DEBUG_DEBUG("Applying vignetting corr");
397  // TODO: merge into a single update command
398  const HuginBase::VariableMapVector & vars = optPano.getVariables();
399  std::vector<PanoCommand::PanoCommand*> optCommands;
400  optCommands.push_back(new PanoCommand::UpdateImagesVariablesCmd(*m_pano, imgs, vars));
401  //now update panorama exposure value
404  optCommands.push_back(new PanoCommand::SetPanoOptionsCmd(*m_pano, opts));
406  }
407 }
408 
409 void OptimizePhotometricPanel::OnClose(wxCloseEvent& event)
410 {
411  DEBUG_TRACE("OnClose");
412  // do not close, just hide if we're not forced
413  if (event.CanVeto())
414  {
415  event.Veto();
416  Hide();
417  DEBUG_DEBUG("Hiding");
418  }
419  else
420  {
421  DEBUG_DEBUG("Closing");
422  Destroy();
423  }
424 }
425 
426 void OptimizePhotometricPanel::OnReset(wxCommandEvent& e)
427 {
430  if(cmd!=NULL)
431  {
433  };
434 };
435 
437 
439  : wxXmlResourceHandler()
440 {
441  AddWindowStyles();
442 }
443 
445 {
446  XRC_MAKE_INSTANCE(cp, OptimizePhotometricPanel)
447 
448  cp->Create(m_parentAsWindow,
449  GetID(),
450  GetPosition(), GetSize(),
451  GetStyle(wxT("style")),
452  GetName());
453 
454  SetupWindow( cp);
455 
456  return cp;
457 }
458 
460 {
461  return IsOfClass(node, wxT("OptimizePhotometricPanel"));
462 }
463 
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:1653
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
END_EVENT_TABLE()
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:215
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:939
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:2181
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:954
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:910
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:189
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:996