Hugin trunk 0.1
Loading...
Searching...
No Matches
EnfusePanel.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
10/* This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This software is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public
21 * License along with this software. If not, see
22 * <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include "EnfusePanel.h"
27#include <wx/stdpaths.h>
28#include <wx/propgrid/advprops.h>
29#include "base_wx/platform.h"
30#include "base_wx/wxPlatform.h"
32#include "base_wx/Executor.h"
33#include <wx/fileconf.h>
34#include <wx/wfstream.h>
35#include <wx/sstream.h>
36#include "hugin_utils/utils.h"
38#include "base_wx/LensTools.h"
39#include "base_wx/wxutils.h"
40#include "CreateBrightImgDlg.h"
41
43class EnfuseDropTarget : public wxFileDropTarget
44{
45public:
46 EnfuseDropTarget(EnfusePanel* parent) : wxFileDropTarget()
47 {
49 }
50
52 {
53 // try to add as images
54 wxArrayString files;
55 for (unsigned int i = 0; i < filenames.GetCount(); i++)
56 {
57 wxFileName file(filenames[i]);
58 if (file.GetExt().CmpNoCase("jpg") == 0 ||
59 file.GetExt().CmpNoCase("jpeg") == 0 ||
60 file.GetExt().CmpNoCase("tif") == 0 ||
61 file.GetExt().CmpNoCase("tiff") == 0 ||
62 file.GetExt().CmpNoCase("png") == 0 ||
63 file.GetExt().CmpNoCase("bmp") == 0 ||
64 file.GetExt().CmpNoCase("gif") == 0 ||
65 file.GetExt().CmpNoCase("pnm") == 0 ||
66 file.GetExt().CmpNoCase("sun") == 0 ||
67 file.GetExt().CmpNoCase("hdr") == 0 ||
68 file.GetExt().CmpNoCase("viff") == 0)
69 {
70 files.push_back(file.GetFullPath());
71 };
72 };
73 // we got some images to add.
74 if (!files.empty())
75 {
76 for (auto& f : files)
77 {
79 };
80 };
81 return true;
82 }
83private:
85};
86
87// load wxPropertyGrid settings from string
89{
91 for (size_t i = 0; i < properties.size(); ++i)
92 {
94 if (prop.size() == 3)
95 {
96 if (prop[1] == "double")
97 {
98 double doubleVal;
99 if (prop[2].ToCDouble(&doubleVal))
100 {
101 grid->SetPropertyValue(prop[0], doubleVal);
102 };
103 }
104 else
105 {
106 if (prop[1] == "long")
107 {
108 long longVal;
109 if (prop[2].ToLong(&longVal))
110 {
111 grid->SetPropertyValue(prop[0], longVal);
112 }
113 }
114 else
115 {
116 if (prop[1] == "bool")
117 {
118 if (prop[2] == "true")
119 {
120 grid->SetPropertyValue(prop[0], true);
121 }
122 else
123 {
124 grid->SetPropertyValue(prop[0], false);
125 };
126 }
127 else
128 {
129 // unknown type, currently not implemented
130 };
131 };
132 };
133 };
134 };
135}
136
137// save wxPropertyGrid settings into a string
139{
142 for (it = grid->GetIterator(); !it.AtEnd(); it++)
143 {
144 const wxPGProperty* p = *it;
145 if (p->IsCategory())
146 {
147 // skip categories
148 continue;
149 }
150 if (!output.IsEmpty())
151 {
152 output.Append("|");
153 };
154 const wxString type = p->GetValueType();
155 output.Append(p->GetName() + ":");
156 if (type == "double")
157 {
158 output.Append("double:" + wxString::FromCDouble(p->GetValue().GetDouble()));
159 }
160 else
161 {
162 if (type == "long")
163 {
164 output.Append("long:" + wxString::FromCDouble(p->GetValue().GetLong()));
165 }
166 else
167 {
168 if (type == "bool")
169 {
170 if (p->GetValue().GetBool())
171 {
172 output.Append("bool:true");
173 }
174 else
175 {
176 output.Append("bool:false");
177 };
178 }
179 else
180 {
181 // this should not happen
182 output.Append(type);
183 };
184 };
185 };
186 };
187 return output;
188}
189
190// destructor, save settings
192{
193 wxConfigBase* config = wxConfigBase::Get();
194 config->Write("/ToolboxFrame/Enfuse/Splitter", XRCCTRL(*this, "enfuse_splitter", wxSplitterWindow)->GetSashPosition());
195 config->Write("/ToolboxFrame/Enfuse/LastSettings", GetPropertyGridContent(m_enfuseOptions));
196 //save width of list ctrl column width
197 for (int j = 0; j < m_fileListCtrl->GetColumnCount(); j++)
198 {
199 config->Write(wxString::Format("/ToolboxFrame/Enfuse/FileListColumnWidth%d", j), m_fileListCtrl->GetColumnWidth(j));
200 };
201 config->Flush();
203}
204
206{
207 if (!wxPanel::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, "panel"))
208 {
209 return false;
210 }
211 // populate wxPropertyGrid with all options
214 // create preview window
215 m_preview = new PreviewWindow();
216 m_preview->Create(this);
217
219 // load from xrc file and attach unknown controls
220 wxXmlResource::Get()->LoadPanel(this, "enfuse_panel");
221 wxXmlResource::Get()->AttachUnknownControl("enfuse_properties", m_enfuseOptions->GetGrid(), this);
222 wxXmlResource::Get()->AttachUnknownControl("enfuse_preview_window", m_preview, this);
223 // add to sizer
224 wxPanel* mainPanel = XRCCTRL(*this, "enfuse_panel", wxPanel);
226 topsizer->Add(mainPanel, wxSizerFlags(1).Expand());
227 // create columns in wxListCtrl
228 m_fileListCtrl = XRCCTRL(*this, "enfuse_files", wxListCtrl);
229 m_fileListCtrl->InsertColumn(0, _("Filename"), wxLIST_FORMAT_LEFT, 200);
230 m_fileListCtrl->InsertColumn(1, _("Aperture"), wxLIST_FORMAT_LEFT, 50);
231 m_fileListCtrl->InsertColumn(2, _("Shutter Speed"), wxLIST_FORMAT_LEFT, 50);
232 m_fileListCtrl->InsertColumn(3, _("ISO"), wxLIST_FORMAT_LEFT, 50);
233 m_fileListCtrl->EnableCheckBoxes(true);
236
237 wxConfigBase* config = wxConfigBase::Get();
238 // restore splitter position
239 if (config->HasEntry("/ToolboxFrame/Enfuse/Splitter"))
240 {
241 XRCCTRL(*this, "enfuse_splitter", wxSplitterWindow)->SetSashPosition(config->ReadLong("/ToolboxFrame/Enfuse/Splitter", 300));
242 }
243 const wxString enfuseOptionsString=config->Read("/ToolboxFrame/Enfuse/LastSettings");
244 if (!enfuseOptionsString.IsEmpty())
245 {
247 };
248 //get saved width of list ctrl column width
249 for (int j = 0; j < m_fileListCtrl->GetColumnCount(); j++)
250 {
251 // -1 is auto
252 int width = config->Read(wxString::Format("/ToolboxFrame/Enfuse/FileListColumnWidth%d", j), -1);
253 if (width != -1)
254 {
255 m_fileListCtrl->SetColumnWidth(j, width);
256 };
257 };
258 // bind event handler
259 Bind(wxEVT_BUTTON, &EnfusePanel::OnAddFiles, this, XRCID("enfuse_add_file"));
260 Bind(wxEVT_BUTTON, &EnfusePanel::OnRemoveFile, this, XRCID("enfuse_remove_file"));
261 Bind(wxEVT_BUTTON, &EnfusePanel::OnCreateFile, this, XRCID("enfuse_create_file"));
267 Bind(wxEVT_BUTTON, &EnfusePanel::OnLoadSetting, this, XRCID("enfuse_load_setting"));
268 Bind(wxEVT_BUTTON, &EnfusePanel::OnSaveSetting, this, XRCID("enfuse_save_setting"));
269 Bind(wxEVT_BUTTON, &EnfusePanel::OnResetSetting, this, XRCID("enfuse_reset_setting"));
270 Bind(wxEVT_BUTTON, &EnfusePanel::OnGeneratePreview, this, XRCID("enfuse_preview"));
271 Bind(wxEVT_BUTTON, &EnfusePanel::OnGenerateOutput, this, XRCID("enfuse_enfuse"));
272 Bind(wxEVT_CHOICE, &EnfusePanel::OnZoom, this, XRCID("enfuse_choice_zoom"));
273
275 EnableOutputButtons(false);
276 return true;
277}
278
279void EnfusePanel::AddFile(const wxString& filename)
280{
281 // add filename
282 m_files.push_back(filename);
283 // add to wxListCtrl
284 wxFileName fullFilename(filename);
285 long index = m_fileListCtrl->InsertItem(m_fileListCtrl->GetItemCount(), fullFilename.GetFullName());
286 // set checkbox
287 m_fileListCtrl->CheckItem(index, true);
288 // read exif
289 {
291 srcImage.setFilename(std::string(fullFilename.GetFullPath().mb_str(HUGIN_CONV_FILENAME)));
292 if (srcImage.readEXIF())
293 {
294 m_fileListCtrl->SetItem(index, 1, FormatString::GetAperture(&srcImage));
295 m_fileListCtrl->SetItem(index, 2, FormatString::GetExposureTime(&srcImage));
296 m_fileListCtrl->SetItem(index, 3, FormatString::GetIso(&srcImage));
297 };
298 };
300}
301
302void EnfusePanel::OnAddFiles(wxCommandEvent& e)
303{
304 wxConfigBase* config = wxConfigBase::Get();
305 wxString path = config->Read("/actualPath", "");
306 wxFileDialog dlg(this, _("Add images"), path, wxEmptyString,
308 dlg.SetDirectory(path);
309
310 // remember the image extension
312 if (config->HasEntry("lastImageType"))
313 {
314 img_ext = config->Read("lastImageType").c_str();
315 }
316 if (img_ext == "all images")
317 dlg.SetFilterIndex(0);
318 else if (img_ext == "jpg")
319 dlg.SetFilterIndex(1);
320 else if (img_ext == "tiff")
321 dlg.SetFilterIndex(2);
322 else if (img_ext == "png")
323 dlg.SetFilterIndex(3);
324 else if (img_ext == "hdr")
325 dlg.SetFilterIndex(4);
326 else if (img_ext == "exr")
327 dlg.SetFilterIndex(5);
328 else if (img_ext == "all files")
329 dlg.SetFilterIndex(6);
330
331 // call the file dialog
332 if (dlg.ShowModal() == wxID_OK)
333 {
334 // get the selections
336 dlg.GetPaths(Pathnames);
337 // save the current path to config
338 config->Write("/actualPath", dlg.GetDirectory());
339 // save the image extension
340 switch (dlg.GetFilterIndex())
341 {
342 case 0: config->Write("lastImageType", "all images"); break;
343 case 1: config->Write("lastImageType", "jpg"); break;
344 case 2: config->Write("lastImageType", "tiff"); break;
345 case 3: config->Write("lastImageType", "png"); break;
346 case 4: config->Write("lastImageType", "hdr"); break;
347 case 5: config->Write("lastImageType", "exr"); break;
348 case 6: config->Write("lastImageType", "all files"); break;
349 }
350 for (auto& f : Pathnames)
351 {
352 AddFile(f);
353 }
354 }
355}
356
357void EnfusePanel::OnRemoveFile(wxCommandEvent& e)
358{
360 if (m_fileListCtrl->GetSelectedItemCount() >= 1)
361 {
362 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
363 {
365 {
366 selected.insert(i);
367 };
368 };
369 };
370 if (!selected.empty())
371 {
372 // remove selected file from wxListBox and internal file list
373 for (auto i = selected.rbegin(); i != selected.rend(); ++i)
374 {
375 if (*i >= 0 && *i < m_files.size())
376 {
377 m_fileListCtrl->DeleteItem(*i);
378 m_files.RemoveAt(*i, 1);
379 };
380 };
383 }
384 else
385 {
386 wxBell();
387 };
388}
389
390void EnfusePanel::OnCreateFile(wxCommandEvent& e)
391{
392 if (m_fileListCtrl->GetSelectedItemCount() == 1)
393 {
394 // single image selected
395 long index = m_fileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
396 if (index != -1)
397 {
400 if (dlg.SetImage(std::string(m_files[index].mb_str(HUGIN_CONV_FILENAME)), errorMsg))
401 {
402 if (dlg.ShowModal() == wxID_OK)
403 {
404 // get all new files
405 wxArrayString newFiles = dlg.GetTempFiles();
406 // wait a little bit before reading the files back
407 // wxMilliSleep(1000);
408 for (const auto& f : newFiles)
409 {
410 // add to list of temp files for cleanup at end
411 m_tempFiles.Add(f);
412 // add to list
413 AddFile(f);
414 };
415 };
416 }
417 else
418 {
419 hugin_utils::HuginMessageBox(errorMsg, _("Hugin toolbox"), wxOK | wxICON_QUESTION, this);
420 };
421 };
422 }
423 else
424 {
425 wxBell();
426 };
427}
428
430{
431 // ctrl + a, select all files
432 if (e.GetKeyCode() == 1 && e.CmdDown())
433 {
434 // select all
435 for (int i = 0; i < m_fileListCtrl->GetItemCount(); i++)
436 {
438 };
439 };
440 // insert key, add file
441 if ((e.GetKeyCode() == WXK_INSERT || e.GetKeyCode() == WXK_NUMPAD_INSERT) && !e.HasAnyModifiers())
442 {
443 wxCommandEvent e(wxEVT_BUTTON);
444 e.SetId(XRCID("enfuse_add_file"));
445 this->GetEventHandler()->AddPendingEvent(e);
446 };
447 // delete key, delete selected file
448 if ((e.GetKeyCode() == WXK_DELETE || e.GetKeyCode() == WXK_NUMPAD_DELETE) && !e.HasAnyModifiers())
449 {
450 if (m_fileListCtrl->GetSelectedItemCount() > 0)
451 {
452 wxCommandEvent e(wxEVT_BUTTON);
453 e.SetId(XRCID("enfuse_remove_file"));
454 this->GetEventHandler()->AddPendingEvent(e);
455 }
456 else
457 {
458 wxBell();
459 };
460 };
461 e.Skip();
462}
463
465{
466 // enable/disable button according to selected files
468}
469
474
477{
478 "[Enfuse_Settings]\n"
479 "Exposure fusion=exposureWeight:double:1|saturationWeight:double:0|contrastWeight:double:0|entropyWeight:double:0|hardMask:bool:false|levels:long:0|blendColorspace:long:0|wrapMode:long:0|exposureOptimum:double:0.5|exposureWidth:double:0.2|contrastEdgeScale:double:0|contrastMinCurvature:double:0|contrastWindowSize:long:5|entropyLowerCutoff:double:0|entropyUpperCutoff:double:100|entropyWindowSize:long:3|exposureLowerCutoff:double:0|exposureUpperCutoff:double:100|exposureWeightFunction:long:0|grayProjector:long:1\n"
480 "Focus stacking=exposureWeight:double:0|saturationWeight:double:0|contrastWeight:double:1|entropyWeight:double:0|hardMask:bool:true|levels:long:0|blendColorspace:long:0|wrapMode:long:0|exposureOptimum:double:0.5|exposureWidth:double:0.2|contrastEdgeScale:double:0|contrastMinCurvature:double:0|contrastWindowSize:long:5|entropyLowerCutoff:double:0|entropyUpperCutoff:double:100|entropyWindowSize:long:3|exposureLowerCutoff:double:0|exposureUpperCutoff:double:100|exposureWeightFunction:long:0|grayProjector:long:1\n"
481};
482
484{
485 wxInputStream* iniStream{ nullptr };
486 if (wxFileExists(filename))
487 {
488 iniStream = new wxFileInputStream(filename);
489 if (!iniStream->IsOk())
490 {
491 delete iniStream;
492 iniStream = nullptr;
493 }
494 };
495 if (iniStream == nullptr)
496 {
498 };
499 // now read from stream
501 delete iniStream;
502 return iniFile;
503}
504
505void EnfusePanel::OnLoadSetting(wxCommandEvent& e)
506{
508 wxFileConfig* iniFile = ReadIni(iniFilename.GetFullPath());
509 // read known settings from file
510 iniFile->SetPath("Enfuse_Settings");
514 long indexKey;
515 bool hasKeys = iniFile->GetFirstEntry(key, indexKey);
516 while (hasKeys)
517 {
518 knownNames.push_back(key);
519 knownSettings.push_back(iniFile->Read(key));
520 hasKeys = iniFile->GetNextEntry(key, indexKey);
521 };
522 int selection=wxGetSingleChoiceIndex(_("Select the Enfuse setting, which should be loaded."), _("Hugin toolbox"), knownNames, 0, this);
523 if (selection != -1)
524 {
526 };
527 delete iniFile;
528}
529
530void EnfusePanel::OnSaveSetting(wxCommandEvent& e)
531{
533 wxFileConfig* iniFile = ReadIni(iniFilename.GetFullPath());
534 // read known settings from file
535 iniFile->SetPath("Enfuse_Settings");
538 long indexKey;
539 bool hasKeys = iniFile->GetFirstEntry(key, indexKey);
540 while (hasKeys)
541 {
542 knownNames.push_back(key);
543 hasKeys = iniFile->GetNextEntry(key, indexKey);
544 };
545 wxString name;
546 while (true)
547 {
548 name = wxGetTextFromUser(_("Enter name of Enfuse setting"), "Enfuse settings", name, this);
549 if (name.IsEmpty())
550 {
551 // empty name or cancel
552 delete iniFile;
553 return;
554 };
555 // remove the '=' character from name, it is used as separator in ini file
556 name.Replace("=", "", true);
557 if (knownNames.Index(name) != wxNOT_FOUND)
558 {
559 if (hugin_utils::HuginMessageBox(wxString::Format(_("Enfuse setting with name \"%s\" is already existing.\nShould it be overwritten?"), name),
560 _("Hugin toolbox"), wxYES_NO | wxICON_QUESTION, this) == wxYES)
561 {
562 break;
563 };
564 }
565 else
566 {
567 break;
568 };
569 };
570 // finally write settings
572 // finally write to disc
574 bool success = true;
575 if (iniStream.IsOk())
576 {
577 success = iniFile->Save(iniStream);
578 };
579 if (!success)
580 {
581 hugin_utils::HuginMessageBox(wxString::Format(_("Could not save ini file \"%s\"."), iniFilename.GetFullPath()), _("Hugin toolbox"), wxOK | wxICON_ERROR, this);
582 };
583 delete iniFile;
584}
585
586void EnfusePanel::OnResetSetting(wxCommandEvent& e)
587{
588 // reset all settings to default values
589 m_enfuseOptions->SetPropertyValue("exposureWeight", 1.0);
590 m_enfuseOptions->SetPropertyValue("saturationWeight", 0.0);
591 m_enfuseOptions->SetPropertyValue("contrastWeight", 0.0);
592 m_enfuseOptions->SetPropertyValue("entropyWeight", 0.0);
593 m_enfuseOptions->SetPropertyValue("hardMask", false);
594 m_enfuseOptions->SetPropertyValue("levels", 0);
595 m_enfuseOptions->SetPropertyValue("blendColorspace", 0);
596 m_enfuseOptions->SetPropertyValue("wrapMode", 0);
597 m_enfuseOptions->SetPropertyValue("exposureOptimum", 0.5);
598 m_enfuseOptions->SetPropertyValue("exposureWidth", 0.2);
599 m_enfuseOptions->SetPropertyValue("contrastEdgeScale", 0.0);
600 m_enfuseOptions->SetPropertyValue("contrastMinCurvature", 0.0);
601 m_enfuseOptions->SetPropertyValue("contrastWindowSize", 5);
602 m_enfuseOptions->SetPropertyValue("entropyLowerCutoff", 0.0);
603 m_enfuseOptions->SetPropertyValue("entropyUpperCutoff", 100.0);
604 m_enfuseOptions->SetPropertyValue("entropyWindowSize", 3);
605 m_enfuseOptions->SetPropertyValue("exposureLowerCutoff", 0.0);
606 m_enfuseOptions->SetPropertyValue("exposureUpperCutoff", 100.0);
607 m_enfuseOptions->SetPropertyValue("exposureWeightFunction", 0);
608 m_enfuseOptions->SetPropertyValue("grayProjector", 1);
609}
610
611void EnfusePanel::OnGeneratePreview(wxCommandEvent& e)
612{
613 // create temp file name, set extension to tif
614 m_outputFilenames.resize(2);
615 wxFileName tempfile(wxFileName::CreateTempFileName(HuginQueue::GetConfigTempDir(wxConfig::Get()) + "he"));
616 m_outputFilenames[1] = tempfile.GetFullPath();
617 tempfile.SetExt("tif");
618 m_outputFilenames[0] = tempfile.GetFullPath();
619 m_cleanupOutput = true;
620 // get command line and execute
622}
623
636
638{
640 if (!cmd.IsEmpty())
641 {
642 EnableOutputButtons(false);
646 queue->push_back(new HuginQueue::NormalCommand(HuginQueue::GetExternalProgram(wxConfig::Get(), exePath, "enfuse"), cmd, _("Merging images") + " (" + cmd + ")"));
647 // get first image
648 long index = -1;
649 for (long i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
650 {
651 if (m_fileListCtrl->IsItemChecked(i))
652 {
653 index = i;
654 break;
655 };
656 };
657 wxString exiftoolArgs(" -overwrite_original -tagsfromfile " + HuginQueue::wxEscapeFilename(m_files[index]));
658 exiftoolArgs.Append(" -all:all --thumbnail --thumbnailimage --xposition --yposition --imagefullwidth --imagefullheight ");
660 queue->push_back(new HuginQueue::OptionalCommand(HuginQueue::GetExternalProgram(wxConfig::Get(), exePath, "exiftool"), exiftoolArgs, _("Updating EXIF")));
661 m_logWindow->ExecQueue(queue);
662 };
663}
664
665void EnfusePanel::OnGenerateOutput(wxCommandEvent& e)
666{
667 if (m_files.IsEmpty())
668 {
669 wxBell();
670 return;
671 };
672 wxConfigBase* config = wxConfigBase::Get();
673 wxString path = config->Read("/actualPath", "");
675 dlg.SetDirectory(path);
676
677 // remember the image extension
679 if (config->HasEntry("lastImageType"))
680 {
681 img_ext = config->Read("lastImageType").c_str();
682 }
683 if (img_ext == "jpg")
684 {
685 dlg.SetFilterIndex(0);
686 }
687 else
688 {
689 if (img_ext == "tiff")
690 {
691 dlg.SetFilterIndex(1);
692 }
693 else
694 {
695 if (img_ext == "png")
696 {
697 dlg.SetFilterIndex(2);
698 };
699 };
700 };
702 outputfilename.SetName(outputfilename.GetName() + "_stacked");
703 dlg.SetFilename(outputfilename.GetFullPath());
704 // call the file dialog
705 if (dlg.ShowModal() == wxID_OK)
706 {
707 m_outputFilenames.resize(1);
708 m_outputFilenames[0] = dlg.GetPath();
709 // save the current path to config
710 config->Write("/actualPath", dlg.GetDirectory());
711 // save the image extension
712 switch (dlg.GetFilterIndex())
713 {
714 case 0:
715 config->Write("lastImageType", "jpg");
716 break;
717 case 1:
718 config->Write("lastImageType", "tiff");
719 break;
720 case 2:
721 config->Write("lastImageType", "png");
722 break;
723 };
724 m_cleanupOutput = false;
726 };
727}
728
729void EnfusePanel::OnZoom(wxCommandEvent& e)
730{
731 double factor;
732 switch (e.GetSelection())
733 {
734 case 0:
735 factor = 1;
736 break;
737 case 1:
738 // fit to window
739 factor = 0;
740 break;
741 case 2:
742 factor = 2;
743 break;
744 case 3:
745 factor = 1.5;
746 break;
747 case 4:
748 factor = 0.75;
749 break;
750 case 5:
751 factor = 0.5;
752 break;
753 case 6:
754 factor = 0.25;
755 break;
756 default:
757 DEBUG_ERROR("unknown scale factor");
758 factor = 1;
759 }
760 m_preview->setScale(factor);
761}
762
763void EnfusePanel::OnProcessFinished(wxCommandEvent& e)
764{
766 if (output.FileExists() && output.GetSize()>0)
767 {
768 m_preview->setImage(output.GetFullPath());
769 };
771 if (m_cleanupOutput && output.FileExists())
772 {
773 // cleanup up preview files
774 for (const auto& f : m_outputFilenames)
775 {
776 wxRemoveFile(f);
777 };
778 };
779}
780
782{
783 // all weight options, with spin control
784 wxPGProperty* prop = m_enfuseOptions->Append(new wxFloatProperty("Exposure weight", "exposureWeight", 1));
785 prop->SetEditor(wxPGEditor_SpinCtrl);
786 prop->SetAttribute(wxPG_ATTR_MIN, 0);
787 prop->SetAttribute(wxPG_ATTR_MAX, 1);
788 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
789 prop = m_enfuseOptions->Append(new wxFloatProperty("Saturation weight", "saturationWeight", 0));
790 prop->SetEditor(wxPGEditor_SpinCtrl);
791 prop->SetAttribute(wxPG_ATTR_MIN, 0);
792 prop->SetAttribute(wxPG_ATTR_MAX, 1);
793 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
794 prop = m_enfuseOptions->Append(new wxFloatProperty("Contrast weight", "contrastWeight", 0));
795 prop->SetEditor(wxPGEditor_SpinCtrl);
796 prop->SetAttribute(wxPG_ATTR_MIN, 0);
797 prop->SetAttribute(wxPG_ATTR_MAX, 1);
798 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
799 prop = m_enfuseOptions->Append(new wxFloatProperty("Entropy weight", "entropyWeight", 0));
800 prop->SetEditor(wxPGEditor_SpinCtrl);
801 prop->SetAttribute(wxPG_ATTR_MIN, 0);
802 prop->SetAttribute(wxPG_ATTR_MAX, 1);
803 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
804 // hard / soft mask
805 m_enfuseOptions->Append(new wxBoolProperty("Hard mask", "hardMask", false));
806 // general options
807 prop = m_enfuseOptions->Append(new wxPropertyCategory(_("General"), "general"));
808 prop = m_enfuseOptions->Append(new wxIntProperty("Levels", "levels", 0));
809 prop->SetEditor(wxPGEditor_SpinCtrl);
810 prop->SetAttribute(wxPG_ATTR_MIN, -29);
811 prop->SetAttribute(wxPG_ATTR_MAX, 29);
812 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 1);
814 blendColorspaces.Add("Auto");
815 blendColorspaces.Add("Identity (RGB)");
816 blendColorspaces.Add("CIELab");
817 blendColorspaces.Add("CIELuv");
818 blendColorspaces.Add("CIECAM02");
819 m_enfuseOptions->Append(new wxEnumProperty("Blend colorspace", "blendColorspace", blendColorspaces));
821 wrapMode.Add("None");
822 wrapMode.Add("Horizontal");
823 wrapMode.Add("Vertical");
824 wrapMode.Add("Both");
825 m_enfuseOptions->Append(new wxEnumProperty("Wrap mode", "wrapMode", wrapMode));
826 m_enfuseOptions->Collapse("general");
827 m_enfuseOptions->Append(new wxPropertyCategory(_("Fusions options"), "fusionOptions"));
828 prop = m_enfuseOptions->Append(new wxFloatProperty("Exposure optimum", "exposureOptimum", 0.5));
829 prop->SetEditor(wxPGEditor_SpinCtrl);
830 prop->SetAttribute(wxPG_ATTR_MIN, 0);
831 prop->SetAttribute(wxPG_ATTR_MAX, 1);
832 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
833 prop = m_enfuseOptions->Append(new wxFloatProperty("Exposure width", "exposureWidth", 0.2));
834 prop->SetEditor(wxPGEditor_SpinCtrl);
835 prop->SetAttribute(wxPG_ATTR_MIN, 0);
836 prop->SetAttribute(wxPG_ATTR_MAX, 1);
837 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.05);
838 prop = m_enfuseOptions->Append(new wxFloatProperty("Contrast edge scale", "contrastEdgeScale", 0));
839 prop->SetEditor(wxPGEditor_SpinCtrl);
840 prop->SetAttribute(wxPG_ATTR_MIN, 0);
841 prop->SetAttribute(wxPG_ATTR_MAX, 5);
842 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.1);
843 prop = m_enfuseOptions->Append(new wxFloatProperty("Contrast min curvature", "contrastMinCurvature", 0));
844 prop->SetEditor(wxPGEditor_SpinCtrl);
845 prop->SetAttribute(wxPG_ATTR_MIN, 0);
846 prop->SetAttribute(wxPG_ATTR_MAX, 50);
847 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.5);
848 prop = m_enfuseOptions->Append(new wxIntProperty("Contrast window size", "contrastWindowSize", 5));
849 prop->SetEditor(wxPGEditor_SpinCtrl);
850 prop->SetAttribute(wxPG_ATTR_MIN, 3);
851 prop->SetAttribute(wxPG_ATTR_MAX, 30);
852 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 1);
853 prop = m_enfuseOptions->Append(new wxFloatProperty("Entropy lower cutoff", "entropyLowerCutoff", 0));
854 prop->SetEditor(wxPGEditor_SpinCtrl);
855 prop->SetAttribute(wxPG_ATTR_MIN, 0);
856 prop->SetAttribute(wxPG_ATTR_MAX, 100);
857 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.5);
858 prop = m_enfuseOptions->Append(new wxFloatProperty("Entropy higher cutoff", "entropyUpperCutoff", 100));
859 prop->SetEditor(wxPGEditor_SpinCtrl);
860 prop->SetAttribute(wxPG_ATTR_MIN, 0);
861 prop->SetAttribute(wxPG_ATTR_MAX, 100);
862 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.5);
863 prop = m_enfuseOptions->Append(new wxIntProperty("Entropy window size", "entropyWindowSize", 3));
864 prop->SetEditor(wxPGEditor_SpinCtrl);
865 prop->SetAttribute(wxPG_ATTR_MIN, 3);
866 prop->SetAttribute(wxPG_ATTR_MAX, 7);
867 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 1);
868 prop = m_enfuseOptions->Append(new wxFloatProperty("Expoure lower cutoff", "exposureLowerCutoff", 0));
869 prop->SetEditor(wxPGEditor_SpinCtrl);
870 prop->SetAttribute(wxPG_ATTR_MIN, 0);
871 prop->SetAttribute(wxPG_ATTR_MAX, 100);
872 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.5);
873 prop = m_enfuseOptions->Append(new wxFloatProperty("Exposure higher cutoff", "exposureUpperCutoff", 100));
874 prop->SetEditor(wxPGEditor_SpinCtrl);
875 prop->SetAttribute(wxPG_ATTR_MIN, 0);
876 prop->SetAttribute(wxPG_ATTR_MAX, 100);
877 prop->SetAttribute(wxPG_ATTR_SPINCTRL_STEP, 0.5);
879 exposureWeightFunction.Add("Gaussian");
880 exposureWeightFunction.Add("Lorentzian");
881 exposureWeightFunction.Add("Half-sine");
882 exposureWeightFunction.Add("Full-sine");
883 exposureWeightFunction.Add("Bi-square");
884 m_enfuseOptions->Append(new wxEnumProperty("Exposure weight function", "exposureWeightFunction", exposureWeightFunction));
886 grayProjector.Add("anti-value"); // index 0
887 grayProjector.Add("Average"); // index 1
888 grayProjector.Add("L-channel from Lab (gamma=1)"); // index 2
889 grayProjector.Add("L-channel from Lab (gamma corrected)"); // index 3
890 grayProjector.Add("Lightness"); // index 4
891 grayProjector.Add("Luminance"); // index 5
892 grayProjector.Add("Value from HSV"); // index 6
893 // missing: channelMixel
894 prop = m_enfuseOptions->Append(new wxEnumProperty("Gray projector", "grayProjector", grayProjector));
895 m_enfuseOptions->SetPropertyValue("grayProjector", 1);
896 // if you add new options also update GetEnfuseOptions() and OnResetSetting(..)
897}
898
900{
901 wxString commandline("--verbose ");
902 double doubleValue=m_enfuseOptions->GetPropertyValueAsDouble("exposureWeight");
903 if (doubleValue != 1)
904 {
905 commandline.Append(" --exposure-weight=" + wxString::FromCDouble(doubleValue));
906 };
907 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("saturationWeight");
908 if (doubleValue != 0)
909 {
910 commandline.Append(" --saturation-weight=" + wxString::FromCDouble(doubleValue));
911 };
912 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("contrastWeight");
913 if (doubleValue != 0)
914 {
915 commandline.Append(" --contrast-weight=" + wxString::FromCDouble(doubleValue));
916 };
917 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("entropyWeight");
918 if (doubleValue != 0)
919 {
920 commandline.Append(" --entropy-weight=" + wxString::FromCDouble(doubleValue));
921 };
922 bool boolVal = m_enfuseOptions->GetPropertyValueAsBool("hardMask");
923 if (boolVal)
924 {
925 commandline.Append(" --hard-mask");
926 };
927 int intValue = m_enfuseOptions->GetPropertyValueAsInt("levels");
928 if (intValue != 0)
929 {
930 commandline.Append(wxString::Format(" --level=%d", intValue));
931 };
932 intValue = m_enfuseOptions->GetPropertyValueAsInt("blendColorspace");
933 switch (intValue)
934 {
935 case 1:
936 commandline.Append(" --blend-colorspace=identity");
937 break;
938 case 2:
939 commandline.Append(" --blend-colorspace=cielab");
940 break;
941 case 3:
942 commandline.Append(" --blend-colorspace=cieluv");
943 break;
944 case 4:
945 commandline.Append(" --blend-colorspace=ciecam");
946 break;
947 default:
948 case 0:
949 // do nothing
950 break;
951 };
952 intValue = m_enfuseOptions->GetPropertyValueAsInt("wrapMode");
953 switch (intValue)
954 {
955 case 1:
956 commandline.Append(" --wrap=horizontal");
957 break;
958 case 2:
959 commandline.Append(" --wrap=vertical");
960 break;
961 case 3:
962 commandline.Append(" --wrap=both ");
963 break;
964 case 0:
965 default:
966 break;
967 };
968 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("exposureOptimum");
969 if (doubleValue != 0.5)
970 {
971 commandline.Append(" --exposure-optimum=" + wxString::FromCDouble(doubleValue));
972 };
973 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("exposureWidth");
974 if (doubleValue != 0.2)
975 {
976 commandline.Append(" --exposure-width=" + wxString::FromCDouble(doubleValue));
977 };
978 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("contrastEdgeScale");
979 if (doubleValue != 0)
980 {
981 commandline.Append(" --contrast-edge-scale=" + wxString::FromCDouble(doubleValue));
982 };
983 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("contrastMinCurvature");
984 if (doubleValue != 0)
985 {
986 commandline.Append(" --contrast-min-curvature=" + wxString::FromCDouble(doubleValue) + "%");
987 };
988 intValue = m_enfuseOptions->GetPropertyValueAsInt("contrastWindowSize");
989 if (intValue != 5)
990 {
991 commandline.Append(wxString::Format(" --contrast-window-size=%d", intValue));
992 };
993 // entropy cutoff
994 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("entropyLowerCutoff");
995 double doubleValue2 = m_enfuseOptions->GetPropertyValueAsDouble("entropyUpperCutoff");
996 if (doubleValue > 0 || doubleValue2 < 100)
997 {
998 commandline.Append(" --entropy-cutoff=" + wxString::FromCDouble(doubleValue) + "%");
999 if (doubleValue2 < 100)
1000 {
1001 commandline.Append(":" + wxString::FromCDouble(doubleValue2) + "%");
1002 };
1003 };
1004 intValue = m_enfuseOptions->GetPropertyValueAsInt("entropyWindowSize");
1005 if (intValue != 3)
1006 {
1007 commandline.Append(wxString::Format(" --entropy-window-size=%d", intValue));
1008 };
1009 // exposure cutoff
1010 doubleValue = m_enfuseOptions->GetPropertyValueAsDouble("exposureLowerCutoff");
1011 doubleValue2 = m_enfuseOptions->GetPropertyValueAsDouble("exposureUpperCutoff");
1012 if (doubleValue > 0 || doubleValue2 < 100)
1013 {
1014 commandline.Append(" --exposure-cutoff=" + wxString::FromCDouble(doubleValue) + "%");
1015 if (doubleValue2 < 100)
1016 {
1017 commandline.Append(":" + wxString::FromCDouble(doubleValue2) + "%");
1018 };
1019 };
1020 // exposure weight function
1021 intValue = m_enfuseOptions->GetPropertyValueAsInt("exposureWeightFunction");
1022 switch (intValue)
1023 {
1024 case 1:
1025 commandline.Append(" --exposure-weight-function=lorentz");
1026 break;
1027 case 2:
1028 commandline.Append(" --exposure-weight-function=halfsine");
1029 break;
1030 case 3:
1031 commandline.Append(" --exposure-weight-function=fullsine");
1032 break;
1033 case 4:
1034 commandline.Append(" --exposure-weight-function=bisquare");
1035 break;
1036 case 0:
1037 default:
1038 break;
1039 };
1040 // gray projector
1041 intValue = m_enfuseOptions->GetPropertyValueAsInt("grayProjector");
1042 switch (intValue)
1043 {
1044 case 0:
1045 commandline.Append(" --gray-projector=anti-value");
1046 break;
1047 case 2:
1048 commandline.Append(" --gray-projector=al-star");
1049 break;
1050 case 3:
1051 commandline.Append(" --gray-projector=pl-star");
1052 break;
1053 case 4:
1054 commandline.Append(" --gray-projector=lightness");
1055 break;
1056 case 5:
1057 commandline.Append(" --gray-projector=luminance");
1058 break;
1059 case 6:
1060 commandline.Append(" --gray-projector=value");
1061 break;
1062 case 1:
1063 default:
1064 break;
1065 };
1066 return commandline;
1067}
1068
1070{
1072 // add options from control
1073 commandline.Append(" ");
1074 commandline.Append(GetEnfuseOptions());
1075 // now build image list
1077 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
1078 {
1079 if (m_fileListCtrl->IsItemChecked(i))
1080 {
1081 selectedFiles.push_back(i);
1082 };
1083 };
1084 if (selectedFiles.IsEmpty())
1085 {
1086 hugin_utils::HuginMessageBox(_("Please activate at least one file."), _("Hugin_toolbox"), wxOK | wxOK_DEFAULT | wxICON_WARNING, this);
1087 return wxEmptyString;
1088 }
1089 for (int i = 0; i < selectedFiles.size(); ++i)
1090 {
1091 commandline.Append(" ");
1093 }
1094 return commandline;
1095}
1096
1098{
1099 // enable/disable button according to selected files
1100 XRCCTRL(*this, "enfuse_remove_file", wxButton)->Enable(m_fileListCtrl->GetSelectedItemCount() >= 1);
1101 XRCCTRL(*this, "enfuse_create_file", wxButton)->Enable(m_fileListCtrl->GetSelectedItemCount() == 1);
1102}
1103
1105{
1106 // count checked items
1107 long count = 0;
1108 for (int i = 0; i < m_fileListCtrl->GetItemCount(); ++i)
1109 {
1110 if (m_fileListCtrl->IsItemChecked(i))
1111 {
1112 ++count;
1113 };
1114 };
1115 return count;
1116}
1117
1119{
1120 XRCCTRL(*this, "enfuse_preview", wxButton)->Enable(enable);
1121 XRCCTRL(*this, "enfuse_enfuse", wxButton)->Enable(enable);
1122
1123}
1124
1126{
1127 for (const auto& f : m_tempFiles)
1128 {
1129 wxRemoveFile(f);
1130 };
1131}
1132
1133IMPLEMENT_DYNAMIC_CLASS(EnfusePanel, wxPanel)
Definition of dialog class to create brighter/darker versions of the image.
wxString GetPropertyGridContent(const wxPropertyGrid *grid)
wxFileConfig * ReadIni(const wxString &filename)
static const wxString defaultIni
default ini, if no one exists load this one
void SetPropertyGridContent(wxPropertyGrid *grid, const wxString values)
declaration of panel for enfuse GUI
basic classes and function for queuing commands in wxWidgets
some helper classes for graphes
Dialog for create brighter and/or darker versions of an image.
file drag and drop handler method
EnfusePanel * m_enfusePanel
EnfuseDropTarget(EnfusePanel *parent)
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
panel for enfuse GUI
Definition EnfusePanel.h:38
void PopulateEnfuseOptions()
fill the PropertyGrid with all enfuse options
PreviewWindow * m_preview
Definition EnfusePanel.h:89
bool Create(wxWindow *parent, MyExecPanel *logPanel)
creates the control and populates all controls with their settings
void OnZoom(wxCommandEvent &e)
wxPropertyGrid * m_enfuseOptions
Definition EnfusePanel.h:87
void OnCreateFile(wxCommandEvent &e)
void AddFile(const wxString &filename)
adds the given file to the list
void OnAddFiles(wxCommandEvent &e)
event handler
void OnProcessFinished(wxCommandEvent &e)
call at the end of the enfuse command, to load result back and enable buttons again
void OnFileListChar(wxKeyEvent &e)
void OnRemoveFile(wxCommandEvent &e)
void OnGenerateOutput(wxCommandEvent &e)
void CleanUpTempFiles()
delete all temporary files, to be called mainly at end
void EnableOutputButtons(bool enable)
enable/disable output buttons
void ExecuteEnfuseExiftool()
build the command line and execute enfuse and exiftool afterwards
long GetCheckedItemCount() const
return the number of check images
void OnGeneratePreview(wxCommandEvent &e)
~EnfusePanel()
destructor, save state and settings
wxString GetEnfuseOptions()
build string with all enfuse options from values in wxPropertyGrid this are the mainly the fusion opt...
MyExecPanel * m_logWindow
Definition EnfusePanel.h:90
void OnFileCheckStateChanged(wxCommandEvent &e)
wxString GetEnfuseCommandLine()
get the full commandline for enfuse without program, but with files and output options,...
wxArrayString m_tempFiles
Definition EnfusePanel.h:92
wxArrayString m_outputFilenames
Definition EnfusePanel.h:91
void OnLoadSetting(wxCommandEvent &e)
wxListCtrl * m_fileListCtrl
Definition EnfusePanel.h:86
wxArrayString m_files
Definition EnfusePanel.h:88
void ExecuteEnfuse()
build the command line and execute enfuse command
void OnSaveSetting(wxCommandEvent &e)
void EnableFileButtons()
enable/disable the file(s) remove and create buttons depending on selection of wxListCtrl
bool m_cleanupOutput
Definition EnfusePanel.h:93
void OnResetSetting(wxCommandEvent &e)
void OnFileSelectionChanged(wxCommandEvent &e)
All variables of a source image.
normal command for queue, processing is stopped if an error occurred in program
Definition Executor.h:38
optional command for queue, processing of queue is always continued, also if an error occurred
Definition Executor.h:54
int ExecQueue(HuginQueue::CommandQueue *queue)
void AddString(const wxString &s)
display the string in the panel
int ExecWithRedirect(wxString command)
void ClearOutput()
clear the output
preview window
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
create the control
void setImage(const wxString &filename)
set the current image and mask list, this loads also the image from cache
void setScale(double factor)
set the scaling factor f.
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
#define DEBUG_ERROR(msg)
Definition utils.h:76
wxString GetIso(const HuginBase::SrcPanoImage *img)
returns formatted iso value
wxString GetExposureTime(const HuginBase::SrcPanoImage *img)
returns formatted exposure time
wxString GetAperture(const HuginBase::SrcPanoImage *img)
returns formatted aperture value
std::set< unsigned int > UIntSet
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition Executor.h:79
wxString GetExternalProgram(wxConfigBase *config, const wxString &bindir, const wxString &name)
return path and name of external program, which can be overwritten by the user
Definition Executor.cpp:148
std::vector< NormalCommand * > CommandQueue
Definition Executor.h:61
const wxString GetConfigTempDir(const wxConfigBase *config)
return the temp dir from the preferences, ensure that it ends with path separator
Definition Executor.cpp:302
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 GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition utils.cpp:497
wxString GetFileDialogImageFilters()
return filter for image files, needed by file open dialog it contains all image format vigra can read...
Definition platform.cpp:70
wxString GetMainImageFilters()
return a filter for the main image files (JPG/TIFF/PNG) only
Definition platform.cpp:81
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
platform/compiler specific stuff.