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