00001
00002
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00143
00144 UIntSet imgs;
00145 if (m_only_active_images_cb->IsChecked() || m_pano->getPhotometricOptimizerSwitch()!=0)
00146 {
00147
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
00187
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
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
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
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
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
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
00315
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
00339 return;
00340 };
00341 smartOptimizePhotometric(optPano, optMode, points, progress, error);
00342 }
00343 else
00344 {
00345
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
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
00364 const VariableMapVector & vars = optPano.getVariables();
00365 GlobalCmdHist::getInstance().addCommand(
00366 new PT::UpdateImagesVariablesCmd(*m_pano, imgs, vars)
00367 );
00368
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
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)