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