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 
52 BEGIN_EVENT_TABLE(OptimizePanel, wxPanel)
53  EVT_CLOSE(OptimizePanel::OnClose)
54  EVT_BUTTON(XRCID("optimize_panel_optimize"), OptimizePanel::OnOptimizeButton)
55  EVT_BUTTON(XRCID("optimize_panel_reset"), OptimizePanel::OnReset)
56  EVT_CHECKBOX(XRCID("optimizer_panel_only_active_images"), OptimizePanel::OnCheckOnlyActiveImages)
57  EVT_CHECKBOX(XRCID("optimizer_panel_ignore_line_cp"), OptimizePanel::OnCheckIgnoreLineCP)
59 
60 
62 {
63  DEBUG_TRACE("");
64 }
65 
66 bool OptimizePanel::Create(wxWindow* parent, wxWindowID id , const wxPoint& pos, const wxSize& size, long style, const wxString& name)
67 {
68  DEBUG_TRACE("");
69  // Not needed here, wxPanel::Create is called by LoadPanel below
70  if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
71  return false;
72  }
73 
74  // create a sub-panel and load class into it!
75 
76  // wxPanel::Create is called in here!
77  wxXmlResource::Get()->LoadPanel(this, wxT("optimize_panel"));
78  wxPanel * panel = XRCCTRL(*this, "optimize_panel", wxPanel);
79 
80  wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
81  topsizer->Add(panel, 1, wxEXPAND, 0);
82  SetSizer( topsizer );
83 
84  m_only_active_images_cb = XRCCTRL(*this, "optimizer_panel_only_active_images", wxCheckBox);
86  m_only_active_images_cb->SetValue(false);
87  m_ignore_line_cp = XRCCTRL(*this, "optimizer_panel_ignore_line_cp", wxCheckBox);
89  m_ignore_line_cp->SetValue(false);
90 
91  m_images_tree_list = XRCCTRL(*this, "optimize_panel_images", ImagesTreeCtrl);
93  m_lens_tree_list = XRCCTRL(*this, "optimize_panel_lenses", ImagesTreeCtrl);
95  SetOnlyActiveImages(wxConfigBase::Get()->Read(wxT("/OptimizePanel/OnlyActiveImages"), 1l) != 0);
96 
97  m_edit_cb = XRCCTRL(*this, "optimizer_panel_edit_script", wxCheckBox);
99 
100  XRCCTRL(*this, "optimizer_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
101 
102  return true;
103 }
104 
106 {
107  DEBUG_TRACE("");
108  m_pano = pano;
109 
110  // observe the panorama
111  m_pano->addObserver(this);
115 
120 }
121 
123 {
124  m_images_tree_list->SetGuiLevel(newGuiLevel);
125  m_lens_tree_list->SetGuiLevel(newGuiLevel);
126 };
127 
129 {
130  m_pano->removeObserver(this);
131  DEBUG_TRACE("dtor end");
132 }
133 
135 {
136  //Show(m_pano->getOptimizerSwitch()==0);
139  m_edit_cb->Enable(m_pano->getOptimizerSwitch()==0);
140 }
141 
143  const HuginBase::UIntSet & imgNr)
144 {
145  XRCCTRL(*this, "optimize_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>0);
146  XRCCTRL(*this, "optimize_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);
147 };
148 
149 void OptimizePanel::OnOptimizeButton(wxCommandEvent & e)
150 {
151  DEBUG_TRACE("");
152  // disable window so that user can't click optimize button twice
153  wxWindowDisabler winDisable;
154  // run optimizer
155  HuginBase::UIntSet imgs;
156  if (m_only_active_images_cb->IsChecked() || m_pano->getOptimizerSwitch()!=0)
157  {
158  // use only selected images.
159  imgs = m_pano->getActiveImages();
160  if (imgs.empty())
161  {
162  wxMessageBox(_("The project does not contain any active images.\nPlease activate at least one image in the (fast) preview window.\nOptimization canceled."),
163 #ifdef _WIN32
164  _("Hugin"),
165 #else
166  wxT(""),
167 #endif
168  wxICON_ERROR | wxOK);
169  return;
170  }
171  }
172  else
173  {
174  fill_set(imgs, 0, m_pano->getNrOfImages()-1);
175  }
176  if (CheckLensStacks(m_pano, true))
177  {
178  runOptimizer(imgs, m_ignore_line_cp->IsChecked());
179  };
180 }
181 
182 void OptimizePanel::runOptimizer(const HuginBase::UIntSet & imgs, const bool ignoreLineCp)
183 {
184  DEBUG_TRACE("");
185  // open window that shows a status dialog, and allows to
186  // apply the results
187  int mode=m_pano->getOptimizerSwitch();
188  // remember active window for dialogs
189  wxWindow* activeWindow = wxGetActiveWindow();
190 
191  HuginBase::Panorama optPano = m_pano->getSubset(imgs);
192  if (optPano.getNrOfCtrlPoints() == 0)
193  {
194  wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
195 #ifdef __WXMSW__
196  _("Hugin"),
197 #else
198  wxT(""),
199 #endif
200  wxICON_ERROR | wxOK);
201  return;
202  };
203  HuginBase::PanoramaOptions opts = optPano.getOptions();
204  switch(opts.getProjection())
205  {
209  break;
210  default:
211  // temporarily change to equirectangular
213  optPano.setOptions(opts);
214  break;
215  }
216  HuginBase::UIntSet allImg;
217  fill_set(allImg,0, imgs.size()-1);
218 
219  char *p = setlocale(LC_ALL,NULL);
220  char *oldlocale = strdup(p);
221  setlocale(LC_ALL,"C");
222  HuginBase::CPVector originalCps;
223 
224  if (mode & HuginBase::OPT_PAIR )
225  {
226  // temporarily disable PT progress dialog..
228  {
229  wxBusyCursor bc;
230  // run pairwise optimizer
231  HuginBase::AutoOptimise(optPano).run();
232  }
233 #ifdef DEBUG
234  // print optimized script to cout
235  DEBUG_DEBUG("panorama after autoOptimise():");
236  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
237 #endif
238 
240  // do global optimisation
242 #ifdef DEBUG
243  // print optimized script to cout
244  DEBUG_DEBUG("panorama after optimise():");
245  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
246 #endif
247 
248  }
249  else
250  {
251  HuginBase::CPVector optCps;
252  if (ignoreLineCp)
253  {
254  // store for later
255  originalCps = optPano.getCtrlPoints();
256  // remove all line cp
257  for (auto& cp : originalCps)
258  {
259  if (cp.mode == HuginBase::ControlPoint::X_Y)
260  {
261  optCps.push_back(cp);
262  };
263  };
264  if (optCps.empty())
265  {
266  wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
267 #ifdef __WXMSW__
268  _("Hugin"),
269 #else
270  wxT(""),
271 #endif
272  wxICON_ERROR | wxOK);
273  return;
274  }
275  optPano.setCtrlPoints(optCps);
276  };
277  if (m_edit_cb->IsChecked() && mode==0)
278  {
279  // show and edit script..
280  std::ostringstream scriptbuf;
281  optPano.printPanoramaScript(scriptbuf, optPano.getOptimizeVector(), optPano.getOptions(), allImg, true);
282  // open a text dialog with an editor inside
283  wxDialog edit_dlg;
284  wxXmlResource::Get()->LoadDialog(&edit_dlg, this, wxT("edit_script_dialog"));
285  wxTextCtrl *txtCtrl=XRCCTRL(edit_dlg,"script_edit_text",wxTextCtrl);
286  txtCtrl->SetValue(wxString(scriptbuf.str().c_str(), *wxConvCurrent));
287 
288  char * script = 0;
289  if (edit_dlg.ShowModal() == wxID_OK)
290  {
291  script = strdup(txtCtrl->GetValue().mb_str(*wxConvCurrent));
292  }
293  else
294  {
295  setlocale(LC_ALL,oldlocale);
296  free(oldlocale);
297  return;
298  }
299  HuginBase::PTools::optimize(optPano, script);
300  free(script);
301  }
302  else
303  {
305  }
306 #ifdef DEBUG
307  // print optimized script to cout
308  DEBUG_DEBUG("panorama after optimise():");
309  optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
310 #endif
311  }
312 
313  setlocale(LC_ALL,oldlocale);
314  free(oldlocale);
315 #ifdef __WXMSW__
316  // the progress window of the optimizer is marked for deletion
317  // but the final deletion happens only in the idle event
318  // so we need to process the event to really close the progress window
319  wxTheApp->ProcessIdle();
320 #endif
321  // calculate control point errors and display text.
322  if (AskApplyResult(activeWindow, optPano))
323  {
324  if (!originalCps.empty())
325  {
326  // restore all control points
327  optPano.setCtrlPoints(originalCps);
328  // because the line cp were removed we need to calculate the cp error again
330  };
333  );
334  }
335 }
336 
337 bool OptimizePanel::AskApplyResult(wxWindow* activeWindow, const HuginBase::Panorama & pano)
338 {
339  double min;
340  double max;
341  double mean;
342  double var;
344 
345  // check for HFOV lines. if smaller than 1 report a warning;
346  // also check for high distortion coefficients.
347  bool smallHFOV=false;
348  bool highDist = false;
349  const HuginBase::VariableMapVector & vars = pano.getVariables();
350  for (HuginBase::VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
351  {
352  if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
353  if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
354  if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
355  if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
356  }
357 
358  wxString msg;
359  int style=0;
360  if (smallHFOV)
361  {
362  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?"));
363  style = wxYES_NO;
364  }
365  else
366  {
367  if (highDist)
368  {
369  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?"),
370  mean, sqrt(var), max);
371  style = wxYES_NO | wxICON_EXCLAMATION;
372  }
373  else
374  {
375  msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\nApply the changes?"),
376  mean, sqrt(var), max);
377  style = wxYES_NO | wxICON_EXCLAMATION;
378  }
379  };
380 
381  int id = wxMessageBox(msg, _("Optimization result"), style, activeWindow);
382 
383  return id == wxYES;
384 }
385 
386 void OptimizePanel::OnClose(wxCloseEvent& event)
387 {
388  DEBUG_TRACE("OnClose");
389  // do not close, just hide if we're not forced
390  if (event.CanVeto())
391  {
392  event.Veto();
393  Hide();
394  DEBUG_DEBUG("Hiding");
395  }
396  else
397  {
398  DEBUG_DEBUG("Closing");
399  Destroy();
400  }
401 }
402 
403 void OptimizePanel::OnReset(wxCommandEvent& e)
404 {
407  if(cmd!=NULL)
408  {
410  };
411 
412 };
413 
415 {
417 };
418 
419 void OptimizePanel::SetOnlyActiveImages(const bool onlyActive)
420 {
421  m_only_active_images_cb->SetValue(onlyActive);
423  m_lens_tree_list->MarkActiveImages(onlyActive);
424 };
425 
426 void OptimizePanel::OnCheckIgnoreLineCP(wxCommandEvent &e)
427 {
429 };
430 
431 void OptimizePanel::SetIgnoreLineCP(const bool noLineCp)
432 {
433  m_ignore_line_cp->SetValue(noLineCp);
434 };
435 
437 
438 
440  : wxXmlResourceHandler()
441 {
442  AddWindowStyles();
443 }
444 
446 {
447  XRC_MAKE_INSTANCE(cp, OptimizePanel)
448 
449  cp->Create(m_parentAsWindow,
450  GetID(),
451  GetPosition(), GetSize(),
452  GetStyle(wxT("style")),
453  GetName());
454 
455  SetupWindow( cp);
456 
457  return cp;
458 }
459 
461 {
462  return IsOfClass(node, wxT("OptimizePanel"));
463 }
464 
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:1641
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
END_EVENT_TABLE()
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:213
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:937
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:2169
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:1668
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:952
!! 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: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
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:994