Hugin trunk 0.1
Loading...
Searching...
No Matches
OptimizePhotometricPanel.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
11/* This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this software. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 */
26
27#include "hugin_config.h"
28#include "panoinc_WX.h"
29
30#include "panoinc.h"
31
35
36#include <vigra_ext/Pyramid.h>
40#include "base_wx/PanoCommand.h"
41#include "hugin/MainFrame.h"
45#include "hugin/ImagesTree.h"
47#include "hugin/PanoOperation.h"
48#include "base_wx/wxutils.h"
49
50//============================================================================
51//============================================================================
52//============================================================================
53
57
58bool OptimizePhotometricPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
59 long style, const wxString& name)
60{
61 DEBUG_TRACE("");
62 if (! wxPanel::Create(parent, id, pos, size, style, name))
63 {
64 return false;
65 }
66
67 wxXmlResource::Get()->LoadPanel(this, "optimize_photo_panel");
68 wxPanel * panel = XRCCTRL(*this, "optimize_photo_panel", wxPanel);
69
71 topsizer->Add(panel, 1, wxEXPAND, 0);
73
74 m_only_active_images_cb = XRCCTRL(*this, "optimize_photo_panel_only_active_images", wxCheckBox);
77
78 m_images_tree = XRCCTRL(*this, "optimize_photo_panel_images", ImagesTreeCtrl);
80 m_lens_tree = XRCCTRL(*this, "optimize_photo_panel_lens", ImagesTreeCtrl);
82
83 XRCCTRL(*this, "optimize_photo_panel_splitter", wxSplitterWindow)->SetSashGravity(0.66);
84 // bind other events
86 Bind(wxEVT_BUTTON, &OptimizePhotometricPanel::OnOptimizeButton, this, XRCID("optimize_photo_panel_optimize"));
87 Bind(wxEVT_BUTTON, &OptimizePhotometricPanel::OnReset, this, XRCID("optimize_photo_panel_reset"));
88
89 return true;
90}
91
107
113
115{
116 DEBUG_TRACE("dtor, writing config");
117
118 m_pano->removeObserver(this);
119 DEBUG_TRACE("dtor end");
120}
121
126
133
135{
136 DEBUG_TRACE("");
137 // run optimizer
140 {
141 // use only selected images.
142 imgs = m_pano->getActiveImages();
143 if (imgs.size() < 2)
144 {
145 hugin_utils::HuginMessageBox(_("The project does not contain any active images.\nPlease activate at least 2 images in the (fast) preview window.\nOptimization canceled."),
146 _("Hugin"), wxICON_ERROR | wxOK, wxGetActiveWindow());
147 return;
148 }
149 }
150 else
151 {
152 fill_set(imgs, 0, m_pano->getNrOfImages()-1);
153 }
154 runOptimizer(imgs);
155}
156
162
164 const HuginBase::UIntSet & imgNr)
165{
166 XRCCTRL(*this, "optimize_photo_panel_optimize", wxButton)->Enable(pano.getNrOfImages()>1);
167 XRCCTRL(*this, "optimize_photo_panel_reset", wxButton)->Enable(pano.getNrOfImages()>0);
168}
169
171{
172 DEBUG_TRACE("");
173 const int mode = m_pano->getPhotometricOptimizerSwitch();
174 // disable optimize button, so user can't click twice
175 hugin_utils::DisableWindow disableButton(XRCCTRL(*this, "optimize_photo_panel_optimize", wxButton));
176
177 // check if vignetting and response are linked, display a warning if they are not
178 // The variables to check:
180 HuginBase::ImageVariableGroup::IVE_EMoRParams,
181 HuginBase::ImageVariableGroup::IVE_ResponseType,
182 HuginBase::ImageVariableGroup::IVE_VigCorrMode,
183 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff,
184 HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift
185 };
186 // keep a list of commands needed to fix it:
187 std::vector<PanoCommand::PanoCommand *> commands;
190 for (size_t i = 0; i < lenses.getNumberOfParts(); i++)
191 {
192 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed;
193 links_needed.clear();
194 for (int v = 0; v < 5; v++)
195 {
196 if (!lenses.getVarLinkedInPart(vars[v], i))
197 {
198 links_needed.insert(vars[v]);
199 }
200 };
201 if (!links_needed.empty())
202 {
203 commands.push_back(new PanoCommand::LinkLensVarsCmd(*m_pano, i, links_needed));
204 }
205 }
206 // if the list of commands is empty, all is good and we don't need a warning.
207 if (!commands.empty()) {
208 if (hugin_utils::HuginMessageBox(_("The same vignetting and response parameters should\nbe applied for all images of a lens.\nCurrently each image can have different parameters.\nLink parameters?"),
210 {
211 // perform all the commands we stocked up earilier using a CombinedPanoCommand, so only
212 // one command is in the history stack.
214 }
215 else
216 {
217 // free all the commands, the user doesn't want them used.
218 for (std::vector<PanoCommand::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); ++it)
219 {
220 delete *it;
221 }
222 }
223 }
224
226 HuginBase::PanoramaOptions opts = optPano.getOptions();
227
229 if(mode==0)
230 {
231 optvars = optPano.getOptimizeVector();
232 bool valid=false;
233 for(unsigned int i=0;i<optvars.size() && !valid;i++)
234 {
235 if(set_contains(optvars[i], "Eev") || set_contains(optvars[i], "Er") || set_contains(optvars[i], "Eb") ||
236 set_contains(optvars[i], "Vb") || set_contains(optvars[i], "Vx") || set_contains(optvars[i], "Ra"))
237 {
238 valid=true;
239 };
240 };
241 if(!valid)
242 {
243 hugin_utils::HuginMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
244 return;
245 };
246 };
247
248 double error = 0;
249 {
250 std::vector<vigra_ext::PointPairRGB> points;
251 long nPoints = 200;
252 wxConfigBase::Get()->Read("/OptimizePhotometric/nRandomPointsPerImage", &nPoints , HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS);
253
254 ProgressReporterDialog progress(optPano.getNrOfImages()+2, _("Photometric alignment"), _("Loading images"), this);
255 progress.Show();
256
257 nPoints = nPoints * optPano.getNrOfImages();
258 // get the small images
259 std::vector<vigra::FRGBImage *> srcImgs;
261 float imageStepSize = 1 / 255.0f;
262 for (size_t i=0; i < optPano.getNrOfImages(); i++)
263 {
264 ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename());
265 if (!e)
266 {
267 hugin_utils::HuginMessageBox(_("Error: could not load all images"), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
268 return;
269 }
271 vigra::FRGBImage * img = new vigra::FRGBImage;
272 if (e->imageFloat && e->imageFloat->size().area() > 0)
273 {
274 if (e->mask->size().area() > 0)
275 {
276 vigra::BImage maskSmall;
277 vigra_ext::reduceToNextLevel(*(e->imageFloat), *(e->mask), *img, maskSmall);
279 vigra::inspectImageIf(srcImageRange(*img), srcImage(maskSmall), minmax);
280 imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
281 }
282 else
283 {
284 vigra_ext::reduceToNextLevel(*(e->imageFloat), *img);
286 vigra::inspectImage(srcImageRange(*img), minmax);
287 imageStepSize = std::min(imageStepSize, (minmax.max - minmax.min) / 16384.0f);
288 };
290 }
291 else
292 {
293 if (e->image16 && e->image16->size().area() > 0)
294 {
295 vigra_ext::reduceToNextLevel(*(e->image16), *img);
296 vigra::omp::transformImage(vigra::srcImageRange(*img), vigra::destImage(*img),
297 vigra::functor::Arg1() / vigra::functor::Param(65535.0));
299 imageStepSize = std::min(imageStepSize, 1 / 65536.0f);
300 }
301 else
302 {
303 vigra_ext::reduceToNextLevel(*(e->get8BitImage()), *img);
304 vigra::omp::transformImage(vigra::srcImageRange(*img), vigra::destImage(*img),
305 vigra::functor::Arg1() / vigra::functor::Param(255.0));
307 imageStepSize = std::min(imageStepSize, 1 / 255.0f);
308 };
309 };
310 srcImgs.push_back(img);
311 limits.push_back(limit);
312 if (!progress.updateDisplayValue())
313 {
314 // check if user pressed cancel
315 return;
316 };
317 }
319
320 if (!progress.updateDisplayValue())
321 {
322 return;
323 };
324 if (points.empty())
325 {
326 hugin_utils::HuginMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
327 return;
328 }
329
330 progress.setMaximum(0);
331 progress.updateDisplay(_("Optimize..."));
332 try
333 {
334 if (mode != 0)
335 {
336 // run automatic optimisation
337 // ensure that we have a valid anchor.
338 HuginBase::PanoramaOptions opts = optPano.getOptions();
339 if (opts.colorReferenceImage >= optPano.getNrOfImages())
340 {
341 opts.colorReferenceImage = 0;
342 optPano.setOptions(opts);
343 }
345 switch(mode)
346 {
349 break;
352 break;
355 break;
358 break;
359 default:
360 //invalid combination
361 return;
362 };
364 }
365 else
366 {
367 // optimize selected parameters
369 }
370 if (progress.wasCancelled())
371 {
372 return;
373 }
374 }
375 catch (std::exception & error)
376 {
377 hugin_utils::HuginMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
378 return;
379 }
380 }
381 wxYield();
382
383 // display information about the estimation process:
384 if (hugin_utils::HuginMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error * 255),
386 {
387 DEBUG_DEBUG("Applying vignetting corr");
388 // TODO: merge into a single update command
389 const HuginBase::VariableMapVector & vars = optPano.getVariables();
390 std::vector<PanoCommand::PanoCommand*> optCommands;
391 optCommands.push_back(new PanoCommand::UpdateImagesVariablesCmd(*m_pano, imgs, vars));
392 //now update panorama exposure value
397 }
398}
399
401{
402 DEBUG_TRACE("OnClose");
403 // do not close, just hide if we're not forced
404 if (event.CanVeto())
405 {
406 event.Veto();
407 Hide();
408 DEBUG_DEBUG("Hiding");
409 }
410 else
411 {
412 DEBUG_DEBUG("Closing");
413 Destroy();
414 }
415}
416
426
427IMPLEMENT_DYNAMIC_CLASS(OptimizePhotometricPanel, wxPanel)
428
434
436{
438
439 cp->Create(m_parentAsWindow,
440 GetID(),
441 GetPosition(), GetSize(),
442 GetStyle("style"),
443 GetName());
444
445 SetupWindow( cp);
446
447 return cp;
448}
449
451{
452 return IsOfClass(node, "OptimizePhotometricPanel");
453}
454
455IMPLEMENT_DYNAMIC_CLASS(OptimizePhotometricPanelXmlHandler, wxXmlResourceHandler)
GuiLevel
Definition GuiLevel.h:32
declaration of main image tree control
some definitions to work with optimizer master switches
Definition of PanoOperation class.
static double calcMeanExposure(const PanoramaData &pano)
An ImageVariableGroup is a collection of image variables that can have some shared variable values.
Make an ImageVariableGroup for lenses and other common concepts.
class for storing the limits of an image used by the sampler to exclude too dark or too bright pixel
Panorama image options.
Model for a panorama.
Definition Panorama.h:153
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
void addObserver(PanoramaObserver *o)
add a panorama observer.
const int getPhotometricOptimizerSwitch() const
return the photometric optimizer master switch
Definition Panorama.h:467
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
static void optimizePhotometric(PanoramaData &pano, const OptimizeVector &vars, const PointPairs &correspondences, const float imageStepSize, AppBase::ProgressDisplay *progress, double &error)
PointPairs getResultPoints()
PointSampler & execute()
static void smartOptimizePhotometric(PanoramaData &pano, PhotometricOptimizeMode mode, const std::vector< vigra_ext::PointPairRGB > &correspondences, const float imageStepSize, AppBase::ProgressDisplay *progress, double &error)
use various heuristics to decide what to optimize.
PhotometricOptimizeMode
local optimize definition.
the main images tree control, used on images and optimizer tabs
Definition ImagesTree.h:37
HuginBase::UIntSet GetSelectedImages()
returns the selected images
void SetGuiLevel(GuiLevel newSetting)
sets the GuiLevel of the control
void Init(HuginBase::Panorama *pano)
initialization, connects all control with Panorama, register observer
void SetGroupMode(GroupMode newMode)
sets the group mode to given mode
void SetOptimizerMode()
sets to control into optimizer mode
void SetDisplayMode(DisplayMode newMode)
sets the display mode to given mode
@ DISPLAY_PHOTOMETRICS_LENSES
Definition ImagesTree.h:57
@ DISPLAY_PHOTOMETRICS_IMAGES
Definition ImagesTree.h:56
void MarkActiveImages(const bool markActive)
sets the flag, if active/disabled image should be marked with different colour
static MainFrame * Get()
hack.. kind of a pseudo singleton...
const GuiLevel GetGuiLevel() const
Definition MainFrame.h:185
void SetOptimizeOnlyActiveImages(const bool onlyActive)
sets the status of the "optimize only active images" menu item
void runOptimizer(const HuginBase::UIntSet &img)
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
void Init(HuginBase::Panorama *pano)
virtual void panoramaChanged(HuginBase::Panorama &pano)
receives notification about panorama changes
void OnCheckOnlyActiveImages(wxCommandEvent &e)
handle "only active images" checkbox
void SetGuiLevel(GuiLevel newGuiLevel)
virtual void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
receives notification about panorama changes
void SetOnlyActiveImages(const bool onlyActive)
for external setting of "only active image" checkbox
void OnOptimizeButton(wxCommandEvent &e)
run the optimizer
PanoCommand to combine other PanoCommands.
Definition PanoCommand.h:40
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
static GlobalCmdHist & getInstance()
Link a set of lens variables for some lens.
Base class for all panorama commands.
Definition Command.h:39
set the panorama options
update variables of a group of images
virtual PanoCommand::PanoCommand * GetCommand(wxWindow *parent, HuginBase::Panorama &pano, HuginBase::UIntSet images, GuiLevel guiLevel)
returns the appropriate PanoCommand::PanoCommand to be inserted into GlobalCmdHistory,...
PanoOperation to reset image variables.
helper class, it disables the control/window in the constructor and automatically enables it back in ...
Definition wxutils.h:98
#define HUGIN_PHOTOMETRIC_OPTIMIZER_NRPOINTS
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_DEBUG(msg)
Definition utils.h:68
#define DEBUG_TRACE(msg)
Definition utils.h:67
std::vector< VariableMap > VariableMapVector
std::vector< std::set< std::string > > OptimizeVector
std::set< unsigned int > UIntSet
std::vector< LimitIntensity > LimitIntensityVector
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
void transformImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
void reduceToNextLevel(ImageIn &in, ImageOut &out)
Definition Pyramid.h:136
include file for the hugin project
include file for the hugin project
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition stl_utils.h:74
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition stl_utils.h:81
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41