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

Generated on 25 Jul 2016 for Hugintrunk by  doxygen 1.4.7