47 #define DEFAULT_LENSCAL_SCALE 2.0
48 #define DEFAULT_LENSCAL_THRESHOLD 4.0
49 #define DEFAULT_RESIZE_DIMENSION 1600
50 #define DEFAULT_MINLINELENGTH 0.3
62 wxArrayString invalidFiles;
63 for (
unsigned int i=0; i< filenames.GetCount(); i++)
65 wxFileName file(filenames[i]);
66 if (file.GetExt().CmpNoCase(wxT(
"jpg")) == 0 ||
67 file.GetExt().CmpNoCase(wxT(
"jpeg")) == 0 ||
68 file.GetExt().CmpNoCase(wxT(
"tif")) == 0 ||
69 file.GetExt().CmpNoCase(wxT(
"tiff")) == 0 ||
70 file.GetExt().CmpNoCase(wxT(
"png")) == 0 ||
71 file.GetExt().CmpNoCase(wxT(
"bmp")) == 0 ||
72 file.GetExt().CmpNoCase(wxT(
"gif")) == 0 ||
73 file.GetExt().CmpNoCase(wxT(
"pnm")) == 0 ||
74 file.GetExt().CmpNoCase(wxT(
"sun")) == 0 ||
75 file.GetExt().CmpNoCase(wxT(
"hdr")) == 0 ||
76 file.GetExt().CmpNoCase(wxT(
"viff")) == 0 )
80 invalidFiles.push_back(file.GetFullPath());
84 files.push_back(file.GetFullPath());
88 if(!invalidFiles.empty())
103 EVT_LISTBOX(XRCID("lenscal_images_list"),
LensCalFrame::OnImageSelected)
104 EVT_MENU(XRCID("menu_save"),
LensCalFrame::OnSaveProject)
106 EVT_BUTTON(XRCID("lenscal_add_image"),
LensCalFrame::OnAddImage)
107 EVT_BUTTON(XRCID("lenscal_remove_image"),
LensCalFrame::OnRemoveImage)
108 EVT_BUTTON(XRCID("lenscal_find_lines"),
LensCalFrame::OnFindLines)
109 EVT_BUTTON(XRCID("lenscal_reset"),
LensCalFrame::OnReset)
110 EVT_BUTTON(XRCID("lenscal_opt"),
LensCalFrame::OnOptimize)
111 EVT_BUTTON(XRCID("lenscal_show_distortion_graph"),
LensCalFrame::OnShowDistortionGraph)
112 EVT_BUTTON(XRCID("lenscal_save_lens"),
LensCalFrame::OnSaveLens)
113 EVT_BUTTON(XRCID("lenscal_refresh"),
LensCalFrame::OnRefresh)
114 EVT_CHOICE(XRCID("lenscal_preview_content"),
LensCalFrame::OnSelectPreviewContent)
115 EVT_CHECKBOX(XRCID("lenscal_show_lines"),
LensCalFrame::OnShowLines)
123 wxXmlResource::Get()->LoadFrame(
this, parent, wxT(
"lenscal_frame"));
128 wxApp::s_macExitMenuItemId = XRCID(
"menu_quit");
130 SetMenuBar(wxXmlResource::Get()->LoadMenuBar(
this, wxT(
"lenscal_menubar")));
132 m_choice_projection=XRCCTRL(*
this,
"lenscal_proj_choice",wxChoice);
134 m_images_list=XRCCTRL(*
this,
"lenscal_images_list",wxListBox);
137 wxConfigBase* config = wxConfigBase::Get();
142 ParametersToDisplay();
145 config->Read(wxT(
"/LensCalFrame/Optimize_a"),&selected,
false);
146 XRCCTRL(*
this,
"lenscal_opt_a",wxCheckBox)->SetValue(selected);
147 config->Read(wxT(
"/LensCalFrame/Optimize_b"),&selected,
true);
148 XRCCTRL(*
this,
"lenscal_opt_b",wxCheckBox)->SetValue(selected);
149 config->Read(wxT(
"/LensCalFrame/Optimize_c"),&selected,
false);
150 XRCCTRL(*
this,
"lenscal_opt_c",wxCheckBox)->SetValue(selected);
151 config->Read(wxT(
"/LensCalFrame/Optimize_de"),&selected,
false);
152 XRCCTRL(*
this,
"lenscal_opt_de",wxCheckBox)->SetValue(selected);
156 wxIconBundle myIcons(GetXRCPath() + wxT(
"data/hugin.ico"), wxBITMAP_TYPE_ICO);
159 wxIcon myIcon(GetXRCPath() + wxT(
"data/hugin.png"),wxBITMAP_TYPE_PNG);
162 SetTitle(_(
"Hugin Lens calibration GUI"));
168 const int fields (2);
169 CreateStatusBar(fields);
170 int widths[fields] = {-1, 85};
171 SetStatusWidths( fields, &widths[0]);
175 #if defined __WXMAC__ || defined __WXMSW__
177 SetSizeHints(900, 675);
180 SetSizeHints(780, 455);
184 ImageCache::getInstance().setProgressDisplay(
this);
185 #if defined __WXMSW__
188 unsigned long mem_high = config->Read(wxT(
"/ImageCache/UpperBoundHigh"), (
long) 0);
190 mem = ((
unsigned long long) mem_high << 32) + mem_low;
195 ImageCache::getInstance().SetUpperLimit(mem);
201 XRCCTRL(*
this,
"lenscal_remove_image",wxButton)->Enable(
false);
208 ImageCache::getInstance().setProgressDisplay(0);
209 delete & ImageCache::getInstance();
211 wxConfigBase* config = wxConfigBase::Get();
214 config->Write(wxT(
"/LensCalFrame/EdgeScale"),
m_edge_scale);
219 config->Write(wxT(
"/LensCalFrame/Optimize_a"),XRCCTRL(*
this,
"lenscal_opt_a",wxCheckBox)->GetValue());
220 config->Write(wxT(
"/LensCalFrame/Optimize_b"),XRCCTRL(*
this,
"lenscal_opt_b",wxCheckBox)->GetValue());
221 config->Write(wxT(
"/LensCalFrame/Optimize_c"),XRCCTRL(*
this,
"lenscal_opt_c",wxCheckBox)->GetValue());
222 config->Write(wxT(
"/LensCalFrame/Optimize_de"),XRCCTRL(*
this,
"lenscal_opt_de",wxCheckBox)->GetValue());
226 for(
unsigned int i=0;i<
m_images.size();i++)
239 XRCCTRL(*
this,
"lenscal_resizedim", wxTextCtrl)->SetValue(wxString::Format(wxT(
"%d"),
m_resize_dimension));
245 return wxGetApp().GetXRCPath();
254 msg = wxGetTranslation(wxString(
m_message.c_str(), wxConvLocal));
257 msg.Append(wxT(
" "));
261 GetStatusBar()->SetStatusText(msg, 0);
275 wxArrayString wrongSize;
276 wxArrayString wrongExif;
277 for (
unsigned int i=0; i<files.GetCount(); i++)
284 HuginBase::FileMetaData::const_iterator it = metadata.find(
"pixeltype");
285 if (it != metadata.end())
287 if (it->second ==
"BILEVEL")
289 wxMessageBox(wxString::Format(_(
"File \"%s\" is a black/white image.\nHugin does not support this image type. Skipping this image.\nConvert image to grayscale image and try loading again."), files[i].c_str()),
290 _(
"Warning"), wxOK | wxICON_EXCLAMATION,
this);
300 if(image0->getSize()!=image1->getSize())
302 wrongSize.push_back(files[i]);
306 if(!image0->getExifMake().empty() && !image1->getExifMake().empty() &&
307 !image0->getExifModel().empty() && !image1->getExifModel().empty() &&
308 image0->getExifFocalLength()>0 && image1->getExifFocalLength()>0 &&
309 image0->getCropFactor()>0 && image1->getCropFactor()>0
312 if(image0->getExifMake()!=image1->getExifMake() ||
313 image0->getExifModel()!=image1->getExifModel() ||
314 image0->getExifFocalLength()!=image1->getExifFocalLength() ||
315 image0->getCropFactor()!=image1->getCropFactor())
318 wrongExif.push_back(files[i]);
323 SetStatusText(wxString::Format(_(
"Added %s"),image->
GetFilename().c_str()));
326 XRCCTRL(*
this,
"lenscal_focallength", wxTextCtrl)->SetValue(
332 XRCCTRL(*
this,
"lenscal_cropfactor", wxTextCtrl)->SetValue(
343 if(!wrongSize.empty())
346 for(
unsigned int i=0;i<wrongSize.size();i++)
348 wxFileName filename(wrongSize[i]);
349 fileText.Append(filename.GetFullName());
350 if(i<wrongSize.size()-1)
351 fileText.Append(wxT(
", "));
353 wxMessageBox(wxString::Format(_(
"The size of the images (%s) does not match the already added image(s)."),fileText.c_str()),
354 _(
"Error"),wxOK|wxICON_EXCLAMATION,
this);
356 if(!wrongExif.empty())
359 for(
unsigned int i=0;i<wrongExif.size();i++)
361 wxFileName filename(wrongExif[i]);
362 fileText.Append(filename.GetFullName());
363 if(i<wrongExif.size()-1)
364 fileText.Append(wxT(
", "));
366 wxMessageBox(wxString::Format(_(
"The EXIF information of the added images (%s) is not consistent with the already added image(s).\nPlease check the image again, if you selected the correct images."),fileText.c_str()),
367 _(
"Warning"),wxOK|wxICON_EXCLAMATION,
this);
373 wxConfigBase* config = wxConfigBase::Get();
374 wxString path = config->Read(wxT(
"/actualPath"), wxT(
""));
375 wxFileDialog dlg(
this,_(
"Add images"),
378 wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST | wxFD_PREVIEW, wxDefaultPosition);
379 dlg.SetDirectory(path);
383 if (config->HasEntry(wxT(
"lastImageType"))){
384 img_ext = config->Read(wxT(
"lastImageType")).c_str();
386 if (img_ext == wxT(
"all images"))
387 dlg.SetFilterIndex(0);
388 else if (img_ext == wxT(
"jpg"))
389 dlg.SetFilterIndex(1);
390 else if (img_ext == wxT(
"tiff"))
391 dlg.SetFilterIndex(2);
392 else if (img_ext == wxT(
"png"))
393 dlg.SetFilterIndex(3);
394 else if (img_ext == wxT(
"hdr"))
395 dlg.SetFilterIndex(4);
396 else if (img_ext == wxT(
"exr"))
397 dlg.SetFilterIndex(5);
398 else if (img_ext == wxT(
"all files"))
399 dlg.SetFilterIndex(6);
400 DEBUG_INFO (
"Image extention: " << img_ext.mb_str(wxConvLocal) )
403 if (dlg.ShowModal() == wxID_OK)
406 wxArrayString Pathnames;
407 dlg.GetPaths(Pathnames);
412 config->Write(wxT(
"/actualPath"), wxPathOnly(Pathnames[0]));
414 config->Write(wxT(
"/actualPath"), dlg.GetDirectory());
417 wxArrayString invalidFiles;
418 for(
unsigned int i=0;i<Pathnames.GetCount(); i++)
422 invalidFiles.push_back(Pathnames[i]);
425 if(!invalidFiles.empty())
433 DEBUG_INFO ( wxString::Format(wxT(
"img_ext: %d"), dlg.GetFilterIndex()).mb_str(wxConvLocal) )
435 switch ( dlg.GetFilterIndex() )
437 case 0: config->Write(wxT(
"lastImageType"), wxT(
"all images"));
break;
438 case 1: config->Write(wxT(
"lastImageType"), wxT(
"jpg"));
break;
439 case 2: config->Write(wxT(
"lastImageType"), wxT(
"tiff"));
break;
440 case 3: config->Write(wxT(
"lastImageType"), wxT(
"png"));
break;
441 case 4: config->Write(wxT(
"lastImageType"), wxT(
"hdr"));
break;
442 case 5: config->Write(wxT(
"lastImageType"), wxT(
"exr"));
break;
443 case 6: config->Write(wxT(
"lastImageType"), wxT(
"all files"));
break;
449 SetStatusText( _(
"Add Image: cancel"));
456 wxFileName file(
m_images[index]->GetFilename());
457 m_images_list->SetString(index,wxString::Format(_(
"%s (%d lines)"),file.GetFullName().c_str(),
m_images[index]->GetNrOfValidLines()));
464 for(
unsigned int i=0;i<
m_images.size();i++)
466 wxFileName file(
m_images[i]->GetFilename());
467 wxString text=wxString::Format(_(
"%s (%d lines)"),file.GetFullName().c_str(),
m_images[i]->GetNrOfValidLines());
470 if(oldSelection!=wxNOT_FOUND && restoreSelection)
481 if(selection!=wxNOT_FOUND)
485 ImageCache::getInstance().removeImage(filename);
499 const bool enabling = !
m_images.empty();
500 XRCCTRL(*
this,
"lenscal_find_lines",wxButton)->Enable(enabling);
501 XRCCTRL(*
this,
"lenscal_opt",wxButton)->Enable(enabling);
502 XRCCTRL(*
this,
"lenscal_show_distortion_graph", wxButton)->Enable(enabling);
503 XRCCTRL(*
this,
"lenscal_save_lens",wxButton)->Enable(enabling);
504 GetMenuBar()->Enable(XRCID(
"menu_save"),enabling);
535 if(m_minlinelength<=0 || m_minlinelength>1)
538 if(readLensParameter)
558 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
562 for(
unsigned int i=0;i<
m_images.size();i++)
565 ImageCache::EntryPtr img=ImageCache::getInstance().getImage(filename);
567 SetStatusText(_(
"Detecting edges..."));
569 SetStatusText(_(
"Finding lines..."));
573 SetStatusText(_(
"Finished"));
581 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
584 unsigned int count=0;
585 for(
unsigned int i=0;i<
m_images.size();i++)
586 count+=
m_images[i]->GetNrOfValidLines();
589 wxMessageBox(_(
"There are no detected lines.\nPlease run \"Find lines\" first. If there are no lines found, change the parameters."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
603 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."), _(
"Warning"), wxOK | wxICON_INFORMATION,
this);
619 wxWindow *button = (wxWindow*)e.GetEventObject();
620 wxPoint pos = button->ClientToScreen(wxPoint(0, 0));
621 m_popup->Position(pos, button->GetSize());
629 unsigned int line_number=3;
630 for(
unsigned int i=0;i<
m_images.size();i++)
644 std::set<std::string> imgopt;
647 if(XRCCTRL(*
this,
"lenscal_opt_a",wxCheckBox)->GetValue())
649 if(XRCCTRL(*
this,
"lenscal_opt_b",wxCheckBox)->GetValue())
651 if(XRCCTRL(*
this,
"lenscal_opt_c",wxCheckBox)->GetValue())
653 if(XRCCTRL(*
this,
"lenscal_opt_de",wxCheckBox)->GetValue())
659 optvec.push_back(imgopt);
662 for(
unsigned j=0;j<lines.size();j++)
667 for(
unsigned int k=0;k<cpv.size();k++)
682 img.setExposureValue(0);
683 img.setWhiteBalanceRed(1);
684 img.setWhiteBalanceBlue(1);
700 SetStatusText(_(
"Optimizing lens distortion parameters..."));
716 SetStatusText(_(
"Finished"));
721 wxFileDialog dlg(
this,
722 _(
"Save lens parameters file"),
723 wxConfigBase::Get()->Read(wxT(
"/lensPath"),wxT(
"")), wxT(
""),
724 _(
"Lens Project Files (*.ini)|*.ini|All files (*)|*"),
725 wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
726 dlg.SetDirectory(wxConfigBase::Get()->Read(wxT(
"/lensPath"),wxT(
"")));
727 if (dlg.ShowModal() == wxID_OK)
729 wxFileName filename(dlg.GetPath());
730 if(!filename.HasExt())
731 filename.SetExt(wxT(
"ini"));
732 wxConfig::Get()->Write(wxT(
"/lensPath"), dlg.GetDirectory());
733 if (filename.FileExists())
735 int d = wxMessageBox(wxString::Format(_(
"File %s exists. Overwrite?"), filename.GetFullPath().c_str()),
736 _(
"Save project"), wxYES_NO | wxICON_QUESTION);
751 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
754 unsigned int count=0;
755 for(
unsigned int i=0;i<
m_images.size();i++)
756 count+=
m_images[i]->GetNrOfValidLines();
759 wxMessageBox(_(
"There are no detected lines.\nPlease run \"Find lines\" and \"Optimize\" before saving the lens data. If there are no lines found, change the parameters."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
763 wxArrayString choices;
764 choices.push_back(_(
"Save lens parameters to ini file"));
765 choices.push_back(_(
"Save lens parameters to lens database"));
766 wxSingleChoiceDialog save_dlg(
this,_(
"Saving lens data"),_(
"Save lens"),choices);
767 if(save_dlg.ShowModal()==wxID_OK)
769 if(save_dlg.GetSelection()==0)
785 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
789 wxFileDialog dlg(
this,_(
"Save project file"),wxEmptyString,wxEmptyString,
790 _(
"Project files (*.pto)|*.pto|All files (*)|*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
791 dlg.SetDirectory(wxConfigBase::Get()->Read(wxT(
"/actualPath"),wxT(
"")));
792 if (dlg.ShowModal() == wxID_OK)
794 wxConfig::Get()->Write(wxT(
"/actualPath"), dlg.GetDirectory());
795 wxFileName filename(dlg.GetPath());
796 if(!filename.HasExt())
797 filename.SetExt(wxT(
"pto"));
798 if (filename.FileExists())
800 int d = wxMessageBox(wxString::Format(_(
"File %s exists. Overwrite?"), filename.GetFullPath().c_str()),
801 _(
"Save project"), wxYES_NO | wxICON_QUESTION);
816 XRCCTRL(*
this,
"lenscal_remove_image",wxButton)->Enable(selected);
852 wxMessageBox(_(
"There are invalid values in the input boxes.\nPlease check your inputs."),_(
"Warning"),wxOK | wxICON_INFORMATION,
this);
void SetEmptyImage()
set preview to empty image
LensCalImageCtrl * m_preview
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
const unsigned int cps_per_line
bool str2double(const wxString &s, double &d)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
image previewer for lens calibration GUI
HuginBase::SrcPanoImage * GetPanoImage()
return the SrcPanoImage from the given filename
Somewhere to specify what variables belong to what.
wxChoice * m_choice_projection
void OnSelectPreviewContent(wxCommandEvent &e)
wxString doubleTowxString(double d, int digits)
include file for the hugin project
void OnSaveLens(wxCommandEvent &e)
declaration of LensCal main frame class
Lines findLines(vigra::BImage &edge, double length_threshold, double focal_length, double crop_factor)
find straightish non-crossing lines find straightish non-crossing lines in an edge map using 8-neighb...
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
simple class that forward the drop to the mainframe
virtual ~LensCalFrame()
destructor
class to access Hugins camera and lens database
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
file drag and drop handler method
void OnRefresh(wxCommandEvent &e)
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
#define HUGIN_IMGCACHE_UPPERBOUND
void Optimize()
do the optimization
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
void OnShowLines(wxCommandEvent &e)
void OnShowDistortionGraph(wxCommandEvent &e)
show distortion graph
unsigned int m_resize_dimension
void setVar(const std::string &name, double val)
HuginBase::CPVector GetControlPoints(const SingleLine &line, const unsigned int imgNr, const unsigned int lineNr, const unsigned int numberOfCtrlPoints)
returns a HuginBase::CPVector with cps_per_lines
std::size_t getNrOfImages() const
number of images.
void updateProgressDisplay()
called when a progress message should be displayed
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
void OnAddImage(wxCommandEvent &e)
void OnImageSelected(wxCommandEvent &e)
#define DEFAULT_RESIZE_DIMENSION
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
std::map< std::string, std::string > FileMetaData
typedef for general map for storing metadata in files
void EnableButtons()
enable all buttons and menu items depending on number of active images
void UpdateListString(unsigned int index)
double getVar(const std::string &name) const
HuginBase::SrcPanoImage::Projection m_projection
wxGraphTools::GraphPopupWindow * m_popup
void OnReset(wxCommandEvent &e)
vigra::BImage * detectEdges(const vigra::UInt8RGBImage &input, const double scale, const double threshold, const unsigned int resize_dimension, double &size_factor)
detect and mark edges in an edge image using Canny's algorithm
!! from PTOptimise.h 1951
dialogs for loading and saving information from/to lens database
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
void OnOptimize(wxCommandEvent &e)
Same as above, but use a non const panorama.
bool ReadInputs(bool readFocalLength, bool readOptions, bool readLensParameter)
reads all input values into internal values
void OnFindLines(wxCommandEvent &e)
include file for the hugin project
const PanoramaOptions & getOptions() const
returns the options for this panorama
const wxString & GetXRCPath()
get the path to the xrc directory
#define DEFAULT_LENSCAL_THRESHOLD
const LensCalPreviewMode GetMode()
return actual preview mode
std::vector< SingleLine > Lines
vector of extracted lines from image
void OnExit(wxCommandEvent &e)
wxListBox * m_images_list
void SetImage(ImageLineList *newList, unsigned int newIndex)
set preview setting to given ImageLineList
std::vector< ControlPoint > CPVector
static double calcHFOV(SrcPanoImage::Projection proj, double fl, double crop, vigra::Size2D imageSize)
calculate hfov of an image given focal length, image size and crop factor
declaration of application class for lens calibrate application
#define DEFAULT_LENSCAL_SCALE
std::vector< ImageLineList * > m_images
list of all detected lines
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
std::vector< std::set< std::string > > OptimizeVector
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
const wxString GetFilename()
returns the filename
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
#define DEFAULT_MINLINELENGTH
HuginBase::Panorama GetPanorama()
return panorama object with all images
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
void SetLens(const HuginBase::SrcPanoImage::Projection newProjection, const double newFocallength, const double newCropfactor)
updates the internal values of the lens (needed only for remapped image)
All variables of a source image.
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
void SetMode(const LensCalPreviewMode newMode)
set which image (original, edge, remapped/corrected) should be drawn
void ParametersToDisplay()
set all parameter input wxTextField to internal values
void SetLensDistortions(const double newA, const double newB, const double newC, const double newD, const double newE)
updates the internal values of the lens distortions parameters (needed only for remapped image) ...
void OnRemoveImage(wxCommandEvent &e)
void UpdateList(bool restoreSelection)
updates the list box with current values
void SetShowLines(bool showLines)
void OnSaveProject(wxCommandEvent &e)
void AddImages(wxArrayString files)
double outputExposureValue