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 "hugin_config.h"
00028 #include "panoinc_WX.h"
00029 
00030 #include "panoinc.h"
00031 
00032 #include <panotools/PanoToolsOptimizerWrapper.h>
00033 #include "hugin_base/panotools/PanoToolsUtils.h"
00034 #include <algorithms/optimizer/PTOptimizer.h>
00035 #include <algorithms/basic/CalculateCPStatistics.h>
00036 
00037 #include "hugin/OptimizePanel.h"
00038 #include "base_wx/CommandHistory.h"
00039 #include "base_wx/PanoCommand.h"
00040 #include "hugin/MainFrame.h"
00041 #include "base_wx/PTWXDlg.h"
00042 #include "hugin/config_defaults.h"
00043 #include "hugin/ImagesTree.h"
00044 #include "panodata/OptimizerSwitches.h"
00045 #include "hugin/PanoOperation.h"
00046 #include "base_wx/LensTools.h"
00047 
00048 //============================================================================
00049 //============================================================================
00050 //============================================================================
00051 
00052 BEGIN_EVENT_TABLE(OptimizePanel, wxPanel)
00053     EVT_CLOSE(OptimizePanel::OnClose)
00054     EVT_BUTTON(XRCID("optimize_panel_optimize"), OptimizePanel::OnOptimizeButton)
00055     EVT_BUTTON(XRCID("optimize_panel_reset"), OptimizePanel::OnReset)
00056     EVT_CHECKBOX(XRCID("optimizer_panel_only_active_images"), OptimizePanel::OnCheckOnlyActiveImages)
00057     EVT_CHECKBOX(XRCID("optimizer_panel_ignore_line_cp"), OptimizePanel::OnCheckIgnoreLineCP)
00058 END_EVENT_TABLE()
00059 
00060 
00061 OptimizePanel::OptimizePanel()
00062 {
00063     DEBUG_TRACE("");
00064 }
00065 
00066 bool OptimizePanel::Create(wxWindow* parent, wxWindowID id , const wxPoint& pos, const wxSize& size, long style, const wxString& name)
00067 {
00068     DEBUG_TRACE("");
00069     // Not needed here, wxPanel::Create is called by LoadPanel below
00070     if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
00071         return false;
00072     }
00073 
00074     // create a sub-panel and load class into it!
00075 
00076     // wxPanel::Create is called in here!
00077     wxXmlResource::Get()->LoadPanel(this, wxT("optimize_panel"));
00078     wxPanel * panel = XRCCTRL(*this, "optimize_panel", wxPanel);
00079 
00080     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00081     topsizer->Add(panel, 1, wxEXPAND, 0);
00082     SetSizer( topsizer );
00083 
00084     m_only_active_images_cb = XRCCTRL(*this, "optimizer_panel_only_active_images", wxCheckBox);
00085     DEBUG_ASSERT(m_only_active_images_cb);
00086     m_only_active_images_cb->SetValue(false);
00087     m_ignore_line_cp = XRCCTRL(*this, "optimizer_panel_ignore_line_cp", wxCheckBox);
00088     DEBUG_ASSERT(m_ignore_line_cp);
00089     m_ignore_line_cp->SetValue(false);
00090 
00091     m_images_tree_list = XRCCTRL(*this, "optimize_panel_images", ImagesTreeCtrl);
00092     DEBUG_ASSERT(m_images_tree_list);
00093     m_lens_tree_list = XRCCTRL(*this, "optimize_panel_lenses", ImagesTreeCtrl);
00094     DEBUG_ASSERT(m_lens_tree_list);
00095     SetOnlyActiveImages(wxConfigBase::Get()->Read(wxT("/OptimizePanel/OnlyActiveImages"), 1l) != 0);
00096 
00097     m_edit_cb = XRCCTRL(*this, "optimizer_panel_edit_script", wxCheckBox);
00098     DEBUG_ASSERT(m_edit_cb);
00099 
00100     XRCCTRL(*this, "optimizer_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
00101 
00102     return true;
00103 }
00104 
00105 void OptimizePanel::Init(HuginBase::Panorama * pano)
00106 {
00107     DEBUG_TRACE("");
00108     m_pano = pano;
00109 
00110     // observe the panorama
00111     m_pano->addObserver(this);
00112     m_images_tree_list->Init(m_pano);
00113     m_images_tree_list->SetOptimizerMode();
00114     m_images_tree_list->SetDisplayMode(ImagesTreeCtrl::DISPLAY_POSITION);
00115 
00116     m_lens_tree_list->Init(m_pano);
00117     m_lens_tree_list->SetOptimizerMode();
00118     m_lens_tree_list->SetGroupMode(ImagesTreeCtrl::GROUP_LENS);
00119     m_lens_tree_list->SetDisplayMode(ImagesTreeCtrl::DISPLAY_LENS);
00120 }
00121 
00122 void OptimizePanel::SetGuiLevel(GuiLevel newGuiLevel)
00123 {
00124     m_images_tree_list->SetGuiLevel(newGuiLevel);
00125     m_lens_tree_list->SetGuiLevel(newGuiLevel);
00126 };
00127 
00128 OptimizePanel::~OptimizePanel()
00129 {
00130     m_pano->removeObserver(this);
00131     DEBUG_TRACE("dtor end");
00132 }
00133 
00134 void OptimizePanel::panoramaChanged(HuginBase::Panorama & pano)
00135 {
00136     //Show(m_pano->getOptimizerSwitch()==0);
00137     m_images_tree_list->Enable(m_pano->getOptimizerSwitch()==0);
00138     m_lens_tree_list->Enable(m_pano->getOptimizerSwitch()==0);
00139     m_edit_cb->Enable(m_pano->getOptimizerSwitch()==0);
00140 }
00141 
00142 void OptimizePanel::panoramaImagesChanged(HuginBase::Panorama &pano,
00143                                           const HuginBase::UIntSet & imgNr)
00144 {
00145     XRCCTRL(*this, "optimize_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>0);
00146     XRCCTRL(*this, "optimize_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);    
00147 };
00148 
00149 void OptimizePanel::OnOptimizeButton(wxCommandEvent & e)
00150 {
00151     DEBUG_TRACE("");
00152     // run optimizer
00153 
00154     HuginBase::UIntSet imgs;
00155     if (m_only_active_images_cb->IsChecked() || m_pano->getOptimizerSwitch()!=0)
00156     {
00157         // use only selected images.
00158         imgs = m_pano->getActiveImages();
00159         if (imgs.size() == 0)
00160         {
00161             wxMessageBox(_("The project does not contain any active images.\nPlease activate at least one image in the (fast) preview window.\nOptimization canceled."),
00162 #ifdef _WIN32
00163                 _("Hugin"),
00164 #else
00165                 wxT(""),
00166 #endif
00167                 wxICON_ERROR | wxOK);
00168             return;
00169         }
00170     }
00171     else
00172     {
00173         fill_set(imgs, 0, m_pano->getNrOfImages()-1);
00174     }
00175     if (CheckLensStacks(m_pano, true))
00176     {
00177         runOptimizer(imgs, m_ignore_line_cp->IsChecked());
00178     };
00179 }
00180 
00181 void OptimizePanel::runOptimizer(const HuginBase::UIntSet & imgs, const bool ignoreLineCp)
00182 {
00183     DEBUG_TRACE("");
00184     // open window that shows a status dialog, and allows to
00185     // apply the results
00186     int mode=m_pano->getOptimizerSwitch();
00187     // remember active window for dialogs
00188     wxWindow* activeWindow = wxGetActiveWindow();
00189 
00190     HuginBase::Panorama optPano = m_pano->getSubset(imgs);
00191     if (optPano.getNrOfCtrlPoints() == 0)
00192     {
00193         wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
00194 #ifdef __WXMSW__
00195             _("Hugin"),
00196 #else
00197             wxT(""),
00198 #endif
00199             wxICON_ERROR | wxOK);
00200         return;
00201     };
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     HuginBase::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     HuginBase::CPVector originalCps;
00222 
00223     if (mode & HuginBase::OPT_PAIR )
00224     {
00225         // temporarily disable PT progress dialog..
00226         deregisterPTWXDlgFcn();
00227         {
00228             wxBusyCursor bc;
00229             // run pairwise optimizer
00230             HuginBase::AutoOptimise(optPano).run();
00231         }
00232 #ifdef DEBUG
00233         // print optimized script to cout
00234         DEBUG_DEBUG("panorama after autoOptimise():");
00235         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00236 #endif
00237 
00238         registerPTWXDlgFcn();
00239         // do global optimisation
00240         HuginBase::PTools::optimize(optPano);
00241 #ifdef DEBUG
00242         // print optimized script to cout
00243         DEBUG_DEBUG("panorama after optimise():");
00244         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00245 #endif
00246 
00247     }
00248     else
00249     {
00250         HuginBase::CPVector optCps;
00251         if (ignoreLineCp)
00252         {
00253             // store for later
00254             originalCps = optPano.getCtrlPoints();
00255             // remove all line cp
00256             for (auto& cp : originalCps)
00257             {
00258                 if (cp.mode == HuginBase::ControlPoint::X_Y)
00259                 {
00260                     optCps.push_back(cp);
00261                 };
00262             };
00263             if (optCps.empty())
00264             {
00265                 wxMessageBox(_("There are no control points in the current configuration for the optimizer.\nPlease add control points before running the optimizer.\nOptimization canceled."),
00266 #ifdef __WXMSW__
00267                     _("Hugin"),
00268 #else
00269                     wxT(""),
00270 #endif
00271                     wxICON_ERROR | wxOK);
00272                 return;
00273             }
00274             optPano.setCtrlPoints(optCps);
00275         };
00276         if (m_edit_cb->IsChecked() && mode==0)
00277         {
00278             // show and edit script..
00279             std::ostringstream scriptbuf;
00280             optPano.printPanoramaScript(scriptbuf, optPano.getOptimizeVector(), optPano.getOptions(), allImg, true);
00281             // open a text dialog with an editor inside
00282             wxDialog * edit_dlg = wxXmlResource::Get()->LoadDialog(this, wxT("edit_script_dialog"));
00283             wxTextCtrl *txtCtrl=XRCCTRL(*edit_dlg,"script_edit_text",wxTextCtrl);
00284             txtCtrl->SetValue(wxString(scriptbuf.str().c_str(), *wxConvCurrent));
00285 
00286             char * script = 0;
00287             if (edit_dlg->ShowModal() == wxID_OK)
00288             {
00289                 script = strdup(txtCtrl->GetValue().mb_str(*wxConvCurrent));
00290             }
00291             else
00292             {
00293                 setlocale(LC_ALL,oldlocale);
00294                 free(oldlocale);
00295                 return;
00296             }
00297             HuginBase::PTools::optimize(optPano, script);
00298             free(script);
00299         }
00300         else
00301         {
00302             HuginBase::PTools::optimize(optPano);
00303         }
00304 #ifdef DEBUG
00305         // print optimized script to cout
00306         DEBUG_DEBUG("panorama after optimise():");
00307         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00308 #endif
00309     }
00310 
00311     setlocale(LC_ALL,oldlocale);
00312     free(oldlocale);
00313 #ifdef __WXMSW__
00314     // the progress window of the optimizer is marked for deletion
00315     // but the final deletion happens only in the idle event
00316     // so we need to process the event to really close the progress window
00317     wxTheApp->ProcessIdle();
00318 #endif
00319     // calculate control point errors and display text.
00320     if (AskApplyResult(activeWindow, optPano))
00321     {
00322         if (!originalCps.empty())
00323         {
00324             // restore all control points
00325             optPano.setCtrlPoints(originalCps);
00326             // because the line cp were removed we need to calculate the cp error again
00327             HuginBase::PTools::calcCtrlPointErrors(optPano);
00328         };
00329         PanoCommand::GlobalCmdHist::getInstance().addCommand(
00330             new PanoCommand::UpdateVariablesCPSetCmd(*m_pano, imgs, optPano.getVariables(), optPano.getCtrlPoints())
00331         );
00332     }
00333 }
00334 
00335 bool OptimizePanel::AskApplyResult(wxWindow* activeWindow, const HuginBase::Panorama & pano)
00336 {
00337     double min;
00338     double max;
00339     double mean;
00340     double var;
00341     HuginBase::CalculateCPStatisticsError::calcCtrlPntsErrorStats(pano, min, max, mean, var, -1);
00342 
00343     // check for HFOV lines. if smaller than 1 report a warning;
00344     // also check for high distortion coefficients.
00345     bool smallHFOV=false;
00346     bool highDist = false;
00347     const HuginBase::VariableMapVector & vars = pano.getVariables();
00348     for (HuginBase::VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
00349     {
00350         if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
00351         if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
00352         if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
00353         if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
00354     }
00355 
00356     wxString msg;
00357     int style=0;
00358     if (smallHFOV)
00359     {
00360         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?"));
00361         style = wxYES_NO;
00362     }
00363     else
00364     {
00365         if (highDist)
00366         {
00367             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?"),
00368                    mean, sqrt(var), max);
00369             style = wxYES_NO | wxICON_EXCLAMATION;
00370         }
00371         else
00372         {
00373             msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\nApply the changes?"),
00374                    mean, sqrt(var), max);
00375             style = wxYES_NO | wxICON_EXCLAMATION;
00376         }
00377     };
00378 
00379     int id = wxMessageBox(msg, _("Optimization result"), style, activeWindow);
00380 
00381     return id == wxYES;
00382 }
00383 
00384 void OptimizePanel::OnClose(wxCloseEvent& event)
00385 {
00386     DEBUG_TRACE("OnClose");
00387     // do not close, just hide if we're not forced
00388     if (event.CanVeto())
00389     {
00390         event.Veto();
00391         Hide();
00392         DEBUG_DEBUG("Hiding");
00393     }
00394     else
00395     {
00396         DEBUG_DEBUG("Closing");
00397         Destroy();
00398     }
00399 }
00400 
00401 void OptimizePanel::OnReset(wxCommandEvent& e)
00402 {
00403     PanoOperation::ResetOperation op(PanoOperation::ResetOperation::RESET_DIALOG_LENS);
00404     PanoCommand::PanoCommand* cmd=op.GetCommand(this,*m_pano, m_images_tree_list->GetSelectedImages(), MainFrame::Get()->GetGuiLevel());
00405     if(cmd!=NULL)
00406     {
00407         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
00408     };
00409 
00410 };
00411 
00412 void OptimizePanel::OnCheckOnlyActiveImages(wxCommandEvent &e)
00413 {
00414     MainFrame::Get()->SetOptimizeOnlyActiveImages(m_only_active_images_cb->IsChecked());
00415 };
00416 
00417 void OptimizePanel::SetOnlyActiveImages(const bool onlyActive)
00418 {
00419     m_only_active_images_cb->SetValue(onlyActive);
00420     m_images_tree_list->MarkActiveImages(onlyActive);
00421     m_lens_tree_list->MarkActiveImages(onlyActive);
00422 };
00423 
00424 void OptimizePanel::OnCheckIgnoreLineCP(wxCommandEvent &e)
00425 {
00426     MainFrame::Get()->SetOptimizeIgnoreLineCp(m_ignore_line_cp->IsChecked());
00427 };
00428 
00429 void OptimizePanel::SetIgnoreLineCP(const bool noLineCp)
00430 {
00431     m_ignore_line_cp->SetValue(noLineCp);
00432 };
00433 
00434 IMPLEMENT_DYNAMIC_CLASS(OptimizePanel, wxPanel)
00435 
00436 
00437 OptimizePanelXmlHandler::OptimizePanelXmlHandler()
00438                 : wxXmlResourceHandler()
00439 {
00440     AddWindowStyles();
00441 }
00442 
00443 wxObject *OptimizePanelXmlHandler::DoCreateResource()
00444 {
00445     XRC_MAKE_INSTANCE(cp, OptimizePanel)
00446 
00447     cp->Create(m_parentAsWindow,
00448                    GetID(),
00449                    GetPosition(), GetSize(),
00450                    GetStyle(wxT("style")),
00451                    GetName());
00452 
00453     SetupWindow( cp);
00454 
00455     return cp;
00456 }
00457 
00458 bool OptimizePanelXmlHandler::CanHandle(wxXmlNode *node)
00459 {
00460     return IsOfClass(node, wxT("OptimizePanel"));
00461 }
00462 
00463 IMPLEMENT_DYNAMIC_CLASS(OptimizePanelXmlHandler, wxXmlResourceHandler)

Generated on 27 Jun 2017 for Hugintrunk by  doxygen 1.4.7