Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FindPanoDialog.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "FindPanoDialog.h"
28 #include "base_wx/wxPlatform.h"
29 #include "panoinc.h"
31 #include "PTBatcherGUI.h"
32 #include "hugin_utils/alphanum.h"
33 #include "hugin/config_defaults.h"
34 #include "wx/mstream.h"
35 #ifdef _WIN32
36 // workaround for a conflict between exiv2 and wxWidgets/CMake built
37 #define HAVE_PID_T 1
38 #endif
39 #include <exiv2/exiv2.hpp>
40 #ifdef _WIN32
41 #include <commctrl.h>
42 #endif
43 #include "base_wx/LensTools.h"
45 #include "base_wx/wxutils.h"
46 
47 enum
48 {
49  ID_REMOVE_IMAGE = wxID_HIGHEST + 300,
50  ID_SPLIT_PANOS = wxID_HIGHEST + 301
51 };
52 
54 {
55  return doj::alphanum_comp(img1->getFilename(),img2->getFilename())<0;
56 };
57 
58 // thumbnail size currently set to 80x80
59 #define THUMBSIZE 80
60 
61 FindPanoDialog::FindPanoDialog(BatchFrame* batchframe, wxString xrcPrefix)
62 {
63  // load our children. some children might need special
64  // initialization. this will be done later.
65  wxXmlResource::Get()->LoadDialog(this,batchframe,wxT("find_pano_dialog"));
66 
67  m_batchframe=batchframe;
68  m_isRunning=false;
69  m_stopped=false;
70 
71  m_button_start=XRCCTRL(*this,"find_pano_start_stop",wxButton);
72  m_button_start->Bind(wxEVT_BUTTON, &FindPanoDialog::OnButtonStart, this);
73  m_button_choose=XRCCTRL(*this,"find_pano_select_dir",wxButton);
74  m_button_choose->Bind(wxEVT_BUTTON, &FindPanoDialog::OnButtonChoose, this);
75  m_button_send=XRCCTRL(*this,"find_pano_add_queue",wxButton);
76  m_button_send->Bind(wxEVT_BUTTON, &FindPanoDialog::OnButtonSend, this);
77  m_button_close=XRCCTRL(*this,"find_pano_close",wxButton);
78  m_button_close->Bind(wxEVT_BUTTON, &FindPanoDialog::OnButtonClose, this);
79  m_textctrl_dir=XRCCTRL(*this,"find_pano_dir",wxTextCtrl);
80  m_textctrl_dir->AutoCompleteDirectories();
81  m_cb_subdir=XRCCTRL(*this,"find_pano_subdir",wxCheckBox);
82  m_statustext=XRCCTRL(*this,"find_pano_label",wxStaticText);
83  m_list_pano=XRCCTRL(*this,"find_pano_list",wxCheckListBox);
84  m_list_pano->Bind(wxEVT_LISTBOX, &FindPanoDialog::OnSelectPossiblePano, this);
85  m_ch_naming=XRCCTRL(*this,"find_pano_naming",wxChoice);
86  m_cb_createLinks=XRCCTRL(*this,"find_pano_create_links",wxCheckBox);
87  m_cb_loadDistortion=XRCCTRL(*this,"find_pano_load_distortion",wxCheckBox);
88  m_cb_loadVignetting=XRCCTRL(*this,"find_pano_load_vignetting",wxCheckBox);
89  m_sc_minNumberImages=XRCCTRL(*this, "find_pano_min_number_images", wxSpinCtrl);
90  m_sc_maxTimeDiff=XRCCTRL(*this, "find_pano_max_time_diff", wxSpinCtrl);
91  m_ch_blender = XRCCTRL(*this, "find_pano_default_blender", wxChoice);
93 
94  //set parameters
95  wxConfigBase* config = wxConfigBase::Get();
96  // restore position and size
97  int dx,dy;
98  wxDisplaySize(&dx,&dy);
99  bool maximized = config->Read(wxT("/FindPanoDialog/maximized"), 0l) != 0;
100  if (maximized)
101  {
102  this->Maximize();
103  }
104  else
105  {
106  //size
107  int w = config->Read(wxT("/FindPanoDialog/width"),-1l);
108  int h = config->Read(wxT("/FindPanoDialog/height"),-1l);
109  if (w > 0 && w <= dx)
110  {
111  this->SetClientSize(w,h);
112  }
113  else
114  {
115  this->Fit();
116  }
117  //position
118  int x = config->Read(wxT("/FindPanoDialog/positionX"),-1l);
119  int y = config->Read(wxT("/FindPanoDialog/positionY"),-1l);
120  if ( y >= 0 && x >= 0 && x < dx && y < dy)
121  {
122  this->Move(x, y);
123  }
124  else
125  {
126  this->Move(0, 44);
127  }
128  }
129  long splitterPos = config->Read(wxT("/FindPanoDialog/splitterPos"), -1l);
130  if (splitterPos != -1)
131  {
132  XRCCTRL(*this, "find_pano_splitter", wxSplitterWindow)->SetSashPosition(splitterPos);
133  };
134  wxString path=config->Read(wxT("/FindPanoDialog/actualPath"),wxEmptyString);
135  if(!path.IsEmpty())
136  {
137  m_textctrl_dir->SetValue(path);
138  }
139  bool val;
140  config->Read(wxT("/FindPanoDialog/includeSubDirs"),&val,false);
141  m_cb_subdir->SetValue(val);
142  long i=config->Read(wxT("/FindPanoDialog/Naming"),0l);
143  m_ch_naming->SetSelection(i);
144  config->Read(wxT("/FindPanoDialog/linkStacks"),&val,true);
145  m_cb_createLinks->SetValue(val);
146  config->Read(wxT("/FindPanoDialog/loadDistortion"),&val,false);
147  m_cb_loadDistortion->SetValue(val);
148  config->Read(wxT("/FindPanoDialog/loadVignetting"),&val,false);
149  m_cb_loadVignetting->SetValue(val);
150  i=config->Read(wxT("/FindPanoDialog/MinNumberImages"), 2l);
151  m_sc_minNumberImages->SetValue(i);
152  i=config->Read(wxT("/FindPanoDialog/MaxTimeDiff"), 30l);
153  m_sc_maxTimeDiff->SetValue(i);
154  i = config->Read(wxT("/FindPanoDialog/DefaultBlender"), static_cast<long>(HuginBase::PanoramaOptions::ENBLEND_BLEND));
156  m_button_send->Disable();
157  m_thumbs = new wxImageList(THUMBSIZE, THUMBSIZE, true, 0);
158  m_thumbsList = XRCCTRL(*this, "find_pano_selected_thumbslist", wxListCtrl);
159  m_thumbsList->SetImageList(m_thumbs, wxIMAGE_LIST_NORMAL);
160  m_thumbsList->Bind(wxEVT_MOTION, &FindPanoDialog::OnListMouseMove, this);
161  m_thumbsList->Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &FindPanoDialog::OnListItemRightClick, this);
162 #ifdef _WIN32
163  // default image spacing is too big, wxWidgets does not provide direct
164  // access to the spacing, so using the direct API function
165  ListView_SetIconSpacing(m_thumbsList->GetHandle(), THUMBSIZE + 20, THUMBSIZE + 20);
166 #endif
167  Bind(wxEVT_MENU, &FindPanoDialog::OnRemoveImage, this, ID_REMOVE_IMAGE);
168  Bind(wxEVT_MENU, &FindPanoDialog::OnSplitPanos, this, ID_SPLIT_PANOS);
169  Bind(wxEVT_CLOSE_WINDOW, &FindPanoDialog::OnClose, this);
170 };
171 
173 {
174  wxConfigBase* config=wxConfigBase::Get();
175  if(!this->IsMaximized())
176  {
177  wxSize sz = this->GetClientSize();
178  config->Write(wxT("/FindPanoDialog/width"), sz.GetWidth());
179  config->Write(wxT("/FindPanoDialog/height"), sz.GetHeight());
180  wxPoint ps = this->GetPosition();
181  config->Write(wxT("/FindPanoDialog/positionX"), ps.x);
182  config->Write(wxT("/FindPanoDialog/positionY"), ps.y);
183  config->Write(wxT("/FindPanoDialog/maximized"), 0);
184  }
185  else
186  {
187  config->Write(wxT("/FindPanoDialog/maximized"), 1l);
188  };
189  config->Write(wxT("/FindPanoDialog/splitterPos"), XRCCTRL(*this, "find_pano_splitter", wxSplitterWindow)->GetSashPosition());
190  config->Write(wxT("/FindPanoDialog/actualPath"),m_textctrl_dir->GetValue());
191  config->Write(wxT("/FindPanoDialog/includeSubDirs"),m_cb_subdir->GetValue());
192  config->Write(wxT("/FindPanoDialog/Naming"),m_ch_naming->GetSelection());
193  config->Write(wxT("/FindPanoDialog/linkStacks"),m_cb_createLinks->GetValue());
194  config->Write(wxT("/FindPanoDialog/loadDistortion"),m_cb_loadDistortion->GetValue());
195  config->Write(wxT("/FindPanoDialog/loadVignetting"),m_cb_loadDistortion->GetValue());
196  config->Write(wxT("/FindPanoDialog/MinNumberImages"), m_sc_minNumberImages->GetValue());
197  config->Write(wxT("/FindPanoDialog/MaxTimeDiff"), m_sc_maxTimeDiff->GetValue());
198  config->Write(wxT("/FindPanoDialog/DefaultBlender"), static_cast<long>(GetSelectedValue(m_ch_blender)));
199  CleanUpPanolist();
200  delete m_thumbs;
201 };
202 
204 {
205  while(!m_panos.empty())
206  {
207  delete m_panos.back();
208  m_panos.pop_back();
209  };
210 };
211 
212 //prevent closing window when running detection
213 void FindPanoDialog::OnClose(wxCloseEvent& e)
214 {
215  if(e.CanVeto() && m_isRunning)
216  {
217  wxBell();
218  e.Veto();
219  }
220  else
221  {
222  e.Skip();
223  };
224 };
225 
226 void FindPanoDialog::OnButtonClose(wxCommandEvent& e)
227 {
228  if(!m_panos.empty())
229  {
230  if(wxMessageBox(_("The list contains possibly unprocessed panoramas.\nIf you close the dialog, you will lose them.\nContinue anyway?"),
231  _("Question"),wxYES_NO|wxICON_WARNING,this)==wxNO)
232  {
233  return;
234  };
235  };
236  this->Close();
237 };
238 
239 void FindPanoDialog::OnButtonChoose(wxCommandEvent& e)
240 {
241  wxDirDialog dlg(this, _("Specify a directory to search for projects in"),
242  m_textctrl_dir->GetValue(), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
243  if (dlg.ShowModal()==wxID_OK)
244  {
245  m_textctrl_dir->SetValue(dlg.GetPath());
246  };
247 };
248 
249 void FindPanoDialog::OnButtonStart(wxCommandEvent& e)
250 {
251  if(m_isRunning)
252  {
253  //stop detection
254  m_stopped=true;
255  m_button_start->SetLabel(_("Accepted"));
256  }
257  else
258  {
259  //start detection
260  m_start_dir=m_textctrl_dir->GetValue();
261  if(wxDir::Exists(m_start_dir))
262  {
263  if(!m_panos.empty())
264  {
265  if (wxMessageBox(_("The list contains still not yet processed panoramas.\nIf you continue, they will be disregarded.\nDo you still want to continue?"),
266  _("Question"),wxYES_NO|wxICON_WARNING,this)==wxNO)
267  {
268  return;
269  };
270  };
271  m_isRunning=true;
272  m_stopped=false;
273  //deactivate TIFF warning message boxes
274  m_oldtiffwarning=TIFFSetWarningHandler(NULL);
275  m_button_start->SetLabel(_("Stop"));
276  CleanUpPanolist();
277  m_list_pano->Clear();
278  wxCommandEvent dummy;
279  OnSelectPossiblePano(dummy);
280  EnableButtons(false);
281  SearchInDir(m_start_dir,m_cb_subdir->GetValue(), m_cb_loadDistortion->GetValue(), m_cb_loadVignetting->GetValue(),
282  m_sc_minNumberImages->GetValue(), m_sc_maxTimeDiff->GetValue());
283  }
284  else
285  {
286  wxMessageBox(wxString::Format(_("Directory %s does not exist.\nPlease give an existing directory."),m_start_dir.c_str()),
287  _("Warning"),wxOK | wxICON_EXCLAMATION,this);
288  };
289  };
290 }
291 
292 void FindPanoDialog::OnButtonSend(wxCommandEvent& e)
293 {
294  if(m_panos.empty())
295  {
296  return;
297  }
298  unsigned int nr=0;
299  for(unsigned int i=0; i<m_list_pano->GetCount(); i++)
300  {
301  if(m_list_pano->IsChecked(i))
302  {
303  nr++;
304  };
305  };
306  if(nr==0)
307  {
308  wxMessageBox(_("You have not selected a panorama.\nPlease select at least one panorama and try again."),_("Warning"),wxOK|wxICON_EXCLAMATION,this);
309  return;
310  }
311  bool failed=false;
312  bool createLinks=m_cb_createLinks->GetValue();
313  for(unsigned int i=0; i<m_list_pano->GetCount(); i++)
314  {
315  if(m_list_pano->IsChecked(i))
316  {
317  wxString filename=m_panos[i]->GeneratePanorama((PossiblePano::NamingConvention)(m_ch_naming->GetSelection()),createLinks,
318  static_cast<HuginBase::PanoramaOptions::BlendingMechanism>(GetSelectedValue(m_ch_blender)));
319  if(!filename.IsEmpty())
320  {
322  }
323  else
324  {
325  failed=true;
326  };
327  };
328  };
329  if(failed)
330  {
331  wxMessageBox(_("Not all project files could be written successfully.\nMaybe you have no write permission for these directories or your disc is full."),_("Error"),wxOK,this);
332  };
333  this->Close();
334 };
335 
336 void FindPanoDialog::EnableButtons(const bool state)
337 {
338  m_textctrl_dir->Enable(state);
339  m_button_choose->Enable(state);
340  m_cb_subdir->Enable(state);
341  m_ch_naming->Enable(state);
342  m_cb_createLinks->Enable(state);
343  m_button_close->Enable(state);
344  m_button_send->Enable(state);
345 };
346 
348 {
349  int selected = m_list_pano->GetSelection();
350  if (selected != wxNOT_FOUND)
351  {
352  XRCCTRL(*this, "find_pano_selected_cam", wxStaticText)->SetLabel(m_panos[selected]->GetCameraName());
353  XRCCTRL(*this, "find_pano_selected_lens", wxStaticText)->SetLabel(m_panos[selected]->GetLensName());
354  XRCCTRL(*this, "find_pano_selected_focallength", wxStaticText)->SetLabel(m_panos[selected]->GetFocalLength());
355  XRCCTRL(*this, "find_pano_selected_date_time", wxStaticText)->SetLabel(m_panos[selected]->GetStartString() + wxT(" (")+ m_panos[selected]->GetDuration() + wxT(")"));
356  m_panos[selected]->PopulateListCtrl(m_thumbsList, m_thumbs, m_tooltips);
357  }
358  else
359  {
360  XRCCTRL(*this, "find_pano_selected_cam", wxStaticText)->SetLabel(wxEmptyString);
361  XRCCTRL(*this, "find_pano_selected_lens", wxStaticText)->SetLabel(wxEmptyString);
362  XRCCTRL(*this, "find_pano_selected_focallength", wxStaticText)->SetLabel(wxEmptyString);
363  XRCCTRL(*this, "find_pano_selected_date_time", wxStaticText)->SetLabel(wxEmptyString);
364  m_thumbsList->DeleteAllItems();
365  m_thumbs->RemoveAll();
366  m_tooltips.Clear();
367  };
368 };
369 
371 {
372  // build menu
373  wxMenu contextMenu;
374  const int selectedPano = m_list_pano->GetSelection();
375  if (m_panos[selectedPano]->GetImageCount() > 2)
376  {
377  contextMenu.Append(ID_REMOVE_IMAGE, _("Remove image from project"));
378  };
379  long imageIndex = -1;
380  imageIndex = m_thumbsList->GetNextItem(imageIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
381  if(imageIndex > 1 && imageIndex <= static_cast<long>(m_panos[selectedPano]->GetImageCount()) - 2)
382  {
383  contextMenu.Append(ID_SPLIT_PANOS, _("Split here into two panoramas"));
384  }
385  // show popup menu
386  if (contextMenu.GetMenuItemCount() > 0)
387  {
388  PopupMenu(&contextMenu);
389  };
390 };
391 
392 void FindPanoDialog::OnRemoveImage(wxCommandEvent &e)
393 {
394  const int selectedPano = m_list_pano->GetSelection();
395  if (selectedPano != wxNOT_FOUND)
396  {
397  if (m_panos[selectedPano]->GetImageCount() > 2)
398  {
399  long imageIndex = -1;
400  imageIndex = m_thumbsList->GetNextItem(imageIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
401  if (imageIndex != wxNOT_FOUND)
402  {
403  // remove image from possible pano
404  m_panos[selectedPano]->RemoveImage(imageIndex);
405  // now remove from the wxListCtrl
406  m_thumbsList->DeleteItem(imageIndex);
407  // update the pano list
408  m_list_pano->SetString(selectedPano, m_panos[selectedPano]->GetItemString(m_start_dir));
409  // update the labels above
410  wxCommandEvent dummy;
411  OnSelectPossiblePano(dummy);
412  };
413  };
414  };
415 };
416 
417 void FindPanoDialog::OnSplitPanos(wxCommandEvent &e)
418 {
419  const int selectedPano = m_list_pano->GetSelection();
420  if (selectedPano != wxNOT_FOUND)
421  {
422  long imageIndex = -1;
423  imageIndex = m_thumbsList->GetNextItem(imageIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
424  if (imageIndex != wxNOT_FOUND)
425  {
426  if (imageIndex > 1 && imageIndex <= static_cast<long>(m_panos[selectedPano]->GetImageCount()) - 2)
427  {
428  // do split
429  PossiblePano* newSubPano = m_panos[selectedPano]->SplitPano(imageIndex);
430  if (newSubPano->GetImageCount() > 0)
431  {
432  // insert new pano into internal list
433  m_panos.insert(m_panos.begin() + selectedPano + 1, newSubPano);
434  // update pano list
435  m_list_pano->SetString(selectedPano, m_panos[selectedPano]->GetItemString(m_start_dir));
436  int newItem = m_list_pano->Insert(m_panos[selectedPano + 1]->GetItemString(m_start_dir), selectedPano + 1);
437  m_list_pano->Check(newItem, true);
438  // update display
439  wxCommandEvent dummy;
440  OnSelectPossiblePano(dummy);
441  }
442  else
443  {
444  wxBell();
445  delete newSubPano;
446  };
447  };
448  };
449  };
450 }
451 
452 void FindPanoDialog::OnListMouseMove(wxMouseEvent & e)
453 {
454  if (m_tooltips.IsEmpty())
455  {
456  return;
457  }
458  int flags;
459  long item = m_thumbsList->HitTest(e.GetPosition(), flags);
460  if (item != wxNOT_FOUND && (flags&wxLIST_HITTEST_ONITEM) && item < m_tooltips.GetCount())
461  {
462  m_thumbsList->SetToolTip(m_tooltips[item]);
463  }
464  else
465  {
466  m_thumbsList->UnsetToolTip();
467  };
468 };
469 
470 int SortWxFilenames(const wxString& s1,const wxString& s2)
471 {
472  return doj::alphanum_comp(std::string(s1.mb_str(wxConvLocal)),std::string(s2.mb_str(wxConvLocal)));
473 };
474 
475 void FindPanoDialog::SearchInDir(wxString dirstring, const bool includeSubdir, const bool loadDistortion, const bool loadVignetting, const size_t minNumberImages, const size_t maxTimeDiff)
476 {
477  std::vector<PossiblePano*> newPanos;
478  wxTimeSpan max_diff(0, 0, maxTimeDiff, 0);
479  wxString filename;
480  wxArrayString fileList;
481  wxDir::GetAllFiles(dirstring,&fileList,wxEmptyString,wxDIR_FILES|wxDIR_HIDDEN);
482  fileList.Sort(SortWxFilenames);
483  //map for caching projection information to prevent reading from database for each image
484  for(size_t j=0; j<fileList.size() && !m_stopped; j++)
485  {
486  m_statustext->SetLabel(wxString::Format(_("Reading file %s"),fileList[j].c_str()));
487  wxFileName file(fileList[j]);
488  file.MakeAbsolute();
489  wxString ext=file.GetExt();
490  if(ext.CmpNoCase(wxT("jpg"))==0 || ext.CmpNoCase(wxT("jpeg"))==0 ||
491  ext.CmpNoCase(wxT("tif"))==0 || ext.CmpNoCase(wxT("tiff"))==0)
492  {
493  std::string filenamestr(file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
495  img->setFilename(filenamestr);
496  img->readEXIF();
497  // check for black/white images, if so skip
498  const HuginBase::FileMetaData& metadata = img->getFileMetadata();
499  HuginBase::FileMetaData::const_iterator it = metadata.find("pixeltype");
500  if (it != metadata.end())
501  {
502  if (it->second == "BILEVEL")
503  {
504  wxGetApp().Yield(true);
505  continue;
506  };
507  };
508  img->applyEXIFValues();
509  if(!img->getExifMake().empty() && !img->getExifModel().empty() &&
510  img->getExifFocalLength()!=0 && img->getCropFactor()!=0)
511  {
512  img->readProjectionFromDB(false);
513  if(loadDistortion)
514  {
515  img->readDistortionFromDB();
516  };
517  if(loadVignetting)
518  {
519  img->readVignettingFromDB();
520  };
521  bool found=false;
522  for(unsigned int i=0; i<newPanos.size() && !m_stopped && !found; i++)
523  {
524  //compare with all other image groups
525  if(newPanos[i]->BelongsTo(img,max_diff))
526  {
527  newPanos[i]->AddSrcPanoImage(img);
528  found=true;
529  };
530  if(i%10==0)
531  {
532  wxGetApp().Yield(true);
533  };
534  };
535  if(!found)
536  {
537  PossiblePano* newPano=new PossiblePano();
538  newPano->AddSrcPanoImage(img);
539  newPanos.push_back(newPano);
540  };
541  }
542  else
543  {
544  //could not read exif infos, disregard this image
545  delete img;
546  };
547  };
548  //allow processing events
549  wxGetApp().Yield(true);
550  };
551  if(!m_stopped && !newPanos.empty())
552  {
553  for(size_t i=0; i<newPanos.size(); i++)
554  {
555  if(newPanos[i]->GetImageCount()>=minNumberImages)
556  {
557  m_panos.push_back(newPanos[i]);
558  int newItem=m_list_pano->Append(m_panos[m_panos.size()-1]->GetItemString(m_start_dir));
559  m_list_pano->Check(newItem,true);
560  }
561  else
562  {
563  delete newPanos[i];
564  };
565  };
566  };
567 
568  if(includeSubdir && !m_stopped)
569  {
570  //now we go into all directories
571  wxDir dir(dirstring);
572  bool cont=dir.GetFirst(&filename,wxEmptyString,wxDIR_DIRS);
573  while(cont && !m_stopped)
574  {
575  SearchInDir(dir.GetName()+wxFileName::GetPathSeparator()+filename,includeSubdir, loadDistortion, loadVignetting, minNumberImages, maxTimeDiff);
576  cont=dir.GetNext(&filename);
577  }
578  };
579  if(m_start_dir.Cmp(dirstring)==0)
580  {
581  m_stopped=false;
582  m_isRunning=false;
583  m_button_start->SetLabel(_("Start"));
584  EnableButtons(true);
585  //enable send button if at least one panorama found
586  m_button_send->Enable(!m_panos.empty());
587  if(!m_panos.empty())
588  {
589  m_statustext->SetLabel(wxString::Format(_("Found %d possible panoramas"), static_cast<int>(m_panos.size())));
590  }
591  else
592  {
593  m_statustext->SetLabel(_("No possible panoramas found"));
594  };
595  TIFFSetWarningHandler(m_oldtiffwarning);
596  };
597 };
598 
600 {
601  if(!m_images.empty())
602  {
603  for(ImageSet::reverse_iterator it=m_images.rbegin(); it!=m_images.rend(); ++it)
604  {
605  delete (*it);
606  }
607  };
608 };
609 
610 bool PossiblePano::BelongsTo(HuginBase::SrcPanoImage* img, const wxTimeSpan max_time_diff)
611 {
612  if(m_make.compare(img->getExifMake())!=0)
613  {
614  return false;
615  }
616  if(m_camera.compare(img->getExifModel())!=0)
617  {
618  return false;
619  }
620  if(m_lens.compare(img->getExifLens())!=0)
621  {
622  return false;
623  }
624  if(fabs(m_focallength-img->getExifFocalLength())>0.01)
625  {
626  return false;
627  }
628  if (fabs(m_cropfactor - img->getCropFactor()) > 0.01)
629  {
630  return false;
631  }
632  if(m_size!=img->getSize())
633  {
634  return false;
635  }
636  if(!GetDateTime(img).IsBetween(m_dt_start-max_time_diff,m_dt_end+max_time_diff))
637  {
638  return false;
639  };
640  return true;
641 };
642 
644 {
645  struct tm exifdatetime;
646  if(img->getExifDateTime(&exifdatetime)==0)
647  {
648  return wxDateTime(exifdatetime);
649  }
650  else
651  {
652  wxFileName file(wxString(img->getFilename().c_str(),HUGIN_CONV_FILENAME));
653  return file.GetModificationTime();
654  };
655 };
656 
658 {
659  if(m_images.empty())
660  {
661  //fill all values from first image
662  m_make=img->getExifMake();
663  m_camera=img->getExifModel();
664  m_lens=img->getExifLens();
665  m_focallength=img->getExifFocalLength();
666  m_cropfactor = img->getCropFactor();
667  m_size=img->getSize();
668  m_dt_start=GetDateTime(img);
670  }
671  else
672  {
673  wxDateTime dt=GetDateTime(img);
674  if(dt.IsEarlierThan(m_dt_start))
675  {
676  m_dt_start=dt;
677  }
678  if(dt.IsLaterThan(m_dt_end))
679  {
680  m_dt_end=dt;
681  };
682  };
683  m_images.insert(img);
684 };
685 
686 const wxString PossiblePano::GetFilestring(const wxString BasePath, const bool stripExtension) const
687 {
688  ImageSet::const_iterator it=m_images.begin();
689  wxFileName f1(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
690  f1.MakeRelativeTo(BasePath);
691  ImageSet::const_reverse_iterator rit=m_images.rbegin();
692  wxFileName f2(wxString((*rit)->getFilename().c_str(),HUGIN_CONV_FILENAME));
693  if(stripExtension)
694  {
695  return f1.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)+f1.GetName()+wxT("-")+f2.GetName();
696  }
697  else
698  {
699  return f1.GetFullPath()+wxT(" - ")+f2.GetFullName();
700  };
701 };
702 
703 const wxString PossiblePano::GetItemString(const wxString BasePath) const
704 {
705  return wxString::Format(_("%d images: %s"), static_cast<int>(m_images.size()), GetFilestring(BasePath).c_str());
706 };
707 
708 bool PossiblePano::GetNewProjectFilename(NamingConvention nc,const wxString basePath, wxFileName& projectFile)
709 {
710  wxString mask;
711  unsigned int i=1;
712  projectFile.SetPath(basePath);
713  projectFile.SetName(wxT("pano"));
714  projectFile.SetExt(wxT("pto"));
715  if(!projectFile.IsDirWritable())
716  {
717  return false;
718  };
719  switch(nc)
720  {
721  case NAMING_PANO:
722  mask=wxT("panorama%d");
723  break;
724  case NAMING_FIRST_LAST:
725  mask=GetFilestring(basePath,true);
726  projectFile.SetName(mask);
727  if(!projectFile.FileExists())
728  {
729  return true;
730  };
731  mask=mask+wxT("_%d");
732  break;
733  case NAMING_FOLDER:
734  {
735  wxArrayString folders=projectFile.GetDirs();
736  if(folders.GetCount()==0)
737  {
738  return false;
739  }
740  mask=folders.Last();
741  projectFile.SetName(mask);
742  if(!projectFile.FileExists())
743  {
744  return true;
745  }
746  mask=mask+wxT("_%d");
747  }
748  break;
749  case NAMING_TEMPLATE:
750  {
751  HuginBase::Panorama tempPano;
752  tempPano.addImage(**m_images.begin());
753  tempPano.addImage(**m_images.rbegin());
754  wxFileName newProject(getDefaultProjectName(tempPano));
755  mask=newProject.GetName();
756  projectFile.SetName(mask);
757  if(!projectFile.FileExists())
758  {
759  return true;
760  }
761  mask=mask+wxT("_%d");
762  };
763  break;
764  default:
765  mask=wxT("panorama%d");
766  };
767 
768  projectFile.SetName(wxString::Format(mask,i));
769  while(projectFile.FileExists())
770  {
771  i++;
772  projectFile.SetName(wxString::Format(mask,i));
773  //security fall through
774  if(i>1000)
775  {
776  return false;
777  };
778  }
779  return true;
780 };
781 
783 {
784  if(m_images.empty())
785  {
786  return wxEmptyString;
787  };
788  ImageSet::const_iterator it=m_images.begin();
789  wxFileName firstFile(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
790  firstFile.MakeAbsolute();
791  wxFileName projectFile;
792  if(!GetNewProjectFilename(nc,firstFile.GetPath(),projectFile))
793  {
794  return wxEmptyString;
795  };
796  //generate panorama
797  double redBalanceAnchor = (*m_images.begin())->getExifRedBalance();
798  double blueBalanceAnchor = (*m_images.begin())->getExifBlueBalance();
799  if (fabs(redBalanceAnchor)<1e-2)
800  {
801  redBalanceAnchor = 1;
802  };
803  if (fabs(blueBalanceAnchor)<1e-2)
804  {
805  blueBalanceAnchor = 1;
806  };
807  HuginBase::Panorama pano;
808  for(ImageSet::iterator it=m_images.begin(); it!=m_images.end(); ++it)
809  {
810  (*it)->setWhiteBalanceRed((*it)->getExifRedBalance() / redBalanceAnchor);
811  (*it)->setWhiteBalanceBlue((*it)->getExifBlueBalance() / blueBalanceAnchor);
812  pano.addImage(*(*it));
813  };
814  //assign all images the same lens number
815  HuginBase::StandardImageVariableGroups variable_groups(pano);
816  HuginBase::ImageVariableGroup& lenses = variable_groups.getLenses();
817  if(pano.getNrOfImages()>1)
818  {
819  for(unsigned int i=1; i<pano.getNrOfImages(); i++)
820  {
821  lenses.switchParts(i, lenses.getPartNumber(0));
822  };
823  };
824  if (pano.hasPossibleStacks())
825  {
826  pano.linkPossibleStacks(createLinks);
827  };
828  // Setup pano with options from preferences
830  //set default exposure value
831  opts.outputExposureValue = pano.getImage(0).getExposureValue();
832  wxConfigBase* config = wxConfigBase::Get();
833  opts.quality = config->Read(wxT("/output/jpeg_quality"),HUGIN_JPEG_QUALITY);
834  switch(config->Read(wxT("/output/tiff_compression"), HUGIN_TIFF_COMPRESSION))
835  {
836  case 0:
837  default:
838  opts.outputImageTypeCompression = "NONE";
839  opts.tiffCompression = "NONE";
840  break;
841  case 1:
842  opts.outputImageTypeCompression = "PACKBITS";
843  opts.tiffCompression = "PACKBITS";
844  break;
845  case 2:
846  opts.outputImageTypeCompression = "LZW";
847  opts.tiffCompression = "LZW";
848  break;
849  case 3:
850  opts.outputImageTypeCompression = "DEFLATE";
851  opts.tiffCompression = "DEFLATE";
852  break;
853  }
854  switch (config->Read(wxT("/output/ldr_format"), HUGIN_LDR_OUTPUT_FORMAT))
855  {
856  case 1:
857  opts.outputImageType ="jpg";
858  break;
859  case 2:
860  opts.outputImageType ="png";
861  break;
862  case 3:
863  opts.outputImageType ="exr";
864  break;
865  default:
866  case 0:
867  opts.outputImageType ="tif";
868  break;
869  }
871  opts.blendMode = defaultBlender;
872  opts.enblendOptions = config->Read(wxT("Enblend/Args"),wxT(HUGIN_ENBLEND_ARGS)).mb_str(wxConvLocal);
873  opts.enfuseOptions = config->Read(wxT("Enfuse/Args"),wxT(HUGIN_ENFUSE_ARGS)).mb_str(wxConvLocal);
874  opts.interpolator = (vigra_ext::Interpolator)config->Read(wxT("Nona/Interpolator"),HUGIN_NONA_INTERPOLATOR);
875  opts.tiff_saveROI = config->Read(wxT("Nona/CroppedImages"),HUGIN_NONA_CROPPEDIMAGES)!=0;
878  opts.verdandiOptions = config->Read(wxT("/VerdandiDefaultArgs"), wxEmptyString).mb_str(wxConvLocal);
879  pano.setOptions(opts);
880  // set optimizer switches
883 
884  if (pano.WritePTOFile(std::string(projectFile.GetFullPath().mb_str(HUGIN_CONV_FILENAME)),
885  std::string(projectFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME))))
886  {
887  return projectFile.GetFullPath();
888  }
889  else
890  {
891  return wxEmptyString;
892  };
893 };
894 
896 {
897  return wxString(m_camera.c_str(), wxConvLocal);
898 }
899 
901 {
902  return wxString(m_lens.c_str(), wxConvLocal);
903 };
904 
906 {
907  if (!m_images.empty())
908  {
909  return FormatString::GetFocalLength(*m_images.begin());
910  };
911  return wxString::Format(wxT("%0.1f mm"), m_focallength);
912 };
913 
915 {
916  return m_dt_start.Format();
917 };
918 
920 {
921  return GetFormattedTimeSpan(m_dt_end.Subtract(m_dt_start));
922 };
923 
924 void PossiblePano::PopulateListCtrl(wxListCtrl* list, wxImageList* thumbs, wxArrayString& tooltips)
925 {
926  list->DeleteAllItems();
927  thumbs->RemoveAll();
928  tooltips.Clear();
929  wxBusyCursor cursor;
930  for (ImageSet::iterator it = m_images.begin(); it != m_images.end(); ++it)
931  {
932 #if defined EXIV2_VERSION && EXIV2_TEST_VERSION(0,27,99)
933  Exiv2::Image::UniquePtr image;
934 #else
935  Exiv2::Image::AutoPtr image;
936 #endif
937  bool opened = false;
938  try
939  {
940  image = Exiv2::ImageFactory::open((*it)->getFilename().c_str());
941  opened = true;
942  }
943  catch (...)
944  {
945  std::cerr << __FILE__ << " " << __LINE__ << " Error opening file" << std::endl;
946  continue;
947  }
948  int index = -1;
949  if (opened)
950  {
951  try
952  {
953  image->readMetadata();
954  }
955  catch (const Exiv2::Error& e)
956  {
957  std::cerr << __FILE__ << " " << __LINE__ << " Exiv2: Error reading metadata (" << e.what() << ")" << std::endl;
958  continue;
959  }
960  // read all thumbnails
961  Exiv2::PreviewManager previews(*image);
962  Exiv2::PreviewPropertiesList lists = previews.getPreviewProperties();
963  if (!lists.empty())
964  {
965  // select a preview with matching size
966  int previewIndex = 0;
967  while (previewIndex < lists.size() - 1 && lists[previewIndex].width_ < THUMBSIZE && lists[previewIndex].height_ < THUMBSIZE)
968  {
969  ++previewIndex;
970  };
971  // load preview image to wxImage
972  wxImage rawImage;
973  Exiv2::PreviewImage previewImage = previews.getPreviewImage(lists[previewIndex]);
974  wxMemoryInputStream stream(previewImage.pData(), previewImage.size());
975  rawImage.LoadFile(stream, wxString(previewImage.mimeType().c_str(), wxConvLocal), -1);
976  int x = 0;
977  int y = 0;
978  if (previewImage.width() > previewImage.height())
979  {
980  //landscape format
981  int newHeight = THUMBSIZE*previewImage.height() / previewImage.width();
982  rawImage.Rescale(THUMBSIZE, newHeight);
983  x = 0;
984  y = (THUMBSIZE - newHeight) / 2;
985  }
986  else
987  {
988  //portrait format
989  int newWidth = THUMBSIZE*previewImage.width() / previewImage.height();
990  rawImage.Rescale(newWidth, THUMBSIZE);
991  x = (THUMBSIZE - newWidth) / 2;
992  y = 0;
993  }
994  // rotate according to orientation tag
995  if ((*it)->getRoll() == 90)
996  {
997  rawImage = rawImage.Rotate90();
998  std::swap(x, y);
999  }
1000  else
1001  {
1002  if ((*it)->getRoll() == 270)
1003  {
1004  rawImage = rawImage.Rotate90(false);
1005  std::swap(x, y);
1006  }
1007  else
1008  {
1009  if ((*it)->getRoll() == 180)
1010  {
1011  rawImage = rawImage.Rotate180();
1012  };
1013  };
1014  };
1015  // create final bitmap with centered thumbnail
1016  wxBitmap bitmap(THUMBSIZE, THUMBSIZE);
1017  wxMemoryDC dc(bitmap);
1018  dc.SetBackground(list->GetBackgroundColour());
1019  dc.Clear();
1020  dc.DrawBitmap(rawImage, x, y);
1021  dc.SelectObject(wxNullBitmap);
1022  // create mask bitmap
1023  wxImage mask(THUMBSIZE, THUMBSIZE);
1024  mask.SetRGB(wxRect(0, 0, THUMBSIZE, THUMBSIZE), 0, 0, 0);
1025  mask.SetRGB(wxRect(x, y, THUMBSIZE - 2 * x, THUMBSIZE - 2 * y), 255, 255, 255);
1026  // add to wxImageList
1027  index = thumbs->Add(bitmap, wxBitmap(mask, 1));
1028  };
1029  };
1030  // create item in thumb list
1031  wxFileName fn(wxString((*it)->getFilename().c_str(), HUGIN_CONV_FILENAME));
1032  list->InsertItem(list->GetItemCount(), fn.GetFullName(), index);
1033  // build tooltip text
1034  tooltips.Add(fn.GetFullName() + "\n" + FormatString::GetAperture(*it) + ", "
1035  + FormatString::GetExposureTime(*it) + ", " + _("ISO") + FormatString::GetIso(*it)
1036  + "\n" + FormatString::GetExifDateTime(*it));
1037  };
1038 };
1039 
1040 void PossiblePano::RemoveImage(const unsigned int index)
1041 {
1042  // remove image with given index
1043  if (index < m_images.size())
1044  {
1045  ImageSet::iterator item = m_images.begin();
1046  std::advance(item, index);
1047  delete *item;
1048  m_images.erase(item);
1049  //update the internal times
1050  UpdateDateTimes();
1051  };
1052 }
1053 
1054 PossiblePano* PossiblePano::SplitPano(const unsigned int index)
1055 {
1056  PossiblePano* newPano = new PossiblePano();
1057  if (index < m_images.size())
1058  {
1059  // now move all images to right pano
1060  ImageSet allImages = m_images;
1061  m_images.clear();
1062  ImageSet::iterator img = allImages.begin();
1063  while (m_images.size() < index && img != allImages.end())
1064  {
1065  m_images.insert(*img);
1066  ++img;
1067  };
1068  while (img != allImages.end())
1069  {
1070  newPano->AddSrcPanoImage(*img);
1071  ++img;
1072  }
1073  UpdateDateTimes();
1074  };
1075  return newPano;
1076 }
1077 
1079 {
1080  // update internal stored start and end time
1081  m_dt_start = GetDateTime(*m_images.begin());
1082  m_dt_end = m_dt_start;
1083  for (auto& img : m_images)
1084  {
1085  wxDateTime dt = GetDateTime(img);
1086  if (dt.IsEarlierThan(m_dt_start))
1087  {
1088  m_dt_start = dt;
1089  }
1090  if (dt.IsLaterThan(m_dt_end))
1091  {
1092  m_dt_end = dt;
1093  };
1094  };
1095 }
std::string m_lens
wxString GetFocalLength()
returns the focal length as string
WXIMPEX wxString GetFormattedTimeSpan(const wxTimeSpan &timeSpan)
Definition: wxutils.cpp:27
int alphanum_comp(const std::string &l, const std::string &r)
Compare l and r with the same semantics as strcmp(), but with the &quot;Alphanum Algorithm&quot; which produces...
Definition: alphanum.cpp:119
static void swap(T &x, T &y)
Definition: svm.cpp:67
#define HUGIN_NONA_CROPPEDIMAGES
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
wxChoice * m_ch_naming
bool operator()(const HuginBase::SrcPanoImage *img1, const HuginBase::SrcPanoImage *img2) const
wxSpinCtrl * m_sc_maxTimeDiff
wxDateTime m_dt_start
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
void AddSrcPanoImage(HuginBase::SrcPanoImage *img)
adds the given SrcPanoImage to this pano-group
#define HUGIN_JPEG_QUALITY
~PossiblePano()
destructor, cleans up used variables
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Definition: Panorama.cpp:311
Somewhere to specify what variables belong to what.
void AddToList(wxString aFile, Project::Target target=Project::STITCHING, wxString userDefined=wxEmptyString)
Definition: BatchFrame.cpp:491
void RemoveImage(const unsigned int index)
removes the image at given index
some helper classes for graphes
void EnableButtons(const bool state)
wxImageList * m_thumbs
wxButton * m_button_start
include file for the hugin project
wxCheckBox * m_cb_loadDistortion
std::string outputImageTypeCompression
wxString GetCameraName()
returns the camera name
void setOptimizerSwitch(const int newSwitch)
set optimizer master switch
Definition: Panorama.cpp:303
wxCheckBox * m_cb_createLinks
ImageSet m_images
double m_cropfactor
Batch processor for Hugin with GUI.
int SortWxFilenames(const wxString &s1, const wxString &s2)
void OnButtonClose(wxCommandEvent &e)
closes window
wxCheckBox * m_cb_loadVignetting
void UpdateDateTimes()
updates the internal date/time representations
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
Definition: Panorama.cpp:2181
Model for a panorama.
Definition: Panorama.h:152
PossiblePano * SplitPano(const unsigned int index)
split pano into 2 subpanos, index is used as first image of second pano
BatchFrame * m_batchframe
wxArrayString m_tooltips
some definitions to work with optimizer master switches
size_t GetSelectedValue(wxControlWithItems *list)
Returns the client value of the selected item from list.
Definition: LensTools.cpp:102
wxDateTime m_dt_end
const wxString GetFilestring(const wxString BasePath, const bool stripExtension=false) const
returns a string with the filename of the first and last file
wxString GetDuration()
returns the duration as string
void PopulateListCtrl(wxListCtrl *list, wxImageList *thumbs, wxArrayString &tooltips)
add all images to wxListCtrl
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
void SearchInDir(wxString dirstring, const bool includeSubdir, const bool loadDistortion, const bool loadVignetting, const size_t minNumberImages, const size_t maxTimeDiff)
const int getExifDateTime(struct tm *datetime) const
try to convert Exif date time string to struct tm
void OnSplitPanos(wxCommandEvent &e)
event handler to split into 2 panos
vigra_ext::Interpolator interpolator
const unsigned int GetImageCount() const
returns number of images in this group
Definition of dialog to change user defined sequence.
wxString GetStartString()
return the start date/time as string
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
#define HUGIN_NONA_INTERPOLATOR
#define HUGIN_TIFF_COMPRESSION
void OnListMouseMove(wxMouseEvent &e)
mouse move handler for tooltips
wxCheckBox * m_cb_subdir
std::map< std::string, std::string > FileMetaData
typedef for general map for storing metadata in files
Definition: SrcPanoImage.h:55
wxString GetLensName()
returns the lens name
std::set< HuginBase::SrcPanoImage *, SortFilename > ImageSet
IMPEX double h[25][1024]
Definition: emor.cpp:169
std::string stripExtension(const std::string &basename2)
remove extension of a filename
Definition: utils.cpp:130
TIFFErrorHandler m_oldtiffwarning
void OnSelectPossiblePano(wxCommandEvent &e)
event to populate information on the right
wxStaticText * m_statustext
void OnListItemRightClick(wxListEvent &e)
event handler for context menu
#define HUGIN_HDRMERGE_ARGS
#define HUGIN_LDR_OUTPUT_FORMAT
bool BelongsTo(HuginBase::SrcPanoImage *img, const wxTimeSpan max_time_diff)
return true, if the image could belong to the given PossiblePano, it checks camera maker and model...
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition: Panorama.cpp:319
wxTextCtrl * m_textctrl_dir
wxString GetExposureTime(const HuginBase::SrcPanoImage *img)
returns formatted exposure time
Definition: LensTools.cpp:554
Same as above, but use a non const panorama.
wxButton * m_button_close
NamingConvention
enumeration for different naming conventions, must be match combobox in ressource ...
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
wxString GeneratePanorama(NamingConvention nc, bool createLinks, HuginBase::PanoramaOptions::BlendingMechanism defaultBlender)
generates the panorama file from this set of images
wxString GetExifDateTime(const HuginBase::SrcPanoImage *img)
returns Exif DateTimeOriginal as formatted wxString
Definition: LensTools.cpp:503
#define THUMBSIZE
void SelectListValue(wxControlWithItems *list, size_t newValue)
Selects the given value (stored in the client data) in the given list item.
Definition: LensTools.cpp:89
wxListCtrl * m_thumbsList
vigra::Size2D m_size
double m_focallength
wxString m_start_dir
bool GetNewProjectFilename(NamingConvention nc, const wxString basePath, wxFileName &projectFile)
returns a given filename, which does not already exists
#define HUGIN_ENFUSE_ARGS
bool readEXIF()
try to fill out information about the image, by examining the exif data
const wxDateTime GetDateTime(const HuginBase::SrcPanoImage *img)
does some reformating date/time format
PossiblePano()
constructor, init values
void OnClose(wxCloseEvent &e)
prevents closing window when running detection
platform/compiler specific stuff.
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
wxSpinCtrl * m_sc_minNumberImages
~FindPanoDialog()
destructor, saves size and position
std::string m_camera
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
FindPanoDialog(BatchFrame *batchframe, wxString xrcPrefix)
Constructor, read from xrc ressource; restore last uses settings, size and position.
const wxString GetItemString(const wxString BasePath) const
returns a string which contains description of this pano
void OnRemoveImage(wxCommandEvent &e)
event handler to remove selected image from list
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
Definition: Panorama.cpp:1531
wxString GetFocalLength(const HuginBase::SrcPanoImage *img)
return focallength and focallength 35 mm as wxString
Definition: LensTools.cpp:519
Interpolator
enum with all interpolation methods
Definition: Interpolators.h:78
static uint16_t flags
All variables of a source image.
Definition: SrcPanoImage.h:194
Panorama image options.
wxString GetAperture(const HuginBase::SrcPanoImage *img)
returns formatted aperture value
Definition: LensTools.cpp:540
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
Definition: Panorama.cpp:2137
wxButton * m_button_choose
#define HUGIN_ENBLEND_ARGS
wxChoice * m_ch_blender
void OnButtonSend(wxCommandEvent &e)
add selected projects to queue
wxString getDefaultProjectName(const HuginBase::Panorama &pano, const wxString filenameTemplate)
gets the default project name, as defined in the preferences
void OnButtonChoose(wxCommandEvent &e)
select directory with dialog
BlendingMechanism blendMode
std::string m_make
wxCheckListBox * m_list_pano
void FillBlenderList(wxControlWithItems *list)
Fills a wxControlWithItem with all possible blender options, the client data contains the associated ...
Definition: LensTools.cpp:81
wxString GetIso(const HuginBase::SrcPanoImage *img)
returns formatted iso value
Definition: LensTools.cpp:591
wxButton * m_button_send
void OnButtonStart(wxCommandEvent &e)
start/stops detections
std::vector< PossiblePano * > m_panos