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);
834 interpol_choice->SetSelection(opt.interpolator);
835 cropped_cb->SetValue(opt.tiff_saveROI);
836 dlg.CentreOnParent();
837
838 if (dlg.ShowModal() == wxID_OK) {
839 int interpol = interpol_choice->GetSelection();
840 if (interpol >= 0) {
841 opt.interpolator = (vigra_ext::Interpolator) interpol;
842 }
843 opt.tiff_saveROI = cropped_cb->GetValue();
846 );
847 }
848 } else {
849 wxLogError(_("PTmender options not yet implemented"));
850 }
851}
852
862
863void PanoPanel::OnBlenderOptions(wxCommandEvent & e)
864{
867 wxDialog dlg;
868 wxXmlResource::Get()->LoadDialog(&dlg, this, "enblend_options_dialog");
869 wxTextCtrl * enblend_opts_text = XRCCTRL(dlg, "blender_arguments_text", wxTextCtrl);
870 enblend_opts_text->ChangeValue(wxString(opt.enblendOptions.c_str(), wxConvLocal));
871 dlg.Bind(wxEVT_COMMAND_BUTTON_CLICKED, [](wxCommandEvent &) {MainFrame::Get()->DisplayHelp("Enblend.html"); }, wxID_HELP);
872 dlg.CentreOnParent();
873
874 if (dlg.ShowModal() == wxID_OK) {
875 opt.enblendOptions = enblend_opts_text->GetValue().mb_str(wxConvLocal);
878 );
879 }
880 }
881 else
882 {
884 {
885 wxDialog dlg;
886 wxXmlResource::Get()->LoadDialog(&dlg, this, "verdandi_options_dialog");
887 wxChoice * verdandiBlendModeChoice = XRCCTRL(dlg, "verdandi_blend_mode_choice", wxChoice);
888 if (opt.verdandiOptions.find("--seam=blend")!=std::string::npos)
889 {
890 verdandiBlendModeChoice->SetSelection(1);
891 }
892 else
893 {
894 verdandiBlendModeChoice->SetSelection(0);
895 };
896 dlg.CentreOnParent();
897
898 if (dlg.ShowModal() == wxID_OK)
899 {
900 if (verdandiBlendModeChoice->GetSelection() == 1)
901 {
902 opt.verdandiOptions = "--seam=blend";
903 }
904 else
905 {
906 opt.verdandiOptions = "";
907 };
909 };
910 }
911 else
912 {
913 wxLogError(_("PTblender options not yet implemented"));
914 };
915 };
916}
917
932
933void PanoPanel::OnEdgeFillOptions(wxCommandEvent& e)
934{
936 wxDialog dlg;
937 wxXmlResource::Get()->LoadDialog(&dlg, this, "filledge_options_dialog");
938 wxCheckBox* keepUnfillVersion = XRCCTRL(dlg, "edgefill_save_input", wxCheckBox);
939 keepUnfillVersion->SetValue(opt.keepEdgeFillInput);
940 dlg.CentreOnParent();
941
942 if (dlg.ShowModal() == wxID_OK)
943 {
944 opt.keepEdgeFillInput = keepUnfillVersion->IsChecked();
946 };
947}
948
949void PanoPanel::FusionChanged(wxCommandEvent & e)
950{
951 int fusion = m_FusionChoice->GetSelection();
952 DEBUG_DEBUG("changing stacking program to " << fusion);
953}
954
955void PanoPanel::OnFusionOptions(wxCommandEvent & e)
956{
958 wxDialog dlg;
959 wxXmlResource::Get()->LoadDialog(&dlg, this, "enfuse_options_dialog");
960 wxTextCtrl * enfuse_opts_text = XRCCTRL(dlg, "enfuse_arguments_text", wxTextCtrl);
961 enfuse_opts_text->ChangeValue(wxString(opt.enfuseOptions.c_str(), wxConvLocal));
962 dlg.Bind(wxEVT_COMMAND_BUTTON_CLICKED, [](wxCommandEvent &) {MainFrame::Get()->DisplayHelp("Enfuse.html"); }, wxID_HELP);
963 dlg.CentreOnParent();
964
965 if (dlg.ShowModal() == wxID_OK) {
966 opt.enfuseOptions = enfuse_opts_text->GetValue().mb_str(wxConvLocal);
969 );
970 }
971}
972
973
974void PanoPanel::HDRMergeChanged(wxCommandEvent & e)
975{
976 int blender = m_HDRMergeChoice->GetSelection();
977 DEBUG_DEBUG("changing HDR merger to " << blender);
978}
979
980void PanoPanel::OnHDRMergeOptions(wxCommandEvent & e)
981{
985 dlg.SetCommandLineArgument(wxString(opt.hdrmergeOptions.c_str(), wxConvLocal));
986 if (dlg.ShowModal() == wxOK)
987 {
988 opt.hdrmergeOptions=dlg.GetCommandLineArgument().mb_str(wxConvLocal);
991 );
992 }
993 } else {
994 wxLogError(_("Options for this HDRMerge program not yet implemented"));
995 }
996}
997
998
999
1000void PanoPanel::DoCalcFOV(wxCommandEvent & e)
1001{
1002 DEBUG_TRACE("");
1003 if (pano->getActiveImages().empty()) return;
1004
1007 fitPano.run();
1008 opt.setHFOV(fitPano.getResultHorizontalFOV());
1009 opt.setHeight(hugin_utils::roundi(fitPano.getResultHeight()));
1010
1011 DEBUG_INFO ( "hfov: " << opt.getHFOV() << " w: " << opt.getWidth() << " h: " << opt.getHeight() << " => vfov: " << opt.getVFOV() << " before update");
1012
1015 );
1016
1018 DEBUG_INFO ( "hfov: " << opt2.getHFOV() << " w: " << opt2.getWidth() << " h: " << opt2.getHeight() << " => vfov: " << opt2.getVFOV() << " after update");
1019
1020}
1021
1022void PanoPanel::DoCalcOptimalWidth(wxCommandEvent & e)
1023{
1024 if (pano->getActiveImages().empty()) return;
1025
1027 double sizeFactor = 1.0;
1029 {
1030 wxConfigBase::Get()->Read("/Assistant/panoDownsizeFactor", &sizeFactor, HUGIN_ASS_PANO_DOWNSIZE_FACTOR);
1031 };
1032
1034
1035 if (width > 0) {
1036 opt.setWidth( width );
1039 );
1040 }
1041 DEBUG_INFO ( "new optimal width: " << opt.getWidth() );
1042}
1043
1044
1045void PanoPanel::DoCalcOptimalROI(wxCommandEvent & e)
1046{
1047 DEBUG_INFO("Dirty ROI Calc\n");
1048 if (pano->getActiveImages().empty())
1049 {
1050 return;
1051 };
1052
1053 vigra::Rect2D newROI;
1054 {
1055 ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
1057 cropPano.run();
1058 if (cropPano.hasRunSuccessfully())
1059 {
1060 newROI = cropPano.getResultOptimalROI();
1061 };
1062 };
1063
1064 //set the ROI - fail if the right/bottom is zero, meaning all zero
1065 if(!newROI.isEmpty())
1066 {
1068 opt.setROI(newROI);
1071 );
1072 };
1073};
1074
1076{
1077 if (pano->getNrOfImages() == 0) {
1078 return;
1079 }
1080
1081 if (!CheckGoodSize()) {
1082 // oversized pano and the user no longer wants to stitch.
1083 return;
1084 }
1085 if (!CheckHasImages())
1086 {
1087 // output ROI contains no images
1088 return;
1089 };
1090
1091 // save project
1092 // copy pto file to temporary file
1093 wxString tempDir= wxConfigBase::Get()->Read("tempDir",wxEmptyString);
1094 if(!tempDir.IsEmpty())
1095 if(tempDir.Last()!=wxFileName::GetPathSeparator())
1096 tempDir.Append(wxFileName::GetPathSeparator());
1097 wxString currentPTOfn = wxFileName::CreateTempFileName(tempDir+"huginpto_");
1098 if(currentPTOfn.empty()) {
1099 hugin_utils::HuginMessageBox(_("Could not create temporary project file"), _("Hugin"), wxCANCEL | wxICON_ERROR, wxGetActiveWindow());
1100 return;
1101 }
1102 DEBUG_DEBUG("tmp PTO file: " << (const char *)currentPTOfn.mb_str(wxConvLocal));
1103 // copy is not enough, need to adjust image path names...
1104 pano->WritePTOFile(std::string(currentPTOfn.mb_str(HUGIN_CONV_FILENAME)));
1105
1106// wxCommandEvent dummy;
1107// MainFrame::Get()->OnSaveProject(dummy);
1108
1109#if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
1110 // HuginStitchProject inside main bundle
1113 {
1114 DEBUG_ERROR("hugin_stitch_project could not be found in the bundle.");
1115 return;
1116 }
1118#elif defined __WXMAC__
1119 // HuginStitchProject installed in INSTALL_OSX_BUNDLE_DIR
1121 hugin_stitch_project_app.AppendDir("HuginStitchProject.app");
1125#else
1126 wxString hugin_stitch_project = "hugin_stitch_project";
1127#endif
1128
1129 // Derive a default output prefix from the project filename if set, otherwise default project filename
1132
1133 // Show a file save dialog so user can confirm/change the prefix.
1134 // (We don't have to worry about overwriting existing files, since hugin_switch_project checks this.)
1135 // TODO: The following code is similar to stitchApp::OnInit in hugin_switch_project.cpp. Should be refactored.
1136 // TODO: We should save the output prefix somewhere, so we can recall it as the default if the user stitches this project again.
1137 wxFileDialog dlg(this,_("Specify output prefix"),
1138 outputPrefix.GetPath(), outputPrefix.GetName(), wxEmptyString,
1140 if (dlg.ShowModal() != wxID_OK)
1141 {
1142 return;
1143 };
1144 while(containsInvalidCharacters(dlg.GetPath()))
1145 {
1146 wxArrayString list;
1147 list.Add(dlg.GetPath());
1148 ShowFilenameWarning(this, list);
1149 if(dlg.ShowModal()!=wxID_OK)
1150 return;
1151 };
1152 wxFileName prefix(dlg.GetPath());
1153 while (!prefix.IsDirWritable())
1154 {
1155 hugin_utils::HuginMessageBox(wxString::Format(_("You have no permissions to write in folder \"%s\".\nPlease select another folder for the final output."), prefix.GetPath()),
1157 if (dlg.ShowModal() != wxID_OK)
1158 {
1159 return;
1160 };
1161 prefix = dlg.GetPath();
1162 };
1163 // check free space
1164 if (!CheckFreeSpace(prefix.GetPath()))
1165 {
1166 return;
1167 };
1168
1169 wxString switches(" --delete -o ");
1170 if (readSetting && wxConfigBase::Get()->Read("/Processor/overwrite", HUGIN_PROCESSOR_OVERWRITE) == 1)
1171 {
1172 switches = " --overwrite" + switches;
1173 };
1174 if (!userDefinedSetting.IsEmpty())
1175 {
1176 switches = " --user-defined-output=" + hugin_utils::wxQuoteFilename(userDefinedSetting) + " " + switches;
1177 };
1179
1180 wxConfigBase::Get()->Flush();
1181#ifdef __WXGTK__
1182 // work around a wxExecute bug/problem
1183 // (endless polling of fd 0 and 1 in hugin_stitch_project)
1184 wxProcess *my_process = new wxProcess(this);
1185 my_process->Redirect();
1186
1187 // Delete itself once processes terminated.
1188 my_process->Detach();
1190#else
1192#endif
1194}
1195
1197{
1198 if (pano->getNrOfImages() == 0)
1199 {
1200 return;
1201 }
1202
1203 if (!CheckGoodSize())
1204 {
1205 // oversized pano and the user no longer wants to stitch.
1206 return;
1207 }
1208 if( !CheckHasImages())
1209 {
1210 // output ROI contains no images
1211 return;
1212 };
1213
1214 wxString switches(" ");
1215 if (wxConfigBase::Get()->Read("/Processor/start", HUGIN_PROCESSOR_START) != 0)
1216 {
1217 switches += "-b ";
1218 };
1219 if (wxConfigBase::Get()->Read("/Processor/overwrite", HUGIN_PROCESSOR_OVERWRITE) != 0)
1220 {
1221 switches += "-o ";
1222 };
1223 if (wxConfigBase::Get()->Read("/Processor/verbose", HUGIN_PROCESSOR_VERBOSE) != 0)
1224 {
1225 switches += "-v ";
1226 };
1227 if (!userDefinedSetting.IsEmpty())
1228 {
1229 switches += "--user-defined=" + hugin_utils::wxQuoteFilename(userDefinedSetting) + " ";
1230 };
1231 if(pano->isDirty())
1232 {
1233 bool showDlg=wxConfigBase::Get()->Read("ShowSaveMessage", 1l)==1;
1234 if(showDlg)
1235 {
1236 // show information that project file needs to be saved first
1237 // and user has to give the output prefix afterwards
1238 wxDialog dlg;
1239 wxXmlResource::Get()->LoadDialog(&dlg, this, "stitch_message_dlg");
1240 if (!(MainFrame::Get()->getProjectName().IsEmpty()))
1241 {
1242 // project file was already saved with a name, adapt message text for this use case
1243 XRCCTRL(dlg, "stitch_message_text", wxStaticText)->SetLabel(
1244 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."),
1245 MainFrame::Get()->getProjectName().c_str()
1246 )
1247 );
1248 };
1249 if(dlg.ShowModal())
1250 {
1251 if(XRCCTRL(dlg, "stitch_dont_show_checkbox", wxCheckBox)->IsChecked())
1252 {
1253 wxConfigBase::Get()->Write("ShowSaveMessage", 0l);
1254 };
1255 };
1256 };
1257 wxCommandEvent dummy;
1259 //test if save was sucessful
1260 if(pano->isDirty())
1261 {
1262 return;
1263 };
1264 };
1266 if(wxFileName::FileExists(projectFile))
1267 {
1270
1271 // Show a file save dialog so user can confirm/change the prefix.
1272 // (We don't have to worry about overwriting existing files, since PTBatcherGUI checks this, or the overwrite flag was set.)
1273 wxFileDialog dlg(this,_("Specify output prefix"),
1274 outputPrefix.GetPath(), outputPrefix.GetName(), wxEmptyString,
1276 if (dlg.ShowModal() != wxID_OK)
1277 {
1278 return;
1279 };
1280 while(containsInvalidCharacters(dlg.GetPath()))
1281 {
1282 wxArrayString list;
1283 list.Add(dlg.GetPath());
1284 ShowFilenameWarning(this, list);
1285 if(dlg.ShowModal()!=wxID_OK)
1286 return;
1287 };
1288 wxFileName prefix(dlg.GetPath());
1289 while (!prefix.IsDirWritable())
1290 {
1291 hugin_utils::HuginMessageBox(wxString::Format(_("You have no permissions to write in folder \"%s\".\nPlease select another folder for the final output."), prefix.GetPath()),
1293 if (dlg.ShowModal() != wxID_OK)
1294 {
1295 return;
1296 };
1297 prefix = dlg.GetPath();
1298 };
1299 // check free space
1300 if (!CheckFreeSpace(prefix.GetPath()))
1301 {
1302 return;
1303 };
1304
1305#if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
1306 wxString cmd = MacGetPathToMainExecutableFileOfRegisteredBundle(CFSTR("net.sourceforge.hugin.PTBatcherGUI"));
1307 if(cmd != wxEmptyString)
1308 {
1309 //Found PTBatcherGui inside the (registered) PTBatcherGui bundle. Call it directly.
1310 //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
1311 //will provide the menu
1314 wxExecute(cmd);
1315 }
1316 else
1317 { //Can't find PTBatcherGui.app bundle. Use the most straightforward call possible to the bundle but this should actually not work either.
1318 hugin_utils::HuginMessageBox(wxString::Format(_("External program %s not found in the bundle, reverting to system path"), "open"), _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
1319 cmd = "open -b net.sourceforge.hugin.PTBatcherGUI "+hugin_utils::wxQuoteFilename(projectFile);
1320 wxExecute(cmd);
1321 }
1322
1323#else
1324 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
1326#endif
1328 }
1329};
1330
1332{
1333 if (pano->getNrOfImages() == 0)
1334 {
1335 return;
1336 }
1337
1338 if (!CheckGoodSize())
1339 {
1340 // oversized pano and the user no longer wants to stitch.
1341 return;
1342 }
1343 if (!CheckHasImages())
1344 {
1345 // output ROI contains no images
1346 return;
1347 };
1349 if (settings.IsEmpty())
1350 {
1351 // no filename given, ask user
1352 wxConfigBase* config = wxConfigBase::Get();
1353 wxString path = config->Read("/userDefinedOutputPath", MainFrame::Get()->GetDataPath());
1354 wxFileDialog userOutputDlg(this, _("Select user defined output"),
1355 path, wxEmptyString, _("User defined output|*.executor"),
1357 if (userOutputDlg.ShowModal() != wxID_OK)
1358 {
1359 return;
1360 };
1361 // remember path for later
1362 config->Write("/userDefinedOutputPath", userOutputDlg.GetDirectory());
1364 }
1365 else
1366 {
1367 //filename given, check existance
1368 userOutputSequence = settings;
1369 if (!userOutputSequence.Exists())
1370 {
1371 hugin_utils::HuginMessageBox(wxString::Format("User defined output %s not found.\nStopping processing.", userOutputSequence.GetFullPath()), _("Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
1372 return;
1373 };
1374 };
1376}
1377
1379{
1380 long t;
1381 bool readSettings = true;
1383 {
1384 t=1;
1385 readSettings = false;
1386 }
1387 else
1388 {
1389 wxConfigBase::Get()->Read("/Processor/gui", &t, HUGIN_PROCESSOR_GUI);
1390 };
1391 switch (t)
1392 {
1393 // PTBatcher
1394 case 0:
1396 break;
1397 // hugin_stitch_project
1398 case 1:
1400 break;
1401 // there is an error in the preferences
1402 default :
1403 // TODO: notify user and fix preferences misconfiguration
1404 break;
1405 }
1406}
1407
1408void PanoPanel::OnDoStitch(wxCommandEvent& e)
1409{
1411}
1412
1413void PanoPanel::FileFormatChanged(wxCommandEvent & e)
1414{
1415
1416 int fmt = m_FileFormatChoice->GetSelection();
1417 DEBUG_DEBUG("changing file format to " << fmt);
1418
1420 switch (fmt) {
1421 case 1:
1422 opt.outputImageType ="jpg";
1423 break;
1424 case 2:
1425 opt.outputImageType ="png";
1426 break;
1427 case 3:
1428 opt.outputImageType ="exr";
1429 break;
1430 default:
1431 case 0:
1432 opt.outputImageType ="tif";
1433 break;
1434 }
1435
1438 );
1439}
1440
1441void PanoPanel::HDRFileFormatChanged(wxCommandEvent & e)
1442{
1443
1444 int fmt = m_HDRFileFormatChoice->GetSelection();
1445 DEBUG_DEBUG("changing file format to " << fmt);
1446
1448 switch (fmt) {
1449 case 1:
1450 opt.outputImageTypeHDR ="tif";
1451 break;
1452 default:
1453 case 0:
1454 opt.outputImageTypeHDR ="exr";
1455 break;
1456 }
1457
1460 );
1461}
1462
1463void PanoPanel::OnJPEGQualityText(wxCommandEvent & e)
1464{
1466 long l = 100;
1467 m_FileFormatJPEGQualityText->GetValue().ToLong(&l);
1468 if (l < 0) l=1;
1469 if (l > 100) l=100;
1470 DEBUG_DEBUG("Setting jpeg quality to " << l);
1471 opt.quality = l;
1474 );
1475}
1476
1478{
1480 switch(e.GetSelection()) {
1481 case 0:
1482 default:
1484 opt.tiffCompression = "NONE";
1485 break;
1486 case 1:
1487 opt.outputImageTypeCompression = "PACKBITS";
1488 opt.tiffCompression = "PACKBITS";
1489 break;
1490 case 2:
1491 opt.outputImageTypeCompression = "LZW";
1492 opt.tiffCompression = "LZW";
1493 break;
1494 case 3:
1495 opt.outputImageTypeCompression = "DEFLATE";
1496 opt.tiffCompression = "DEFLATE";
1497 break;
1498 }
1501 );
1502}
1503
1504void PanoPanel::OnHDRTIFFCompression(wxCommandEvent & e)
1505{
1507 switch(e.GetSelection()) {
1508 case 0:
1509 default:
1511 break;
1512 case 1:
1513 opt.outputImageTypeHDRCompression = "PACKBITS";
1514 break;
1515 case 2:
1516 opt.outputImageTypeHDRCompression = "LZW";
1517 break;
1518 case 3:
1519 opt.outputImageTypeHDRCompression = "DEFLATE";
1520 break;
1521 }
1524 );
1525}
1526
1527void PanoPanel::OnOutputFilesChanged(wxCommandEvent & e)
1528{
1529 int id = e.GetId();
1531
1532 if (id == XRCID("pano_cb_ldr_output_blended") ) {
1533 opts.outputLDRBlended = e.IsChecked();
1534 } else if (id == XRCID("pano_cb_ldr_output_layers") ) {
1535 opts.outputLDRLayers = e.IsChecked();
1536 } else if (id == XRCID("pano_cb_ldr_output_exposure_layers") ) {
1537 opts.outputLDRExposureLayers = e.IsChecked();
1538 } else if (id == XRCID("pano_cb_ldr_output_exposure_blended") ) {
1539 opts.outputLDRExposureBlended = e.IsChecked();
1540 } else if (id == XRCID("pano_cb_ldr_output_exposure_layers_fused") ) {
1541 opts.outputLDRExposureLayersFused = e.IsChecked();
1542 } else if (id == XRCID("pano_cb_ldr_output_exposure_remapped") ) {
1543 opts.outputLDRExposureRemapped = e.IsChecked();
1544 } else if (id == XRCID("pano_cb_ldr_output_stacks") ) {
1545 opts.outputLDRStacks = e.IsChecked();
1546 } else if (id == XRCID("pano_cb_hdr_output_blended") ) {
1547 opts.outputHDRBlended = e.IsChecked();
1548 } else if (id == XRCID("pano_cb_hdr_output_stacks") ) {
1549 opts.outputHDRStacks = e.IsChecked();
1550 } else if (id == XRCID("pano_cb_hdr_output_layers") ) {
1551 opts.outputHDRLayers = e.IsChecked();
1552 }
1553
1556 );
1557}
1558
1560{
1562 const vigra::Rect2D cropped_region (opts.getROI());
1563 // width and height of jpeg images has to be smaller than 65500 pixel
1564 if (opts.outputImageType == "jpg" &&
1566 (cropped_region.width()>65500 || cropped_region.height()>65500)
1567 )
1568 {
1570 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()),
1572 return false;
1573 };
1575 const unsigned long long area = (static_cast<unsigned long long>(cropped_region.width()) * cropped_region.height());
1576 // Argh, more than half a gigapixel!
1577 if (area > 500000000)
1578 {
1579 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."),
1580 area / 1000000000.0);
1581 }
1582 else
1583 {
1584 if (cropped_region.width() > 32700 || cropped_region.height() > 32700)
1585 {
1586 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.");
1587 };
1588 };
1589 if (!message.empty())
1590 {
1591 // Tell the user the stitch will be really big, and give them a
1592 // chance to reduce the size.
1593 hugin_utils::MessageDialog dialog = hugin_utils::GetMessageDialog(_("Are you sure you want to stitch such a large panorama?"),
1595 dialog->SetExtendedMessage(message);
1596 dialog->SetYesNoLabels(_("Stitch anyway"), _("Let me fix that"));
1597 switch (dialog->ShowModal())
1598 {
1599 case wxID_OK:
1600 case wxID_YES:
1601 // Continue stitch.
1602 return true;
1603 break;
1604 default:
1605 // bring the user towards the approptiate controls.
1607 if (!mainframe->IsShown())
1608 {
1609 mainframe->Show();
1610 }
1611 mainframe->ShowStitcherTab();
1612 return false;
1613 }
1614 }
1615 // I see nothing wrong with this...
1616 return true;
1617}
1618
1620{
1621 HuginBase::UIntSet images=getImagesinROI(*pano, pano->getActiveImages());
1622 if(images.empty())
1623 {
1624 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."),
1626 };
1627 return !images.empty();
1628};
1629
1631{
1634 {
1635 // 4 channels, 16 bit per channel, assuming the we need the 10 fold space for all temporary space
1636 if (pano->getOptions().getROI().area() * 80 > freeSpace)
1637 {
1638 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),
1640 dialog->SetYesNoLabels(_("Stitch anyway"), _("Let me fix that"));
1641 if (dialog->ShowModal() == wxID_NO)
1642 {
1643 // bring the user towards the approptiate controls.
1645 if (!mainframe->IsShown())
1646 {
1647 mainframe->Show();
1648 }
1649 mainframe->ShowStitcherTab();
1650 return false;
1651 };
1652 };
1653 };
1654 return true;
1655};
1656
1662
1663IMPLEMENT_DYNAMIC_CLASS(PanoPanel, wxPanel)
1664
1666 : wxXmlResourceHandler()
1667{
1669}
1670
1672{
1674
1675 cp->Create(m_parentAsWindow,
1676 GetID(),
1677 GetPosition(), GetSize(),
1678 GetStyle("style"),
1679 GetName());
1680
1681 SetupWindow( cp);
1682
1683 return cp;
1684}
1685
1687{
1688 return IsOfClass(node, "PanoPanel");
1689}
1690
1691IMPLEMENT_DYNAMIC_CLASS(PanoPanelXmlHandler, wxXmlResourceHandler)
1692
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:82
size_t GetSelectedValue(wxControlWithItems *list)
Returns the client value of the selected item from list.
void SelectListValue(wxControlWithItems *list, size_t newValue)
Selects the given value (stored in the client data) in the given list item.
Definition LensTools.cpp:90
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:212
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.