00001
00002
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
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
00118 if (dlg.ShowModal() == wxID_OK)
00119 {
00120
00121 wxArrayString Pathnames;
00122 dlg.GetPaths(Pathnames);
00123
00124
00125 #ifdef __WXGTK__
00126
00127 config->Write(wxT("/actualPath"), wxPathOnly(Pathnames[0]));
00128 #else
00129 config->Write(wxT("/actualPath"), dlg.GetDirectory());
00130 #endif
00131
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
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
00214 struct tm when;
00215 memset(&when, 0, sizeof(when));
00216 when.tm_wday = -1;
00217
00218
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;
00227 when.tm_year -= 1900;
00228 }
00229 else
00230 {
00231
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
00263 std::vector<std::string> files;
00264 if(pano.getNrOfImages()==0)
00265 {
00266 if(!AddImageDialog(parent,files))
00267 {
00268 return NULL;
00269 };
00270
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
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
00295 wxString path = ::wxPathOnly(file) + wxT("/*");
00296 file = ::wxFindFirstFile(path);
00297 while (!file.IsEmpty())
00298 {
00299
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
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
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
00326 int maxtimediff = wxConfigBase::Get()->Read(wxT("CaptureTimeSpan"), HUGIN_CAPTURE_TIMESPAN);
00327
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
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
00345 time_t stamp = filenames[file];
00346 if (abs((int)(pledge - stamp)) < maxtimediff)
00347 {
00348
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
00353 filenames[recruit] = 0;
00354 break;
00355 }
00356 }
00357 }
00358
00359 if(files.size()>0)
00360 {
00361
00362 sortbytime spred(timeMap);
00363 sort(files.begin(), files.end(), spred);
00364
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
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
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
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
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
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
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
00666
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
00671
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
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
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
00735 wxConfigBase *cfg = wxConfigBase::Get();
00736
00737 double threshold = HUGIN_CELESTE_THRESHOLD;
00738 cfg->Read(wxT("/Celeste/Threshold"), &threshold, HUGIN_CELESTE_THRESHOLD);
00739
00740
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
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
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
00920
00921 if (pano.getImage(*it).ExposureValueisLinked())
00922 {
00923
00924
00925 needs_unlink = true;
00926 }
00927 if(eV!=0)
00928 map_get(ImgVars,"Eev").setValue(eV);
00929 }
00930 else
00931 {
00932
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
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
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
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
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 }