Hugin trunk 0.1
Loading...
Searching...
No Matches
PanoPanel.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
28#include "hugin_config.h"
29#include <wx/stdpaths.h>
30
31#include "panoinc_WX.h"
32#include "panoinc.h"
33#include "base_wx/platform.h"
34#include "base_wx/PanoCommand.h"
35#include "base_wx/wxutils.h"
36
38
39#include "nona/Stitcher.h"
40#include "base_wx/wxPlatform.h"
41
42extern "C" {
43#include <pano13/queryfeature.h>
44}
45
47#include "hugin/CPImageCtrl.h"
49#include "hugin/PanoPanel.h"
50#include "hugin/MainFrame.h"
51#include "hugin/huginApp.h"
56#include "base_wx/platform.h"
57#include "base_wx/huginConfig.h"
58#include "base_wx/LensTools.h"
63#include "lensdb/LensDB.h"
65
67 : pano(0), m_guiLevel(GUI_SIMPLE), updatesDisabled(false)
68{
69
70}
71
72bool PanoPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
73 long style, const wxString& name)
74{
75 if (! wxPanel::Create(parent, id, pos, size, style, name)) {
76 return false;
77 }
78
79 wxXmlResource::Get()->LoadPanel(this, "panorama_panel");
80 wxPanel * panel = XRCCTRL(*this, "panorama_panel", wxPanel);
81
83 topsizer->Add(panel, 1, wxEXPAND, 0);
85
86 // converts KILL_FOCUS events to usable TEXT_ENTER events
87 // get gui controls
88 m_ProjectionChoice = XRCCTRL(*this, "pano_choice_pano_type" ,wxChoice);
91
92 m_keepViewOnResize = true;
93 m_hasStacks=false;
94
95#ifdef ThisNeverHappens
96// provide some translatable strings for the drop down menu
97 wxLogMessage(_("Fisheye"));
98 wxLogMessage(_("Stereographic"));
99 wxLogMessage(_("Mercator"));
100 wxLogMessage(_("Trans Mercator"));
101 wxLogMessage(_("Sinusoidal"));
102 wxLogMessage(_("Lambert Cylindrical Equal Area"));
103 wxLogMessage(_("Lambert Equal Area Azimuthal"));
104 wxLogMessage(_("Albers Equal Area Conic"));
105 wxLogMessage(_("Miller Cylindrical"));
106 wxLogMessage(_("Panini"));
107 wxLogMessage(_("Architectural"));
108 wxLogMessage(_("Orthographic"));
109 wxLogMessage(_("Equisolid"));
110 wxLogMessage(_("Equirectangular Panini"));
111 wxLogMessage(_("Biplane"));
112 wxLogMessage(_("Triplane"));
113 wxLogMessage(_("Panini General"));
114 wxLogMessage(_("Thoby Projection"));
115 wxLogMessage(_("Hammer-Aitoff Equal Area"));
116#endif
117
118 /* populate with all available projection types */
120 for(int n=0; n < nP; n++) {
122 if (panoProjectionFeaturesQuery(n, &proj)) {
123 wxString str2(proj.name, wxConvLocal);
125 }
126 }
127 m_HFOVText = XRCCTRL(*this, "pano_text_hfov" ,wxTextCtrl);
129 m_HFOVText->PushEventHandler(new TextKillFocusHandler(this));
131 m_CalcHFOVButton = XRCCTRL(*this, "pano_button_calc_fov" ,wxButton);
134 m_VFOVText = XRCCTRL(*this, "pano_text_vfov" ,wxTextCtrl);
136 m_VFOVText->PushEventHandler(new TextKillFocusHandler(this));
138
139
140 m_WidthTxt = XRCCTRL(*this, "pano_val_width", wxTextCtrl);
142 m_WidthTxt->PushEventHandler(new TextKillFocusHandler(this));
144
145 m_CalcOptWidthButton = XRCCTRL(*this, "pano_button_opt_width" ,wxButton);
148
149 m_HeightTxt = XRCCTRL(*this, "pano_val_height", wxTextCtrl);
151 m_HeightTxt->PushEventHandler(new TextKillFocusHandler(this));
153
154
155 m_ROILeftTxt = XRCCTRL(*this, "pano_val_roi_left", wxTextCtrl);
157 m_ROILeftTxt->PushEventHandler(new TextKillFocusHandler(this));
159
160
161 m_ROIRightTxt = XRCCTRL(*this, "pano_val_roi_right", wxTextCtrl);
163 m_ROIRightTxt->PushEventHandler(new TextKillFocusHandler(this));
165
166 m_ROITopTxt = XRCCTRL(*this, "pano_val_roi_top", wxTextCtrl);
168 m_ROITopTxt->PushEventHandler(new TextKillFocusHandler(this));
170
171
172 m_ROIBottomTxt = XRCCTRL(*this, "pano_val_roi_bottom", wxTextCtrl);
174 m_ROIBottomTxt->PushEventHandler(new TextKillFocusHandler(this));
176
177 m_CalcOptROIButton = XRCCTRL(*this, "pano_button_opt_roi" ,wxButton);
180
181 m_RemapperChoice = XRCCTRL(*this, "pano_choice_remapper", wxChoice);
184 m_FusionChoice = XRCCTRL(*this, "pano_choice_fusion", wxChoice);
187 m_HDRMergeChoice = XRCCTRL(*this, "pano_choice_hdrmerge", wxChoice);
190 m_BlenderChoice = XRCCTRL(*this, "pano_choice_blender", wxChoice);
194 m_edgeFillChoice = XRCCTRL(*this, "pano_choice_edgefill", wxChoice);
196
197 m_StitchButton = XRCCTRL(*this, "pano_button_stitch", wxButton);
200
201 m_FileFormatChoice = XRCCTRL(*this, "pano_choice_file_format", wxChoice);
204 m_FileFormatOptionsLabel = XRCCTRL(*this, "pano_output_ldr_format_options_label", wxStaticText);
205
206 m_FileFormatJPEGQualityText = XRCCTRL(*this, "pano_output_normal_opts_jpeg_quality", wxTextCtrl);
208 m_FileFormatJPEGQualityText->PushEventHandler(new TextKillFocusHandler(this));
210
211 m_FileFormatTIFFCompChoice = XRCCTRL(*this, "pano_output_normal_opts_tiff_compression", wxChoice);
214
215 m_HDRFileFormatChoice = XRCCTRL(*this, "pano_choice_hdr_file_format", wxChoice);
218 m_HDRFileFormatLabelTIFFCompression = XRCCTRL(*this, "pano_output_hdr_opts_tiff_compression_label", wxStaticText);
220 m_FileFormatHDRTIFFCompChoice = XRCCTRL(*this, "pano_output_hdr_opts_tiff_compression", wxChoice);
223
224 m_pano_ctrls = XRCCTRL(*this, "pano_controls_panel", wxScrolledWindow);
226 m_pano_ctrls->SetSizeHints(20, 20);
227 m_pano_ctrls->FitInside();
228 m_pano_ctrls->SetScrollRate(10, 10);
229 // bind event handler for buttons
230 Bind(wxEVT_BUTTON, &PanoPanel::OnRemapperOptions, this, XRCID("pano_button_remapper_opts"));
231 Bind(wxEVT_BUTTON, &PanoPanel::OnFusionOptions, this, XRCID("pano_button_fusion_opts"));
232 Bind(wxEVT_BUTTON, &PanoPanel::OnHDRMergeOptions, this, XRCID("pano_button_hdrmerge_opts"));
233 Bind(wxEVT_BUTTON, &PanoPanel::OnBlenderOptions, this, XRCID("pano_button_blender_opts"));
234 Bind(wxEVT_BUTTON, &PanoPanel::OnEdgeFillOptions, this, XRCID("pano_button_fill_opts"));
235 // bind event handler for checkboxes
236 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_blended"));
237 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_layers"));
238 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_exposure_layers"));
239 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_exposure_blended"));
240 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_exposure_layers_fused"));
241 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_stacks"));
242 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_ldr_output_exposure_remapped"));
243 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_hdr_output_blended"));
244 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_hdr_output_stacks"));
245 Bind(wxEVT_CHECKBOX, &PanoPanel::OnOutputFilesChanged, this, XRCID("pano_cb_hdr_output_layers"));
246
247 return true;
248}
249
251{
252 pano = panorama;
253 // observe the panorama
254 pano->addObserver(this);
256}
257
259{
260 DEBUG_TRACE("dtor");
261 wxConfigBase::Get()->Write("Stitcher/DefaultRemapper",m_RemapperChoice->GetSelection());
262 wxConfigBase::Get()->Flush();
263
264 m_HFOVText->PopEventHandler(true);
265 m_VFOVText->PopEventHandler(true);
266 m_WidthTxt->PopEventHandler(true);
267 m_HeightTxt->PopEventHandler(true);
268 m_ROILeftTxt->PopEventHandler(true);
269 m_ROIRightTxt->PopEventHandler(true);
270 m_ROITopTxt->PopEventHandler(true);
271 m_ROIBottomTxt->PopEventHandler(true);
272 m_FileFormatJPEGQualityText->PopEventHandler(true);
273 pano->removeObserver(this);
274 DEBUG_TRACE("dtor end");
275}
276
277
279{
280 DEBUG_TRACE("");
281
282#ifdef STACK_CHECK //Disabled for 0.7.0 release
283 const bool hasStacks = StackCheck(pano);
284#else
285 const bool hasStacks = false;
286#endif
287
289
290 // update all options for dialog and notebook tab
292
293 m_oldOpt = opt;
294}
295
296
298{
299 DEBUG_TRACE("");
301
302 // Determine if there are stacks in the pano.
303 HuginBase::UIntSet activeImages = pano.getActiveImages();
304 HuginBase::UIntSet images = getImagesinROI(pano, activeImages);
305 std::vector<HuginBase::UIntSet> hdrStacks = HuginBase::getHDRStacks(pano, images, pano.getOptions());
306 DEBUG_DEBUG(hdrStacks.size() << ": HDR stacks detected");
307 const bool hasStacks = (hdrStacks.size() != activeImages.size());
308
309 // Only change the output types if the stack configuration has changed.
310 bool isChanged = (hasStacks != m_hasStacks);
311 if (isChanged) {
312 if (hasStacks) {
313 // Disable normal output formats
314 opt.outputLDRBlended = false;
315 opt.outputLDRLayers = false;
316 // Ensure at least one fused output is enabled
317 if (!(opt.outputLDRExposureBlended ||
318 opt.outputLDRExposureLayers ||
319 opt.outputLDRExposureRemapped ||
320 opt.outputHDRBlended ||
321 opt.outputHDRStacks ||
322 opt.outputHDRLayers)) {
323 opt.outputLDRExposureBlended = true;
324 }
325 } else {
326 // Disable fused output formats
327 opt.outputLDRExposureBlended = false;
328 opt.outputLDRExposureLayers = false;
329 opt.outputLDRExposureRemapped = false;
330 opt.outputHDRBlended = false;
331 opt.outputHDRStacks = false;
332 opt.outputHDRLayers = false;
333 // Ensure at least one normal output is enabled
334 if (!(opt.outputLDRBlended || opt.outputLDRLayers)) {
335 opt.outputLDRBlended = true;
336 }
337 }
339 }
340
342
343 return hasStacks;
344}
345
346
348{
349 Freeze();
350// m_HFOVSpin->SetRange(1,opt.getMaxHFOV());
351// m_VFOVSpin->SetRange(1,opt.getMaxVFOV());
352
353 m_ProjectionChoice->SetSelection(opt.getProjection());
354 m_keepViewOnResize = opt.fovCalcSupported(opt.getProjection());
355
356 std::string val;
357 val = hugin_utils::doubleToString(opt.getHFOV(),1);
358 m_HFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
359 val = hugin_utils::doubleToString(opt.getVFOV(), 1);
360 m_VFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
361
362 // disable VFOV edit field, due to bugs in setHeight(), setWidth()
363 const bool hasImages = !pano->getActiveImages().empty();
368
369 m_WidthTxt->ChangeValue(wxString::Format("%d", opt.getWidth()));
370 m_HeightTxt->ChangeValue(wxString::Format("%d", opt.getHeight()));
371
372 m_ROILeftTxt->ChangeValue(wxString::Format("%d", opt.getROI().left() ));
373 m_ROIRightTxt->ChangeValue(wxString::Format("%d", opt.getROI().right() ));
374 m_ROITopTxt->ChangeValue(wxString::Format("%d", opt.getROI().top() ));
375 m_ROIBottomTxt->ChangeValue(wxString::Format("%d", opt.getROI().bottom() ));
376 {
377 // format text for display of canvas dimension
378 wxString label = wxString::Format("%d x %d", opt.getROI().width(), opt.getROI().height());
379 // using opt.getROI().area() can overflow, so use width and height explicit to prevent this
380 if ( (opt.getROI().width() / 1000.0) * opt.getROI().height() / 1000.0 >= 20.0)
381 {
382 label.Append(wxString::Format("=%.0f MP", (opt.getROI().width() / 1000.0) * opt.getROI().height() / 1000.0));
383 }
384 else
385 {
386 label.Append(wxString::Format("=%.1f MP", opt.getROI().area() / 1000000.0));
387 };
388 if (opt.getROI().width() >0 && opt.getROI().height() > 0)
389 {
390 const int commonDivisor = hugin_utils::gcd(opt.getROI().width(), opt.getROI().height());
391 if (commonDivisor > std::pow(10, hugin_utils::floori(log10f(std::max(opt.getROI().width(), opt.getROI().height()))) - 2))
392 {
393 label.Append(wxString::Format(", %d:%d", opt.getROI().width() / commonDivisor, opt.getROI().height() / commonDivisor));
394 }
395 else
396 {
397 float ratio = 1.0f * opt.getROI().width() / opt.getROI().height();
398 if (ratio > 1.0f)
399 {
400 label.Append(wxString::Format(", %.2f:1", ratio));
401 }
402 else
403 {
404 label.Append(wxString::Format(", 1:%.2f", 1.0f/ratio));
405 };
406 };
407 };
408 XRCCTRL(*this, "pano_size_label", wxStaticText)->SetLabel(label);
409 };
410
411 // output types
412 XRCCTRL(*this, "pano_cb_ldr_output_blended", wxCheckBox)->SetValue(opt.outputLDRBlended);
413 XRCCTRL(*this, "pano_cb_ldr_output_exposure_blended", wxCheckBox)->SetValue(opt.outputLDRExposureBlended);
414 XRCCTRL(*this, "pano_cb_ldr_output_exposure_layers_fused", wxCheckBox)->SetValue(opt.outputLDRExposureLayersFused);
415 XRCCTRL(*this, "pano_cb_hdr_output_blended", wxCheckBox)->SetValue(opt.outputHDRBlended);
416 XRCCTRL(*this, "pano_cb_hdr_output_blended", wxCheckBox)->Show(opt.outputHDRBlended || m_guiLevel>GUI_SIMPLE);
417
418 //remapped images
419 XRCCTRL(*this, "pano_text_remapped_images", wxStaticText)->Show(opt.outputLDRLayers || opt.outputLDRExposureRemapped || opt.outputHDRLayers || m_guiLevel>GUI_SIMPLE);
420 XRCCTRL(*this, "pano_cb_ldr_output_layers", wxCheckBox)->SetValue(opt.outputLDRLayers);
421 XRCCTRL(*this, "pano_cb_ldr_output_layers", wxCheckBox)->Show(opt.outputLDRLayers || m_guiLevel>GUI_SIMPLE);
422 XRCCTRL(*this, "pano_cb_ldr_output_exposure_remapped", wxCheckBox)->SetValue(opt.outputLDRExposureRemapped);
423 XRCCTRL(*this, "pano_cb_ldr_output_exposure_remapped", wxCheckBox)->Show(opt.outputLDRExposureRemapped || m_guiLevel>GUI_SIMPLE);
424 XRCCTRL(*this, "pano_cb_hdr_output_layers", wxCheckBox)->SetValue(opt.outputHDRLayers);
425 XRCCTRL(*this, "pano_cb_hdr_output_layers", wxCheckBox)->Show(opt.outputHDRLayers || m_guiLevel>GUI_SIMPLE);
426
427 //stacks
428 XRCCTRL(*this, "pano_text_stacks", wxStaticText)->Show(opt.outputHDRStacks || opt.outputLDRStacks || m_guiLevel>GUI_SIMPLE);
429 XRCCTRL(*this, "pano_cb_ldr_output_stacks", wxCheckBox)->SetValue(opt.outputLDRStacks);
430 XRCCTRL(*this, "pano_cb_ldr_output_stacks", wxCheckBox)->Show(opt.outputLDRStacks || m_guiLevel>GUI_SIMPLE);
431 XRCCTRL(*this, "pano_cb_hdr_output_stacks", wxCheckBox)->SetValue(opt.outputHDRStacks);
432 XRCCTRL(*this, "pano_cb_hdr_output_stacks", wxCheckBox)->Show(opt.outputHDRStacks || m_guiLevel>GUI_SIMPLE);
433
434 //layers
435 XRCCTRL(*this, "pano_text_layers", wxStaticText)->Show(opt.outputLDRExposureLayers || m_guiLevel>GUI_SIMPLE);
436 XRCCTRL(*this, "pano_cb_ldr_output_exposure_layers", wxCheckBox)->SetValue(opt.outputLDRExposureLayers);
437 XRCCTRL(*this, "pano_cb_ldr_output_exposure_layers", wxCheckBox)->Show(opt.outputLDRExposureLayers || m_guiLevel>GUI_SIMPLE);
438
439 bool anyOutputSelected = (opt.outputLDRBlended ||
440 opt.outputLDRLayers ||
441 opt.outputLDRExposureLayers ||
442 opt.outputLDRExposureBlended ||
443 opt.outputLDRExposureLayersFused ||
444 opt.outputLDRExposureRemapped ||
445 opt.outputLDRStacks ||
446 opt.outputHDRBlended ||
447 opt.outputHDRStacks ||
448 opt.outputHDRLayers);
449
450 //do not let the user stitch unless there are active images and an output selected.
453
454#ifdef STACK_CHECK //Disabled for 0.7.0 release
455 if (hasStacks) {
456 XRCCTRL(*this,"pano_cb_ldr_output_blended",wxCheckBox)->Disable();
457 XRCCTRL(*this,"pano_cb_ldr_output_layers",wxCheckBox)->Disable();
458
459 XRCCTRL(*this,"pano_cb_ldr_output_exposure_layers",wxCheckBox)->Enable();
460 XRCCTRL(*this,"pano_cb_ldr_output_exposure_blended",wxCheckBox)->Enable();
461 XRCCTRL(*this,"pano_cb_ldr_output_exposure_remapped",wxCheckBox)->Enable();
462 XRCCTRL(*this,"pano_cb_hdr_output_blended",wxCheckBox)->Enable();
463 XRCCTRL(*this,"pano_cb_hdr_output_stacks",wxCheckBox)->Enable();
464 XRCCTRL(*this,"pano_cb_hdr_output_layers",wxCheckBox)->Enable();
465
466 } else {
467 XRCCTRL(*this,"pano_cb_ldr_output_blended",wxCheckBox)->Enable();
468 XRCCTRL(*this,"pano_cb_ldr_output_layers",wxCheckBox)->Enable();
469
470 XRCCTRL(*this,"pano_cb_ldr_output_exposure_layers",wxCheckBox)->Disable();
471 XRCCTRL(*this,"pano_cb_ldr_output_exposure_blended",wxCheckBox)->Disable();
472 XRCCTRL(*this,"pano_cb_ldr_output_exposure_remapped",wxCheckBox)->Disable();
473
474 XRCCTRL(*this,"pano_cb_hdr_output_blended",wxCheckBox)->Disable();
475 XRCCTRL(*this,"pano_cb_hdr_output_stacks",wxCheckBox)->Disable();
476 XRCCTRL(*this,"pano_cb_hdr_output_layers",wxCheckBox)->Disable();
477 }
478#endif
479
482 XRCCTRL(*this, "pano_button_remapper_opts", wxButton)->Show(m_guiLevel>GUI_SIMPLE);
483 XRCCTRL(*this, "pano_button_remapper_opts", wxButton)->Enable(m_guiLevel>GUI_SIMPLE);
484 XRCCTRL(*this, "pano_text_remapper", wxStaticText)->Show(m_guiLevel>GUI_SIMPLE);
485 XRCCTRL(*this, "pano_text_processing", wxStaticText)->Show(m_guiLevel>GUI_SIMPLE);
486
487 bool blenderEnabled = (opt.outputLDRBlended ||
488 opt.outputLDRExposureBlended ||
489 opt.outputLDRExposureLayersFused ||
490 opt.outputLDRExposureLayers ||
491 opt.outputHDRBlended ) && m_guiLevel>GUI_SIMPLE;
492
495 // select correct blending mechanism
497 XRCCTRL(*this, "pano_button_blender_opts", wxButton)->Enable(blenderEnabled);
498 XRCCTRL(*this, "pano_button_blender_opts", wxButton)->Show(m_guiLevel>GUI_SIMPLE);
499 XRCCTRL(*this, "pano_text_blender", wxStaticText)->Enable(blenderEnabled);
500 XRCCTRL(*this, "pano_text_blender", wxStaticText)->Show(m_guiLevel>GUI_SIMPLE);
501 m_edgeFillChoice->SetSelection(static_cast<int>(opt.edgeFillMode));
502 XRCCTRL(*this, "pano_button_fill_opts", wxButton)->Enable(m_edgeFillChoice->GetSelection() != 0);
503
504 bool fusionEnabled = (opt.outputLDRExposureBlended || opt.outputLDRExposureLayersFused || opt.outputLDRStacks) && m_guiLevel>GUI_SIMPLE;
507 XRCCTRL(*this, "pano_button_fusion_opts", wxButton)->Enable(fusionEnabled);
508 XRCCTRL(*this, "pano_button_fusion_opts", wxButton)->Show(m_guiLevel>GUI_SIMPLE);
509 XRCCTRL(*this, "pano_text_fusion", wxStaticText)->Enable(fusionEnabled);
510 XRCCTRL(*this, "pano_text_fusion", wxStaticText)->Show(m_guiLevel>GUI_SIMPLE);
511
512 bool hdrMergeEnabled = (opt.outputHDRBlended || opt.outputHDRStacks) && m_guiLevel>GUI_SIMPLE;
515 XRCCTRL(*this, "pano_button_hdrmerge_opts", wxButton)->Enable(hdrMergeEnabled);
516 XRCCTRL(*this, "pano_button_hdrmerge_opts", wxButton)->Show(m_guiLevel>GUI_SIMPLE);
517 XRCCTRL(*this, "pano_text_hdrmerge", wxStaticText)->Enable(hdrMergeEnabled);
518 XRCCTRL(*this, "pano_text_hdrmerge", wxStaticText)->Show(m_guiLevel>GUI_SIMPLE);
519
522 XRCCTRL(*this, "pano_button_fill_opts", wxButton)->Enable(m_guiLevel > GUI_SIMPLE);
523 XRCCTRL(*this, "pano_button_fill_opts", wxButton)->Show(m_guiLevel > GUI_SIMPLE);
524 XRCCTRL(*this, "pano_text_edgefill", wxStaticText)->Enable(m_guiLevel > GUI_SIMPLE);
525 XRCCTRL(*this, "pano_text_edgefill", wxStaticText)->Show(m_guiLevel > GUI_SIMPLE);
526
527 // output file mode
528 bool ldr_pano_enabled = opt.outputLDRBlended ||
529 opt.outputLDRExposureBlended ||
530 opt.outputLDRExposureLayersFused;
531
532 XRCCTRL(*this, "pano_output_ldr_format_label", wxStaticText)->Enable(ldr_pano_enabled);
537
538 long i=0;
539 if (opt.outputImageType == "tif") {
540 i = 0;
542 m_FileFormatOptionsLabel->SetLabel(_("Compression:"));
545 if (opt.outputImageTypeCompression == "PACKBITS") {
546 m_FileFormatTIFFCompChoice->SetSelection(1);
547 } else if (opt.outputImageTypeCompression == "LZW") {
548 m_FileFormatTIFFCompChoice->SetSelection(2);
549 } else if (opt.outputImageTypeCompression == "DEFLATE") {
550 m_FileFormatTIFFCompChoice->SetSelection(3);
551 } else {
552 m_FileFormatTIFFCompChoice->SetSelection(0);
553 }
554 } else if (opt.outputImageType == "jpg") {
555 i = 1;
557 m_FileFormatOptionsLabel->SetLabel(_("Quality:"));
560 m_FileFormatJPEGQualityText->ChangeValue(wxString::Format("%d", opt.quality));
561 } else if (opt.outputImageType == "png") {
565 i = 2;
566 } else if (opt.outputImageType == "exr") {
571 i = 3;
572 } else
573 wxLogError("INTERNAL error: unknown output image type");
574
575 m_FileFormatChoice->SetSelection(i);
576
577 bool hdr_pano_enabled = opt.outputHDRBlended;
578
579 XRCCTRL(*this, "pano_output_hdr_format_label", wxStaticText)->Enable(hdr_pano_enabled);
580 XRCCTRL(*this, "pano_output_hdr_format_label", wxStaticText)->Show(hdr_pano_enabled || m_guiLevel>GUI_SIMPLE);
587
588 i=0;
589 if (opt.outputImageTypeHDR == "exr") {
590 i = 0;
593 } else if (opt.outputImageTypeHDR == "tif") {
594 i = 1;
597 if (opt.outputImageTypeHDRCompression == "PACKBITS") {
598 m_FileFormatHDRTIFFCompChoice->SetSelection(1);
599 } else if (opt.outputImageTypeHDRCompression == "LZW") {
600 m_FileFormatHDRTIFFCompChoice->SetSelection(2);
601 } else if (opt.outputImageTypeHDRCompression == "DEFLATE") {
602 m_FileFormatHDRTIFFCompChoice->SetSelection(3);
603 } else {
604 m_FileFormatHDRTIFFCompChoice->SetSelection(0);
605 }
606 } else
607 wxLogError("INTERNAL error: unknown hdr output image type");
608
609 m_HDRFileFormatChoice->SetSelection(i);
610
611 m_pano_ctrls->FitInside();
612 Layout();
613 Thaw();
614
615#ifdef __WXMSW__
616 this->Refresh(false);
617#endif
618}
619
620void PanoPanel::ProjectionChanged ( wxCommandEvent & e )
621{
622 if (updatesDisabled) return;
624// PanoramaOptions::ProjectionFormat oldP = opt.getProjection();
625
627// int w = opt.getWidth();
628// int h = opt.getHeight();
630
633 );
634 DEBUG_DEBUG ("Projection changed: " << newP)
635}
636
637void PanoPanel::HFOVChanged ( wxCommandEvent & e )
638{
639 if (updatesDisabled) return;
641
642
643 wxString text = m_HFOVText->GetValue();
644 DEBUG_INFO ("HFOV = " << text.mb_str(wxConvLocal) );
645 if (text == wxEmptyString) {
646 return;
647 }
648
649 double hfov;
650 if (!hugin_utils::str2double(text, hfov)) {
651 wxLogError(_("Value must be numeric."));
652 return;
653 }
654
655 if ( hfov <=0 || hfov > opt.getMaxHFOV()) {
656 wxLogError(wxString::Format(
657 _("Invalid HFOV value. Maximum HFOV for this projection is %lf."),
658 opt.getMaxHFOV()));
659 }
660 opt.setHFOV(hfov);
661 // recalculate panorama height...
664 );
665
666 DEBUG_INFO ( "new hfov: " << hfov )
667}
668
669void PanoPanel::VFOVChanged ( wxCommandEvent & e )
670{
671 if (updatesDisabled) return;
673
674 wxString text = m_VFOVText->GetValue();
675 DEBUG_INFO ("VFOV = " << text.mb_str(wxConvLocal) );
676 if (text == wxEmptyString) {
677 return;
678 }
679
680 double vfov;
682 wxLogError(_("Value must be numeric."));
683 return;
684 }
685
686 if ( vfov <=0 || vfov > opt.getMaxVFOV()) {
687 wxLogError(wxString::Format(
688 _("Invalid VFOV value. Maximum VFOV for this projection is %lf."),
689 opt.getMaxVFOV()));
690 vfov = opt.getMaxVFOV();
691 }
692 opt.setVFOV(vfov);
693 // recalculate panorama height...
696 );
697
698 DEBUG_INFO ( "new vfov: " << vfov )
699}
700
701/*
702void PanoPanel::VFOVChanged ( wxCommandEvent & e )
703{
704 DEBUG_TRACE("")
705 if (updatesDisabled) return;
706 PanoramaOptions opt = pano->getOptions();
707 int vfov = m_VFOVSpin->GetValue() ;
708
709 if (vfov != opt.getVFOV()) {
710 opt.setVFOV(vfov);
711 GlobalCmdHist::getInstance().addCommand(
712 new PanoCommand::SetPanoOptionsCmd( pano, opt )
713 );
714 DEBUG_INFO ( "new vfov: " << vfov << " => height: " << opt.getHeight() );
715 } else {
716 DEBUG_DEBUG("not setting same fov");
717 }
718}
719*/
720
721void PanoPanel::WidthChanged ( wxCommandEvent & e )
722{
723 if (updatesDisabled) return;
725 long nWidth;
726 if (m_WidthTxt->GetValue().ToLong(&nWidth)) {
727 if (nWidth <= 0) return;
728 opt.setWidth((unsigned int) nWidth, m_keepViewOnResize);
731 );
733 } else {
734 wxLogError(_("width needs to be an integer bigger than 0"));
735 }
736}
737
738void PanoPanel::HeightChanged ( wxCommandEvent & e )
739{
740 if (updatesDisabled) return;
742 long nHeight;
743 if (m_HeightTxt->GetValue().ToLong(&nHeight)) {
744 if(nHeight <= 0) return;
745 opt.setHeight((unsigned int) nHeight);
748 );
750 } else {
751 wxLogError(_("height needs to be an integer bigger than 0"));
752 }
753}
754
755void PanoPanel::ROIChanged ( wxCommandEvent & e )
756{
757 if (updatesDisabled) return;
759 long left, right, top, bottom;
760 if (!m_ROITopTxt->GetValue().ToLong(&top)) {
761 wxLogError(_("Top needs to be an integer bigger than 0"));
762 return;
763 }
764 if (!m_ROILeftTxt->GetValue().ToLong(&left)) {
765 wxLogError(_("left needs to be an integer bigger than 0"));
766 return;
767 }
768 if (!m_ROIRightTxt->GetValue().ToLong(&right)) {
769 wxLogError(_("right needs to be an integer bigger than 0"));
770 return;
771 }
772 if (!m_ROIBottomTxt->GetValue().ToLong(&bottom)) {
773 wxLogError(_("bottom needs to be an integer bigger than 0"));
774 return;
775 }
776 opt.setROI(vigra::Rect2D(left, top, right, bottom));
777
778 // make sure that left is really to the left of right
779 if(opt.getROI().width()<1) {
780 wxLogError(_("Left boundary must be smaller than right."));
781 UpdateDisplay(pano->getOptions(), false);
782 return;
783 }
784 // make sure that top is really higher than bottom
785 if(opt.getROI().height()<1) {
786 wxLogError(_("Top boundary must be smaller than bottom."));
787 UpdateDisplay(pano->getOptions(), false);
788 return;
789 }
790
793 );
794}
795
796
798{
799// m_HFOVSpin->Enable(enable);
800// m_VFOVSpin->Enable(enable);
801 m_WidthTxt->Enable(enable);
802 m_RemapperChoice->Enable(enable);
803 m_BlenderChoice->Enable(enable);
804// m_CalcHFOVButton->Enable(enable);
805// m_CalcOptWidthButton->Enable(enable);
806// m_CalcOptROIButton->Enable(enable);
807}
808
809void PanoPanel::RemapperChanged(wxCommandEvent & e)
810{
811 int remapper = m_RemapperChoice->GetSelection();
812 DEBUG_DEBUG("changing remapper to " << remapper);
813
815 if (remapper == 1) {
817 } else {
819 }
820
823 );
824}
825
826void PanoPanel::OnRemapperOptions(wxCommandEvent & e)
827{
829 if (opt.remapper == HuginBase::PanoramaOptions::NONA) {
830 wxDialog dlg;
831 wxXmlResource::Get()->LoadDialog(&dlg, this, "nona_options_dialog");
832 wxChoice * interpol_choice = XRCCTRL(dlg, "nona_choice_interpolator", wxChoice);
833 wxCheckBox * cropped_cb = XRCCTRL(dlg, "nona_save_cropped", wxCheckBox);
835 SelectListValue(interpol_choice, opt.interpolator);
836 cropped_cb->SetValue(opt.tiff_saveROI);
837 dlg.Fit();
838 dlg.CentreOnParent();
839
840 if (dlg.ShowModal() == wxID_OK) {
842 if (interpol >= 0) {
843 opt.interpolator = (vigra_ext::Interpolator) interpol;
844 }
845 opt.tiff_saveROI = cropped_cb->GetValue();
848 );
849 }
850 } else {
851 wxLogError(_("PTmender options not yet implemented"));
852 }
853}
854
864
865void PanoPanel::OnBlenderOptions(wxCommandEvent & e)
866{
869 wxDialog dlg;
870 wxXmlResource::Get()->LoadDialog(&dlg, this, "enblend_options_dialog");
871 wxTextCtrl * enblend_opts_text = XRCCTRL(dlg, "blender_arguments_text", wxTextCtrl);
872 enblend_opts_text->ChangeValue(wxString(opt.enblendOptions.c_str(), wxConvLocal));
873 dlg.Bind(wxEVT_COMMAND_BUTTON_CLICKED, [](wxCommandEvent &) {MainFrame::Get()->DisplayHelp("Enblend.html"); }, wxID_HELP);
874 dlg.CentreOnParent();
875
876 if (dlg.ShowModal() == wxID_OK) {
877 opt.enblendOptions = enblend_opts_text->GetValue().mb_str(wxConvLocal);
880 );
881 }
882 }
883 else
884 {
886 {
887 wxDialog dlg;
888 wxXmlResource::Get()->LoadDialog(&dlg, this, "verdandi_options_dialog");
889 wxChoice * verdandiBlendModeChoice = XRCCTRL(dlg, "verdandi_blend_mode_choice", wxChoice);
890 if (opt.verdandiOptions.find("--seam=blend")!=std::string::npos)
891 {
892 verdandiBlendModeChoice->SetSelection(1);
893 }
894 else
895 {
896 verdandiBlendModeChoice->SetSelection(0);
897 };
898 dlg.CentreOnParent();
899
900 if (dlg.ShowModal() == wxID_OK)
901 {
902 if (verdandiBlendModeChoice->GetSelection() == 1)
903 {
904 opt.verdandiOptions = "--seam=blend";
905 }
906 else
907 {
908 opt.verdandiOptions = "";
909 };
911 };
912 }
913 else
914 {
915 wxLogError(_("PTblender options not yet implemented"));
916 };
917 };
918}
919
934
935void PanoPanel::OnEdgeFillOptions(wxCommandEvent& e)
936{
938 wxDialog dlg;
939 wxXmlResource::Get()->LoadDialog(&dlg, this, "filledge_options_dialog");
940 wxCheckBox* keepUnfillVersion = XRCCTRL(dlg, "edgefill_save_input", wxCheckBox);
941 keepUnfillVersion->SetValue(opt.keepEdgeFillInput);
942 dlg.CentreOnParent();
943
944 if (dlg.ShowModal() == wxID_OK)
945 {
946 opt.keepEdgeFillInput = keepUnfillVersion->IsChecked();
948 };
949}
950
951void PanoPanel::FusionChanged(wxCommandEvent & e)
952{
953 int fusion = m_FusionChoice->GetSelection();
954 DEBUG_DEBUG("changing stacking program to " << fusion);
955}
956
957void PanoPanel::OnFusionOptions(wxCommandEvent & e)
958{
960 wxDialog dlg;
961 wxXmlResource::Get()->LoadDialog(&dlg, this, "enfuse_options_dialog");
962 wxTextCtrl * enfuse_opts_text = XRCCTRL(dlg, "enfuse_arguments_text", wxTextCtrl);
963 enfuse_opts_text->ChangeValue(wxString(opt.enfuseOptions.c_str(), wxConvLocal));
964 dlg.Bind(wxEVT_COMMAND_BUTTON_CLICKED, [](wxCommandEvent &) {MainFrame::Get()->DisplayHelp("Enfuse.html"); }, wxID_HELP);
965 dlg.CentreOnParent();
966
967 if (dlg.ShowModal() == wxID_OK) {
968 opt.enfuseOptions = enfuse_opts_text->GetValue().mb_str(wxConvLocal);
971 );
972 }
973}
974
975
976void PanoPanel::HDRMergeChanged(wxCommandEvent & e)
977{
978 int blender = m_HDRMergeChoice->GetSelection();
979 DEBUG_DEBUG("changing HDR merger to " << blender);
980}
981
982void PanoPanel::OnHDRMergeOptions(wxCommandEvent & e)
983{
987 dlg.SetCommandLineArgument(wxString(opt.hdrmergeOptions.c_str(), wxConvLocal));
988 if (dlg.ShowModal() == wxOK)
989 {
990 opt.hdrmergeOptions=dlg.GetCommandLineArgument().mb_str(wxConvLocal);
993 );
994 }
995 } else {
996 wxLogError(_("Options for this HDRMerge program not yet implemented"));
997 }
998}
999
1000
1001
1002void PanoPanel::DoCalcFOV(wxCommandEvent & e)
1003{
1004 DEBUG_TRACE("");
1005 if (pano->getActiveImages().empty()) return;
1006
1009 fitPano.run();
1010 opt.setHFOV(fitPano.getResultHorizontalFOV());
1011 opt.setHeight(hugin_utils::roundi(fitPano.getResultHeight()));
1012
1013 DEBUG_INFO ( "hfov: " << opt.getHFOV() << " w: " << opt.getWidth() << " h: " << opt.getHeight() << " => vfov: " << opt.getVFOV() << " before update");
1014
1017 );
1018
1020 DEBUG_INFO ( "hfov: " << opt2.getHFOV() << " w: " << opt2.getWidth() << " h: " << opt2.getHeight() << " => vfov: " << opt2.getVFOV() << " after update");
1021
1022}
1023
1024void PanoPanel::DoCalcOptimalWidth(wxCommandEvent & e)
1025{
1026 if (pano->getActiveImages().empty()) return;
1027
1029 double sizeFactor = 1.0;
1031 {
1032 wxConfigBase::Get()->Read("/Assistant/panoDownsizeFactor", &sizeFactor, HUGIN_ASS_PANO_DOWNSIZE_FACTOR);
1033 };
1034
1036
1037 if (width > 0) {
1038 opt.setWidth( width );
1041 );
1042 }
1043 DEBUG_INFO ( "new optimal width: " << opt.getWidth() );
1044}
1045
1046
1047void PanoPanel::DoCalcOptimalROI(wxCommandEvent & e)
1048{
1049 DEBUG_INFO("Dirty ROI Calc\n");
1050 if (pano->getActiveImages().empty())
1051 {
1052 return;
1053 };
1054
1055 vigra::Rect2D newROI;
1056 {
1057 ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
1059 cropPano.run();
1060 if (cropPano.hasRunSuccessfully())
1061 {
1062 newROI = cropPano.getResultOptimalROI();
1063 };
1064 };
1065
1066 //set the ROI - fail if the right/bottom is zero, meaning all zero
1067 if(!newROI.isEmpty())
1068 {
1070 opt.setROI(newROI);
1073 );
1074 };
1075};
1076
1078{
1079 if (pano->getNrOfImages() == 0) {
1080 return;
1081 }
1082
1083 if (!CheckGoodSize()) {
1084 // oversized pano and the user no longer wants to stitch.
1085 return;
1086 }
1087 if (!CheckHasImages())
1088 {
1089 // output ROI contains no images
1090 return;
1091 };
1092
1093 // save project
1094 // copy pto file to temporary file
1095 wxString tempDir= wxConfigBase::Get()->Read("tempDir",wxEmptyString);
1096 if(!tempDir.IsEmpty())
1097 if(tempDir.Last()!=wxFileName::GetPathSeparator())
1098 tempDir.Append(wxFileName::GetPathSeparator());
1099 wxString currentPTOfn = wxFileName::CreateTempFileName(tempDir+"huginpto_");
1100 if(currentPTOfn.empty()) {
1101 hugin_utils::HuginMessageBox(_("Could not create temporary project file"), _("Hugin"), wxCANCEL | wxICON_ERROR, wxGetActiveWindow());
1102 return;
1103 }
1104 DEBUG_DEBUG("tmp PTO file: " << (const char *)currentPTOfn.mb_str(wxConvLocal));
1105 // copy is not enough, need to adjust image path names...
1106 pano->WritePTOFile(std::string(currentPTOfn.mb_str(HUGIN_CONV_FILENAME)));
1107
1108// wxCommandEvent dummy;
1109// MainFrame::Get()->OnSaveProject(dummy);
1110
1111#if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
1112 // HuginStitchProject inside main bundle
1115 {
1116 DEBUG_ERROR("hugin_stitch_project could not be found in the bundle.");
1117 return;
1118 }
1120#elif defined __WXMAC__
1121 // HuginStitchProject installed in INSTALL_OSX_BUNDLE_DIR
1123 hugin_stitch_project_app.AppendDir("HuginStitchProject.app");
1127#else
1128 wxString hugin_stitch_project = "hugin_stitch_project";
1129#endif
1130
1131 // Derive a default output prefix from the project filename if set, otherwise default project filename
1134
1135 // Show a file save dialog so user can confirm/change the prefix.
1136 // (We don't have to worry about overwriting existing files, since hugin_switch_project checks this.)
1137 // TODO: The following code is similar to stitchApp::OnInit in hugin_switch_project.cpp. Should be refactored.
1138 // TODO: We should save the output prefix somewhere, so we can recall it as the default if the user stitches this project again.
1139 wxFileDialog dlg(this,_("Specify output prefix"),
1140 outputPrefix.GetPath(), outputPrefix.GetName(), wxEmptyString,
1142 if (dlg.ShowModal() != wxID_OK)
1143 {
1144 return;
1145 };
1146 while(containsInvalidCharacters(dlg.GetPath()))
1147 {
1148 wxArrayString list;
1149 list.Add(dlg.GetPath());
1150 ShowFilenameWarning(this, list);
1151 if(dlg.ShowModal()!=wxID_OK)
1152 return;
1153 };
1154 wxFileName prefix(dlg.GetPath());
1155 while (!prefix.IsDirWritable())
1156 {
1157 hugin_utils::HuginMessageBox(wxString::Format(_("You have no permissions to write in folder \"%s\".\nPlease select another folder for the final output."), prefix.GetPath()),
1159 if (dlg.ShowModal() != wxID_OK)
1160 {
1161 return;
1162 };
1163 prefix = dlg.GetPath();
1164 };
1165 // check free space
1166 if (!CheckFreeSpace(prefix.GetPath()))
1167 {
1168 return;
1169 };
1170
1171 wxString switches(" --delete -o ");
1172 if (readSetting && wxConfigBase::Get()->Read("/Processor/overwrite", HUGIN_PROCESSOR_OVERWRITE) == 1)
1173 {
1174 switches = " --overwrite" + switches;
1175 };
1176 if (!userDefinedSetting.IsEmpty())
1177 {
1178 switches = " --user-defined-output=" + hugin_utils::wxQuoteFilename(userDefinedSetting) + " " + switches;
1179 };
1181
1182 wxConfigBase::Get()->Flush();
1183#ifdef __WXGTK__
1184 // work around a wxExecute bug/problem
1185 // (endless polling of fd 0 and 1 in hugin_stitch_project)
1186 wxProcess *my_process = new wxProcess(this);
1187 my_process->Redirect();
1188
1189 // Delete itself once processes terminated.
1190 my_process->Detach();
1192#else
1194#endif
1196}
1197
1199{
1200 if (pano->getNrOfImages() == 0)
1201 {
1202 return;
1203 }
1204
1205 if (!CheckGoodSize())
1206 {
1207 // oversized pano and the user no longer wants to stitch.
1208 return;
1209 }
1210 if( !CheckHasImages())
1211 {
1212 // output ROI contains no images
1213 return;
1214 };
1215
1216 wxString switches(" ");
1217 if (wxConfigBase::Get()->Read("/Processor/start", HUGIN_PROCESSOR_START) != 0)
1218 {
1219 switches += "-b ";
1220 };
1221 if (wxConfigBase::Get()->Read("/Processor/overwrite", HUGIN_PROCESSOR_OVERWRITE) != 0)
1222 {
1223 switches += "-o ";
1224 };
1225 if (wxConfigBase::Get()->Read("/Processor/verbose", HUGIN_PROCESSOR_VERBOSE) != 0)
1226 {
1227 switches += "-v ";
1228 };
1229 if (!userDefinedSetting.IsEmpty())
1230 {
1231 switches += "--user-defined=" + hugin_utils::wxQuoteFilename(userDefinedSetting) + " ";
1232 };
1233 if(pano->isDirty())
1234 {
1235 bool showDlg=wxConfigBase::Get()->Read("ShowSaveMessage", 1l)==1;
1236 if(showDlg)
1237 {
1238 // show information that project file needs to be saved first
1239 // and user has to give the output prefix afterwards
1240 wxDialog dlg;
1241 wxXmlResource::Get()->LoadDialog(&dlg, this, "stitch_message_dlg");
1242 if (!(MainFrame::Get()->getProjectName().IsEmpty()))
1243 {
1244 // project file was already saved with a name, adapt message text for this use case
1245 XRCCTRL(dlg, "stitch_message_text", wxStaticText)->SetLabel(
1246 wxString::Format(_("The project %s will be automatically saved before it can be sent to the batch processor PTBatcherGUI.\nYou will then be asked for the prefix for the panorama output.\n\nYou may need to start the stitching in the batch processor\n PTBatcherGUI if it doesn't start automatically."),
1247 MainFrame::Get()->getProjectName().c_str()
1248 )
1249 );
1250 };
1251 if(dlg.ShowModal())
1252 {
1253 if(XRCCTRL(dlg, "stitch_dont_show_checkbox", wxCheckBox)->IsChecked())
1254 {
1255 wxConfigBase::Get()->Write("ShowSaveMessage", 0l);
1256 };
1257 };
1258 };
1259 wxCommandEvent dummy;
1261 //test if save was sucessful
1262 if(pano->isDirty())
1263 {
1264 return;
1265 };
1266 };
1268 if(wxFileName::FileExists(projectFile))
1269 {
1272
1273 // Show a file save dialog so user can confirm/change the prefix.
1274 // (We don't have to worry about overwriting existing files, since PTBatcherGUI checks this, or the overwrite flag was set.)
1275 wxFileDialog dlg(this,_("Specify output prefix"),
1276 outputPrefix.GetPath(), outputPrefix.GetName(), wxEmptyString,
1278 if (dlg.ShowModal() != wxID_OK)
1279 {
1280 return;
1281 };
1282 while(containsInvalidCharacters(dlg.GetPath()))
1283 {
1284 wxArrayString list;
1285 list.Add(dlg.GetPath());
1286 ShowFilenameWarning(this, list);
1287 if(dlg.ShowModal()!=wxID_OK)
1288 return;
1289 };
1290 wxFileName prefix(dlg.GetPath());
1291 while (!prefix.IsDirWritable())
1292 {
1293 hugin_utils::HuginMessageBox(wxString::Format(_("You have no permissions to write in folder \"%s\".\nPlease select another folder for the final output."), prefix.GetPath()),
1295 if (dlg.ShowModal() != wxID_OK)
1296 {
1297 return;
1298 };
1299 prefix = dlg.GetPath();
1300 };
1301 // check free space
1302 if (!CheckFreeSpace(prefix.GetPath()))
1303 {
1304 return;
1305 };
1306
1307#if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
1308 wxString cmd = MacGetPathToMainExecutableFileOfRegisteredBundle(CFSTR("net.sourceforge.hugin.PTBatcherGUI"));
1309 if(cmd != wxEmptyString)
1310 {
1311 //Found PTBatcherGui inside the (registered) PTBatcherGui bundle. Call it directly.
1312 //We need to call the binary from it's own bundle and not from the hugin bundle otherwise we get no menu as OSX assumes that the hugin bundle
1313 //will provide the menu
1316 wxExecute(cmd);
1317 }
1318 else
1319 { //Can't find PTBatcherGui.app bundle. Use the most straightforward call possible to the bundle but this should actually not work either.
1320 hugin_utils::HuginMessageBox(wxString::Format(_("External program %s not found in the bundle, reverting to system path"), "open"), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
1321 cmd = "open -b net.sourceforge.hugin.PTBatcherGUI "+hugin_utils::wxQuoteFilename(projectFile);
1322 wxExecute(cmd);
1323 }
1324
1325#else
1326 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
1328#endif
1330 }
1331};
1332
1334{
1335 if (pano->getNrOfImages() == 0)
1336 {
1337 return;
1338 }
1339
1340 if (!CheckGoodSize())
1341 {
1342 // oversized pano and the user no longer wants to stitch.
1343 return;
1344 }
1345 if (!CheckHasImages())
1346 {
1347 // output ROI contains no images
1348 return;
1349 };
1351 if (settings.IsEmpty())
1352 {
1353 // no filename given, ask user
1354 wxConfigBase* config = wxConfigBase::Get();
1355 wxString path = config->Read("/userDefinedOutputPath", MainFrame::Get()->GetDataPath());
1356 wxFileDialog userOutputDlg(this, _("Select user defined output"),
1357 path, wxEmptyString, _("User defined output|*.executor"),
1359 if (userOutputDlg.ShowModal() != wxID_OK)
1360 {
1361 return;
1362 };
1363 // remember path for later
1364 config->Write("/userDefinedOutputPath", userOutputDlg.GetDirectory());
1366 }
1367 else
1368 {
1369 //filename given, check existance
1370 userOutputSequence = settings;
1371 if (!userOutputSequence.Exists())
1372 {
1373 hugin_utils::HuginMessageBox(wxString::Format("User defined output %s not found.\nStopping processing.", userOutputSequence.GetFullPath()), _("Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
1374 return;
1375 };
1376 };
1378}
1379
1381{
1382 long t;
1383 bool readSettings = true;
1385 {
1386 t=1;
1387 readSettings = false;
1388 }
1389 else
1390 {
1391 wxConfigBase::Get()->Read("/Processor/gui", &t, HUGIN_PROCESSOR_GUI);
1392 };
1393 switch (t)
1394 {
1395 // PTBatcher
1396 case 0:
1398 break;
1399 // hugin_stitch_project
1400 case 1:
1402 break;
1403 // there is an error in the preferences
1404 default :
1405 // TODO: notify user and fix preferences misconfiguration
1406 break;
1407 }
1408}
1409
1410void PanoPanel::OnDoStitch(wxCommandEvent& e)
1411{
1413}
1414
1415void PanoPanel::FileFormatChanged(wxCommandEvent & e)
1416{
1417
1418 int fmt = m_FileFormatChoice->GetSelection();
1419 DEBUG_DEBUG("changing file format to " << fmt);
1420
1422 switch (fmt) {
1423 case 1:
1424 opt.outputImageType ="jpg";
1425 break;
1426 case 2:
1427 opt.outputImageType ="png";
1428 break;
1429 case 3:
1430 opt.outputImageType ="exr";
1431 break;
1432 default:
1433 case 0:
1434 opt.outputImageType ="tif";
1435 break;
1436 }
1437
1440 );
1441}
1442
1443void PanoPanel::HDRFileFormatChanged(wxCommandEvent & e)
1444{
1445
1446 int fmt = m_HDRFileFormatChoice->GetSelection();
1447 DEBUG_DEBUG("changing file format to " << fmt);
1448
1450 switch (fmt) {
1451 case 1:
1452 opt.outputImageTypeHDR ="tif";
1453 break;
1454 default:
1455 case 0:
1456 opt.outputImageTypeHDR ="exr";
1457 break;
1458 }
1459
1462 );
1463}
1464
1465void PanoPanel::OnJPEGQualityText(wxCommandEvent & e)
1466{
1468 long l = 100;
1469 m_FileFormatJPEGQualityText->GetValue().ToLong(&l);
1470 if (l < 0) l=1;
1471 if (l > 100) l=100;
1472 DEBUG_DEBUG("Setting jpeg quality to " << l);
1473 opt.quality = l;
1476 );
1477}
1478
1480{
1482 switch(e.GetSelection()) {
1483 case 0:
1484 default:
1486 opt.tiffCompression = "NONE";
1487 break;
1488 case 1:
1489 opt.outputImageTypeCompression = "PACKBITS";
1490 opt.tiffCompression = "PACKBITS";
1491 break;
1492 case 2:
1493 opt.outputImageTypeCompression = "LZW";
1494 opt.tiffCompression = "LZW";
1495 break;
1496 case 3:
1497 opt.outputImageTypeCompression = "DEFLATE";
1498 opt.tiffCompression = "DEFLATE";
1499 break;
1500 }
1503 );
1504}
1505
1506void PanoPanel::OnHDRTIFFCompression(wxCommandEvent & e)
1507{
1509 switch(e.GetSelection()) {
1510 case 0:
1511 default:
1513 break;
1514 case 1:
1515 opt.outputImageTypeHDRCompression = "PACKBITS";
1516 break;
1517 case 2:
1518 opt.outputImageTypeHDRCompression = "LZW";
1519 break;
1520 case 3:
1521 opt.outputImageTypeHDRCompression = "DEFLATE";
1522 break;
1523 }
1526 );
1527}
1528
1529void PanoPanel::OnOutputFilesChanged(wxCommandEvent & e)
1530{
1531 int id = e.GetId();
1533
1534 if (id == XRCID("pano_cb_ldr_output_blended") ) {
1535 opts.outputLDRBlended = e.IsChecked();
1536 } else if (id == XRCID("pano_cb_ldr_output_layers") ) {
1537 opts.outputLDRLayers = e.IsChecked();
1538 } else if (id == XRCID("pano_cb_ldr_output_exposure_layers") ) {
1539 opts.outputLDRExposureLayers = e.IsChecked();
1540 } else if (id == XRCID("pano_cb_ldr_output_exposure_blended") ) {
1541 opts.outputLDRExposureBlended = e.IsChecked();
1542 } else if (id == XRCID("pano_cb_ldr_output_exposure_layers_fused") ) {
1543 opts.outputLDRExposureLayersFused = e.IsChecked();
1544 } else if (id == XRCID("pano_cb_ldr_output_exposure_remapped") ) {
1545 opts.outputLDRExposureRemapped = e.IsChecked();
1546 } else if (id == XRCID("pano_cb_ldr_output_stacks") ) {
1547 opts.outputLDRStacks = e.IsChecked();
1548 } else if (id == XRCID("pano_cb_hdr_output_blended") ) {
1549 opts.outputHDRBlended = e.IsChecked();
1550 } else if (id == XRCID("pano_cb_hdr_output_stacks") ) {
1551 opts.outputHDRStacks = e.IsChecked();
1552 } else if (id == XRCID("pano_cb_hdr_output_layers") ) {
1553 opts.outputHDRLayers = e.IsChecked();
1554 }
1555
1558 );
1559}
1560
1562{
1564 const vigra::Rect2D cropped_region (opts.getROI());
1565 // width and height of jpeg images has to be smaller than 65500 pixel
1566 if (opts.outputImageType == "jpg" &&
1568 (cropped_region.width()>65500 || cropped_region.height()>65500)
1569 )
1570 {
1572 wxString::Format(_("The width and height of jpeg images has to be smaller than 65500 pixel. But you have requested a jpeg image with %dx%d pixel.\nThis is not supported by the jpeg file format.\nDecrease the canvas size on the stitch panel or select TIF or PNG as output format."), cropped_region.width(), cropped_region.height()),
1574 return false;
1575 };
1577 const unsigned long long area = (static_cast<unsigned long long>(cropped_region.width()) * cropped_region.height());
1578 // Argh, more than half a gigapixel!
1579 if (area > 500000000)
1580 {
1581 message = wxString::Format(_("The panorama you are trying to stitch is %.1f gigapixels.\nIf this is too big, reduce the panorama Canvas Size and the cropped region and stitch from the Stitcher tab. Stitching a panorama this size could take a long time and a large amount of memory."),
1582 area / 1000000000.0);
1583 }
1584 else
1585 {
1586 if (cropped_region.width() > 32700 || cropped_region.height() > 32700)
1587 {
1588 message = _("The width or the height of the final panorama exceeds 32700 pixel.\nSome programs have problems to open or display such big images.\n\nIf this is too big, reduce the panorama Canvas Size or the cropped region.");
1589 };
1590 };
1591 if (!message.empty())
1592 {
1593 // Tell the user the stitch will be really big, and give them a
1594 // chance to reduce the size.
1595 hugin_utils::MessageDialog dialog = hugin_utils::GetMessageDialog(_("Are you sure you want to stitch such a large panorama?"),
1597 dialog->SetExtendedMessage(message);
1598 dialog->SetYesNoLabels(_("Stitch anyway"), _("Let me fix that"));
1599 switch (dialog->ShowModal())
1600 {
1601 case wxID_OK:
1602 case wxID_YES:
1603 // Continue stitch.
1604 return true;
1605 break;
1606 default:
1607 // bring the user towards the approptiate controls.
1609 if (!mainframe->IsShown())
1610 {
1611 mainframe->Show();
1612 }
1613 mainframe->ShowStitcherTab();
1614 return false;
1615 }
1616 }
1617 // I see nothing wrong with this...
1618 return true;
1619}
1620
1622{
1623 HuginBase::UIntSet images=getImagesinROI(*pano, pano->getActiveImages());
1624 if(images.empty())
1625 {
1626 hugin_utils::HuginMessageBox(_("There are no active images in the output region.\nPlease check your settings, so that at least one image is in the output region."),
1628 };
1629 return !images.empty();
1630};
1631
1633{
1636 {
1637 // 4 channels, 16 bit per channel, assuming the we need the 10 fold space for all temporary space
1638 if (pano->getOptions().getROI().area() * 80 > freeSpace)
1639 {
1640 hugin_utils::MessageDialog dialog = hugin_utils::GetMessageDialog(wxString::Format(_("The folder \"%s\" has only %.1f MiB free. This is not enough for stitching the current panorama. Decrease the output size or select another output folder.\nAre you sure that you still want to stitch it?"), folder.c_str(), freeSpace.ToDouble() / 1048576.0),
1642 dialog->SetYesNoLabels(_("Stitch anyway"), _("Let me fix that"));
1643 if (dialog->ShowModal() == wxID_NO)
1644 {
1645 // bring the user towards the approptiate controls.
1647 if (!mainframe->IsShown())
1648 {
1649 mainframe->Show();
1650 }
1651 mainframe->ShowStitcherTab();
1652 return false;
1653 };
1654 };
1655 };
1656 return true;
1657};
1658
1664
1665IMPLEMENT_DYNAMIC_CLASS(PanoPanel, wxPanel)
1666
1668 : wxXmlResourceHandler()
1669{
1671}
1672
1674{
1676
1677 cp->Create(m_parentAsWindow,
1678 GetID(),
1679 GetPosition(), GetSize(),
1680 GetStyle("style"),
1681 GetName());
1682
1683 SetupWindow( cp);
1684
1685 return cp;
1686}
1687
1689{
1690 return IsOfClass(node, "PanoPanel");
1691}
1692
1693IMPLEMENT_DYNAMIC_CLASS(PanoPanelXmlHandler, wxXmlResourceHandler)
1694
Definition of CPImagesComboBox and CPImagesComboBoxXmlHandler class.
wxString GetDataPath()
return path to data directory, it depends on operating system
GuiLevel
Definition GuiLevel.h:32
@ GUI_SIMPLE
Definition GuiLevel.h:33
Definition of dialog for hdrmerge options.
declaration of functions to handle stacks and layers
class to access Hugins camera and lens database
void FillBlenderList(wxControlWithItems *list)
Fills a wxControlWithItem with all possible blender options, the client data contains the associated ...
Definition LensTools.cpp:83
size_t GetSelectedValue(wxControlWithItems *list)
Returns the client value of the selected item from list.
void FillInterpolatorList(wxControlWithItems *list)
Fill a wxControlWithItem with all possible interpolators.
Definition LensTools.cpp:91
void SelectListValue(wxControlWithItems *list, size_t newValue)
Selects the given value (stored in the client data) in the given list item.
some helper classes for graphes
Contains various routines used for stitching panoramas.
Dialog for reset panorama settings.
virtual double getResultHorizontalFOV()
Definition FitPanorama.h:68
virtual double getResultHeight()
Definition FitPanorama.h:75
static double calcOptimalScale(PanoramaData &panorama)
virtual void run()
runs the algorithm.
Panorama image options.
bool outputHDRLayers
save remapped layers (HDR)
bool outputLDRExposureLayers
save blended exposure layers, do not perform fusion (no exposure adjustment)
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
bool outputLDRExposureBlended
< save exposure fused stacks (no exposure adjustment)
void setHeight(unsigned int h)
set panorama height
bool outputLDRExposureRemapped
save remapped layers (no exposure adjustment)
const vigra::Rect2D & getROI() const
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
void setROI(const vigra::Rect2D &val)
bool outputLDRBlended
save blended panorama (LDR)
bool outputLDRLayers
save remapped layers (LDR)
bool outputHDRStacks
save image stacks (HDR)
ProjectionFormat
Projection of final panorama.
bool outputLDRExposureLayersFused
save blended exposure layers which are then fused (no exposure adjustment)
std::string outputImageTypeHDRCompression
bool outputHDRBlended
save blended panorama (HDR)
Model for a panorama.
Definition Panorama.h:153
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
bool isDirty() const
true if there are unsaved changes
Definition Panorama.h:636
void addObserver(PanoramaObserver *o)
add a panorama observer.
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
The main window frame.
Definition MainFrame.h:84
static MainFrame * Get()
hack.. kind of a pseudo singleton...
void OnSaveProject(wxCommandEvent &e)
wxString getProjectName()
void DisplayHelp(wxString section=wxEmptyString)
call help browser with given file
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
static GlobalCmdHist & getInstance()
set the panorama options
virtual wxObject * DoCreateResource()
virtual bool CanHandle(wxXmlNode *node)
Define the pano edit panel.
Definition PanoPanel.h:44
virtual void panoramaChanged(HuginBase::Panorama &pano)
this is called whenever the panorama has changed.
wxTextCtrl * m_ROIRightTxt
Definition PanoPanel.h:198
void HFOVChanged(wxCommandEvent &e)
void OnHDRMergeOptions(wxCommandEvent &e)
void DoCalcFOV(wxCommandEvent &e)
wxTextCtrl * m_HeightTxt
Definition PanoPanel.h:196
bool CheckFreeSpace(const wxString &folder)
check if there is enough free disk space
wxButton * m_CalcOptWidthButton
Definition PanoPanel.h:208
wxChoice * m_FileFormatChoice
Definition PanoPanel.h:211
wxChoice * m_HDRMergeChoice
Definition PanoPanel.h:203
bool CheckGoodSize()
Check the canvas size isn't overly huge, or the user knows what they are doing.
void DoCalcOptimalWidth(wxCommandEvent &e)
set the highest sensible width
void FileFormatChanged(wxCommandEvent &e)
wxTextCtrl * m_VFOVText
Definition PanoPanel.h:193
void OnDoStitch(wxCommandEvent &e)
void BlenderChanged(wxCommandEvent &e)
wxTextCtrl * m_FileFormatJPEGQualityText
Definition PanoPanel.h:213
void DoSendToBatch(const wxString &userDefinedSetting=wxEmptyString)
stitching with PTBatcherGUI
void EnableControls(bool enable)
enable/disable control influenced by quick mode
bool CheckHasImages()
check if the output contains images at all
bool updatesDisabled
Definition PanoPanel.h:183
void OnJPEGQualityText(wxCommandEvent &e)
void ProjectionChanged(wxCommandEvent &e)
wxScrolledWindow * m_pano_ctrls
Definition PanoPanel.h:220
wxChoice * m_ProjectionChoice
Definition PanoPanel.h:191
void DoStitchOrSendBatch(const wxString &userDefinedSetting=wxEmptyString)
general stitching command, selects PTBatcherGUI or hugin_stitch_project depending on the settings in ...
void ROIChanged(wxCommandEvent &e)
HuginBase::PanoramaOptions m_oldOpt
Definition PanoPanel.h:184
void OnOutputFilesChanged(wxCommandEvent &e)
wxTextCtrl * m_HFOVText
Definition PanoPanel.h:192
wxTextCtrl * m_ROIBottomTxt
Definition PanoPanel.h:200
bool m_keepViewOnResize
Definition PanoPanel.h:187
virtual ~PanoPanel(void)
wxTextCtrl * m_WidthTxt
Definition PanoPanel.h:195
void OnFusionOptions(wxCommandEvent &e)
wxChoice * m_edgeFillChoice
Definition PanoPanel.h:205
void OnNormalTIFFCompression(wxCommandEvent &e)
wxChoice * m_FileFormatTIFFCompChoice
Definition PanoPanel.h:214
wxChoice * m_FileFormatHDRTIFFCompChoice
Definition PanoPanel.h:218
wxButton * m_CalcOptROIButton
Definition PanoPanel.h:209
void Init(HuginBase::Panorama *pano)
wxChoice * m_HDRFileFormatChoice
Definition PanoPanel.h:216
wxButton * m_CalcHFOVButton
Definition PanoPanel.h:207
bool m_hasStacks
Definition PanoPanel.h:188
bool StackCheck(HuginBase::Panorama &pano)
void OnEdgeFillChanged(wxCommandEvent &e)
void UpdateDisplay(const HuginBase::PanoramaOptions &opt, const bool hasStacks)
void HDRMergeChanged(wxCommandEvent &e)
void HeightChanged(wxCommandEvent &e)
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
Definition PanoPanel.cpp:72
void VFOVChanged(wxCommandEvent &e)
void OnBlenderOptions(wxCommandEvent &e)
void OnRemapperOptions(wxCommandEvent &e)
wxButton * m_StitchButton
Definition PanoPanel.h:206
void FusionChanged(wxCommandEvent &e)
void RemapperChanged(wxCommandEvent &e)
void SetGuiLevel(GuiLevel newGuiLevel)
wxTextCtrl * m_ROILeftTxt
Definition PanoPanel.h:197
void DoStitch(const wxString &userDefinedSetting=wxEmptyString, const bool readSetting=true)
stitching using hugin_stitch_project
wxChoice * m_BlenderChoice
Definition PanoPanel.h:204
wxStaticText * m_HDRFileFormatLabelTIFFCompression
Definition PanoPanel.h:217
void DoUserDefinedStitch(const wxString &settings=wxString())
stitching with user defined file
void WidthChanged(wxCommandEvent &e)
wxChoice * m_RemapperChoice
Definition PanoPanel.h:201
GuiLevel m_guiLevel
Definition PanoPanel.h:178
void DoCalcOptimalROI(wxCommandEvent &e)
set the largest rectangle for crop ROI
void HDRFileFormatChanged(wxCommandEvent &e)
wxChoice * m_FusionChoice
Definition PanoPanel.h:202
void OnEdgeFillOptions(wxCommandEvent &e)
HuginBase::Panorama * pano
Definition PanoPanel.h:176
wxTextCtrl * m_ROITopTxt
Definition PanoPanel.h:199
wxStaticText * m_FileFormatOptionsLabel
Definition PanoPanel.h:212
void OnHDRTIFFCompression(wxCommandEvent &e)
Handle EVT_KILL_FOCUS and convert it to a EVT_TEXT_ENTER event.
#define HUGIN_PROCESSOR_VERBOSE
#define HUGIN_PROCESSOR_GUI
#define HUGIN_PROCESSOR_START
#define HUGIN_ASS_PANO_DOWNSIZE_FACTOR
#define HUGIN_PROCESSOR_OVERWRITE
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
wxString getDefaultOutputName(const wxString projectname, const HuginBase::Panorama &pano, const wxString filenameTemplate)
gets the default output prefix, based on filename and images in project the setting is read from the ...
functions for interaction with the hugin configuration file
misc math function & classes used by other parts of the program
#define DEBUG_ERROR(msg)
Definition utils.h:76
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_DEBUG(msg)
Definition utils.h:68
#define DEBUG_TRACE(msg)
Definition utils.h:67
#define DEBUG_INFO(msg)
Definition utils.h:69
bool SaveLensDataFromPano(const HuginBase::Panorama &pano)
routine for automatically saving information from pano into database
Definition LensDB.cpp:2553
std::set< unsigned int > UIntSet
std::vector< UIntSet > getHDRStacks(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output stacks
bool str2double(const wxString &s, double &d)
str wxQuoteFilename(const str &arg)
Quote a filename, so that it is surrounded by "".
Definition wxPlatform.h:82
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
std::string doubleToString(double d, int digits)
convert a double to a string, suitable for display within a GUI.
Definition utils.cpp:228
std::unique_ptr< wxMessageDialogBase > MessageDialog
Definition wxutils.h:90
int floori(double x)
Definition hugin_math.h:65
int roundi(T x)
Definition hugin_math.h:73
str wxQuoteString(const str &arg)
Try to escape special chars on windows and linux.
Definition wxPlatform.h:66
int gcd(int a, int b)
function to calculate greated common divisor using Euclidean algorithm both arguments should be >=0
MessageDialog GetMessageDialog(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:187
Interpolator
enum with all interpolation methods
include file for the hugin project
include file for the hugin project
bool containsInvalidCharacters(const wxString stringToTest)
returns true, if the given strings contains invalid characters
Definition platform.cpp:511
void ShowFilenameWarning(wxWindow *parent, const wxArrayString filelist)
shows a dialog about filename with invalid characters, all names in filelist will be show in list
Definition platform.cpp:524
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
platform/compiler specific stuff.