FindPanoDialog.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Lesser General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software. If not, see
00023  *  <http://www.gnu.org/licenses/>.
00024  *
00025  */
00026 
00027 #include "FindPanoDialog.h"
00028 #include "base_wx/wxPlatform.h"
00029 #include "panoinc.h"
00030 #include "panodata/OptimizerSwitches.h"
00031 #include "PTBatcherGUI.h"
00032 #include "hugin_utils/alphanum.h"
00033 #include "hugin/config_defaults.h"
00034 #include "wx/mstream.h"
00035 #include "exiv2/exiv2.hpp"
00036 #include "exiv2/preview.hpp"
00037 #ifdef _WIN32
00038 #include <CommCtrl.h>
00039 #endif
00040 #include "base_wx/LensTools.h"
00041 #include "panodata/StandardImageVariableGroups.h"
00042 
00043 BEGIN_EVENT_TABLE(FindPanoDialog,wxDialog)
00044     EVT_BUTTON(XRCID("find_pano_close"), FindPanoDialog::OnButtonClose)
00045     EVT_BUTTON(XRCID("find_pano_select_dir"), FindPanoDialog::OnButtonChoose)
00046     EVT_BUTTON(XRCID("find_pano_start_stop"), FindPanoDialog::OnButtonStart)
00047     EVT_BUTTON(XRCID("find_pano_add_queue"), FindPanoDialog::OnButtonSend)
00048     EVT_LISTBOX(XRCID("find_pano_list"), FindPanoDialog::OnSelectPossiblePano)
00049     EVT_CLOSE(FindPanoDialog::OnClose)
00050 END_EVENT_TABLE()
00051 
00052 bool SortFilename::operator()(const SrcPanoImage* img1, const SrcPanoImage* img2)
00053 {
00054     return doj::alphanum_comp(img1->getFilename(),img2->getFilename())<0;
00055 };
00056 
00057 // thumbnail size currently set to 80x80
00058 #define THUMBSIZE 80
00059 
00060 FindPanoDialog::FindPanoDialog(BatchFrame* batchframe, wxString xrcPrefix)
00061 {
00062     // load our children. some children might need special
00063     // initialization. this will be done later.
00064     wxXmlResource::Get()->LoadDialog(this,batchframe,wxT("find_pano_dialog"));
00065 
00066 #ifdef __WXMSW__
00067     wxIcon myIcon(xrcPrefix+ wxT("data/ptbatcher.ico"),wxBITMAP_TYPE_ICO);
00068 #else
00069     wxIcon myIcon(xrcPrefix + wxT("data/ptbatcher.png"),wxBITMAP_TYPE_PNG);
00070 #endif
00071     SetIcon(myIcon);
00072     m_batchframe=batchframe;
00073     m_isRunning=false;
00074     m_stopped=false;
00075 
00076     m_button_start=XRCCTRL(*this,"find_pano_start_stop",wxButton);
00077     m_button_choose=XRCCTRL(*this,"find_pano_select_dir",wxButton);
00078     m_button_send=XRCCTRL(*this,"find_pano_add_queue",wxButton);
00079     m_button_close=XRCCTRL(*this,"find_pano_close",wxButton);
00080     m_textctrl_dir=XRCCTRL(*this,"find_pano_dir",wxTextCtrl);
00081 #if wxCHECK_VERSION(2,9,3)
00082     m_textctrl_dir->AutoCompleteDirectories();
00083 #endif
00084     m_cb_subdir=XRCCTRL(*this,"find_pano_subdir",wxCheckBox);
00085     m_statustext=XRCCTRL(*this,"find_pano_label",wxStaticText);
00086     m_list_pano=XRCCTRL(*this,"find_pano_list",wxCheckListBox);
00087     m_ch_naming=XRCCTRL(*this,"find_pano_naming",wxChoice);
00088     m_cb_createLinks=XRCCTRL(*this,"find_pano_create_links",wxCheckBox);
00089     m_cb_loadDistortion=XRCCTRL(*this,"find_pano_load_distortion",wxCheckBox);
00090     m_cb_loadVignetting=XRCCTRL(*this,"find_pano_load_vignetting",wxCheckBox);
00091     m_sc_minNumberImages=XRCCTRL(*this, "find_pano_min_number_images", wxSpinCtrl);
00092     m_sc_maxTimeDiff=XRCCTRL(*this, "find_pano_max_time_diff", wxSpinCtrl);
00093     m_ch_blender = XRCCTRL(*this, "find_pano_default_blender", wxChoice);
00094     FillBlenderList(m_ch_blender);
00095 
00096     //set parameters
00097     wxConfigBase* config = wxConfigBase::Get();
00098     // restore position and size
00099     int dx,dy;
00100     wxDisplaySize(&dx,&dy);
00101     bool maximized = config->Read(wxT("/FindPanoDialog/maximized"), 0l) != 0;
00102     if (maximized)
00103     {
00104         this->Maximize();
00105     }
00106     else
00107     {
00108         //size
00109         int w = config->Read(wxT("/FindPanoDialog/width"),-1l);
00110         int h = config->Read(wxT("/FindPanoDialog/height"),-1l);
00111         if (w > 0 && w <= dx)
00112         {
00113             this->SetClientSize(w,h);
00114         }
00115         else
00116         {
00117             this->Fit();
00118         }
00119         //position
00120         int x = config->Read(wxT("/FindPanoDialog/positionX"),-1l);
00121         int y = config->Read(wxT("/FindPanoDialog/positionY"),-1l);
00122         if ( y >= 0 && x >= 0 && x < dx && y < dy)
00123         {
00124             this->Move(x, y);
00125         }
00126         else
00127         {
00128             this->Move(0, 44);
00129         }
00130     }
00131     long splitterPos = config->Read(wxT("/FindPanoDialog/splitterPos"), -1l);
00132     if (splitterPos != -1)
00133     {
00134         XRCCTRL(*this, "find_pano_splitter", wxSplitterWindow)->SetSashPosition(splitterPos);
00135     };
00136     wxString path=config->Read(wxT("/FindPanoDialog/actualPath"),wxEmptyString);
00137     if(!path.IsEmpty())
00138     {
00139         m_textctrl_dir->SetValue(path);
00140     }
00141     bool val;
00142     config->Read(wxT("/FindPanoDialog/includeSubDirs"),&val,false);
00143     m_cb_subdir->SetValue(val);
00144     long i=config->Read(wxT("/FindPanoDialog/Naming"),0l);
00145     m_ch_naming->SetSelection(i);
00146     config->Read(wxT("/FindPanoDialog/linkStacks"),&val,true);
00147     m_cb_createLinks->SetValue(val);
00148     config->Read(wxT("/FindPanoDialog/loadDistortion"),&val,false);
00149     m_cb_loadDistortion->SetValue(val);
00150     config->Read(wxT("/FindPanoDialog/loadVignetting"),&val,false);
00151     m_cb_loadVignetting->SetValue(val);
00152     i=config->Read(wxT("/FindPanoDialog/MinNumberImages"), 2l);
00153     m_sc_minNumberImages->SetValue(i);
00154     i=config->Read(wxT("/FindPanoDialog/MaxTimeDiff"), 30l);
00155     m_sc_maxTimeDiff->SetValue(i);
00156     i = config->Read(wxT("/FindPanoDialog/DefaultBlender"), static_cast<long>(HuginBase::PanoramaOptions::ENBLEND_BLEND));
00157     SelectListValue(m_ch_blender, i);
00158     m_button_send->Disable();
00159     m_thumbs = new wxImageList(THUMBSIZE, THUMBSIZE, true, 0);
00160     wxListCtrl* thumbs_list = XRCCTRL(*this, "find_pano_selected_thumbslist", wxListCtrl);
00161     thumbs_list->SetImageList(m_thumbs, wxIMAGE_LIST_NORMAL);
00162 #ifdef _WIN32
00163     // default image spacing is too big, wxWidgets does not provide direct 
00164     // access to the spacing, so using the direct API function
00165     ListView_SetIconSpacing(thumbs_list->GetHandle(), THUMBSIZE + 20, THUMBSIZE + 20);
00166 #endif
00167 };
00168 
00169 FindPanoDialog::~FindPanoDialog()
00170 {
00171     wxConfigBase* config=wxConfigBase::Get();
00172     if(!this->IsMaximized())
00173     {
00174         wxSize sz = this->GetClientSize();
00175         config->Write(wxT("/FindPanoDialog/width"), sz.GetWidth());
00176         config->Write(wxT("/FindPanoDialog/height"), sz.GetHeight());
00177         wxPoint ps = this->GetPosition();
00178         config->Write(wxT("/FindPanoDialog/positionX"), ps.x);
00179         config->Write(wxT("/FindPanoDialog/positionY"), ps.y);
00180         config->Write(wxT("/FindPanoDialog/maximized"), 0);
00181     }
00182     else
00183     {
00184         config->Write(wxT("/FindPanoDialog/maximized"), 1l);
00185     };
00186     config->Write(wxT("/FindPanoDialog/splitterPos"), XRCCTRL(*this, "find_pano_splitter", wxSplitterWindow)->GetSashPosition());
00187     config->Write(wxT("/FindPanoDialog/actualPath"),m_textctrl_dir->GetValue());
00188     config->Write(wxT("/FindPanoDialog/includeSubDirs"),m_cb_subdir->GetValue());
00189     config->Write(wxT("/FindPanoDialog/Naming"),m_ch_naming->GetSelection());
00190     config->Write(wxT("/FindPanoDialog/linkStacks"),m_cb_createLinks->GetValue());
00191     config->Write(wxT("/FindPanoDialog/loadDistortion"),m_cb_loadDistortion->GetValue());
00192     config->Write(wxT("/FindPanoDialog/loadVignetting"),m_cb_loadDistortion->GetValue());
00193     config->Write(wxT("/FindPanoDialog/MinNumberImages"), m_sc_minNumberImages->GetValue());
00194     config->Write(wxT("/FindPanoDialog/MaxTimeDiff"), m_sc_maxTimeDiff->GetValue());
00195     config->Write(wxT("/FindPanoDialog/DefaultBlender"), static_cast<long>(GetSelectedValue(m_ch_blender)));
00196     CleanUpPanolist();
00197     delete m_thumbs;
00198 };
00199 
00200 void FindPanoDialog::CleanUpPanolist()
00201 {
00202     if(m_panos.size()>0)
00203     {
00204         while(!m_panos.empty())
00205         {
00206             delete m_panos.back();
00207             m_panos.pop_back();
00208         };
00209     };
00210 };
00211 
00212 //prevent closing window when running detection
00213 void FindPanoDialog::OnClose(wxCloseEvent& e)
00214 {
00215     if(e.CanVeto() && m_isRunning)
00216     {
00217         wxBell();
00218         e.Veto();
00219     }
00220     else
00221     {
00222         e.Skip();
00223     };
00224 };
00225 
00226 void FindPanoDialog::OnButtonClose(wxCommandEvent& e)
00227 {
00228     if(m_panos.size()>0)
00229     {
00230         if(wxMessageBox(_("The list contains possibly unprocessed panoramas.\nIf you close the dialog, you will lose them.\nContinue anyway?"),
00231                         _("Question"),wxYES_NO|wxICON_QUESTION,this)==wxNO)
00232         {
00233             return;
00234         };
00235     };
00236     this->Close();
00237 };
00238 
00239 void FindPanoDialog::OnButtonChoose(wxCommandEvent& e)
00240 {
00241     wxDirDialog dlg(this, _("Specify a directory to search for projects in"),
00242                     m_textctrl_dir->GetValue(), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
00243     if (dlg.ShowModal()==wxID_OK)
00244     {
00245         m_textctrl_dir->SetValue(dlg.GetPath());
00246     };
00247 };
00248 
00249 void FindPanoDialog::OnButtonStart(wxCommandEvent& e)
00250 {
00251     if(m_isRunning)
00252     {
00253         //stop detection
00254         m_stopped=true;
00255         m_button_start->SetLabel(_("Accepted"));
00256     }
00257     else
00258     {
00259         //start detection
00260         m_start_dir=m_textctrl_dir->GetValue();
00261         if(wxDir::Exists(m_start_dir))
00262         {
00263             if(m_panos.size()>0)
00264             {
00265                 if(wxMessageBox(_("The list contains still not yet processed panoramas.\nIf you continue, they will be disregarded.\nDo you still want to continue?"),
00266                                 _("Question"),wxYES_NO|wxICON_QUESTION,this)==wxNO)
00267                 {
00268                     return;
00269                 };
00270             };
00271             m_isRunning=true;
00272             m_stopped=false;
00273             //deactivate TIFF warning message boxes
00274             m_oldtiffwarning=TIFFSetWarningHandler(NULL);
00275             m_button_start->SetLabel(_("Stop"));
00276             CleanUpPanolist();
00277             m_list_pano->Clear();
00278             wxCommandEvent dummy;
00279             OnSelectPossiblePano(dummy);
00280             EnableButtons(false);
00281             SearchInDir(m_start_dir,m_cb_subdir->GetValue(), m_cb_loadDistortion->GetValue(), m_cb_loadVignetting->GetValue(), 
00282                 m_sc_minNumberImages->GetValue(), m_sc_maxTimeDiff->GetValue());
00283         }
00284         else
00285         {
00286             wxMessageBox(wxString::Format(_("Directory %s does not exist.\nPlease give an existing directory."),m_start_dir.c_str()),
00287                          _("Warning"),wxOK | wxICON_EXCLAMATION,this);
00288         };
00289     };
00290 }
00291 
00292 void FindPanoDialog::OnButtonSend(wxCommandEvent& e)
00293 {
00294     if(m_panos.size()==0)
00295     {
00296         return;
00297     }
00298     unsigned int nr=0;
00299     for(unsigned int i=0; i<m_list_pano->GetCount(); i++)
00300     {
00301         if(m_list_pano->IsChecked(i))
00302         {
00303             nr++;
00304         };
00305     };
00306     if(nr==0)
00307     {
00308         wxMessageBox(_("You have selected no possible panorama.\nPlease select at least one panorama and try again."),_("Warning"),wxOK|wxICON_EXCLAMATION,this);
00309         return;
00310     }
00311     bool failed=false;
00312     bool createLinks=m_cb_createLinks->GetValue();
00313     for(unsigned int i=0; i<m_list_pano->GetCount(); i++)
00314     {
00315         if(m_list_pano->IsChecked(i))
00316         {
00317             wxString filename=m_panos[i]->GeneratePanorama((PossiblePano::NamingConvention)(m_ch_naming->GetSelection()),createLinks, 
00318                 static_cast<HuginBase::PanoramaOptions::BlendingMechanism>(GetSelectedValue(m_ch_blender)));
00319             if(!filename.IsEmpty())
00320             {
00321                 m_batchframe->AddToList(filename,Project::DETECTING);
00322             }
00323             else
00324             {
00325                 failed=true;
00326             };
00327         };
00328     };
00329     if(failed)
00330     {
00331         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);
00332     };
00333     this->Close();
00334 };
00335 
00336 void FindPanoDialog::EnableButtons(const bool state)
00337 {
00338     m_textctrl_dir->Enable(state);
00339     m_button_choose->Enable(state);
00340     m_cb_subdir->Enable(state);
00341     m_ch_naming->Enable(state);
00342     m_cb_createLinks->Enable(state);
00343     m_button_close->Enable(state);
00344     m_button_send->Enable(state);
00345 };
00346 
00347 void FindPanoDialog::OnSelectPossiblePano(wxCommandEvent &e)
00348 {
00349     int selected = m_list_pano->GetSelection();
00350     if (selected != wxNOT_FOUND)
00351     {
00352         XRCCTRL(*this, "find_pano_selected_cam", wxStaticText)->SetLabel(m_panos[selected]->GetCameraName());
00353         XRCCTRL(*this, "find_pano_selected_lens", wxStaticText)->SetLabel(m_panos[selected]->GetLensName());
00354         XRCCTRL(*this, "find_pano_selected_focallength", wxStaticText)->SetLabel(m_panos[selected]->GetFocalLength());
00355         XRCCTRL(*this, "find_pano_selected_date_time", wxStaticText)->SetLabel(m_panos[selected]->GetStartString() + wxT(" (")+ m_panos[selected]->GetDuration() + wxT(")"));
00356         m_panos[selected]->PopulateListCtrl(XRCCTRL(*this, "find_pano_selected_thumbslist", wxListCtrl), m_thumbs);
00357     }
00358     else
00359     {
00360         XRCCTRL(*this, "find_pano_selected_cam", wxStaticText)->SetLabel(wxEmptyString);
00361         XRCCTRL(*this, "find_pano_selected_lens", wxStaticText)->SetLabel(wxEmptyString);
00362         XRCCTRL(*this, "find_pano_selected_focallength", wxStaticText)->SetLabel(wxEmptyString);
00363         XRCCTRL(*this, "find_pano_selected_date_time", wxStaticText)->SetLabel(wxEmptyString);
00364         XRCCTRL(*this, "find_pano_selected_thumbslist", wxListCtrl)->DeleteAllItems();
00365         m_thumbs->RemoveAll();
00366     };
00367 };
00368 
00369 int SortWxFilenames(const wxString& s1,const wxString& s2)
00370 {
00371     return doj::alphanum_comp(std::string(s1.mb_str(wxConvLocal)),std::string(s2.mb_str(wxConvLocal)));
00372 };
00373 
00374 void FindPanoDialog::SearchInDir(wxString dirstring, const bool includeSubdir, const bool loadDistortion, const bool loadVignetting, const size_t minNumberImages, const size_t maxTimeDiff)
00375 {
00376     std::vector<PossiblePano*> newPanos;
00377     wxTimeSpan max_diff(0, 0, maxTimeDiff, 0); 
00378     wxString filename;
00379     wxArrayString fileList;
00380     wxDir::GetAllFiles(dirstring,&fileList,wxEmptyString,wxDIR_FILES|wxDIR_HIDDEN);
00381     fileList.Sort(SortWxFilenames);
00382     //map for caching projection information to prevent reading from database for each image
00383     for(size_t j=0; j<fileList.size() && !m_stopped; j++)
00384     {
00385         m_statustext->SetLabel(wxString::Format(_("Reading file %s"),fileList[j].c_str()));
00386         wxFileName file(fileList[j]);
00387         file.MakeAbsolute();
00388         wxString ext=file.GetExt();
00389         if(ext.CmpNoCase(wxT("jpg"))==0 || ext.CmpNoCase(wxT("jpeg"))==0 ||
00390                 ext.CmpNoCase(wxT("tif"))==0 || ext.CmpNoCase(wxT("tiff"))==0)
00391         {
00392             std::string filenamestr(file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00393             SrcPanoImage* img=new SrcPanoImage;
00394             img->setFilename(filenamestr);
00395             img->readEXIF();
00396             // check for black/white images, if so skip
00397             const HuginBase::FileMetaData& metadata = img->getFileMetadata();
00398             HuginBase::FileMetaData::const_iterator it = metadata.find("pixeltype");
00399             if (it != metadata.end())
00400             {
00401                 if (it->second == "BILEVEL")
00402                 { 
00403                     wxGetApp().Yield(true);
00404                     continue;
00405                 };
00406             };
00407             img->applyEXIFValues();
00408             if(!img->getExifMake().empty() && !img->getExifModel().empty() && 
00409                 img->getExifFocalLength()!=0 && img->getCropFactor()!=0)
00410             {
00411                 img->readProjectionFromDB();
00412                 if(loadDistortion)
00413                 {
00414                     img->readDistortionFromDB();
00415                 };
00416                 if(loadVignetting)
00417                 {
00418                     img->readVignettingFromDB();
00419                 };
00420                 bool found=false;
00421                 for(unsigned int i=0; i<newPanos.size() && !m_stopped && !found; i++)
00422                 {
00423                     //compare with all other image groups
00424                     if(newPanos[i]->BelongsTo(img,max_diff))
00425                     {
00426                         newPanos[i]->AddSrcPanoImage(img);
00427                         found=true;
00428                     };
00429                     if(i%10==0)
00430                     {
00431                         wxGetApp().Yield(true);
00432                     };
00433                 };
00434                 if(!found)
00435                 {
00436                     PossiblePano* newPano=new PossiblePano();
00437                     newPano->AddSrcPanoImage(img);
00438                     newPanos.push_back(newPano);
00439                 };
00440             }
00441             else
00442             {
00443                 //could not read exif infos, disregard this image
00444                 delete img;
00445             };
00446         };
00447         //allow processing events
00448         wxGetApp().Yield(true);
00449     };
00450     if(!m_stopped && newPanos.size()>0)
00451     {
00452         for(size_t i=0; i<newPanos.size(); i++)
00453         {
00454             if(newPanos[i]->GetImageCount()>=minNumberImages)
00455             {
00456                 m_panos.push_back(newPanos[i]);
00457                 int newItem=m_list_pano->Append(m_panos[m_panos.size()-1]->GetItemString(m_start_dir));
00458                 m_list_pano->Check(newItem,true);
00459             }
00460             else
00461             {
00462                 delete newPanos[i];
00463             };
00464         };
00465     };
00466 
00467     if(includeSubdir && !m_stopped)
00468     {
00469         //now we go into all directories
00470         wxDir dir(dirstring);
00471         bool cont=dir.GetFirst(&filename,wxEmptyString,wxDIR_DIRS);
00472         while(cont && !m_stopped)
00473         {
00474             SearchInDir(dir.GetName()+wxFileName::GetPathSeparator()+filename,includeSubdir, loadDistortion, loadVignetting, minNumberImages, maxTimeDiff);
00475             cont=dir.GetNext(&filename);
00476         }
00477     };
00478     if(m_start_dir.Cmp(dirstring)==0)
00479     {
00480         m_stopped=false;
00481         m_isRunning=false;
00482         m_button_start->SetLabel(_("Start"));
00483         EnableButtons(true);
00484         //enable send button if at least one panorama found
00485         m_button_send->Enable(m_panos.size()>0);
00486         if(m_panos.size()>0)
00487         {
00488             m_statustext->SetLabel(wxString::Format(_("Found %d possible panoramas."), static_cast<int>(m_panos.size())));
00489         }
00490         else
00491         {
00492             m_statustext->SetLabel(_("No possible panoramas found."));
00493         };
00494         TIFFSetWarningHandler(m_oldtiffwarning);
00495     };
00496 };
00497 
00498 PossiblePano::~PossiblePano()
00499 {
00500     if(m_images.size()>0)
00501     {
00502         for(ImageSet::reverse_iterator it=m_images.rbegin(); it!=m_images.rend(); ++it)
00503         {
00504             delete (*it);
00505         }
00506     };
00507 };
00508 
00509 bool PossiblePano::BelongsTo(SrcPanoImage* img, const wxTimeSpan max_time_diff)
00510 {
00511     if(m_make.compare(img->getExifMake())!=0)
00512     {
00513         return false;
00514     }
00515     if(m_camera.compare(img->getExifModel())!=0)
00516     {
00517         return false;
00518     }
00519     if(m_lens.compare(img->getExifLens())!=0)
00520     {
00521         return false;
00522     }
00523     if(fabs(m_focallength-img->getExifFocalLength())>0.01)
00524     {
00525         return false;
00526     }
00527     if(m_size!=img->getSize())
00528     {
00529         return false;
00530     }
00531     if(!GetDateTime(img).IsBetween(m_dt_start-max_time_diff,m_dt_end+max_time_diff))
00532     {
00533         return false;
00534     };
00535     return true;
00536 };
00537 
00538 const wxDateTime PossiblePano::GetDateTime(const SrcPanoImage* img)
00539 {
00540     struct tm exifdatetime;
00541     if(img->getExifDateTime(&exifdatetime)==0)
00542     {
00543         return wxDateTime(exifdatetime);
00544     }
00545     else
00546     {
00547         wxFileName file(wxString(img->getFilename().c_str(),HUGIN_CONV_FILENAME));
00548         return file.GetModificationTime();
00549     };
00550 };
00551 
00552 void PossiblePano::AddSrcPanoImage(HuginBase::SrcPanoImage* img)
00553 {
00554     if(m_images.empty())
00555     {
00556         //fill all values from first image
00557         m_make=img->getExifMake();
00558         m_camera=img->getExifModel();
00559         m_lens=img->getExifLens();
00560         m_focallength=img->getExifFocalLength();
00561         m_size=img->getSize();
00562         m_dt_start=GetDateTime(img);
00563         m_dt_end=m_dt_start;
00564     }
00565     else
00566     {
00567         wxDateTime dt=GetDateTime(img);
00568         if(dt.IsEarlierThan(m_dt_start))
00569         {
00570             m_dt_start=dt;
00571         }
00572         if(dt.IsLaterThan(m_dt_end))
00573         {
00574             m_dt_end=dt;
00575         };
00576     };
00577     m_images.insert(img);
00578 };
00579 
00580 const wxString PossiblePano::GetFilestring(const wxString BasePath, const bool stripExtension) const
00581 {
00582     ImageSet::const_iterator it=m_images.begin();
00583     wxFileName f1(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
00584     f1.MakeRelativeTo(BasePath);
00585     ImageSet::const_reverse_iterator rit=m_images.rbegin();
00586     wxFileName f2(wxString((*rit)->getFilename().c_str(),HUGIN_CONV_FILENAME));
00587     if(stripExtension)
00588     {
00589         return f1.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)+f1.GetName()+wxT("-")+f2.GetName();
00590     }
00591     else
00592     {
00593         return f1.GetFullPath()+wxT(" - ")+f2.GetFullName();
00594     };
00595 };
00596 
00597 const wxString PossiblePano::GetItemString(const wxString BasePath) const
00598 {
00599     return wxString::Format(_("%d images: %s"), static_cast<int>(m_images.size()), GetFilestring(BasePath).c_str());
00600 };
00601 
00602 bool PossiblePano::GetNewProjectFilename(NamingConvention nc,const wxString basePath, wxFileName& projectFile)
00603 {
00604     wxString mask;
00605     unsigned int i=1;
00606     projectFile.SetPath(basePath);
00607     projectFile.SetName(wxT("pano"));
00608     projectFile.SetExt(wxT("pto"));
00609     if(!projectFile.IsDirWritable())
00610     {
00611         return false;
00612     };
00613     switch(nc)
00614     {
00615         case NAMING_PANO:
00616             mask=wxT("panorama%d");
00617             break;
00618         case NAMING_FIRST_LAST:
00619             mask=GetFilestring(basePath,true);
00620             projectFile.SetName(mask);
00621             if(!projectFile.FileExists())
00622             {
00623                 return true;
00624             };
00625             mask=mask+wxT("_%d");
00626             break;
00627         case NAMING_FOLDER:
00628             {
00629                 wxArrayString folders=projectFile.GetDirs();
00630                 if(folders.GetCount()==0)
00631                 {
00632                     return false;
00633                 }
00634                 mask=folders.Last();
00635                 projectFile.SetName(mask);
00636                 if(!projectFile.FileExists())
00637                 {
00638                     return true;
00639                 }
00640                 mask=mask+wxT("_%d");
00641             }
00642             break;
00643         case NAMING_TEMPLATE:
00644             {
00645                 HuginBase::Panorama tempPano;
00646                 tempPano.addImage(**m_images.begin());
00647                 tempPano.addImage(**m_images.rbegin());
00648                 wxFileName newProject(getDefaultProjectName(tempPano));
00649                 mask=newProject.GetName();
00650                 projectFile.SetName(mask);
00651                 if(!projectFile.FileExists())
00652                 {
00653                     return true;
00654                 }
00655                 mask=mask+wxT("_%d");
00656             };
00657             break;
00658         default:
00659             mask=wxT("panorama%d");
00660     };
00661 
00662     projectFile.SetName(wxString::Format(mask,i));
00663     while(projectFile.FileExists())
00664     {
00665         i++;
00666         projectFile.SetName(wxString::Format(mask,i));
00667         //security fall through
00668         if(i>1000)
00669         {
00670             return false;
00671         };
00672     }
00673     return true;
00674 };
00675 
00676 wxString PossiblePano::GeneratePanorama(NamingConvention nc, bool createLinks, HuginBase::PanoramaOptions::BlendingMechanism defaultBlender)
00677 {
00678     if(m_images.empty())
00679     {
00680         return wxEmptyString;
00681     };
00682     ImageSet::const_iterator it=m_images.begin();
00683     wxFileName firstFile(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
00684     firstFile.MakeAbsolute();
00685     wxFileName projectFile;
00686     if(!GetNewProjectFilename(nc,firstFile.GetPath(),projectFile))
00687     {
00688         return wxEmptyString;
00689     };
00690     //generate panorama
00691     HuginBase::Panorama pano;
00692     for(ImageSet::iterator it=m_images.begin(); it!=m_images.end(); ++it)
00693     {
00694         pano.addImage(*(*it));
00695     };
00696     //assign all images the same lens number
00697     HuginBase::StandardImageVariableGroups variable_groups(pano);
00698     HuginBase::ImageVariableGroup& lenses = variable_groups.getLenses();
00699     if(pano.getNrOfImages()>1)
00700     {
00701         double redBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifRedBalance();
00702         double blueBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifBlueBalance();
00703         if(fabs(redBalanceAnchor)<1e-2)
00704         {
00705             redBalanceAnchor=1;
00706         };
00707         if(fabs(blueBalanceAnchor)<1e-2)
00708         {
00709             blueBalanceAnchor=1;
00710         };
00711         for(unsigned int i=1; i<pano.getNrOfImages(); i++)
00712         {
00713             SrcPanoImage img=pano.getSrcImage(i);
00714             double ev=img.getExposureValue();
00715             lenses.switchParts(i,lenses.getPartNumber(0));
00716             lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i);
00717             img.setExposureValue(ev);
00718             lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i);
00719             lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i);
00720             img.setWhiteBalanceRed(img.getExifRedBalance()/redBalanceAnchor);
00721             img.setWhiteBalanceBlue(img.getExifBlueBalance()/blueBalanceAnchor);
00722             pano.setSrcImage(i, img);
00723         };
00724     };
00725     if (pano.hasPossibleStacks())
00726     {
00727         pano.linkPossibleStacks(createLinks);
00728     };
00729     // Setup pano with options from preferences
00730     PanoramaOptions opts = pano.getOptions();
00731     //set default exposure value
00732     opts.outputExposureValue = pano.getImage(0).getExposureValue();
00733     wxConfigBase* config = wxConfigBase::Get();
00734     opts.quality = config->Read(wxT("/output/jpeg_quality"),HUGIN_JPEG_QUALITY);
00735     switch(config->Read(wxT("/output/tiff_compression"), HUGIN_TIFF_COMPRESSION))
00736     {
00737         case 0:
00738         default:
00739             opts.outputImageTypeCompression = "NONE";
00740             opts.tiffCompression = "NONE";
00741             break;
00742         case 1:
00743             opts.outputImageTypeCompression = "PACKBITS";
00744             opts.tiffCompression = "PACKBITS";
00745             break;
00746         case 2:
00747             opts.outputImageTypeCompression = "LZW";
00748             opts.tiffCompression = "LZW";
00749             break;
00750         case 3:
00751             opts.outputImageTypeCompression = "DEFLATE";
00752             opts.tiffCompression = "DEFLATE";
00753             break;
00754     }
00755     switch (config->Read(wxT("/output/ldr_format"), HUGIN_LDR_OUTPUT_FORMAT))
00756     {
00757         case 1:
00758             opts.outputImageType ="jpg";
00759             break;
00760         case 2:
00761             opts.outputImageType ="png";
00762             break;
00763         case 3:
00764             opts.outputImageType ="exr";
00765             break;
00766         default:
00767         case 0:
00768             opts.outputImageType ="tif";
00769             break;
00770     }
00771     opts.outputFormat = PanoramaOptions::TIFF_m;
00772     opts.blendMode = defaultBlender;
00773     opts.enblendOptions = config->Read(wxT("Enblend/Args"),wxT(HUGIN_ENBLEND_ARGS)).mb_str(wxConvLocal);
00774     opts.enfuseOptions = config->Read(wxT("Enfuse/Args"),wxT(HUGIN_ENFUSE_ARGS)).mb_str(wxConvLocal);
00775     opts.interpolator = (vigra_ext::Interpolator)config->Read(wxT("Nona/Interpolator"),HUGIN_NONA_INTERPOLATOR);
00776     opts.tiff_saveROI = config->Read(wxT("Nona/CroppedImages"),HUGIN_NONA_CROPPEDIMAGES)!=0;
00777     opts.hdrMergeMode = PanoramaOptions::HDRMERGE_AVERAGE;
00778     opts.hdrmergeOptions = HUGIN_HDRMERGE_ARGS;
00779     pano.setOptions(opts);
00780     // set optimizer switches
00781     pano.setOptimizerSwitch(HuginBase::OPT_POSITION);
00782     pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
00783 
00784     std::ofstream script(projectFile.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00785     script.exceptions ( std::ofstream::eofbit | std::ofstream::failbit | std::ofstream::badbit );
00786     if(!script.good())
00787     {
00788         return wxEmptyString;
00789     };
00790     HuginBase::UIntSet all;
00791     fill_set(all, 0, pano.getNrOfImages()-1);
00792     try
00793     {
00794         std::string Pathprefix(projectFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME));
00795         pano.printPanoramaScript(script, pano.getOptimizeVector(), pano.getOptions(), all, false, Pathprefix);
00796     }
00797     catch (...)
00798     {
00799         return wxEmptyString;
00800     };
00801     script.close();
00802     return projectFile.GetFullPath();
00803 };
00804 
00805 wxString PossiblePano::GetCameraName()
00806 {
00807     return wxString(m_camera.c_str(), wxConvLocal);
00808 }
00809 
00810 wxString PossiblePano::GetLensName()
00811 {
00812     return wxString(m_lens.c_str(), wxConvLocal);
00813 };
00814 
00815 wxString PossiblePano::GetFocalLength()
00816 {
00817     return wxString::Format(wxT("%0.1f mm"), m_focallength);
00818 };
00819 
00820 wxString PossiblePano::GetStartString()
00821 {
00822     return m_dt_start.Format();
00823 };
00824 
00825 wxString PossiblePano::GetDuration()
00826 {
00827     wxTimeSpan diff = m_dt_end.Subtract(m_dt_start);
00828     if (diff.GetSeconds() > 60)
00829     {
00830         return diff.Format(_("%M:%S min"));
00831     }
00832     else
00833     {
00834         return diff.Format(_("%S s"));
00835     };
00836 };
00837 
00838 void PossiblePano::PopulateListCtrl(wxListCtrl* list, wxImageList* thumbs)
00839 {
00840     list->DeleteAllItems();
00841     thumbs->RemoveAll();
00842     wxBusyCursor cursor;
00843     for (ImageSet::iterator it = m_images.begin(); it != m_images.end(); ++it)
00844     {
00845         Exiv2::Image::AutoPtr image;
00846         bool opened = false;
00847         try
00848         {
00849             image = Exiv2::ImageFactory::open((*it)->getFilename().c_str());
00850             opened = true;
00851         }
00852         catch (...)
00853         {
00854             std::cerr << __FILE__ << " " << __LINE__ << " Error opening file" << std::endl;
00855         }
00856         int index = -1;
00857         if (opened)
00858         {
00859             image->readMetadata();
00860             // read all thumbnails
00861             Exiv2::PreviewManager previews(*image);
00862             Exiv2::PreviewPropertiesList lists = previews.getPreviewProperties();
00863             if (!lists.empty())
00864             {
00865                 // select a preview with matching size
00866                 int previewIndex = 0;
00867                 while (previewIndex < lists.size() - 1 && lists[previewIndex].width_ < THUMBSIZE && lists[previewIndex].height_ < THUMBSIZE)
00868                 {
00869                     ++previewIndex;
00870                 };
00871                 // load preview image to wxImage
00872                 wxImage rawImage;
00873                 Exiv2::PreviewImage previewImage = previews.getPreviewImage(lists[previewIndex]);
00874                 wxMemoryInputStream stream(previewImage.pData(), previewImage.size());
00875                 rawImage.LoadFile(stream, wxString(previewImage.mimeType().c_str(), wxConvLocal), -1);
00876                 int x = 0;
00877                 int y = 0;
00878                 if (previewImage.width() > previewImage.height())
00879                 {
00880                     //landscape format
00881                     int newHeight = THUMBSIZE*previewImage.height() / previewImage.width();
00882                     rawImage.Rescale(THUMBSIZE, newHeight);
00883                     x = 0;
00884                     y = (THUMBSIZE - newHeight) / 2;
00885                 }
00886                 else
00887                 {
00888                     //portrait format
00889                     int newWidth = THUMBSIZE*previewImage.width() / previewImage.height();
00890                     rawImage.Rescale(newWidth, THUMBSIZE);
00891                     x = (THUMBSIZE - newWidth) / 2;
00892                     y = 0;
00893                 }
00894                 // create final bitmap with centered thumbnail
00895                 wxBitmap bitmap(THUMBSIZE, THUMBSIZE);
00896                 wxMemoryDC dc(bitmap);
00897                 dc.SetBackground(list->GetBackgroundColour());
00898                 dc.Clear();
00899                 dc.DrawBitmap(rawImage, x, y);
00900                 dc.SelectObject(wxNullBitmap);
00901                 // create mask bitmap
00902                 wxImage mask(THUMBSIZE, THUMBSIZE);
00903                 mask.SetRGB(wxRect(0, 0, THUMBSIZE, THUMBSIZE), 0, 0, 0);
00904                 mask.SetRGB(wxRect(x, y, THUMBSIZE - 2 * x, THUMBSIZE - 2 * y), 255, 255, 255);
00905                 // add to wxImageList
00906                 index = thumbs->Add(bitmap, wxBitmap(mask, 1));
00907             };
00908         };
00909         // create item in thumb list
00910         wxFileName fn(wxString((*it)->getFilename().c_str(), HUGIN_CONV_FILENAME));
00911         list->InsertItem(list->GetItemCount(), fn.GetFullName(), index);
00912     };
00913 };

Generated on 30 Jul 2015 for Hugintrunk by  doxygen 1.4.7