PanoOperation.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00009 /*  This program is free software; you can redistribute it and/or
00010  *  modify it under the terms of the GNU General Public
00011  *  License as published by the Free Software Foundation; either
00012  *  version 2 of the License, or (at your option) any later version.
00013  *
00014  *  This software is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  *  General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public
00020  *  License along with this software; if not, write to the Free Software
00021  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "hugin/PanoOperation.h"
00026 #include "hugin/config_defaults.h"
00027 #include "hugin/wxPanoCommand.h"
00028 #include "huginapp/ImageCache.h"
00029 #include "base_wx/MyProgressDialog.h"
00030 #include "base_wx/PTWXDlg.h"
00031 #include "algorithms/optimizer/ImageGraph.h"
00032 #include "algorithms/control_points/CleanCP.h"
00033 #include "celeste/Celeste.h"
00034 #include <exiv2/exif.hpp>
00035 #include <exiv2/image.hpp>
00036 #include "base_wx/LensTools.h"
00037 #include "base_wx/wxLensDB.h"
00038 #include "hugin/ResetDialog.h"
00039 #include "hugin/MainFrame.h"
00040 
00041 using namespace HuginBase;
00042 
00043 namespace PanoOperation
00044 {
00045 
00046 wxString PanoOperation::GetLabel()
00047 {
00048     return wxEmptyString;
00049 };
00050 
00051 bool PanoOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00052 {
00053     return true;
00054 };
00055 
00056 PT::PanoCommand* PanoOperation::GetCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00057 {
00058     //remember gui level, only used by some PanoOperation's
00059     m_guiLevel=guiLevel;
00060     if(IsEnabled(pano, images, m_guiLevel))
00061     {
00062         return GetInternalCommand(parent,pano,images);
00063     }
00064     else
00065     {
00066         return NULL;
00067     };
00068 };
00069 
00070 bool PanoSingleImageOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00071 {
00072     return images.size()==1;
00073 };
00074 
00075 bool PanoMultiImageOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00076 {
00077     return images.size()>0;
00078 };
00079 
00085 bool AddImageDialog(wxWindow* parent, std::vector<std::string>& files)
00086 {
00087     // get stored path
00088     wxConfigBase* config = wxConfigBase::Get();
00089     wxString path = config->Read(wxT("/actualPath"), wxT(""));
00090     wxFileDialog dlg(parent,_("Add images"),
00091                      path, wxT(""),
00092                      HUGIN_WX_FILE_IMG_FILTER,
00093                      wxFD_OPEN | wxFD_MULTIPLE, wxDefaultPosition);
00094     dlg.SetDirectory(path);
00095 
00096     // remember the image extension
00097     wxString img_ext;
00098     if (config->HasEntry(wxT("lastImageType")))
00099     {
00100       img_ext = config->Read(wxT("lastImageType")).c_str();
00101     }
00102     if (img_ext == wxT("all images"))
00103       dlg.SetFilterIndex(0);
00104     else if (img_ext == wxT("jpg"))
00105       dlg.SetFilterIndex(1);
00106     else if (img_ext == wxT("tiff"))
00107       dlg.SetFilterIndex(2);
00108     else if (img_ext == wxT("png"))
00109       dlg.SetFilterIndex(3);
00110     else if (img_ext == wxT("hdr"))
00111       dlg.SetFilterIndex(4);
00112     else if (img_ext == wxT("exr"))
00113       dlg.SetFilterIndex(5);
00114     else if (img_ext == wxT("all files"))
00115       dlg.SetFilterIndex(6);
00116 
00117     // call the file dialog
00118     if (dlg.ShowModal() == wxID_OK)
00119     {
00120         // get the selections
00121         wxArrayString Pathnames;
00122         dlg.GetPaths(Pathnames);
00123 
00124         // remember path for later
00125 #ifdef __WXGTK__
00126         //workaround a bug in GTK, see https://bugzilla.redhat.com/show_bug.cgi?id=849692 and http://trac.wxwidgets.org/ticket/14525
00127         config->Write(wxT("/actualPath"), wxPathOnly(Pathnames[0]));
00128 #else
00129         config->Write(wxT("/actualPath"), dlg.GetDirectory());
00130 #endif
00131         // save the image extension
00132         switch (dlg.GetFilterIndex())
00133         {
00134             case 0: config->Write(wxT("lastImageType"), wxT("all images")); break;
00135             case 1: config->Write(wxT("lastImageType"), wxT("jpg")); break;
00136             case 2: config->Write(wxT("lastImageType"), wxT("tiff")); break;
00137             case 3: config->Write(wxT("lastImageType"), wxT("png")); break;
00138             case 4: config->Write(wxT("lastImageType"), wxT("hdr")); break;
00139             case 5: config->Write(wxT("lastImageType"), wxT("exr")); break;
00140             case 6: config->Write(wxT("lastImageType"), wxT("all files")); break;
00141         }
00142 
00143         //check for forbidden/non working chars
00144         wxArrayString invalidFiles;
00145         for(unsigned int i=0;i<Pathnames.GetCount(); i++)
00146         {
00147            if(containsInvalidCharacters(Pathnames[i]))
00148            {
00149                invalidFiles.Add(Pathnames[i]);
00150            };
00151         };
00152         if(invalidFiles.size()>0)
00153         {
00154             ShowFilenameWarning(parent, invalidFiles);
00155             return false;
00156         }
00157         for (unsigned int i=0; i<Pathnames.GetCount(); i++)
00158         {
00159             files.push_back((const char *)Pathnames[i].mb_str(HUGIN_CONV_FILENAME));
00160         };
00161         return true;
00162     };
00163     return false;
00164 };
00165 
00166 wxString AddImageOperation::GetLabel()
00167 {
00168     return _("Add individual images...");
00169 };
00170 
00171 PT::PanoCommand* AddImageOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00172 {
00173     std::vector<std::string> files;
00174     if(AddImageDialog(parent, files))
00175     {
00176         if(files.size()>0)
00177         {
00178             return new PT::wxAddImagesCmd(pano,files);
00179         };
00180     };
00181     return NULL;
00182 };
00183 
00184 WX_DECLARE_STRING_HASH_MAP(time_t, StringToPointerHash);
00185 WX_DECLARE_STRING_HASH_MAP(int, StringToFlagHash);
00186 
00187 time_t ReadExifTime(const char* filename)
00188 {
00189     Exiv2::Image::AutoPtr image;
00190     try
00191     {
00192         image = Exiv2::ImageFactory::open(filename);
00193     }
00194     catch(...)
00195     {
00196         return 0;
00197     }
00198     if (image.get() == 0)
00199     {
00200         return 0;
00201     }
00202 
00203     image->readMetadata();
00204     Exiv2::ExifData &exifData = image->exifData();
00205     if (exifData.empty())
00206     {
00207         return 0;
00208     }
00209 
00210     Exiv2::Exifdatum& tag = exifData["Exif.Image.DateTime"];
00211     const std::string date_time = tag.toString();
00212 
00213     // Remember the file and a shutter timestamp.
00214     struct tm when;
00215     memset(&when, 0, sizeof(when));
00216     when.tm_wday = -1;
00217 
00218     // parse into the tm_structure
00219     const int a = sscanf(date_time.c_str(), "%d:%d:%d %d:%d:%d",
00220             &when.tm_year, &when.tm_mon, &when.tm_mday,
00221             &when.tm_hour, &when.tm_min, &when.tm_sec);
00222 
00223     if (a == 6)
00224     {
00225         when.tm_isdst = -1;
00226         when.tm_mon -= 1;      // Adjust for unix zero-based months
00227         when.tm_year -= 1900;  // Adjust for year starting at 1900
00228     }
00229     else
00230     {
00231         // Not in EXIF format
00232         return 0;
00233     }
00234 
00235     time_t stamp;
00236     stamp = mktime(&when);
00237     if (stamp == (time_t)(-1))
00238         return 0;
00239 
00240     return stamp;
00241 }
00242 
00243 struct sortbytime
00244 {
00245     sortbytime(map<string, time_t> & h) : m_time(h) {};
00246     bool operator()(const std::string & s1, const std::string & s2)
00247     {
00248         time_t t1 = m_time[s1];
00249         time_t t2 = m_time[s2];
00250         return t1 < t2;
00251     };
00252     map<string, time_t> & m_time;
00253 };
00254 
00255 wxString AddImagesSeriesOperation::GetLabel()
00256 {
00257     return _("Add time-series of images...");
00258 };
00259 
00260 PT::PanoCommand* AddImagesSeriesOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00261 {
00262     //load image if pano contains no images
00263     std::vector<std::string> files;
00264     if(pano.getNrOfImages()==0)
00265     {
00266         if(!AddImageDialog(parent,files))
00267         {
00268             return NULL;
00269         };
00270         //just in case
00271         if(files.size()==0)
00272         {
00273             return NULL;
00274         };
00275     }
00276     else
00277     {
00278         for(size_t i=0;i<pano.getNrOfImages();i++)
00279         {
00280             files.push_back(pano.getImage(i).getFilename());
00281         };
00282     };
00283 
00284     DEBUG_TRACE("seeking similarly timed images");
00285 
00286     // Collect potential image-mates.
00287     StringToPointerHash filenames;
00288     StringToFlagHash preloaded;
00289     for(size_t i=0;i<files.size();i++)
00290     {
00291         wxString file(files[i].c_str(), HUGIN_CONV_FILENAME);
00292         preloaded[file] = 1;
00293 
00294         // Glob for all files of same type in same directory.
00295         wxString path = ::wxPathOnly(file) + wxT("/*");
00296         file = ::wxFindFirstFile(path);
00297         while (!file.IsEmpty())
00298         {
00299             // Associated with a NULL dummy timestamp for now.
00300             if(vigra::isImage(files[i].c_str()))
00301             {
00302                 filenames[file] = 0;
00303             };
00304             file = ::wxFindNextFile();
00305         }
00306     }
00307 
00308     DEBUG_INFO("found " << filenames.size() << " candidate files to search.");
00309 
00310     // For each globbed or loaded file,
00311     StringToPointerHash::iterator found;
00312     std::map<std::string, time_t> timeMap;
00313     for (found = filenames.begin(); found != filenames.end(); found++)
00314     {
00315         wxString file = found->first;
00316         // Check the time if it's got a camera EXIF timestamp.
00317         time_t stamp = ReadExifTime(file.mb_str(HUGIN_CONV_FILENAME));
00318         if (stamp)
00319         {
00320             filenames[file] = stamp;
00321             timeMap[(const char *)file.mb_str(HUGIN_CONV_FILENAME)] = stamp;
00322         }
00323     }
00324 
00325     //TODO: sorting the filenames keys by timestamp would be useful
00326     int maxtimediff = wxConfigBase::Get()->Read(wxT("CaptureTimeSpan"), HUGIN_CAPTURE_TIMESPAN);
00327     // For each timestamped file,
00328     for (found = filenames.begin(); found != filenames.end(); found++)
00329     {
00330         wxString recruit = found->first;
00331         if (preloaded[recruit] == 1)
00332             continue;
00333         time_t pledge = filenames[recruit];
00334         if (!pledge)
00335             continue;
00336 
00337         // For each other image already loaded,
00338         for(size_t i=0;i<files.size();i++)
00339         {
00340             wxString file(files[i].c_str(), HUGIN_CONV_FILENAME);
00341             if (file == recruit)
00342                 continue;
00343 
00344             // If it is within threshold time,
00345             time_t stamp = filenames[file];
00346             if (abs((int)(pledge - stamp)) < maxtimediff)
00347             {
00348                 // Load this file, and remember it.
00349                 DEBUG_TRACE("Recruited " << recruit.mb_str(wxConvLocal));
00350                 std::string file = (const char *)recruit.mb_str(HUGIN_CONV_FILENAME);
00351                 files.push_back(file);
00352                 // Don't recruit it again.
00353                 filenames[recruit] = 0;
00354                 break;
00355             }
00356         }
00357     }
00358 
00359     if(files.size()>0)
00360     {
00361         // sort files by date
00362         sortbytime spred(timeMap);
00363         sort(files.begin(), files.end(), spred);
00364         // Load all of the named files.
00365         return new PT::wxAddImagesCmd(pano,files);
00366     }
00367     else
00368     {
00369         wxMessageBox(
00370             _("No matching images found."),
00371 #ifdef _WINDOWS
00372             _("Hugin"),
00373 #else
00374             wxT(""),
00375 #endif
00376             wxOK | wxICON_INFORMATION, parent);
00377         return NULL;
00378     };
00379 };
00380 
00381 wxString RemoveImageOperation::GetLabel()
00382 {
00383     return _("Remove selected image(s)");
00384 };
00385 
00386 PT::PanoCommand* RemoveImageOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00387 {
00388     //remove images from cache
00389     for (UIntSet::iterator it = images.begin(); it != images.end(); ++it)
00390     {
00391         ImageCache::getInstance().removeImage(pano.getImage(*it).getFilename());
00392     }
00393     return new PT::RemoveImagesCmd(pano, images);
00394 };
00395 
00396 wxString ChangeAnchorImageOperation::GetLabel()
00397 {
00398     return _("Anchor this image for position");
00399 };
00400 
00401 PT::PanoCommand* ChangeAnchorImageOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00402 {
00403     PanoramaOptions opt = pano.getOptions();
00404     opt.optimizeReferenceImage = *(images.begin());
00405     return new PT::SetPanoOptionsCmd(pano,opt);
00406 };
00407 
00408 wxString ChangeColorAnchorImageOperation::GetLabel()
00409 {
00410     return _("Anchor this image for exposure");
00411 };
00412 
00413 PT::PanoCommand* ChangeColorAnchorImageOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00414 {
00415     PanoramaOptions opt = pano.getOptions();
00416     opt.colorReferenceImage = *(images.begin());
00417     // Set the color correction mode so that the anchor image is persisted
00418     if (opt.colorCorrection == 0)
00419     {
00420         opt.colorCorrection = (PanoramaOptions::ColorCorrection) 1;
00421     }
00422     return new PT::SetPanoOptionsCmd(pano, opt);
00423 };
00424 
00425 bool NewLensOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00426 {
00427     if(pano.getNrOfImages()==0 || images.size()==0)
00428     {
00429         return false;
00430     }
00431     else
00432     {
00433         HuginBase::StandardImageVariableGroups variable_groups(pano);
00434         return variable_groups.getLenses().getNumberOfParts()<pano.getNrOfImages();
00435     };
00436 };
00437 
00438 wxString NewLensOperation::GetLabel()
00439 {
00440     return _("New lens");
00441 };
00442 
00443 PT::PanoCommand* NewLensOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00444 {
00445     return new PT::NewPartCmd(pano, images, HuginBase::StandardImageVariableGroups::getLensVariables());
00446 };
00447 
00448 bool ChangeLensOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00449 {
00450     if(pano.getNrOfImages()==0 || images.size()==0)
00451     {
00452         return false;
00453     }
00454     else
00455     {
00456         //project must have more than 1 lens before you can assign an other lens number
00457         HuginBase::StandardImageVariableGroups variableGroups(pano);
00458         return variableGroups.getLenses().getNumberOfParts() > 1;
00459     };
00460 };
00461 
00462 wxString ChangeLensOperation::GetLabel()
00463 {
00464     return _("Change lens...");
00465 };
00466 
00467 PT::PanoCommand* ChangeLensOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00468 {
00469     HuginBase::StandardImageVariableGroups variable_groups(pano);
00470     long nr = wxGetNumberFromUser(
00471                             _("Enter new lens number"),
00472                             _("Lens number"),
00473                             _("Change lens number"), 0, 0,
00474                             variable_groups.getLenses().getNumberOfParts()-1
00475                                  );
00476     if (nr >= 0)
00477     {
00478         // user accepted
00479         return new PT::ChangePartNumberCmd(pano, images, nr, HuginBase::StandardImageVariableGroups::getLensVariables());
00480     }
00481     else
00482     {
00483         return NULL;
00484     };
00485 };
00486 
00487 LoadLensOperation::LoadLensOperation(bool fromLensfunDB)
00488 {
00489     m_fromLensfunDB=fromLensfunDB;
00490 };
00491 
00492 wxString LoadLensOperation::GetLabel()
00493 {
00494     if(m_fromLensfunDB)
00495     {
00496         return _("Load lens from Lensfun database");
00497     }
00498     else
00499     {
00500         return _("Load lens from ini file");
00501     };
00502 };
00503 
00504 PT::PanoCommand* LoadLensOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00505 {
00506     HuginBase::StandardImageVariableGroups variable_groups(pano);
00507     if(images.size()==1)
00508     {
00509         if(wxMessageBox(_("You selected only one image.\nShould the loaded parameters be applied to all images with the same lens?"),_("Question"), wxICON_QUESTION | wxYES_NO)==wxYES)
00510         {
00511             unsigned int lensNr = variable_groups.getLenses().getPartNumber(*images.begin());
00512             // get all images with the current lens.
00513             for (size_t i = 0; i < pano.getNrOfImages(); i++)
00514             {
00515                 if (variable_groups.getLenses().getPartNumber(i) == lensNr)
00516                 {
00517                     images.insert(i);
00518                 };
00519             };
00520         };
00521     };
00522     vigra::Size2D sizeImg0=pano.getImage(*(images.begin())).getSize();
00523     //check if all images have the same size
00524     bool differentImageSize=false;
00525     for(UIntSet::const_iterator it=images.begin();it!=images.end() && !differentImageSize;it++)
00526     {
00527         differentImageSize=(pano.getImage(*it).getSize()!=sizeImg0);
00528     };
00529     if(differentImageSize)
00530     {
00531         if(wxMessageBox(_("You selected images with different sizes.\nApply lens parameter file can result in unwanted results.\nApply settings anyway?"), _("Error"), wxICON_QUESTION |wxYES_NO)==wxID_NO)
00532         {
00533             return NULL;
00534         };
00535     };
00536     PT::PanoCommand* cmd=NULL;
00537     bool isLoaded=false;
00538     if(m_fromLensfunDB)
00539     {
00540         isLoaded=ApplyLensDBParameters(parent,&pano,images,cmd);
00541     }
00542     else
00543     {
00544         isLoaded=ApplyLensParameters(parent,&pano,images,cmd);
00545     };
00546     if(isLoaded)
00547     {
00548         return cmd;
00549     }
00550     else
00551     {
00552         return NULL;
00553     }
00554 };
00555 
00556 SaveLensOperation::SaveLensOperation(int lensInfo)
00557 {
00558     m_lensInfo=lensInfo;
00559 };
00560 
00561 wxString SaveLensOperation::GetLabel()
00562 {
00563     switch(m_lensInfo)
00564     {
00565         case 0:
00566             return _("Save lens to ini file");
00567             break;
00568         case 1:
00569             return _("Save lens parameters to lensfun database");
00570             break;
00571         case 2:
00572             return _("Save camera parameters to lensfun database");
00573             break;
00574     }
00575     return wxEmptyString;
00576 };
00577 
00578 PT::PanoCommand* SaveLensOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00579 {
00580     unsigned int imgNr = *(images.begin());
00581     switch(m_lensInfo)
00582     {
00583         case 1:
00584             SaveLensParameters(parent,pano.getImage(imgNr));
00585             break;
00586         case 2:
00587             SaveCameraCropFactor(parent,pano.getImage(imgNr));
00588             break;
00589         case 0:
00590         default:
00591             SaveLensParametersToIni(parent, &pano, images);
00592             break;
00593     };
00594     return NULL;
00595 };
00596 
00597 wxString RemoveControlPointsOperation::GetLabel()
00598 {
00599     return _("Remove control points");
00600 };
00601 
00602 bool RemoveControlPointsOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00603 {
00604     return pano.getNrOfImages()>0 && pano.getNrOfCtrlPoints()>0;
00605 };
00606 
00607 PT::PanoCommand* RemoveControlPointsOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00608 {
00609     UIntSet selImages;
00610     if(images.size()==0)
00611     {
00612         fill_set(selImages,0,pano.getNrOfCtrlPoints()-1);
00613     }
00614     else
00615     {
00616         selImages=images;
00617     };
00618     UIntSet cpsToDelete;
00619     const CPVector & cps = pano.getCtrlPoints();
00620     for (CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
00621     {
00622         if (set_contains(selImages, (*it).image1Nr) && set_contains(selImages, (*it).image2Nr) )
00623         {
00624             cpsToDelete.insert(it - cps.begin());
00625         }
00626     }
00627     if(cpsToDelete.size()==0)
00628     {
00629         wxMessageBox(_("Selected images have no control points."),
00630 #ifdef __WXMSW__
00631             wxT("Hugin"),
00632 #else
00633             wxT(""),
00634 #endif
00635             wxICON_EXCLAMATION | wxOK);
00636         return NULL;
00637     };
00638     int r =wxMessageBox(wxString::Format(_("Really delete %lu control points?"),
00639                                          (unsigned long int) cpsToDelete.size()),
00640                         _("Delete Control Points"),
00641                         wxICON_QUESTION | wxYES_NO);
00642     if (r == wxYES)
00643     {
00644         return new PT::RemoveCtrlPointsCmd(pano, cpsToDelete );
00645     }
00646     else
00647     {
00648         return NULL;
00649     };
00650 };
00651 
00652 wxString CleanControlPointsOperation::GetLabel()
00653 {
00654     return _("Clean control points");
00655 };
00656 
00657 bool CleanControlPointsOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00658 {
00659     return pano.getNrOfCtrlPoints()>2;
00660 };
00661 
00662 PT::PanoCommand* CleanControlPointsOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00663 {
00664     deregisterPTWXDlgFcn();
00665     // work around a flaw in wxProgresDialog that results in incorrect layout
00666     // by pre-allocting sufficient horizontal space
00667     ProgressReporterDialog progress(2, _("Cleaning Control points"), _("Checking pairwise")+wxString((wxChar)' ',10),parent, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_ELAPSED_TIME);
00668     UIntSet removedCPs=getCPoutsideLimit_pair(pano,2.0);
00669 
00670     //create a copy to work with
00671     //we copy remaining control points to new pano object for running second step
00672     HuginBase::Panorama newPano=pano.duplicate();
00673     std::map<size_t,size_t> cpMap;
00674     CPVector allCPs=newPano.getCtrlPoints();
00675     CPVector firstCleanedCP;
00676     size_t j=0;
00677     for(size_t i=0;i<allCPs.size();i++)
00678     {
00679         ControlPoint cp=allCPs[i];
00680         if(cp.mode==ControlPoint::X_Y && !set_contains(removedCPs,i))
00681         {
00682             firstCleanedCP.push_back(cp);
00683             cpMap[j++]=i;
00684         };
00685     };
00686     newPano.setCtrlPoints(firstCleanedCP);
00687 
00688     //check for unconnected images
00689     CPGraph graph;
00690     createCPGraph(newPano, graph);
00691     CPComponents comps;
00692     int n=findCPComponents(graph, comps);
00693     progress.increaseProgress(1, std::wstring(wxString(_("Checking whole project")).wc_str(wxConvLocal)));
00694     if (n <= 1)
00695     {
00696         //now run the second step
00697         UIntSet removedCP2=getCPoutsideLimit(newPano,2.0);
00698         if(removedCP2.size()>0)
00699         {
00700             for(UIntSet::const_iterator it=removedCP2.begin();it!=removedCP2.end();it++)
00701             {
00702                 removedCPs.insert(cpMap[*it]);
00703             };
00704         };
00705     }
00706     progress.increaseProgress(1, std::wstring(wxString(_("Finished cleaning")).wc_str(wxConvLocal)));
00707     registerPTWXDlgFcn(MainFrame::Get());
00708     if(removedCPs.size()>0)
00709     {
00710         wxMessageBox(wxString::Format(_("Removed %lu control points"), removedCPs.size()), _("Cleaning"),wxOK|wxICON_INFORMATION,parent);
00711         return new PT::RemoveCtrlPointsCmd(pano,removedCPs);
00712     };
00713     return NULL;
00714 };
00715 
00716 wxString CelesteOperation::GetLabel()
00717 {
00718     return _("Remove control points on clouds");
00719 };
00720 
00721 PT::PanoCommand* CelesteOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00722 {
00723     ProgressReporterDialog progress(images.size()+2, _("Running Celeste"), _("Running Celeste"),parent);
00724     MainFrame::Get()->SetStatusText(_("searching for cloud-like control points..."),0);
00725     progress.increaseProgress(1.0, std::wstring(wxString(_("Loading model file")).wc_str(wxConvLocal)));
00726 
00727     struct celeste::svm_model* model=MainFrame::Get()->GetSVMModel();
00728     if(model==NULL)
00729     {
00730         MainFrame::Get()->SetStatusText(wxT(""),0);
00731         return NULL;
00732     };
00733 
00734     // Get Celeste parameters
00735     wxConfigBase *cfg = wxConfigBase::Get();
00736     // SVM threshold
00737     double threshold = HUGIN_CELESTE_THRESHOLD;
00738     cfg->Read(wxT("/Celeste/Threshold"), &threshold, HUGIN_CELESTE_THRESHOLD);
00739 
00740     // Mask resolution - 1 sets it to fine
00741     bool t = (cfg->Read(wxT("/Celeste/Filter"), HUGIN_CELESTE_FILTER) == 0);
00742     int radius=(t)?10:20;
00743     DEBUG_TRACE("Running Celeste");
00744 
00745     UIntSet cpsToRemove;
00746     for (UIntSet::const_iterator it=images.begin(); it!=images.end(); it++)
00747     {
00748         // Image to analyse
00749         HuginBase::CPointVector cps=pano.getCtrlPointsVectorForImage(*it);
00750         if(cps.size()==0)
00751         {
00752             progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
00753             continue;
00754         };
00755         ImageCache::EntryPtr img=ImageCache::getInstance().getImage(pano.getImage(*it).getFilename());
00756         vigra::UInt16RGBImage in;
00757         if(img->image16->width()>0)
00758         {
00759             in.resize(img->image16->size());
00760             vigra::copyImage(srcImageRange(*(img->image16)),destImage(in));
00761         }
00762         else
00763         {
00764             ImageCache::ImageCacheRGB8Ptr im8=img->get8BitImage();
00765             in.resize(im8->size());
00766             vigra::transformImage(srcImageRange(*im8),destImage(in),vigra::functor::Arg1()*vigra::functor::Param(65535/255));
00767         };
00768         UIntSet cloudCP=celeste::getCelesteControlPoints(model,in,cps,radius,threshold,800);
00769         in.resize(0,0);
00770         if(cloudCP.size()>0)
00771         {
00772             for(UIntSet::const_iterator it2=cloudCP.begin();it2!=cloudCP.end();it2++)
00773             {
00774                 cpsToRemove.insert(*it2);
00775             };
00776         };
00777         progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
00778     };
00779 
00780     progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
00781     if(cpsToRemove.size()>0)
00782     {
00783         wxMessageBox(wxString::Format(_("Removed %lu control points"), (unsigned long int) cpsToRemove.size()), _("Celeste result"),wxOK|wxICON_INFORMATION);
00784         MainFrame::Get()->SetStatusText(wxT(""),0);
00785         return new PT::RemoveCtrlPointsCmd(pano,cpsToRemove);
00786     }
00787     else
00788     {
00789         MainFrame::Get()->SetStatusText(wxT(""),0);
00790         return NULL;
00791     };
00792 };
00793 
00794 ResetOperation::ResetOperation(ResetMode newResetMode)
00795 {
00796     m_resetMode=newResetMode;
00797     m_resetPos=(m_resetMode==RESET_POSITION);
00798     m_resetTranslation=(m_resetMode==RESET_TRANSLATION);
00799     m_resetHFOV=(m_resetMode==RESET_LENS);
00800     m_resetLens=(m_resetMode==RESET_LENS);
00801     m_resetExposure=0;
00802     if(m_resetMode==RESET_PHOTOMETRICS)
00803     {
00804         m_resetExposure=1;
00805     };
00806     m_resetVignetting=(m_resetMode==RESET_PHOTOMETRICS);
00807     m_resetColor=(m_resetMode==RESET_PHOTOMETRICS);
00808     m_resetCameraResponse=(m_resetMode==RESET_PHOTOMETRICS);
00809 };
00810 
00811 wxString ResetOperation::GetLabel()
00812 {
00813     switch(m_resetMode)
00814     {
00815         case RESET_DIALOG:
00816         case RESET_DIALOG_LENS:
00817         case RESET_DIALOG_PHOTOMETRICS:
00818             return _("Reset user defined...");
00819             break;
00820         case RESET_POSITION:
00821             return _("Reset positions");
00822             break;
00823         case RESET_TRANSLATION:
00824             return _("Reset translation parameters");
00825             break;
00826         case RESET_LENS:
00827             return _("Reset lens parameters");
00828             break;
00829         case RESET_PHOTOMETRICS:
00830             return _("Reset photometric parameters");
00831     };
00832     return wxEmptyString;
00833 };
00834 
00835 bool ResetOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
00836 {
00837     switch(m_resetMode)
00838     {
00839         case RESET_TRANSLATION:
00840             return guiLevel>=GUI_EXPERT && pano.getNrOfImages()>0;
00841             break;
00842         default:
00843             return pano.getNrOfImages()>0;
00844     };
00845 };
00846 
00847 PT::PanoCommand* ResetOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
00848 {
00849     if(m_resetMode==RESET_DIALOG || m_resetMode==RESET_DIALOG_LENS || m_resetMode==RESET_DIALOG_PHOTOMETRICS)
00850     {
00851         if(!ShowDialog(parent))
00852         {
00853             return NULL;
00854         };
00855     };
00856     if(images.size()==0)
00857     {
00858         fill_set(images,0,pano.getNrOfImages()-1);
00859     };
00860     // If we should unlink exposure value (to load it from EXIF)
00861     bool needs_unlink = false;
00862     VariableMapVector vars;
00863     for(UIntSet::const_iterator it = images.begin(); it != images.end(); it++)
00864     {
00865         unsigned int imgNr = *it;
00866         VariableMap ImgVars=pano.getImageVariables(imgNr);
00867         if(m_resetPos)
00868         {
00869             map_get(ImgVars,"y").setValue(0);
00870             map_get(ImgVars,"p").setValue(0);
00871             map_get(ImgVars,"r").setValue(pano.getSrcImage(imgNr).getExifOrientation());
00872             map_get(ImgVars,"TrX").setValue(0);
00873             map_get(ImgVars,"TrY").setValue(0);
00874             map_get(ImgVars,"TrZ").setValue(0);
00875             map_get(ImgVars,"Tpy").setValue(0);
00876             map_get(ImgVars,"Tpp").setValue(0);
00877         };
00878         if(m_resetTranslation)
00879         {
00880             map_get(ImgVars,"TrX").setValue(0);
00881             map_get(ImgVars,"TrY").setValue(0);
00882             map_get(ImgVars,"TrZ").setValue(0);
00883             map_get(ImgVars,"Tpy").setValue(0);
00884             map_get(ImgVars,"Tpp").setValue(0);
00885         };
00886         double cropFactor = 0;
00887         double focalLength = 0;
00888         double eV = 0;
00889         SrcPanoImage srcImg = pano.getSrcImage(imgNr);
00890         if(m_resetHFOV || m_resetExposure>0)
00891         {
00892             srcImg.readEXIF(focalLength,cropFactor,eV,false,false);
00893         };
00894         if(m_resetHFOV)
00895         {
00896             if(focalLength!=0&&cropFactor!=0)
00897             {
00898                 double newHFOV=calcHFOV(srcImg.getProjection(),focalLength,cropFactor,srcImg.getSize());
00899                 if(newHFOV!=0)
00900                 {
00901                     map_get(ImgVars,"v").setValue(newHFOV);
00902                 };
00903             };
00904         };
00905         if(m_resetLens)
00906         {
00907             map_get(ImgVars,"a").setValue(0);
00908             map_get(ImgVars,"b").setValue(0);
00909             map_get(ImgVars,"c").setValue(0);
00910             map_get(ImgVars,"d").setValue(0);
00911             map_get(ImgVars,"e").setValue(0);
00912             map_get(ImgVars,"g").setValue(0);
00913             map_get(ImgVars,"t").setValue(0);
00914         };
00915         if(m_resetExposure>0)
00916         {
00917             if(m_resetExposure==1)
00918             {
00919                 //reset to exif value
00920                 
00921                 if (pano.getImage(*it).ExposureValueisLinked())
00922                 {
00923                     /* Unlink exposure value variable so the EXIF values can be
00924                      * independant. */
00925                     needs_unlink = true;
00926                 }
00927                 if(eV!=0)
00928                     map_get(ImgVars,"Eev").setValue(eV);
00929             }
00930             else
00931             {
00932                 //reset to zero
00933                 map_get(ImgVars,"Eev").setValue(0);
00934             };
00935         };
00936         if(m_resetColor)
00937         {
00938             map_get(ImgVars,"Er").setValue(1);
00939             map_get(ImgVars,"Eb").setValue(1);
00940         };
00941         if(m_resetVignetting)
00942         {
00943             map_get(ImgVars,"Vb").setValue(0);
00944             map_get(ImgVars,"Vc").setValue(0);
00945             map_get(ImgVars,"Vd").setValue(0);
00946             map_get(ImgVars,"Vx").setValue(0);
00947             map_get(ImgVars,"Vy").setValue(0);
00948 
00949         };
00950         if(m_resetCameraResponse)
00951         {
00952             map_get(ImgVars,"Ra").setValue(0);
00953             map_get(ImgVars,"Rb").setValue(0);
00954             map_get(ImgVars,"Rc").setValue(0);
00955             map_get(ImgVars,"Rd").setValue(0);
00956             map_get(ImgVars,"Re").setValue(0);
00957         };
00958         vars.push_back(ImgVars);
00959     };
00960     std::vector<PT::PanoCommand *> reset_commands;
00961     if (needs_unlink)
00962     {
00963         std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
00964         variables.insert(HuginBase::ImageVariableGroup::IVE_ExposureValue);
00965         
00966         reset_commands.push_back(
00967                 new ChangePartImagesLinkingCmd(
00968                             pano,
00969                             images,
00970                             variables,
00971                             false,
00972                             HuginBase::StandardImageVariableGroups::getLensVariables())
00973                 );
00974     }
00975     reset_commands.push_back(
00976                             new PT::UpdateImagesVariablesCmd(pano, images, vars)
00977                                            );
00978     if(m_resetExposure>0)
00979     {
00980         //reset panorama output exposure value
00981         reset_commands.push_back(new PT::ResetToMeanExposure(pano));
00982     };
00983     return new PT::CombinedPanoCommand(pano, reset_commands);
00984 };
00985 
00986 bool ResetOperation::ShowDialog(wxWindow* parent)
00987 {
00988     ResetDialog reset_dlg(parent, m_guiLevel);
00989     bool checkGeometric;
00990     bool checkPhotometric;
00991     switch(m_resetMode)
00992     {
00993         case RESET_DIALOG:
00994             checkGeometric=true;
00995             checkPhotometric=true;
00996             break;
00997         case RESET_DIALOG_LENS:
00998             reset_dlg.LimitToGeometric();
00999             checkGeometric=true;
01000             checkPhotometric=false;
01001             break;
01002         case RESET_DIALOG_PHOTOMETRICS:
01003             reset_dlg.LimitToPhotometric();
01004             checkGeometric=false;
01005             checkPhotometric=true;
01006     };
01007     if(reset_dlg.ShowModal()==wxID_OK)
01008     {
01009         if(checkGeometric)
01010         {
01011             m_resetPos=reset_dlg.GetResetPos();
01012             m_resetTranslation=reset_dlg.GetResetTranslation();
01013             m_resetHFOV=reset_dlg.GetResetFOV();
01014             m_resetLens=reset_dlg.GetResetLens();
01015         };
01016         if(checkPhotometric)
01017         {
01018             if(reset_dlg.GetResetExposure())
01019             {
01020                 if(reset_dlg.GetResetExposureToExif())
01021                 {
01022                     m_resetExposure=1;
01023                 }
01024                 else
01025                 {
01026                     m_resetExposure=2;
01027                 };
01028             }
01029             else
01030             {
01031                 m_resetExposure=0;
01032             };
01033             m_resetVignetting=reset_dlg.GetResetVignetting();
01034             m_resetColor=reset_dlg.GetResetColor();
01035             m_resetCameraResponse=reset_dlg.GetResetResponse();
01036         };
01037         return true;
01038     }
01039     else
01040     {
01041         return false;
01042     };
01043 };
01044 
01045 bool NewStackOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
01046 {
01047     if(pano.getNrOfImages()==0 || images.size()==0)
01048     {
01049         return false;
01050     }
01051     else
01052     {
01053         HuginBase::StandardImageVariableGroups variable_groups(pano);
01054         return variable_groups.getStacks().getNumberOfParts()<pano.getNrOfImages();
01055     };
01056 };
01057 
01058 wxString NewStackOperation::GetLabel()
01059 {
01060     return _("New stack");
01061 };
01062 
01063 PT::PanoCommand* NewStackOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
01064 {
01065     return new PT::NewPartCmd(pano, images, HuginBase::StandardImageVariableGroups::getStackVariables());
01066 };
01067 
01068 bool ChangeStackOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
01069 {
01070     if(pano.getNrOfImages()==0 || images.size()==0)
01071     {
01072         return false;
01073     }
01074     else
01075     {
01076         //project must have more than 1 stack before you can assign an other stack number
01077         HuginBase::StandardImageVariableGroups variableGroups(pano);
01078         return variableGroups.getStacks().getNumberOfParts() > 1;
01079     };
01080 };
01081 
01082 wxString ChangeStackOperation::GetLabel()
01083 {
01084     return _("Change stack...");
01085 };
01086 
01087 PT::PanoCommand* ChangeStackOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
01088 {
01089     HuginBase::StandardImageVariableGroups variable_groups(pano);
01090     long nr = wxGetNumberFromUser(
01091                             _("Enter new stack number"),
01092                             _("stack number"),
01093                             _("Change stack number"), 0, 0,
01094                             variable_groups.getStacks().getNumberOfParts()-1
01095                                  );
01096     if (nr >= 0)
01097     {
01098         // user accepted
01099         return new PT::ChangePartNumberCmd(pano, images, nr, HuginBase::StandardImageVariableGroups::getStackVariables());
01100     }
01101     else
01102     {
01103         return NULL;
01104     };
01105 };
01106 
01107 bool AssignStacksOperation::IsEnabled(PT::Panorama& pano, HuginBase::UIntSet images, GuiLevel guiLevel)
01108 {
01109     return pano.getNrOfImages()>1;
01110 };
01111 
01112 wxString AssignStacksOperation::GetLabel()
01113 {
01114     return _("Set stack size...");
01115 };
01116 
01117 PT::PanoCommand* AssignStacksOperation::GetInternalCommand(wxWindow* parent, PT::Panorama& pano, HuginBase::UIntSet images)
01118 {
01119     long stackSize = wxGetNumberFromUser(
01120                             _("Enter image count per stack"),
01121                             _("stack size"),
01122                             _("Images per stack"), 3, 1,
01123                             pano.getNrOfImages()
01124                                  );
01125     if(stackSize<0)
01126     {
01127         return NULL;
01128     };
01129     std::vector<PT::PanoCommand *> commands;
01130     HuginBase::StandardImageVariableGroups variable_groups(pano);
01131     if(variable_groups.getStacks().getNumberOfParts()<pano.getNrOfImages())
01132     {
01133         // first remove all existing stacks
01134         for(size_t i=1; i<pano.getNrOfImages(); i++)
01135         {
01136             UIntSet imgs;
01137             imgs.insert(i);
01138             commands.push_back(new PT::NewPartCmd(pano, imgs, HuginBase::StandardImageVariableGroups::getStackVariables()));
01139         };
01140     };
01141 
01142     if (stackSize > 1)
01143     {
01144         size_t stackNr=0;
01145         size_t imgNr=0;
01146         while(imgNr<pano.getNrOfImages())
01147         {
01148             UIntSet imgs;
01149             for(size_t i=0; i<stackSize && imgNr<pano.getNrOfImages(); i++)
01150             {
01151                 imgs.insert(imgNr);
01152                 imgNr++;
01153             };
01154             commands.push_back(new PT::ChangePartNumberCmd(pano, imgs, stackNr, HuginBase::StandardImageVariableGroups::getStackVariables()));
01155             stackNr++;
01156         };
01157     };
01158     return new PT::CombinedPanoCommand(pano, commands);
01159 };
01160 
01161 static PanoOperationVector PanoOpImages;
01162 static PanoOperationVector PanoOpLens;
01163 static PanoOperationVector PanoOpStacks;
01164 static PanoOperationVector PanoOpControlPoints;
01165 static PanoOperationVector PanoOpReset;
01166 
01167 PanoOperationVector* GetImagesOperationVector()
01168 {
01169     return &PanoOpImages;
01170 };
01171 
01172 PanoOperationVector* GetLensesOperationVector()
01173 {
01174     return &PanoOpLens;
01175 };
01176 
01177 PanoOperationVector* GetStacksOperationVector()
01178 {
01179     return &PanoOpStacks;
01180 };
01181 
01182 PanoOperationVector* GetControlPointsOperationVector()
01183 {
01184     return &PanoOpControlPoints;
01185 };
01186 
01187 PanoOperationVector* GetResetOperationVector()
01188 {
01189     return &PanoOpReset;
01190 };
01191 
01192 void GeneratePanoOperationVector()
01193 {
01194     PanoOpImages.push_back(new AddImageOperation());
01195     PanoOpImages.push_back(new AddImagesSeriesOperation());
01196     PanoOpImages.push_back(new RemoveImageOperation());
01197     PanoOpImages.push_back(new ChangeAnchorImageOperation());
01198     PanoOpImages.push_back(new ChangeColorAnchorImageOperation());
01199 
01200     PanoOpLens.push_back(new NewLensOperation());
01201     PanoOpLens.push_back(new ChangeLensOperation());
01202     PanoOpLens.push_back(new LoadLensOperation(false));
01203     PanoOpLens.push_back(new LoadLensOperation(true));
01204     PanoOpLens.push_back(new SaveLensOperation(0));
01205     PanoOpLens.push_back(new SaveLensOperation(1));
01206     PanoOpLens.push_back(new SaveLensOperation(2));
01207 
01208     PanoOpStacks.push_back(new NewStackOperation());
01209     PanoOpStacks.push_back(new ChangeStackOperation());
01210     PanoOpStacks.push_back(new AssignStacksOperation());
01211 
01212     PanoOpControlPoints.push_back(new RemoveControlPointsOperation());
01213     PanoOpControlPoints.push_back(new CelesteOperation());
01214     PanoOpControlPoints.push_back(new CleanControlPointsOperation());
01215 
01216     PanoOpReset.push_back(new ResetOperation(ResetOperation::RESET_POSITION));
01217     PanoOpReset.push_back(new ResetOperation(ResetOperation::RESET_TRANSLATION));
01218     PanoOpReset.push_back(new ResetOperation(ResetOperation::RESET_LENS));
01219     PanoOpReset.push_back(new ResetOperation(ResetOperation::RESET_PHOTOMETRICS));
01220     PanoOpReset.push_back(new ResetOperation(ResetOperation::RESET_DIALOG));
01221 
01222 };
01223 
01224 
01225 void _CleanPanoOperationVector(PanoOperationVector& vec)
01226 {
01227     for(size_t i=0; i<vec.size(); i++)
01228     {
01229         delete vec[i];
01230     }
01231     vec.clear();
01232 };
01233 
01234 void CleanPanoOperationVector()
01235 {
01236     _CleanPanoOperationVector(PanoOpImages);
01237     _CleanPanoOperationVector(PanoOpLens);
01238     _CleanPanoOperationVector(PanoOpStacks);
01239     _CleanPanoOperationVector(PanoOpControlPoints);
01240     _CleanPanoOperationVector(PanoOpReset);
01241 };
01242 
01243 } //namespace

Generated on 5 Dec 2014 for Hugintrunk by  doxygen 1.4.7