00001
00002
00025 #include <config.h>
00026
00027 #include "panoinc_WX.h"
00028 #include "panoinc.h"
00029
00030 #include <fstream>
00031 #ifdef __GNUC__
00032 #include <ext/stdio_filebuf.h>
00033 #endif
00034
00035 #include "PT/Panorama.h"
00036 #include "PT/ImageGraph.h"
00037
00038 #include <hugin_utils/platform.h>
00039 #include <wx/app.h>
00040 #include "hugin/config_defaults.h"
00041 #include "icpfind/AutoCtrlPointCreator.h"
00042 #include <algorithms/optimizer/PTOptimizer.h>
00043 #include <algorithms/basic/CalculateOverlap.h>
00044
00045 #include "base_wx/MyExternalCmdExecDialog.h"
00046 #include "base_wx/platform.h"
00047 #include "base_wx/huginConfig.h"
00048 #include "base_wx/wxPlatform.h"
00049 #include <wx/utils.h>
00050
00051
00052 #ifdef SetDesc
00053 #undef SetDesc
00054 #endif
00055
00056 #include <wx/cmdline.h>
00057
00058 #if defined MAC_SELF_CONTAINED_BUNDLE
00059 #include <wx/dir.h>
00060 #include <CoreFoundation/CFBundle.h>
00061 #endif
00062
00063 using namespace std;
00064 using namespace PT;
00065 using namespace hugin_utils;
00066
00067 void CPMessage(const wxString message,const wxString caption, wxWindow *parent)
00068 {
00069 if(parent!=NULL)
00070 {
00071 wxMessageBox(message,caption,wxOK | wxICON_ERROR,parent);
00072 }
00073 else
00074 {
00075 std::cout << message << std::endl;
00076 }
00077 };
00078
00079 int CPExecute(wxString prog, wxString args, wxString caption, wxWindow *parent)
00080 {
00081 if(parent!=NULL)
00082 {
00083 return MyExecuteCommandOnDialog(prog, args, parent, caption);
00084 }
00085 else
00086 {
00087 wxString cmdline=prog+wxT(" ")+args;
00088 return wxExecute(cmdline,wxEXEC_SYNC | wxEXEC_MAKE_GROUP_LEADER);
00089 };
00090 };
00091
00092 CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file,
00093 PT::Panorama & pano)
00094 {
00095 ifstream stream(file.c_str());
00096 if (! stream.is_open()) {
00097 DEBUG_ERROR("Could not open autopano output: " << file);
00098 return CPVector();
00099 }
00100
00101 Panorama tmpp;
00102 PanoramaMemento newPano;
00103 int ptoVersion = 0;
00104 newPano.loadPTScript(stream, ptoVersion, "");
00105 tmpp.setMemento(newPano);
00106
00107
00108 map<unsigned int, unsigned int> imgMapping;
00109 for (unsigned int ni = 0; ni < tmpp.getNrOfImages(); ni++) {
00110 std::string nname = stripPath(tmpp.getImage(ni).getFilename());
00111 for (unsigned int oi=0; oi < pano.getNrOfImages(); oi++) {
00112 std::string oname = stripPath(pano.getImage(oi).getFilename());
00113 if (nname == oname) {
00114
00115 imgMapping[ni] = oi;
00116 break;
00117 }
00118 }
00119 if (! set_contains(imgMapping, ni)) {
00120 DEBUG_ERROR("Could not find image " << ni << ", name: " << tmpp.getImage(ni).getFilename() << " in autopano output");
00121 return CPVector();
00122 }
00123 }
00124
00125
00126
00127 CPVector ctrlPoints = tmpp.getCtrlPoints();
00128
00129 for (CPVector::iterator it= ctrlPoints.begin(); it != ctrlPoints.end(); ++it) {
00130 (*it).image1Nr = imgMapping[(*it).image1Nr];
00131 (*it).image2Nr = imgMapping[(*it).image2Nr];
00132 }
00133
00134 return ctrlPoints;
00135 }
00136
00137 CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file,
00138 PT::Panorama & pano, const PT::UIntSet & imgs)
00139 {
00140 ifstream stream(file.c_str());
00141 if (! stream.is_open()) {
00142 DEBUG_ERROR("Could not open control point detector output: " << file);
00143 return CPVector();
00144 }
00145
00146 Panorama tmpp;
00147 PanoramaMemento newPano;
00148 int ptoVersion = 0;
00149 newPano.loadPTScript(stream, ptoVersion, "");
00150 tmpp.setMemento(newPano);
00151
00152
00153 if(tmpp.getNrOfImages()!=imgs.size())
00154 {
00155 return CPVector();
00156 };
00157
00158
00159 vector<size_t> imgMapping(imgs.size());
00160 size_t i=0;
00161 for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
00162 {
00163 imgMapping[i++]=*it;
00164 };
00165
00166
00167 CPVector ctrlPoints = tmpp.getCtrlPoints();
00168
00169 for (CPVector::iterator it= ctrlPoints.begin(); it != ctrlPoints.end(); ++it) {
00170 (*it).image1Nr = imgMapping[(*it).image1Nr];
00171 (*it).image2Nr = imgMapping[(*it).image2Nr];
00172 }
00173
00174 return ctrlPoints;
00175 }
00176
00177 #if defined MAC_SELF_CONTAINED_BUNDLE
00178 wxString GetBundledProg(wxString progName)
00179 {
00180
00181 wxFileName file(progName);
00182
00183 if(file.GetPath().IsEmpty())
00184
00185 return MacGetPathToBundledExecutableFile(MacCreateCFStringWithWxString(progName));
00186 return wxEmptyString;
00187 }
00188 #endif
00189
00190 wxString GetProgPath(wxString progName)
00191 {
00192 #if defined MAC_SELF_CONTAINED_BUNDLE
00193 wxString bundled=GetBundledProg(progName);
00194 if(!bundled.IsEmpty())
00195 return bundled;
00196 #else
00197 #ifdef __WXMSW__
00198 wxFileName prog(progName);
00199 if(prog.IsAbsolute())
00200 {
00201 return progName;
00202 }
00203 else
00204 {
00205 wxPathList pathlist;
00206 pathlist.Add(getExePath(wxTheApp->argv[0]));
00207 pathlist.AddEnvList(wxT("PATH"));
00208 return pathlist.FindAbsoluteValidPath(progName);
00209 };
00210 #endif
00211 #endif
00212 return progName;
00213 };
00214
00215 bool CanStartProg(wxString progName,wxWindow* parent)
00216 {
00217 #if defined MAC_SELF_CONTAINED_BUNDLE
00218 if(!GetBundledProg(progName).IsEmpty())
00219 return true;
00220 #endif
00221 wxFileName prog(progName);
00222 bool canStart=false;
00223 if(prog.IsAbsolute())
00224 {
00225 canStart=(prog.IsFileExecutable());
00226 }
00227 else
00228 {
00229 wxPathList pathlist;
00230 #ifdef __WXMSW__
00231 pathlist.Add(getExePath(wxTheApp->argv[0]));
00232 #endif
00233 pathlist.AddEnvList(wxT("PATH"));
00234 wxString path = pathlist.FindAbsoluteValidPath(progName);
00235 if(path.IsEmpty())
00236 canStart=false;
00237 else
00238 {
00239 wxFileName prog2(path);
00240 canStart=(prog2.IsFileExecutable());
00241 };
00242 };
00243 if(!canStart)
00244 CPMessage(wxString::Format(
00245 _("Could not find \"%s\" in path.\nMaybe you have not installed it properly or given a wrong path in the settings."),progName.c_str()),
00246 _("Error"),parent);
00247 return canStart;
00248 };
00249
00250 CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
00251 int nFeatures, wxWindow *parent)
00252 {
00253 int return_value;
00254 return automatch(setting,pano,imgs,nFeatures,return_value,parent);
00255 };
00256
00257 CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting,
00258 Panorama & pano,
00259 const UIntSet & imgs,
00260 int nFeatures,
00261 int & ret_value,
00262 wxWindow *parent)
00263 {
00264 CPVector cps;
00265 CPDetectorType t = setting.GetType();
00266
00267 if(!CanStartProg(setting.GetProg(),parent))
00268 return cps;
00269 if(setting.IsTwoStepDetector())
00270 if(!CanStartProg(setting.GetProgMatcher(),parent))
00271 return cps;
00272 if(t==CPDetector_AutoPanoSiftStack || t==CPDetector_AutoPanoSiftMultiRowStack)
00273 if(!setting.GetProgStack().IsEmpty())
00274 if(!CanStartProg(setting.GetProgStack(),parent))
00275 return cps;
00276
00277 char * p = setlocale(LC_NUMERIC,NULL);
00278 char * old_locale = strdup(p);
00279 setlocale(LC_NUMERIC,"C");
00280 switch (t) {
00281 case CPDetector_AutoPano:
00282 {
00283
00284 AutoPanoKolor matcher;
00285 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00286 break;
00287 }
00288 case CPDetector_AutoPanoSift:
00289 {
00290
00291 AutoPanoSift matcher;
00292 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00293 break;
00294 }
00295 case CPDetector_AutoPanoSiftStack:
00296 {
00297
00298 AutoPanoSiftStack matcher;
00299 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00300 break;
00301 }
00302 case CPDetector_AutoPanoSiftMultiRow:
00303 {
00304
00305 AutoPanoSiftMultiRow matcher;
00306 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00307 break;
00308 }
00309 case CPDetector_AutoPanoSiftMultiRowStack:
00310 {
00311
00312 AutoPanoSiftMultiRowStack matcher;
00313 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00314 break;
00315 }
00316 case CPDetector_AutoPanoSiftPreAlign:
00317 {
00318
00319 AutoPanoSiftPreAlign matcher;
00320 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
00321 break;
00322 }
00323 default:
00324 DEBUG_ERROR("Invalid autopano type");
00325 }
00326 setlocale(LC_NUMERIC,old_locale);
00327 free(old_locale);
00328 return cps;
00329 }
00330
00331 void AutoCtrlPointCreator::Cleanup(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
00332 std::vector<wxString> &keyFiles, wxWindow *parent)
00333 {
00334 if(setting.IsTwoStepDetector())
00335 {
00336 if(keyFiles.size()>0)
00337 {
00338 for(unsigned int i=0;i<keyFiles.size();i++)
00339 {
00340 if(wxFileExists(keyFiles[i]))
00341 {
00342 if(!wxRemoveFile(keyFiles[i]))
00343 {
00344 DEBUG_DEBUG("could not remove temporary file: " << keyFiles[i].c_str());
00345 };
00346 };
00347 };
00348 };
00349 }
00350 else
00351 {
00352 if(!setting.IsCleanupPossible())
00353 {
00354 return;
00355 };
00356
00357 wxString cleanupExe = GetProgPath(setting.GetProg());
00358 wxString cleanupArgs = setting.GetArgsCleanup();
00359 if(cleanupArgs.IsEmpty())
00360 {
00361 return;
00362 };
00363
00364 wxString ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj"));
00365 cleanupArgs.Replace(wxT("%s"), ptoinfile_name);
00366 ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
00367 pano.printPanoramaScript(ptoinstream, pano.getOptimizeVector(), pano.getOptions(), imgs, false);
00368
00369 int ret_value=CPExecute(cleanupExe, cleanupArgs, _("cleaning up temporary keypoint files"), parent);
00370
00371 if(ret_value!=0)
00372 {
00373 DEBUG_DEBUG("could not cleanup temporary keypoint files");
00374 };
00375 if(!wxRemoveFile(ptoinfile_name))
00376 {
00377 DEBUG_DEBUG("could not remove temporary file: " << ptoinfile_name.c_str());
00378 };
00379 };
00380 };
00381
00382 CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
00383 int nFeatures, int & ret_value, wxWindow *parent)
00384 {
00385 CPVector cps;
00386 if (imgs.size() == 0) {
00387 return cps;
00388 }
00389
00390 wxString autopanoExe = GetProgPath(setting.GetProg());
00391 if(setting.IsTwoStepDetector())
00392 {
00393 std::vector<wxString> keyFiles(pano.getNrOfImages());
00394 cps=automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
00395 Cleanup(setting, pano, imgs, keyFiles, parent);
00396 return cps;
00397 };
00398 wxString autopanoArgs = setting.GetArgs();
00399
00400
00401 wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
00402 autopanoArgs.Replace(wxT("%o"), ptofile);
00403 wxString tmp;
00404 tmp.Printf(wxT("%d"), nFeatures);
00405 autopanoArgs.Replace(wxT("%p"), tmp);
00406
00407 SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
00408 tmp.Printf(wxT("%f"), firstImg.getHFOV());
00409 autopanoArgs.Replace(wxT("%v"), tmp);
00410
00411 tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
00412 autopanoArgs.Replace(wxT("%f"), tmp);
00413
00414 long idx = autopanoArgs.Find(wxT("%namefile")) ;
00415 DEBUG_DEBUG("find %namefile in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
00416 bool use_namefile = idx >=0;
00417 idx = autopanoArgs.Find(wxT("%i"));
00418 DEBUG_DEBUG("find %i in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
00419 bool use_params = idx >=0;
00420 idx = autopanoArgs.Find(wxT("%s"));
00421 bool use_inputscript = idx >=0;
00422
00423 if (! (use_namefile || use_params || use_inputscript)) {
00424 CPMessage(_("Please use %namefile, %i or %s to specify the input files for the control point detector"),
00425 _("Error in control point detector command"), parent);
00426 return cps;
00427 }
00428
00429 wxFile namefile;
00430 wxString namefile_name;
00431 if (use_namefile) {
00432
00433 namefile_name = wxFileName::CreateTempFileName(wxT("ap_imgnames"), &namefile);
00434 DEBUG_DEBUG("before replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
00435 autopanoArgs.Replace(wxT("%namefile"), namefile_name);
00436 DEBUG_DEBUG("after replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
00437 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
00438 {
00439 namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME));
00440 namefile.Write(wxT("\r\n"));
00441 }
00442
00443 if (namefile_name != wxString(wxT(""))) {
00444 namefile.Close();
00445 }
00446 } else {
00447 string imgFiles;
00448 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
00449 {
00450 imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
00451 }
00452 autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
00453 }
00454
00455 wxString ptoinfile_name;
00456 if (use_inputscript) {
00457 wxFile ptoinfile;
00458 ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj"));
00459 autopanoArgs.Replace(wxT("%s"), ptoinfile_name);
00460
00461 ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
00462
00463
00464 Panorama tempPano=pano.duplicate();
00465 CPVector emptyCPV;
00466 tempPano.setCtrlPoints(emptyCPV);
00467 tempPano.printPanoramaScript(ptoinstream, tempPano.getOptimizeVector(), tempPano.getOptions(), imgs, false);
00468 }
00469
00470 #ifdef __WXMSW__
00471 if (autopanoArgs.size() > 32000) {
00472 CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"),
00473 _("Too many images selected"), parent );
00474 return cps;
00475 }
00476 #endif
00477
00478 wxString cmd = autopanoExe + wxT(" ") + autopanoArgs;
00479 DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal));
00480
00481 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(autopanoArgs);
00482 if (arguments.GetCount() > 127) {
00483 DEBUG_ERROR("Too many arguments for call to wxExecute()");
00484 DEBUG_ERROR("Try using the %%s parameter in preferences");
00485 CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent);
00486 return cps;
00487 }
00488
00489 ret_value = 0;
00490
00491 ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
00492
00493 if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
00494 return cps;
00495 } else if (ret_value == -1) {
00496 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
00497 return cps;
00498 } else if (ret_value > 0) {
00499 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
00500 _("wxExecute Error"), parent);
00501 return cps;
00502 }
00503
00504 if (! wxFileExists(ptofile.c_str())) {
00505 CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
00506 _("Control point detector failure"), parent );
00507 return cps;
00508 }
00509
00510
00511 if(use_inputscript)
00512 {
00513 cps = readUpdatedControlPoints((const char*)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs);
00514 }
00515 else
00516 {
00517 cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
00518 };
00519
00520 if (namefile_name != wxString(wxT(""))) {
00521 namefile.Close();
00522 wxRemoveFile(namefile_name);
00523 }
00524
00525 if (ptoinfile_name != wxString(wxT(""))) {
00526 wxRemoveFile(ptoinfile_name);
00527 }
00528
00529 if (!wxRemoveFile(ptofile)) {
00530 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
00531 }
00532
00533 return cps;
00534 }
00535
00536 CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
00537 int nFeatures, vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
00538 {
00539 CPVector cps;
00540 if (imgs.size() == 0)
00541 {
00542 return cps;
00543 }
00544 DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
00545
00546 wxString generateKeysExe=GetProgPath(setting.GetProg());
00547 wxString matcherExe = GetProgPath(setting.GetProgMatcher());
00548 wxString generateKeysArgs=setting.GetArgs();
00549 wxString matcherArgs = setting.GetArgsMatcher();
00550
00551 wxString tempDir= wxConfigBase::Get()->Read(wxT("tempDir"),wxT(""));
00552 if(!tempDir.IsEmpty())
00553 if(tempDir.Last()!=wxFileName::GetPathSeparator())
00554 tempDir.Append(wxFileName::GetPathSeparator());
00555
00556 if(generateKeysArgs.Find(wxT("%i"))==wxNOT_FOUND || generateKeysArgs.Find(wxT("%k"))==wxNOT_FOUND)
00557 {
00558 CPMessage(_("Please use %i to specify the input files and %k to specify the keypoint file for the generate keys step"),
00559 _("Error in control point detector command"), parent);
00560 return cps;
00561 };
00562 if(matcherArgs.Find(wxT("%k"))==wxNOT_FOUND || matcherArgs.Find(wxT("%o"))==wxNOT_FOUND)
00563 {
00564 CPMessage(_("Please use %k to specify the keypoint files and %o to specify the output project file for the matching step"),
00565 _("Error in control point detector command"), parent);
00566 return cps;
00567 };
00568
00569 ret_value=0;
00570 for(UIntSet::const_iterator img=imgs.begin();img!=imgs.end();img++)
00571 {
00572 if(keyFiles[*img].IsEmpty())
00573 {
00574
00575 wxString keyfile=wxFileName::CreateTempFileName(tempDir+wxT("apk_"));
00576 keyFiles[*img]=keyfile;
00577 wxString cmd=generateKeysArgs;
00578 wxString tmp;
00579 tmp.Printf(wxT("%d"), nFeatures);
00580 cmd.Replace(wxT("%p"), tmp);
00581
00582 SrcPanoImage srcImg = pano.getSrcImage(*img);
00583 tmp.Printf(wxT("%f"), srcImg.getHFOV());
00584 cmd.Replace(wxT("%v"), tmp);
00585
00586 tmp.Printf(wxT("%d"), (int) srcImg.getProjection());
00587 cmd.Replace(wxT("%f"), tmp);
00588
00589 cmd.Replace(wxT("%i"),wxQuoteFilename(wxString(srcImg.getFilename().c_str(), HUGIN_CONV_FILENAME)));
00590 cmd.Replace(wxT("%k"),wxQuoteFilename(keyfile));
00591
00592 ret_value = CPExecute(generateKeysExe, cmd, _("generating key file"), parent);
00593 cmd=generateKeysExe+wxT(" ")+cmd;
00594 if (ret_value == HUGIN_EXIT_CODE_CANCELLED)
00595 return cps;
00596 else
00597 if (ret_value == -1)
00598 {
00599 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
00600 return cps;
00601 }
00602 else
00603 if (ret_value > 0)
00604 {
00605 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
00606 _("wxExecute Error"), parent);
00607 return cps;
00608 };
00609 };
00610 };
00611
00612
00613 wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
00614 matcherArgs.Replace(wxT("%o"), ptofile);
00615 wxString tmp;
00616 tmp.Printf(wxT("%d"), nFeatures);
00617 matcherArgs.Replace(wxT("%p"), tmp);
00618
00619 SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
00620 tmp.Printf(wxT("%f"), firstImg.getHFOV());
00621 matcherArgs.Replace(wxT("%v"), tmp);
00622
00623 tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
00624 matcherArgs.Replace(wxT("%f"), tmp);
00625
00626 wxString imgFiles;
00627 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
00628 {
00629 imgFiles.append(wxT(" ")).append(wxQuoteFilename(keyFiles[*it]));
00630 };
00631 matcherArgs.Replace(wxT("%k"), wxString (imgFiles.wc_str(), HUGIN_CONV_FILENAME));
00632
00633 #ifdef __WXMSW__
00634 if (matcherArgs.size() > 32000) {
00635 CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"),
00636 _("Too many images selected"), parent );
00637 return cps;
00638 }
00639 #endif
00640
00641 wxString cmd = matcherExe + wxT(" ") + matcherArgs;
00642 DEBUG_DEBUG("Executing: " << matcherExe.mb_str(wxConvLocal) << " " << matcherArgs.mb_str(wxConvLocal));
00643
00644 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(matcherArgs);
00645 if (arguments.GetCount() > 127) {
00646 DEBUG_ERROR("Too many arguments for call to wxExecute()");
00647 CPMessage(wxString::Format(_("Too many arguments (images). Try using a cp generator setting which supports the %%s parameter in preferences.\n\n Could not execute command: %s"), matcherExe.c_str()), _("wxExecute Error"), parent);
00648 return cps;
00649 }
00650
00651
00652 ret_value = CPExecute(matcherExe, matcherArgs, _("finding control points"), parent);
00653
00654 if (ret_value == HUGIN_EXIT_CODE_CANCELLED)
00655 return cps;
00656 else
00657 if (ret_value == -1)
00658 {
00659 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
00660 return cps;
00661 }
00662 else
00663 if (ret_value > 0)
00664 {
00665 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
00666 _("wxExecute Error"), parent);
00667 return cps;
00668 };
00669
00670 if (! wxFileExists(ptofile.c_str()))
00671 {
00672 CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
00673 _("Control point detector failure"), parent );
00674 return cps;
00675 }
00676
00677
00678 cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
00679
00680 if (!wxRemoveFile(ptofile)) {
00681 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
00682 }
00683
00684 return cps;
00685 };
00686
00687 CPVector AutoPanoKolor::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
00688 int nFeatures, int & ret_value, wxWindow *parent)
00689 {
00690 CPVector cps;
00691 wxString autopanoExe = setting.GetProg();
00692
00693
00694 wxString autopanoArgs = setting.GetArgs();
00695
00696 string imgFiles;
00697 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
00698 {
00699 imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
00700 }
00701
00702 wxString ptofilepath = wxFileName::CreateTempFileName(wxT("ap_res"));
00703 wxFileName ptofn(ptofilepath);
00704 wxString ptofile = ptofn.GetFullName();
00705 autopanoArgs.Replace(wxT("%o"), ptofile);
00706 wxString tmp;
00707 tmp.Printf(wxT("%d"), nFeatures);
00708 autopanoArgs.Replace(wxT("%p"), tmp);
00709 SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
00710 tmp.Printf(wxT("%f"), firstImg.getHFOV());
00711 autopanoArgs.Replace(wxT("%v"), tmp);
00712
00713 tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
00714 autopanoArgs.Replace(wxT("%f"), tmp);
00715
00716 autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
00717
00718 wxString tempdir = ptofn.GetPath();
00719 autopanoArgs.Replace(wxT("%d"), ptofn.GetPath());
00720 wxString cmd;
00721 cmd.Printf(wxT("%s %s"), wxQuoteFilename(autopanoExe).c_str(), autopanoArgs.c_str());
00722 #ifdef __WXMSW__
00723 if (cmd.size() > 32766) {
00724 CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"),
00725 _("Too many images selected"), parent);
00726 return cps;
00727 }
00728 #endif
00729 DEBUG_DEBUG("Executing: " << cmd.c_str());
00730
00731 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(cmd);
00732 if (arguments.GetCount() > 127) {
00733 DEBUG_ERROR("Too many arguments for call to wxExecute()");
00734 DEBUG_ERROR("Try using the %s parameter in preferences");
00735 CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent);
00736 return cps;
00737 }
00738
00739 ret_value = 0;
00740
00741 ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
00742
00743 if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
00744 return cps;
00745 } else if (ret_value == -1) {
00746 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
00747 return cps;
00748 } else if (ret_value > 0) {
00749 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
00750 _("wxExecute Error"), parent);
00751 return cps;
00752 }
00753
00754 ptofile = ptofn.GetFullPath();
00755 ptofile.append(wxT("0.oto"));
00756 if (! wxFileExists(ptofile.c_str()) ) {
00757 CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
00758 _("Control point detector failure"), parent );
00759 return cps;
00760 }
00761
00762 cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
00763
00764 if (!wxRemoveFile(ptofile)) {
00765 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
00766 }
00767 return cps;
00768 }
00769
00770 struct img_ev
00771 {
00772 unsigned int img_nr;
00773 double ev;
00774 };
00775 struct stack_img
00776 {
00777 unsigned int layer_nr;
00778 std::vector<img_ev> images;
00779 };
00780 bool sort_img_ev (img_ev i1, img_ev i2) { return (i1.ev<i2.ev); };
00781
00782 void AddControlPointsWithCheck(CPVector &cpv, CPVector &new_cp, Panorama *pano=NULL)
00783 {
00784 for(unsigned int i=0;i<new_cp.size();i++)
00785 {
00786 HuginBase::ControlPoint cp=new_cp[i];
00787 bool duplicate=false;
00788 for(unsigned int j=0;j<cpv.size();j++)
00789 {
00790 if(cp==cpv[j])
00791 {
00792 duplicate=true;
00793 break;
00794 }
00795 };
00796 if(!duplicate)
00797 {
00798 cpv.push_back(cp);
00799 if(pano!=NULL)
00800 pano->addCtrlPoint(cp);
00801 };
00802 };
00803 };
00804
00805 CPVector AutoPanoSiftStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
00806 int nFeatures, int & ret_value, wxWindow *parent)
00807 {
00808 CPVector cps;
00809 if (imgs.size() == 0) {
00810 return cps;
00811 };
00812 std::vector<stack_img> stack_images;
00813 HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano);
00814 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
00815 {
00816 unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
00817
00818 bool found=false;
00819 unsigned int index=0;
00820 for(index=0;index<stack_images.size();index++)
00821 {
00822 found=(stack_images[index].layer_nr==stack_nr);
00823 if(found)
00824 break;
00825 };
00826 if(!found)
00827 {
00828
00829 stack_images.resize(stack_images.size()+1);
00830 index=stack_images.size()-1;
00831
00832 stack_images[index].layer_nr=stack_nr;
00833 };
00834
00835 unsigned int new_image_index=stack_images[index].images.size();
00836 stack_images[index].images.resize(new_image_index+1);
00837 stack_images[index].images[new_image_index].img_nr=*it;
00838 stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
00839 };
00840 delete variable_groups;
00841
00842 UIntSet images_layer;
00843 for(unsigned int i=0;i<stack_images.size();i++)
00844 {
00845 std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
00846 unsigned int index=0;
00847 if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
00848 {
00849 index=stack_images[i].images.size() / 2;
00850 };
00851 images_layer.insert(stack_images[i].images[index].img_nr);
00852 };
00853
00854 ret_value=0;
00855 if(images_layer.size()>1)
00856 {
00857 AutoPanoSift matcher;
00858 cps=matcher.automatch(setting, pano, images_layer, nFeatures, ret_value, parent);
00859 if(ret_value!=0)
00860 return cps;
00861 };
00862
00863 if(!setting.GetProgStack().IsEmpty())
00864 {
00865 CPDetectorSetting stack_setting;
00866 stack_setting.SetType(CPDetector_AutoPanoSift);
00867 stack_setting.SetProg(setting.GetProgStack());
00868 stack_setting.SetArgs(setting.GetArgsStack());
00869
00870 for(unsigned int i=0;i<stack_images.size();i++)
00871 {
00872 UIntSet images_stack;
00873 images_stack.clear();
00874 for(unsigned int j=0;j<stack_images[i].images.size();j++)
00875 images_stack.insert(stack_images[i].images[j].img_nr);
00876 if(images_stack.size()>1)
00877 {
00878 AutoPanoSift matcher;
00879 CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
00880 if(new_cps.size()>0)
00881 AddControlPointsWithCheck(cps,new_cps);
00882 if(ret_value!=0)
00883 return cps;
00884 };
00885 };
00886 }
00887 return cps;
00888 };
00889
00890 CPVector AutoPanoSiftMultiRow::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
00891 int nFeatures, int & ret_value, wxWindow *parent)
00892 {
00893 CPVector cps;
00894 if (imgs.size() < 2)
00895 {
00896 return cps;
00897 };
00898 std::vector<wxString> keyFiles(pano.getNrOfImages());
00899
00900 unsigned int counter=0;
00901 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); )
00902 {
00903 if(counter==imgs.size()-1)
00904 break;
00905 counter++;
00906 UIntSet ImagePair;
00907 ImagePair.clear();
00908 ImagePair.insert(*it);
00909 it++;
00910 ImagePair.insert(*it);
00911 AutoPanoSift matcher;
00912 CPVector new_cps;
00913 new_cps.clear();
00914 if(setting.IsTwoStepDetector())
00915 new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, keyFiles, ret_value, parent);
00916 else
00917 new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, ret_value, parent);
00918 if(new_cps.size()>0)
00919 AddControlPointsWithCheck(cps,new_cps);
00920 if(ret_value!=0)
00921 {
00922 Cleanup(setting, pano, imgs, keyFiles, parent);
00923 return cps;
00924 };
00925 };
00926
00927
00928 UIntSet allImgs;
00929 fill_set(allImgs, 0, pano.getNrOfImages()-1);
00930 Panorama optPano=pano.getSubset(allImgs);
00931 for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
00932 optPano.addCtrlPoint(*it);
00933
00934 CPGraph graph;
00935 createCPGraph(optPano, graph);
00936 CPComponents comps;
00937 int n = findCPComponents(graph, comps);
00938 if(n>1)
00939 {
00940 UIntSet ImagesGroups;
00941 for(unsigned int i=0;i<n;i++)
00942 {
00943 ImagesGroups.insert(*(comps[i].begin()));
00944 if(comps[i].size()>1)
00945 ImagesGroups.insert(*(comps[i].rbegin()));
00946 };
00947 AutoPanoSift matcher;
00948 CPVector new_cps;
00949 if(setting.IsTwoStepDetector())
00950 new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, keyFiles, ret_value, parent);
00951 else
00952 new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, ret_value, parent);
00953 if(new_cps.size()>0)
00954 AddControlPointsWithCheck(cps,new_cps,&optPano);
00955 if(ret_value!=0)
00956 {
00957 Cleanup(setting, pano, imgs, keyFiles, parent);
00958 return cps;
00959 };
00960 createCPGraph(optPano,graph);
00961 n=findCPComponents(graph, comps);
00962 };
00963 if(n==1 && setting.GetOption())
00964 {
00965
00966
00967 PanoramaOptions opts = pano.getOptions();
00968 opts.setProjection(PanoramaOptions::EQUIRECTANGULAR);
00969
00970
00971 opts.setWidth(30000, false);
00972 opts.setHeight(15000);
00973
00974 optPano.setOptions(opts);
00975 int w = optPano.calcOptimalWidth();
00976 opts.setWidth(w);
00977 opts.setHeight(w/2);
00978 optPano.setOptions(opts);
00979
00980
00981 OptimizeVector optvars;
00982 const SrcPanoImage & anchorImage = optPano.getImage(opts.optimizeReferenceImage);
00983 for (unsigned i=0; i < optPano.getNrOfImages(); i++)
00984 {
00985 std::set<std::string> imgopt;
00986 if(i==opts.optimizeReferenceImage)
00987 {
00988
00989 imgopt.insert("p");
00990 }
00991 else
00992 {
00993
00994 if(!optPano.getImage(i).YawisLinkedWith(anchorImage))
00995 {
00996 imgopt.insert("p");
00997 imgopt.insert("y");
00998 };
00999 };
01000 optvars.push_back(imgopt);
01001 }
01002 optPano.setOptimizeVector(optvars);
01003
01004
01005 CPVector backupOldCPS = optPano.getCtrlPoints();
01006 CPVector backupNewCPS;
01007 for (CPVector::const_iterator it = backupOldCPS.begin(); it != backupOldCPS.end(); it++) {
01008 if (it->mode == ControlPoint::X_Y)
01009 {
01010 backupNewCPS.push_back(*it);
01011 }
01012 }
01013 optPano.setCtrlPoints(backupNewCPS);
01014
01015 HuginBase::AutoOptimise::autoOptimise(optPano,false);
01016 HuginBase::PTools::optimize(optPano);
01017 optPano.setCtrlPoints(backupOldCPS);
01018
01019
01020 AutoPanoSiftPreAlign matcher;
01021 CPDetectorSetting newSetting;
01022 newSetting.SetProg(setting.GetProg());
01023 newSetting.SetArgs(setting.GetArgs());
01024 if(setting.IsTwoStepDetector())
01025 {
01026 newSetting.SetProgMatcher(setting.GetProgMatcher());
01027 newSetting.SetArgsMatcher(setting.GetArgsMatcher());
01028 };
01029 newSetting.SetOption(true);
01030 CPVector new_cps;
01031 if(setting.IsTwoStepDetector())
01032 new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, keyFiles, ret_value, parent);
01033 else
01034 new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, ret_value, parent);
01035 if(new_cps.size()>0)
01036 AddControlPointsWithCheck(cps,new_cps);
01037 };
01038 Cleanup(setting, pano, imgs, keyFiles, parent);
01039 return cps;
01040 };
01041
01042 CPVector AutoPanoSiftMultiRowStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
01043 int nFeatures, int & ret_value, wxWindow *parent)
01044 {
01045 CPVector cps;
01046 if (imgs.size() == 0) {
01047 return cps;
01048 };
01049 std::vector<stack_img> stack_images;
01050 HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano);
01051 for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
01052 {
01053 unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
01054
01055 bool found=false;
01056 unsigned int index=0;
01057 for(index=0;index<stack_images.size();index++)
01058 {
01059 found=(stack_images[index].layer_nr==stack_nr);
01060 if(found)
01061 break;
01062 };
01063 if(!found)
01064 {
01065
01066 stack_images.resize(stack_images.size()+1);
01067 index=stack_images.size()-1;
01068
01069 stack_images[index].layer_nr=stack_nr;
01070 };
01071
01072 unsigned int new_image_index=stack_images[index].images.size();
01073 stack_images[index].images.resize(new_image_index+1);
01074 stack_images[index].images[new_image_index].img_nr=*it;
01075 stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
01076 };
01077 delete variable_groups;
01078
01079 UIntSet images_layer;
01080 for(unsigned int i=0;i<stack_images.size();i++)
01081 {
01082 std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
01083 unsigned int index=0;
01084 if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
01085 {
01086 index=stack_images[i].images.size() / 2;
01087 };
01088 images_layer.insert(stack_images[i].images[index].img_nr);
01089 };
01090 ret_value=0;
01091
01092 if(!setting.GetProgStack().IsEmpty())
01093 {
01094 CPDetectorSetting stack_setting;
01095 stack_setting.SetType(CPDetector_AutoPanoSift);
01096 stack_setting.SetProg(setting.GetProgStack());
01097 stack_setting.SetArgs(setting.GetArgsStack());
01098
01099 for(unsigned int i=0;i<stack_images.size();i++)
01100 {
01101 UIntSet images_stack;
01102 images_stack.clear();
01103 for(unsigned int j=0;j<stack_images[i].images.size();j++)
01104 images_stack.insert(stack_images[i].images[j].img_nr);
01105 if(images_stack.size()>1)
01106 {
01107 AutoPanoSift matcher;
01108 CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
01109 if(new_cps.size()>0)
01110 AddControlPointsWithCheck(cps,new_cps);
01111 if(ret_value!=0)
01112 {
01113 std::vector<wxString> emptyKeyfiles;
01114 Cleanup(setting, pano, imgs, emptyKeyfiles, parent);
01115 return cps;
01116 };
01117 };
01118 };
01119 }
01120
01121 if(images_layer.size()>1)
01122 {
01123 UIntSet allImgs;
01124 fill_set(allImgs, 0, pano.getNrOfImages()-1);
01125 Panorama newPano=pano.getSubset(allImgs);
01126 if(cps.size()>0)
01127 for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
01128 newPano.addCtrlPoint(*it);
01129
01130 AutoPanoSiftMultiRow matcher;
01131 CPVector new_cps=matcher.automatch(setting, newPano, images_layer, nFeatures, ret_value, parent);
01132 if(new_cps.size()>0)
01133 AddControlPointsWithCheck(cps,new_cps);
01134 };
01135 return cps;
01136 };
01137
01138 CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
01139 int nFeatures, int & ret_value, wxWindow *parent)
01140 {
01141 std::vector<wxString> keyFiles(pano.getNrOfImages());
01142 return automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
01143 };
01144
01145 CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
01146 int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
01147 {
01148 CPVector cps;
01149 if (imgs.size()<2)
01150 return cps;
01151 DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
01152
01153 vector<UIntSet> usedImages;
01154 usedImages.resize(pano.getNrOfImages());
01155 if(setting.GetOption())
01156 {
01157
01158 CPVector oldCps=pano.getCtrlPoints();
01159 for(unsigned i=0;i<oldCps.size();i++)
01160 {
01161 if(oldCps[i].mode==ControlPoint::X_Y)
01162 {
01163 usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr);
01164 usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr);
01165 };
01166 };
01167 };
01168 HuginBase::CalculateImageOverlap overlap(&pano);
01169 overlap.calculate(10);
01170 for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
01171 {
01172 UIntSet images;
01173 images.clear();
01174 images.insert(*it);
01175 UIntSet::const_iterator it2=it;
01176 for(++it2;it2!=imgs.end();it2++)
01177 {
01178
01179 if(set_contains(usedImages[*it2],*it))
01180 continue;
01181
01182 if(overlap.getOverlap(*it,*it2)>0)
01183 {
01184 images.insert(*it2);
01185 };
01186 };
01187 if(images.size()<2)
01188 continue;
01189
01190 for(UIntSet::const_iterator img_it=images.begin();img_it!=images.end();img_it++)
01191 for(UIntSet::const_iterator img_it2=images.begin();img_it2!=images.end();img_it2++)
01192 usedImages[*img_it].insert(*img_it2);
01193 AutoPanoSift matcher;
01194 CPVector new_cps;
01195 if(setting.IsTwoStepDetector())
01196 new_cps=matcher.automatch(setting, pano, images, nFeatures, keyFiles, ret_value, parent);
01197 else
01198 new_cps=matcher.automatch(setting, pano, images, nFeatures, ret_value, parent);
01199 if(new_cps.size()>0)
01200 AddControlPointsWithCheck(cps,new_cps);
01201 if(ret_value!=0)
01202 {
01203 Cleanup(setting, pano, imgs, keyFiles, parent);
01204 return cps;
01205 };
01206 };
01207 Cleanup(setting, pano, imgs, keyFiles, parent);
01208 return cps;
01209 };