Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OptimizePanel.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 
36 
37 #include "hugin/OptimizePanel.h"
38 #include "base_wx/CommandHistory.h"
39 #include "base_wx/PanoCommand.h"
40 #include "hugin/MainFrame.h"
41 #include "base_wx/PTWXDlg.h"
42 #include "hugin/config_defaults.h"
43 #include "hugin/ImagesTree.h"
45 #include "hugin/PanoOperation.h"
46 #include "base_wx/LensTools.h"
47 
48 //============================================================================
49 //============================================================================
50 //============================================================================
51 
53 {
54  DEBUG_TRACE("");
55 }
56 
57 bool OptimizePanel::Create(wxWindow* parent, wxWindowID id , const wxPoint& pos, const wxSize& size, long style, const wxString& name)
58 {
59  DEBUG_TRACE("");
60  // Not needed here, wxPanel::Create is called by LoadPanel below
61  if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
62  return false;
63  }
64 
65  // create a sub-panel and load class into it!
66 
67  // wxPanel::Create is called in here!
68  wxXmlResource::Get()->LoadPanel(this, wxT("optimize_panel"));
69  wxPanel * panel = XRCCTRL(*this, "optimize_panel", wxPanel);
70 
71  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
72  topsizer->Add(panel, 1, wxEXPAND, 0);
73  SetSizer( topsizer );
74 
75  m_only_active_images_cb = XRCCTRL(*this, "optimizer_panel_only_active_images", wxCheckBox);
77  m_only_active_images_cb->SetValue(false);
79  m_ignore_line_cp = XRCCTRL(*this, "optimizer_panel_ignore_line_cp", wxCheckBox);
81  m_ignore_line_cp->SetValue(false);
82  m_ignore_line_cp->Bind(wxEVT_CHECKBOX, &OptimizePanel::OnCheckIgnoreLineCP, this);
83 
84  m_images_tree_list = XRCCTRL(*this, "optimize_panel_images", ImagesTreeCtrl);
86  m_lens_tree_list = XRCCTRL(*this, "optimize_panel_lenses", ImagesTreeCtrl);
88  SetOnlyActiveImages(wxConfigBase::Get()->Read(wxT("/OptimizePanel/OnlyActiveImages"), 1l) != 0);
89 
90  m_edit_cb = XRCCTRL(*this, "optimizer_panel_edit_script", wxCheckBox);
92 
93  XRCCTRL(*this, "optimizer_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
94  // bind other events
95  Bind(wxEVT_CLOSE_WINDOW, &OptimizePanel::OnClose, this);
96  Bind(wxEVT_BUTTON, &OptimizePanel::OnOptimizeButton, this, XRCID("optimize_panel_optimize"));
97  Bind(wxEVT_BUTTON, &OptimizePanel::OnReset, this, XRCID("optimize_panel_reset"));
98 
99  return true;
100 }
101 
103 {
104  DEBUG_TRACE("");
105  m_pano = pano;
106 
107  // observe the panorama
108  m_pano->addObserver(this);
112 
117 }
118 
120 {
121  m_images_tree_list->SetGuiLevel(newGuiLevel);
122  m_lens_tree_list->SetGuiLevel(newGuiLevel);
123 };
124 
126 {
127  m_pano->removeObserver(this);
128  DEBUG_TRACE("dtor end");
129 }
130 
132 {
133  //Show(m_pano->getOptimizerSwitch()==0);
136  m_edit_cb->Enable(m_pano->getOptimizerSwitch()==0);
137 }
138 
140  const HuginBase::UIntSet & imgNr)
141 {
142  XRCCTRL(*this, "optimize_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>0);
143  XRCCTRL(*this, "optimize_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);
144 };
145 
146 void OptimizePanel::OnOptimizeButton(wxCommandEvent & e)
147 {
148  DEBUG_TRACE("");
149  // disable window so that user can't click optimize button twice
150  wxWindowDisabler winDisable;
151  // run optimizer
152  HuginBase::UIntSet imgs;
153  if (m_only_active_images_cb->IsChecked() || m_pano->getOptimizerSwitch()!=0)
154  {
155  // use only selected images.
156  imgs = m_pano->getActiveImages();
157  if (imgs.empty())
158  {
159  wxMessageBox(_("The project does not contain any active images.\nPlease activate at least one image in the (fast) preview window.\nOptimization canceled."),
160 #ifdef _WIN32
161  _("Hugin"),
162 #else
163  wxT(""),
164 #endif
165  wxICON_ERROR | wxOK);
166  return;
167  }
168  }
169  else
170  {
171  fill_set(imgs, 0, m_pano->getNrOfImages()-1);
172  }
173  if (CheckLensStacks(m_pano, true))
174  {
175  runOptimizer(imgs, m_ignore_line_cp->IsChecked());
176  };
177 }
178 
179 void OptimizePanel::runOptimizer(const HuginBase::UIntSet & imgs, const bool ignoreLineCp)
180 {
181  DEBUG_TRACE("");
182  // open window that shows a status dialog, and allows to
183  // apply the results
184  int mode=m_pano->getOptimizerSwitch();
185  // remember active window for dialogs
186  wxWindow* activeWindow = wxGetActiveWindow();
187 
188  HuginBase::Panorama optPano = m_pano->getSubset(imgs);
189  if (optPano.getNrOfCtrlPoints() == 0)
190  {
191  wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
192 #ifdef __WXMSW__
193  _("Hugin"),
194 #else
195  wxT(""),
196 #endif
197  wxICON_ERROR | wxOK);
198  return;
199  };
200  HuginBase::PanoramaOptions opts = optPano.getOptions();
201  switch(opts.getProjection())
202  {
206  break;
207  default:
208  // temporarily change to equirectangular
210  optPano.setOptions(opts);
211  break;
212  }
213  HuginBase::UIntSet allImg;
214  fill_set(allImg,0, imgs.size()-1);
215 
216  char *p = setlocale(LC_ALL,NULL);
217  char *oldlocale = strdup(p);
218  setlocale(LC_ALL,"C");
219  HuginBase::CPVector originalCps;
220 
221  if (mode & HuginBase::OPT_PAIR )
222  {
223  // temporarily disable PT progress dialog..
225  {
226  wxBusyCursor bc;
227  // run pairwise optimizer
228  HuginBase::AutoOptimise(optPano).run();
229  }
230 #ifdef DEBUG
231  // print optimized script to cout
232  DEBUG_DEBUG("panorama after autoOptimise():");
233  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
234 #endif
235 
237  // do global optimisation
239 #ifdef DEBUG
240  // print optimized script to cout
241  DEBUG_DEBUG("panorama after optimise():");
242  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
243 #endif
244 
245  }
246  else
247  {
248  HuginBase::CPVector optCps;
249  if (ignoreLineCp)
250  {
251  // store for later
252  originalCps = optPano.getCtrlPoints();
253  // remove all line cp
254  for (auto& cp : originalCps)
255  {
256  if (cp.mode == HuginBase::ControlPoint::X_Y)
257  {
258  optCps.push_back(cp);
259  };
260  };
261  if (optCps.empty())
262  {
263  wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
264 #ifdef __WXMSW__
265  _("Hugin"),
266 #else
267  wxT(""),
268 #endif
269  wxICON_ERROR | wxOK);
270  return;
271  }
272  optPano.setCtrlPoints(optCps);
273  };
274  if (m_edit_cb->IsChecked() && mode==0)
275  {
276  // show and edit script..
277  std::ostringstream scriptbuf;
278  optPano.printPanoramaScript(scriptbuf, optPano.getOptimizeVector(), optPano.getOptions(), allImg, true);
279  // open a text dialog with an editor inside
280  wxDialog edit_dlg;
281  wxXmlResource::Get()->LoadDialog(&edit_dlg, this, wxT("edit_script_dialog"));
282  wxTextCtrl *txtCtrl=XRCCTRL(edit_dlg,"script_edit_text",wxTextCtrl);
283  txtCtrl->SetValue(wxString(scriptbuf.str().c_str(), *wxConvCurrent));
284 
285  char * script = 0;
286  if (edit_dlg.ShowModal() == wxID_OK)
287  {
288  script = strdup(txtCtrl->GetValue().mb_str(*wxConvCurrent));
289  }
290  else
291  {
292  setlocale(LC_ALL,oldlocale);
293  free(oldlocale);
294  return;
295  }
296  HuginBase::PTools::optimize(optPano, script);
297  free(script);
298  }
299  else
300  {
302  }
303 #ifdef DEBUG
304  // print optimized script to cout
305  DEBUG_DEBUG("panorama after optimise():");
306  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
307 #endif
308  }
309 
310  setlocale(LC_ALL,oldlocale);
311  free(oldlocale);
312 #ifdef __WXMSW__
313  // the progress window of the optimizer is marked for deletion
314  // but the final deletion happens only in the idle event
315  // so we need to process the event to really close the progress window
316  wxTheApp->ProcessIdle();
317 #endif
318  // calculate control point errors and display text.
319  if (AskApplyResult(activeWindow, optPano))
320  {
321  if (!originalCps.empty())
322  {
323  // restore all control points
324  optPano.setCtrlPoints(originalCps);
325  // because the line cp were removed we need to calculate the cp error again
327  };
330  );
331  }
332 }
333 
334 bool OptimizePanel::AskApplyResult(wxWindow* activeWindow, const HuginBase::Panorama & pano)
335 {
336  double min;
337  double max;
338  double mean;
339  double var;
341 
342  // check for HFOV lines. if smaller than 1 report a warning;
343  // also check for high distortion coefficients.
344  bool smallHFOV=false;
345  bool highDist = false;
346  const HuginBase::VariableMapVector & vars = pano.getVariables();
347  for (HuginBase::VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
348  {
349  if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
350  if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
351  if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
352  if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
353  }
354 
355  wxString msg;
356  int style=0;
357  if (smallHFOV)
358  {
359  msg.Printf( _("Optimizer run finished.\nWARNING: a very small Field of View (v) has been estimated\n\nThe results are probably invalid.\n\nOptimization of the Field of View (v) of partial panoramas can lead to bad results.\nTry adding more images and control points.\n\nApply the changes anyway?"));
360  style = wxYES_NO;
361  }
362  else
363  {
364  if (highDist)
365  {
366  msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\n*WARNING*: very high distortion coefficients (a,b,c) have been estimated.\nThe results are probably invalid.\nOnly optimize all distortion parameters when many, well spread control points are used.\nPlease reset the a,b and c parameters to zero and add more control points\n\nApply the changes anyway?"),
367  mean, sqrt(var), max);
368  style = wxYES_NO | wxICON_EXCLAMATION;
369  }
370  else
371  {
372  msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\nApply the changes?"),
373  mean, sqrt(var), max);
374  style = wxYES_NO | wxICON_EXCLAMATION;
375  }
376  };
377 
378  int id = wxMessageBox(msg, _("Optimization result"), style, activeWindow);
379 
380  return id == wxYES;
381 }
382 
383 void OptimizePanel::OnClose(wxCloseEvent& event)
384 {
385  DEBUG_TRACE("OnClose");
386  // do not close, just hide if we're not forced
387  if (event.CanVeto())
388  {
389  event.Veto();
390  Hide();
391  DEBUG_DEBUG("Hiding");
392  }
393  else
394  {
395  DEBUG_DEBUG("Closing");
396  Destroy();
397  }
398 }
399 
400 void OptimizePanel::OnReset(wxCommandEvent& e)
401 {
404  if(cmd!=NULL)
405  {
407  };
408 
409 };
410 
412 {
414 };
415 
416 void OptimizePanel::SetOnlyActiveImages(const bool onlyActive)
417 {
418  m_only_active_images_cb->SetValue(onlyActive);
420  m_lens_tree_list->MarkActiveImages(onlyActive);
421 };
422 
423 void OptimizePanel::OnCheckIgnoreLineCP(wxCommandEvent &e)
424 {
426 };
427 
428 void OptimizePanel::SetIgnoreLineCP(const bool noLineCp)
429 {
430  m_ignore_line_cp->SetValue(noLineCp);
431 };
432 
434 
435 
437  : wxXmlResourceHandler()
438 {
439  AddWindowStyles();
440 }
441 
443 {
444  XRC_MAKE_INSTANCE(cp, OptimizePanel)
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("OptimizePanel"));
460 }
461 
ImagesTreeCtrl * m_lens_tree_list
Definition: OptimizePanel.h:79
Base class for all panorama commands.
Definition: Command.h:38
PanoramaOptions::ProjectionFormat getProjection() const
ImagesTreeCtrl * m_images_tree_list
Definition: OptimizePanel.h:78
void SetGroupMode(GroupMode newMode)
sets the group mode to given mode
virtual ~OptimizePanel()
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
virtual void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
receives notification about panorama changes
declaration of main image tree control
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
Definition: Panorama.cpp:1551
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"))
Delayed creation.
#define DEBUG_TRACE(msg)
Definition: utils.h:67
void registerPTWXDlgFcn()
Definition: PTWXDlg.cpp:173
static void calcCtrlPntsErrorStats(const PanoramaData &pano, double &min, double &max, double &mean, double &var, const int &imgNr=-1, const bool onlyActive=false, const bool ignoreLineCp=false)
some helper classes for graphes
void OnReset(wxCommandEvent &e)
void deregisterPTWXDlgFcn()
Definition: PTWXDlg.cpp:180
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
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
wraps around PTOptimizer
virtual void run()
runs the algorithm.
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
void OnCheckIgnoreLineCP(wxCommandEvent &e)
handle &quot;ignore line cp&quot; checkbox
virtual bool CanHandle(wxXmlNode *node)
const Map::mapped_type & const_map_get(const Map &m, const typename Map::key_type &key)
Definition: stl_utils.h:110
Definition of PanoOperation class.
void Init(HuginBase::Panorama *pano)
initialization, connects all control with Panorama, register observer
Definition: ImagesTree.cpp:204
wxCheckBox * m_only_active_images_cb
Definition: OptimizePanel.h:81
void Init(HuginBase::Panorama *pano)
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
HuginBase::Panorama * m_pano
Definition: OptimizePanel.h:85
void runOptimizer(const HuginBase::UIntSet &img, const bool ignoreLineCp)
std::vector< VariableMap > VariableMapVector
void calcCtrlPointErrors(PanoramaData &pano)
Update the Ctrl Point errors without optimizing.
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
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
void SetIgnoreLineCP(const bool noLineCp)
for external setting of &quot;ignore line cp&quot; checkbox
void SetOnlyActiveImages(const bool onlyActive)
for external setting of &quot;only active image&quot; checkbox
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
wxCheckBox * m_ignore_line_cp
Definition: OptimizePanel.h:82
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
void OnOptimizeButton(wxCommandEvent &e)
run the optimizer
bool AskApplyResult(wxWindow *activeWindow, const HuginBase::Panorama &pano)
void SetOptimizeIgnoreLineCp(const bool ignoreLineCP)
sets the status of the &quot;ignore line cp&quot; menu item
Definition: MainFrame.cpp:1652
static GlobalCmdHist & getInstance()
virtual wxObject * DoCreateResource()
update all variables &amp; control points
Definition: PanoCommand.h:145
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
run the optimizer.
Definition: OptimizePanel.h:38
void SetGuiLevel(GuiLevel newSetting)
sets the GuiLevel of the control
Definition: ImagesTree.cpp:943
!! from PTOptimise.h 1951
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
Utility calls into PanoTools using CPP interface.
void SetGuiLevel(GuiLevel newGuiLevel)
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
static T max(T x, T y)
Definition: svm.cpp:65
PanoOperation to reset image variables.
const int getOptimizerSwitch() const
returns optimizer master switch
Definition: Panorama.h:461
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
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
void printPanoramaScript(std::ostream &o, const OptimizeVector &optvars, const PanoramaOptions &options, const UIntSet &imgs, bool forPTOptimizer, const std::string &stripPrefix="") const
create an optimizer script
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
virtual void panoramaChanged(HuginBase::Panorama &pano)
receives notification about panorama changes
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
wxCheckBox * m_edit_cb
Definition: OptimizePanel.h:83
Panorama image options.
void OnClose(wxCloseEvent &e)
void OnCheckOnlyActiveImages(wxCommandEvent &e)
handle &quot;only active images&quot; checkbox
static T min(T x, T y)
Definition: svm.cpp:62
void SetOptimizerMode()
sets to control into optimizer mode
Definition: ImagesTree.cpp:985