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;
00283             wxXmlResource::Get()->LoadDialog(&edit_dlg, this, wxT("edit_script_dialog"));
00284             wxTextCtrl *txtCtrl=XRCCTRL(edit_dlg,"script_edit_text",wxTextCtrl);
00285             txtCtrl->SetValue(wxString(scriptbuf.str().c_str(), *wxConvCurrent));
00286 
00287             char * script = 0;
00288             if (edit_dlg.ShowModal() == wxID_OK)
00289             {
00290                 script = strdup(txtCtrl->GetValue().mb_str(*wxConvCurrent));
00291             }
00292             else
00293             {
00294                 setlocale(LC_ALL,oldlocale);
00295                 free(oldlocale);
00296                 return;
00297             }
00298             HuginBase::PTools::optimize(optPano, script);
00299             free(script);
00300         }
00301         else
00302         {
00303             HuginBase::PTools::optimize(optPano);
00304         }
00305 #ifdef DEBUG
00306         // print optimized script to cout
00307         DEBUG_DEBUG("panorama after optimise():");
00308         optPano.printPanoramaScript(std::cerr, optPano.getOptimizeVector(), optPano.getOptions(), allImg, false);
00309 #endif
00310     }
00311 
00312     setlocale(LC_ALL,oldlocale);
00313     free(oldlocale);
00314 #ifdef __WXMSW__
00315     // the progress window of the optimizer is marked for deletion
00316     // but the final deletion happens only in the idle event
00317     // so we need to process the event to really close the progress window
00318     wxTheApp->ProcessIdle();
00319 #endif
00320     // calculate control point errors and display text.
00321     if (AskApplyResult(activeWindow, optPano))
00322     {
00323         if (!originalCps.empty())
00324         {
00325             // restore all control points
00326             optPano.setCtrlPoints(originalCps);
00327             // because the line cp were removed we need to calculate the cp error again
00328             HuginBase::PTools::calcCtrlPointErrors(optPano);
00329         };
00330         PanoCommand::GlobalCmdHist::getInstance().addCommand(
00331             new PanoCommand::UpdateVariablesCPSetCmd(*m_pano, imgs, optPano.getVariables(), optPano.getCtrlPoints())
00332         );
00333     }
00334 }
00335 
00336 bool OptimizePanel::AskApplyResult(wxWindow* activeWindow, const HuginBase::Panorama & pano)
00337 {
00338     double min;
00339     double max;
00340     double mean;
00341     double var;
00342     HuginBase::CalculateCPStatisticsError::calcCtrlPntsErrorStats(pano, min, max, mean, var, -1);
00343 
00344     // check for HFOV lines. if smaller than 1 report a warning;
00345     // also check for high distortion coefficients.
00346     bool smallHFOV=false;
00347     bool highDist = false;
00348     const HuginBase::VariableMapVector & vars = pano.getVariables();
00349     for (HuginBase::VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
00350     {
00351         if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
00352         if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
00353         if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
00354         if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
00355     }
00356 
00357     wxString msg;
00358     int style=0;
00359     if (smallHFOV)
00360     {
00361         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?"));
00362         style = wxYES_NO;
00363     }
00364     else
00365     {
00366         if (highDist)
00367         {
00368             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?"),
00369                    mean, sqrt(var), max);
00370             style = wxYES_NO | wxICON_EXCLAMATION;
00371         }
00372         else
00373         {
00374             msg.Printf(_("Optimizer run finished.\nResults:\n average control point distance: %f\n standard deviation: %f\n maximum: %f\n\nApply the changes?"),
00375                    mean, sqrt(var), max);
00376             style = wxYES_NO | wxICON_EXCLAMATION;
00377         }
00378     };
00379 
00380     int id = wxMessageBox(msg, _("Optimization result"), style, activeWindow);
00381 
00382     return id == wxYES;
00383 }
00384 
00385 void OptimizePanel::OnClose(wxCloseEvent& event)
00386 {
00387     DEBUG_TRACE("OnClose");
00388     // do not close, just hide if we're not forced
00389     if (event.CanVeto())
00390     {
00391         event.Veto();
00392         Hide();
00393         DEBUG_DEBUG("Hiding");
00394     }
00395     else
00396     {
00397         DEBUG_DEBUG("Closing");
00398         Destroy();
00399     }
00400 }
00401 
00402 void OptimizePanel::OnReset(wxCommandEvent& e)
00403 {
00404     PanoOperation::ResetOperation op(PanoOperation::ResetOperation::RESET_DIALOG_LENS);
00405     PanoCommand::PanoCommand* cmd=op.GetCommand(this,*m_pano, m_images_tree_list->GetSelectedImages(), MainFrame::Get()->GetGuiLevel());
00406     if(cmd!=NULL)
00407     {
00408         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
00409     };
00410 
00411 };
00412 
00413 void OptimizePanel::OnCheckOnlyActiveImages(wxCommandEvent &e)
00414 {
00415     MainFrame::Get()->SetOptimizeOnlyActiveImages(m_only_active_images_cb->IsChecked());
00416 };
00417 
00418 void OptimizePanel::SetOnlyActiveImages(const bool onlyActive)
00419 {
00420     m_only_active_images_cb->SetValue(onlyActive);
00421     m_images_tree_list->MarkActiveImages(onlyActive);
00422     m_lens_tree_list->MarkActiveImages(onlyActive);
00423 };
00424 
00425 void OptimizePanel::OnCheckIgnoreLineCP(wxCommandEvent &e)
00426 {
00427     MainFrame::Get()->SetOptimizeIgnoreLineCp(m_ignore_line_cp->IsChecked());
00428 };
00429 
00430 void OptimizePanel::SetIgnoreLineCP(const bool noLineCp)
00431 {
00432     m_ignore_line_cp->SetValue(noLineCp);
00433 };
00434 
00435 IMPLEMENT_DYNAMIC_CLASS(OptimizePanel, wxPanel)
00436 
00437 
00438 OptimizePanelXmlHandler::OptimizePanelXmlHandler()
00439                 : wxXmlResourceHandler()
00440 {
00441     AddWindowStyles();
00442 }
00443 
00444 wxObject *OptimizePanelXmlHandler::DoCreateResource()
00445 {
00446     XRC_MAKE_INSTANCE(cp, OptimizePanel)
00447 
00448     cp->Create(m_parentAsWindow,
00449                    GetID(),
00450                    GetPosition(), GetSize(),
00451                    GetStyle(wxT("style")),
00452                    GetName());
00453 
00454     SetupWindow( cp);
00455 
00456     return cp;
00457 }
00458 
00459 bool OptimizePanelXmlHandler::CanHandle(wxXmlNode *node)
00460 {
00461     return IsOfClass(node, wxT("OptimizePanel"));
00462 }
00463 
00464 IMPLEMENT_DYNAMIC_CLASS(OptimizePanelXmlHandler, wxXmlResourceHandler)

Generated on 17 Dec 2017 for Hugintrunk by  doxygen 1.4.7