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

Generated on Mon Sep 1 01:25:35 2014 for Hugintrunk by  doxygen 1.3.9.1