OptimizePhotometricPanel.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/RandomPointSampler.h>
00033 #include <PT/PhotometricOptimizer.h>
00034 #include <PT/PTOptimise.h>
00035 
00036 #include "hugin/OptimizePhotometricPanel.h"
00037 #include "hugin/CommandHistory.h"
00038 #include "hugin/MainFrame.h"
00039 #include "base_wx/MyProgressDialog.h"
00040 #include "hugin/config_defaults.h"
00041 #include "base_wx/wxImageCache.h"
00042 #include "hugin/ImagesTree.h"
00043 #include "hugin_base/panodata/OptimizerSwitches.h"
00044 #include "hugin/PanoOperation.h"
00045 
00046 using namespace std;
00047 using namespace PT;
00048 using namespace PTools;
00049 using namespace hugin_utils;
00050 using namespace vigra;
00051 using namespace vigra_ext;
00052 
00053 //============================================================================
00054 //============================================================================
00055 //============================================================================
00056 
00057 BEGIN_EVENT_TABLE(OptimizePhotometricPanel, wxPanel)
00058     EVT_CLOSE(OptimizePhotometricPanel::OnClose)
00059     EVT_BUTTON(XRCID("optimize_photo_panel_optimize"), OptimizePhotometricPanel::OnOptimizeButton)
00060     EVT_BUTTON(XRCID("optimize_photo_panel_reset"), OptimizePhotometricPanel::OnReset)
00061 END_EVENT_TABLE()
00062 
00063 OptimizePhotometricPanel::OptimizePhotometricPanel() : m_pano(0)
00064 {
00065 };
00066 
00067 bool OptimizePhotometricPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
00068                       long style, const wxString& name)
00069 {
00070     DEBUG_TRACE("");
00071     if (! wxPanel::Create(parent, id, pos, size, style, name))
00072     {
00073         return false;
00074     }
00075 
00076     wxXmlResource::Get()->LoadPanel(this, wxT("optimize_photo_panel"));
00077     wxPanel * panel = XRCCTRL(*this, "optimize_photo_panel", wxPanel);
00078 
00079     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00080     topsizer->Add(panel, 1, wxEXPAND, 0);
00081     SetSizer(topsizer);
00082 
00083     m_only_active_images_cb = XRCCTRL(*this, "optimize_photo_panel_only_active_images", wxCheckBox);
00084     DEBUG_ASSERT(m_only_active_images_cb);
00085     m_only_active_images_cb->SetValue(wxConfigBase::Get()->Read(wxT("/OptimizeOptimizePhotometricPanelPanel/OnlyActiveImages"),1l) != 0);
00086 
00087     m_images_tree = XRCCTRL(*this, "optimize_photo_panel_images", ImagesTreeCtrl);
00088     DEBUG_ASSERT(m_images_tree);
00089     m_lens_tree = XRCCTRL(*this, "optimize_photo_panel_lens", ImagesTreeCtrl);
00090     DEBUG_ASSERT(m_lens_tree);
00091 
00092     XRCCTRL(*this, "optimize_photo_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
00093 
00094     wxString text(_("Any variables below which are bold and underlined will be optimized."));
00095     text.Append(wxT(" "));
00096 #if defined __WXMAC__ || defined __WXOSX_COCOA__
00097     text.Append(_("Use command + left mouse click to toggle state of variables."));
00098 #else
00099     text.Append(_("Use control + left mouse click to toggle state of variables."));
00100 #endif
00101     text.Append(wxT(" "));
00102     text.Append(_("Variables which shown in normal font will act as references or anchors."));
00103     XRCCTRL(*this, "optimize_photo_panel_information_text", wxStaticText)->SetLabel(text);
00104 
00105     return true;
00106 }
00107 
00108 void OptimizePhotometricPanel::Init(Panorama * panorama)
00109 {
00110     m_pano = panorama;
00111     // observe the panorama
00112     m_pano->addObserver(this);
00113     m_images_tree->Init(m_pano);
00114     m_images_tree->SetOptimizerMode();
00115     m_images_tree->SetDisplayMode(ImagesTreeCtrl::DISPLAY_PHOTOMETRICS_IMAGES);
00116 
00117     m_lens_tree->Init(m_pano);
00118     m_lens_tree->SetOptimizerMode();
00119     m_lens_tree->SetGroupMode(ImagesTreeCtrl::GROUP_LENS);
00120     m_lens_tree->SetDisplayMode(ImagesTreeCtrl::DISPLAY_PHOTOMETRICS_LENSES);
00121     
00122 }
00123 
00124 void OptimizePhotometricPanel::SetGuiLevel(GuiLevel newGuiLevel)
00125 {
00126     m_images_tree->SetGuiLevel(newGuiLevel);
00127     m_lens_tree->SetGuiLevel(newGuiLevel);
00128 };
00129 
00130 OptimizePhotometricPanel::~OptimizePhotometricPanel()
00131 {
00132     DEBUG_TRACE("dtor, writing config");
00133     wxConfigBase::Get()->Write(wxT("/OptimizePhotometricPanel/OnlyActiveImages"),m_only_active_images_cb->IsChecked() ? 1l : 0l);
00134 
00135     m_pano->removeObserver(this);
00136     DEBUG_TRACE("dtor end");
00137 }
00138 
00139 void OptimizePhotometricPanel::OnOptimizeButton(wxCommandEvent & e)
00140 {
00141     DEBUG_TRACE("");
00142     // run optimizer
00143 
00144     UIntSet imgs;
00145     if (m_only_active_images_cb->IsChecked() || m_pano->getPhotometricOptimizerSwitch()!=0)
00146     {
00147         // use only selected images.
00148         imgs = m_pano->getActiveImages();
00149         if (imgs.size() < 2)
00150         {
00151             wxMessageBox(_("The project does not contain any active images.\nPlease activate at least 2 images in the (fast) preview window.\nOptimization canceled."),
00152 #ifdef _WINDOWS
00153                 _("Hugin"),
00154 #else
00155                 wxT(""),
00156 #endif
00157                 wxICON_ERROR | wxOK);
00158             return;
00159         } 
00160     }
00161     else
00162     {
00163         fill_set(imgs, 0, m_pano->getNrOfImages()-1);
00164     }
00165     runOptimizer(imgs);
00166 }
00167 
00168 void OptimizePhotometricPanel::panoramaChanged(PT::Panorama & pano)
00169 {
00170     m_images_tree->Enable(m_pano->getPhotometricOptimizerSwitch()==0);
00171     m_lens_tree->Enable(m_pano->getPhotometricOptimizerSwitch()==0);
00172 }
00173 
00174 void OptimizePhotometricPanel::panoramaImagesChanged(PT::Panorama &pano,
00175                                           const PT::UIntSet & imgNr)
00176 {
00177     XRCCTRL(*this, "optimize_photo_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>1);
00178     XRCCTRL(*this, "optimize_photo_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);    
00179 }
00180 
00181 void OptimizePhotometricPanel::runOptimizer(const UIntSet & imgs)
00182 {
00183     DEBUG_TRACE("");
00184     int mode = m_pano->getPhotometricOptimizerSwitch();
00185 
00186     // check if vignetting and response are linked, display a warning if they are not
00187     // The variables to check:
00188     const HuginBase::ImageVariableGroup::ImageVariableEnum vars[] = {
00189             HuginBase::ImageVariableGroup::IVE_EMoRParams,
00190             HuginBase::ImageVariableGroup::IVE_ResponseType,
00191             HuginBase::ImageVariableGroup::IVE_VigCorrMode,
00192             HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
00193             HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
00194         };
00195     // keep a list of commands needed to fix it:
00196     std::vector<PT::PanoCommand *> commands;
00197     HuginBase::ConstStandardImageVariableGroups variable_groups(*m_pano);
00198     HuginBase::ConstImageVariableGroup & lenses = variable_groups.getLenses();
00199     for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
00200     {
00201         std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
00202         links_needed.clear();
00203         for (int v = 0; v < 5; v++)
00204         {
00205             if (!lenses.getVarLinkedInPart(vars[v], i))
00206             {
00207                 links_needed.insert(vars[v]);
00208             }
00209         };
00210         if (!links_needed.empty())
00211         {
00212             commands.push_back(new PT::LinkLensVarsCmd(*m_pano, i, links_needed));
00213         }
00214     }
00215     // if the list of commands is empty, all is good and we don't need a warning.
00216     if (!commands.empty()) {
00217         int ok = wxMessageBox(_("The same vignetting and response parameters should\nbe applied for all images of a lens.\nCurrently each image can have different parameters.\nLink parameters?"), _("Link parameters"), wxYES_NO | wxICON_INFORMATION);
00218         if (ok == wxYES)
00219         {
00220             // perform all the commands we stocked up earilier.
00221             for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++)
00222             {
00223                 GlobalCmdHist::getInstance().addCommand(*it);
00224             }
00225         }
00226         else
00227         {
00228             // free all the commands, the user doesn't want them used.
00229             for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++)
00230             {
00231                 delete *it;
00232             }
00233         }
00234     }
00235 
00236     Panorama optPano = m_pano->getSubset(imgs);
00237     PanoramaOptions opts = optPano.getOptions();
00238 
00239     OptimizeVector optvars;
00240     if(mode==0)
00241     {
00242         optvars = optPano.getOptimizeVector();
00243         bool valid=false;
00244         for(unsigned int i=0;i<optvars.size() && !valid;i++)
00245         {
00246             if(set_contains(optvars[i], "Eev") || set_contains(optvars[i], "Er") || set_contains(optvars[i], "Eb") ||
00247                 set_contains(optvars[i], "Vb") || set_contains(optvars[i], "Vx") || set_contains(optvars[i], "Ra"))
00248             {
00249                 valid=true;
00250             };
00251         };
00252         if(!valid)
00253         {
00254             wxMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Exposure optimization"), wxOK | wxICON_INFORMATION);
00255             return;
00256         };
00257     };
00258 
00259     double error = 0;
00260     {
00261         std::vector<vigra_ext::PointPairRGB> points;
00262         long nPoints = 200;
00263         wxConfigBase::Get()->Read(wxT("/OptimizePhotometric/nRandomPointsPerImage"), &nPoints , HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS);
00264 
00265         ProgressReporterDialog progress(5.0, _("Photometric alignment"), _("Loading images"));
00266         progress.Show();
00267 
00268         nPoints = nPoints * optPano.getNrOfImages();
00269         // get the small images
00270         std::vector<vigra::FRGBImage *> srcImgs;
00271         for (size_t i=0; i < optPano.getNrOfImages(); i++)
00272         {
00273             ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename());
00274             vigra::FRGBImage * img = new FRGBImage;
00275             if (!e)
00276             {
00277                 wxMessageBox(_("Error: could not load all images"), _("Error"));
00278                 return;
00279             }
00280             if (e->image8 && e->image8->width() > 0)
00281             {
00282                 reduceToNextLevel(*(e->image8), *img);
00283                 transformImage(vigra::srcImageRange(*img), vigra::destImage(*img),
00284                                 vigra::functor::Arg1()/vigra::functor::Param(255.0));
00285             }
00286             else
00287             {
00288                 if (e->image16 && e->image16->width() > 0)
00289                 {
00290                     reduceToNextLevel(*(e->image16), *img);
00291                     transformImage(vigra::srcImageRange(*img), vigra::destImage(*img),
00292                                    vigra::functor::Arg1()/vigra::functor::Param(65535.0));
00293                 }
00294                 else
00295                 {
00296                     reduceToNextLevel(*(e->imageFloat), *img);
00297                 }
00298             };
00299             srcImgs.push_back(img);
00300         }
00301         bool randomPoints = true;
00302         extractPoints(optPano, srcImgs, nPoints, randomPoints, progress, points);
00303 
00304         if (points.size() == 0)
00305         {
00306             wxMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Error"));
00307             return;
00308         }
00309 
00310         try
00311         {
00312             if (mode != 0)
00313             {
00314                 // run automatic optimisation
00315                 // ensure that we have a valid anchor.
00316                 PanoramaOptions opts = optPano.getOptions();
00317                 if (opts.colorReferenceImage >= optPano.getNrOfImages())
00318                 {
00319                     opts.colorReferenceImage = 0;
00320                     optPano.setOptions(opts);
00321                 }
00322                 PhotometricOptimizeMode optMode;
00323                 switch(mode)
00324                 {
00325                     case (HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE):
00326                         optMode=OPT_PHOTOMETRIC_LDR;
00327                         break;
00328                     case (HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE | HuginBase::OPT_WHITEBALANCE):
00329                         optMode=OPT_PHOTOMETRIC_LDR_WB;
00330                         break;
00331                     case (HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE):
00332                         optMode=OPT_PHOTOMETRIC_HDR;
00333                         break;
00334                     case (HuginBase::OPT_WHITEBALANCE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE):
00335                         optMode=OPT_PHOTOMETRIC_HDR_WB;
00336                         break;
00337                     default:
00338                         //invalid combination
00339                         return;
00340                 };
00341                 smartOptimizePhotometric(optPano, optMode, points, progress, error);
00342             }
00343             else
00344             {
00345                 // optimize selected parameters
00346                 optimizePhotometric(optPano, optvars, points, progress, error);
00347             }
00348         }
00349         catch (std::exception & error)
00350         {
00351             wxMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Internal error"));
00352         }
00353     }
00354     wxYield();
00355 
00356     // display information about the estimation process:
00357     int ret = wxMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error*255),
00358                            _("Photometric optimization finished"), wxYES_NO | wxICON_INFORMATION,this);
00359 
00360     if (ret == wxYES)
00361     {
00362         DEBUG_DEBUG("Applying vignetting corr");
00363         // TODO: merge into a single update command
00364         const VariableMapVector & vars = optPano.getVariables();
00365         GlobalCmdHist::getInstance().addCommand(
00366                 new PT::UpdateImagesVariablesCmd(*m_pano, imgs, vars)
00367                                                );
00368         //now update panorama exposure value
00369         PanoramaOptions opts = m_pano->getOptions();
00370         opts.outputExposureValue = calcMeanExposure(*m_pano);
00371         GlobalCmdHist::getInstance().addCommand(
00372                 new PT::SetPanoOptionsCmd(*m_pano, opts)
00373                                                );
00374     }
00375 }
00376 
00377 void OptimizePhotometricPanel::OnClose(wxCloseEvent& event)
00378 {
00379     DEBUG_TRACE("OnClose");
00380     // do not close, just hide if we're not forced
00381     if (event.CanVeto())
00382     {
00383         event.Veto();
00384         Hide();
00385         DEBUG_DEBUG("Hiding");
00386     }
00387     else
00388     {
00389         DEBUG_DEBUG("Closing");
00390         Destroy();
00391     }
00392 }
00393 
00394 void OptimizePhotometricPanel::OnReset(wxCommandEvent& e)
00395 {
00396     PanoOperation::ResetOperation op(PanoOperation::ResetOperation::RESET_DIALOG_PHOTOMETRICS);
00397     PT::PanoCommand* cmd=op.GetCommand(this,*m_pano, m_images_tree->GetSelectedImages(), MainFrame::Get()->GetGuiLevel());
00398     if(cmd!=NULL)
00399     {
00400         GlobalCmdHist::getInstance().addCommand(cmd);
00401     };
00402 };
00403 
00404 IMPLEMENT_DYNAMIC_CLASS(OptimizePhotometricPanel, wxPanel)
00405 
00406 OptimizePhotometricPanelXmlHandler::OptimizePhotometricPanelXmlHandler()
00407                 : wxXmlResourceHandler()
00408 {
00409     AddWindowStyles();
00410 }
00411 
00412 wxObject *OptimizePhotometricPanelXmlHandler::DoCreateResource()
00413 {
00414     XRC_MAKE_INSTANCE(cp, OptimizePhotometricPanel)
00415 
00416     cp->Create(m_parentAsWindow,
00417                    GetID(),
00418                    GetPosition(), GetSize(),
00419                    GetStyle(wxT("style")),
00420                    GetName());
00421 
00422     SetupWindow( cp);
00423 
00424     return cp;
00425 }
00426 
00427 bool OptimizePhotometricPanelXmlHandler::CanHandle(wxXmlNode *node)
00428 {
00429     return IsOfClass(node, wxT("OptimizePhotometricPanel"));
00430 }
00431 
00432 IMPLEMENT_DYNAMIC_CLASS(OptimizePhotometricPanelXmlHandler, wxXmlResourceHandler)

Generated on Thu Sep 18 01:25:31 2014 for Hugintrunk by  doxygen 1.3.9.1