OptimizePanel.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This program is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software. If not, see
00023  *  <http://www.gnu.org/licenses/>.
00024  *
00025  */
00026 
00027 #include <config.h>
00028 #include "panoinc_WX.h"
00029 
00030 #include "panoinc.h"
00031 
00032 #include <panotools/PanoToolsOptimizerWrapper.h>
00033 #include <algorithms/optimizer/PTOptimizer.h>
00034 #include <algorithms/basic/CalculateCPStatistics.h>
00035 
00036 #include "hugin/OptimizePanel.h"
00037 #include "base_wx/CommandHistory.h"
00038 #include "base_wx/PanoCommand.h"
00039 #include "hugin/MainFrame.h"
00040 #include "base_wx/PTWXDlg.h"
00041 #include "hugin/config_defaults.h"
00042 #include "hugin/ImagesTree.h"
00043 #include "panodata/OptimizerSwitches.h"
00044 #include "hugin/PanoOperation.h"
00045 #include "base_wx/LensTools.h"
00046 
00047 using namespace std;
00048 using namespace HuginBase;
00049 using namespace hugin_utils;
00050 
00051 //============================================================================
00052 //============================================================================
00053 //============================================================================
00054 
00055 BEGIN_EVENT_TABLE(OptimizePanel, wxPanel)
00056     EVT_CLOSE(OptimizePanel::OnClose)
00057     EVT_BUTTON(XRCID("optimize_panel_optimize"), OptimizePanel::OnOptimizeButton)
00058     EVT_BUTTON(XRCID("optimize_panel_reset"), OptimizePanel::OnReset)
00059 END_EVENT_TABLE()
00060 
00061 
00062 OptimizePanel::OptimizePanel()
00063 {
00064     DEBUG_TRACE("");
00065 }
00066 
00067 bool OptimizePanel::Create(wxWindow* parent, wxWindowID id , const wxPoint& pos, const wxSize& size, long style, const wxString& name)
00068 {
00069     DEBUG_TRACE("");
00070     // Not needed here, wxPanel::Create is called by LoadPanel below
00071     if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
00072         return false;
00073     }
00074 
00075     // create a sub-panel and load class into it!
00076 
00077     // wxPanel::Create is called in here!
00078     wxXmlResource::Get()->LoadPanel(this, wxT("optimize_panel"));
00079     wxPanel * panel = XRCCTRL(*this, "optimize_panel", wxPanel);
00080 
00081     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00082     topsizer->Add(panel, 1, wxEXPAND, 0);
00083     SetSizer( topsizer );
00084 
00085     m_only_active_images_cb = XRCCTRL(*this, "optimizer_panel_only_active_images", wxCheckBox);
00086     DEBUG_ASSERT(m_only_active_images_cb);
00087     m_only_active_images_cb->SetValue(wxConfigBase::Get()->Read(wxT("/OptimizePanel/OnlyActiveImages"),1l) != 0);
00088 
00089     m_images_tree_list = XRCCTRL(*this, "optimize_panel_images", ImagesTreeCtrl);
00090     DEBUG_ASSERT(m_images_tree_list);
00091     m_lens_tree_list = XRCCTRL(*this, "optimize_panel_lenses", ImagesTreeCtrl);
00092     DEBUG_ASSERT(m_lens_tree_list);
00093 
00094     m_edit_cb = XRCCTRL(*this, "optimizer_panel_edit_script", wxCheckBox);
00095     DEBUG_ASSERT(m_edit_cb);
00096 
00097     XRCCTRL(*this, "optimizer_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
00098 
00099     wxString text(_("Any variables below which are bold and underlined will be optimized."));
00100     text.Append(wxT(" "));
00101 #if defined __WXMAC__ || defined __WXOSX_COCOA__
00102     text.Append(_("Use command + left mouse click to toggle state of variables."));
00103 #else
00104     text.Append(_("Use control + left mouse click to toggle state of variables."));
00105 #endif
00106     text.Append(wxT(" "));
00107     text.Append(_("Variables which shown in normal font will act as references or anchors."));
00108     XRCCTRL(*this, "optimizer_panel_information_text", wxStaticText)->SetLabel(text);
00109 
00110     return true;
00111 }
00112 
00113 void OptimizePanel::Init(HuginBase::Panorama * pano)
00114 {
00115     DEBUG_TRACE("");
00116     m_pano = pano;
00117 
00118     // observe the panorama
00119     m_pano->addObserver(this);
00120     m_images_tree_list->Init(m_pano);
00121     m_images_tree_list->SetOptimizerMode();
00122     m_images_tree_list->SetDisplayMode(ImagesTreeCtrl::DISPLAY_POSITION);
00123 
00124     m_lens_tree_list->Init(m_pano);
00125     m_lens_tree_list->SetOptimizerMode();
00126     m_lens_tree_list->SetGroupMode(ImagesTreeCtrl::GROUP_LENS);
00127     m_lens_tree_list->SetDisplayMode(ImagesTreeCtrl::DISPLAY_LENS);
00128 }
00129 
00130 void OptimizePanel::SetGuiLevel(GuiLevel newGuiLevel)
00131 {
00132     m_images_tree_list->SetGuiLevel(newGuiLevel);
00133     m_lens_tree_list->SetGuiLevel(newGuiLevel);
00134 };
00135 
00136 OptimizePanel::~OptimizePanel()
00137 {
00138     DEBUG_TRACE("dtor, writing config");
00139     wxConfigBase::Get()->Write(wxT("/OptimizePanel/OnlyActiveImages"),m_only_active_images_cb->IsChecked() ? 1l : 0l);
00140 
00141     m_pano->removeObserver(this);
00142     DEBUG_TRACE("dtor end");
00143 }
00144 
00145 void OptimizePanel::panoramaChanged(HuginBase::Panorama & pano)
00146 {
00147     //Show(m_pano->getOptimizerSwitch()==0);
00148     m_images_tree_list->Enable(m_pano->getOptimizerSwitch()==0);
00149     m_lens_tree_list->Enable(m_pano->getOptimizerSwitch()==0);
00150     m_edit_cb->Enable(m_pano->getOptimizerSwitch()==0);
00151 }
00152 
00153 void OptimizePanel::panoramaImagesChanged(HuginBase::Panorama &pano,
00154                                           const HuginBase::UIntSet & imgNr)
00155 {
00156     XRCCTRL(*this, "optimize_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>0);
00157     XRCCTRL(*this, "optimize_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);    
00158 };
00159 
00160 void OptimizePanel::OnOptimizeButton(wxCommandEvent & e)
00161 {
00162     DEBUG_TRACE("");
00163     // run optimizer
00164 
00165     UIntSet imgs;
00166     if (m_only_active_images_cb->IsChecked() || m_pano->getOptimizerSwitch()!=0)
00167     {
00168         // use only selected images.
00169         imgs = m_pano->getActiveImages();
00170         if (imgs.size() == 0)
00171         {
00172             wxMessageBox(_("The project does not contain any active images.\nPlease activate at least one image in the (fast) preview window.\nOptimization canceled."),
00173 #ifdef _WINDOWS
00174                 _("Hugin"),
00175 #else
00176                 wxT(""),
00177 #endif
00178                 wxICON_ERROR | wxOK);
00179             return;
00180         }
00181     }
00182     else
00183     {
00184         fill_set(imgs, 0, m_pano->getNrOfImages()-1);
00185     }
00186     if (CheckLensStacks(m_pano, true))
00187     {
00188         runOptimizer(imgs);
00189     };
00190 }
00191 
00192 void OptimizePanel::runOptimizer(const UIntSet & imgs)
00193 {
00194     DEBUG_TRACE("");
00195     // open window that shows a status dialog, and allows to
00196     // apply the results
00197     int mode=m_pano->getOptimizerSwitch();
00198     // remember active window for dialogs
00199     wxWindow* activeWindow = wxGetActiveWindow();
00200 
00201     Panorama optPano = m_pano->getSubset(imgs);
00202     HuginBase::PanoramaOptions opts = optPano.getOptions();
00203     switch(opts.getProjection())
00204     {
00205         case HuginBase::PanoramaOptions::RECTILINEAR:
00206         case HuginBase::PanoramaOptions::CYLINDRICAL:
00207         case HuginBase::PanoramaOptions::EQUIRECTANGULAR:
00208             break;
00209         default:
00210             // temporarily change to equirectangular
00211             opts.setProjection(HuginBase::PanoramaOptions::EQUIRECTANGULAR);
00212             optPano.setOptions(opts);
00213             break;
00214     }
00215     UIntSet allImg;
00216     fill_set(allImg,0, imgs.size()-1);
00217 
00218     char *p = setlocale(LC_ALL,NULL);
00219     char *oldlocale = strdup(p);
00220     setlocale(LC_ALL,"C");
00221 
00222     if (mode & HuginBase::OPT_PAIR )
00223     {
00224         // temporarily disable PT progress dialog..
00225         deregisterPTWXDlgFcn();
00226         {
00227             wxBusyCursor bc;
00228             // run pairwise optimizer
00229             HuginBase::AutoOptimise(optPano).run();
00230         }
00231 #ifdef DEBUG
00232         // print optimized script to cout
00233         DEBUG_DEBUG("panorama after autoOptimise():");
00234         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00235 #endif
00236 
00237         registerPTWXDlgFcn();
00238         // do global optimisation
00239         HuginBase::PTools::optimize(optPano);
00240 #ifdef DEBUG
00241         // print optimized script to cout
00242         DEBUG_DEBUG("panorama after optimise():");
00243         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00244 #endif
00245 
00246     }
00247     else
00248     {
00249         if (m_edit_cb->IsChecked() && mode==0)
00250         {
00251             // show and edit script..
00252             ostringstream scriptbuf;
00253             optPano.printPanoramaScript(scriptbuf, optPano.getOptimizeVector(), optPano.getOptions(), allImg, true);
00254             // open a text dialog with an editor inside
00255             wxDialog * edit_dlg = wxXmlResource::Get()->LoadDialog(this, wxT("edit_script_dialog"));
00256             wxTextCtrl *txtCtrl=XRCCTRL(*edit_dlg,"script_edit_text",wxTextCtrl);
00257             txtCtrl->SetValue(wxString(scriptbuf.str().c_str(), *wxConvCurrent));
00258 
00259             char * script = 0;
00260             if (edit_dlg->ShowModal() == wxID_OK)
00261             {
00262                 script = strdup(txtCtrl->GetValue().mb_str(*wxConvCurrent));
00263             }
00264             else
00265             {
00266                 setlocale(LC_ALL,oldlocale);
00267                 free(oldlocale);
00268                 return;
00269             }
00270             HuginBase::PTools::optimize(optPano, script);
00271             free(script);
00272         }
00273         else
00274         {
00275             HuginBase::PTools::optimize(optPano);
00276         }
00277 #ifdef DEBUG
00278         // print optimized script to cout
00279         DEBUG_DEBUG("panorama after optimise():");
00280         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00281 #endif
00282     }
00283 
00284     setlocale(LC_ALL,oldlocale);
00285     free(oldlocale);
00286 #ifdef __WXMSW__
00287     // the progress window of the optimizer is marked for deletion
00288     // but the final deletion happens only in the idle event
00289     // so we need to process the event to really close the progress window
00290     wxTheApp->ProcessIdle();
00291 #endif
00292     // calculate control point errors and display text.
00293     if (AskApplyResult(activeWindow, optPano))
00294     {
00295         PanoCommand::GlobalCmdHist::getInstance().addCommand(
00296             new PanoCommand::UpdateVariablesCPSetCmd(*m_pano, imgs, optPano.getVariables(), optPano.getCtrlPoints())
00297         );
00298     }
00299 }
00300 
00301 bool OptimizePanel::AskApplyResult(wxWindow* activeWindow, const Panorama & pano)
00302 {
00303     double min;
00304     double max;
00305     double mean;
00306     double var;
00307     HuginBase::CalculateCPStatisticsError::calcCtrlPntsErrorStats(pano, min, max, mean, var);
00308 
00309     // check for HFOV lines. if smaller than 1 report a warning;
00310     // also check for high distortion coefficients.
00311     bool smallHFOV=false;
00312     bool highDist = false;
00313     const HuginBase::VariableMapVector & vars = pano.getVariables();
00314     for (HuginBase::VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
00315     {
00316         if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
00317         if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
00318         if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
00319         if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
00320     }
00321 
00322     wxString msg;
00323     int style=0;
00324     if (smallHFOV)
00325     {
00326         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?"));
00327         style = wxYES_NO;
00328     }
00329     else
00330     {
00331         if (highDist)
00332         {
00333             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?"),
00334                    mean, sqrt(var), max);
00335             style = wxYES_NO | wxICON_EXCLAMATION;
00336         }
00337         else
00338         {
00339             msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\nApply the changes?"),
00340                    mean, sqrt(var), max);
00341             style = wxYES_NO | wxICON_EXCLAMATION;
00342         }
00343     };
00344 
00345     int id = wxMessageBox(msg, _("Optimization result"), style, activeWindow);
00346 
00347     return id == wxYES;
00348 }
00349 
00350 void OptimizePanel::OnClose(wxCloseEvent& event)
00351 {
00352     DEBUG_TRACE("OnClose");
00353     // do not close, just hide if we're not forced
00354     if (event.CanVeto())
00355     {
00356         event.Veto();
00357         Hide();
00358         DEBUG_DEBUG("Hiding");
00359     }
00360     else
00361     {
00362         DEBUG_DEBUG("Closing");
00363         Destroy();
00364     }
00365 }
00366 
00367 void OptimizePanel::OnReset(wxCommandEvent& e)
00368 {
00369     PanoOperation::ResetOperation op(PanoOperation::ResetOperation::RESET_DIALOG_LENS);
00370     PanoCommand::PanoCommand* cmd=op.GetCommand(this,*m_pano, m_images_tree_list->GetSelectedImages(), MainFrame::Get()->GetGuiLevel());
00371     if(cmd!=NULL)
00372     {
00373         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
00374     };
00375 
00376 };
00377 
00378 IMPLEMENT_DYNAMIC_CLASS(OptimizePanel, wxPanel)
00379 
00380 
00381 OptimizePanelXmlHandler::OptimizePanelXmlHandler()
00382                 : wxXmlResourceHandler()
00383 {
00384     AddWindowStyles();
00385 }
00386 
00387 wxObject *OptimizePanelXmlHandler::DoCreateResource()
00388 {
00389     XRC_MAKE_INSTANCE(cp, OptimizePanel)
00390 
00391     cp->Create(m_parentAsWindow,
00392                    GetID(),
00393                    GetPosition(), GetSize(),
00394                    GetStyle(wxT("style")),
00395                    GetName());
00396 
00397     SetupWindow( cp);
00398 
00399     return cp;
00400 }
00401 
00402 bool OptimizePanelXmlHandler::CanHandle(wxXmlNode *node)
00403 {
00404     return IsOfClass(node, wxT("OptimizePanel"));
00405 }
00406 
00407 IMPLEMENT_DYNAMIC_CLASS(OptimizePanelXmlHandler, wxXmlResourceHandler)

Generated on 31 Aug 2015 for Hugintrunk by  doxygen 1.4.7