Hugin trunk 0.1
Loading...
Searching...
No Matches
AutoCtrlPointCreator.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
25#include "hugin_config.h"
26
27#include "panoinc_WX.h"
28#include "panoinc.h"
29
30#include <fstream>
31#if defined (__GNUC__) && !defined (__FreeBSD__) && !defined (__clang__)
32#include <ext/stdio_filebuf.h>
33#endif
34
36
38#include <wx/app.h>
45
47#include "base_wx/platform.h"
48#include "base_wx/huginConfig.h"
49#include "base_wx/wxPlatform.h"
50#include "base_wx/wxutils.h"
51#include <wx/utils.h>
52#if defined __WXMSW__ || defined UNIX_SELF_CONTAINED_BUNDLE
53#include <wx/stdpaths.h>
54#endif
55
56// somewhere SetDesc gets defined.. this breaks wx/cmdline.h on OSX
57#ifdef SetDesc
58#undef SetDesc
59#endif
60
61#include <wx/cmdline.h>
62
63#if defined MAC_SELF_CONTAINED_BUNDLE
64 #include <wx/dir.h>
65 #include <CoreFoundation/CFBundle.h>
66#endif
67
68void CPMessage(const wxString message,const wxString caption, wxWindow *parent)
69{
70 if(parent!=NULL)
71 {
73 }
74 else
75 {
76 std::cout << message << std::endl;
77 }
78};
79
80int CPExecute(wxString prog, wxString args, wxString caption, wxWindow *parent)
81{
82 if(parent!=NULL)
83 {
84 return MyExecuteCommandOnDialog(prog, args, parent, caption);
85 }
86 else
87 {
88 wxString cmdline=prog+" "+args;
90 };
91};
92
94 HuginBase::Panorama & pano, const HuginBase::UIntSet & imgs, bool reordered)
95{
96 std::ifstream stream(file.c_str());
97 if (! stream.is_open()) {
98 DEBUG_ERROR("Could not open control point detector output: " << file);
99 return HuginBase::CPVector();
100 }
101
104 int ptoVersion = 0;
105 newPano.loadPTScript(stream, ptoVersion, "");
106 tmpp.setMemento(newPano);
107
108 //check if sizes matches
109 if(tmpp.getNrOfImages()!=imgs.size())
110 {
111 return HuginBase::CPVector();
112 };
113
114 // create mapping between the panorama images.
115 std::map<unsigned int, unsigned int> imgMapping;
116
117 // create mapping between the panorama images.
118 if (reordered) {
119 for (unsigned int ni = 0; ni < tmpp.getNrOfImages(); ni++) {
120 std::string nname = hugin_utils::stripPath(tmpp.getImage(ni).getFilename());
121 for(HuginBase::UIntSet::const_iterator it=imgs.begin();it!=imgs.end();++it) {
122 std::string oname = hugin_utils::stripPath(pano.getImage(*it).getFilename());
123 if (nname == oname) {
124 // insert image
125 imgMapping[ni] = *it;
126 break;
127 }
128 }
129 if (! set_contains(imgMapping, ni)) {
130 DEBUG_ERROR("Could not find image " << ni << ", name: " << tmpp.getImage(ni).getFilename() << " in autopano output");
131 return HuginBase::CPVector();
132 }
133 }
134 } else {
135 size_t i=0;
136 for(HuginBase::UIntSet::const_iterator it=imgs.begin();it!=imgs.end();++it)
137 {
138 imgMapping[i++]=*it;
139 };
140 }
141
142 // get control points
143 HuginBase::CPVector ctrlPoints = tmpp.getCtrlPoints();
144 // make sure they are in correct order
145 for (HuginBase::CPVector::iterator it = ctrlPoints.begin(); it != ctrlPoints.end(); ++it) {
146 (*it).image1Nr = imgMapping[(*it).image1Nr];
147 (*it).image2Nr = imgMapping[(*it).image2Nr];
148 }
149
150 return ctrlPoints;
151}
152
153#if defined MAC_SELF_CONTAINED_BUNDLE
155{
156 // First check inside the bundle for (AutoCP generator "without path"), e.g. binary name with path stripped off
157 wxFileName file(progName);
158 // if executable contains no path, look inside bundle, if program can be found there
159 if(file.GetPath().IsEmpty())
160 //return MacGetPathToBundledResourceFile(MacCreateCFStringWithWxString(progName));
162 return wxEmptyString;
163}
164#endif
165
167{
168#if defined MAC_SELF_CONTAINED_BUNDLE
170 if(!bundled.IsEmpty())
171 return bundled;
172#else
173#if defined __WXMSW__ || defined UNIX_SELF_CONTAINED_BUNDLE
174 wxFileName prog(progName);
175 if(prog.IsAbsolute())
176 {
177 return progName;
178 }
179 else
180 {
182 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
184 pathlist.AddEnvList("PATH");
185 return pathlist.FindAbsoluteValidPath(progName);
186 };
187#endif
188#endif
189 return progName;
190};
191
193{
194#if defined MAC_SELF_CONTAINED_BUNDLE
196 return true;
197#endif
198 wxFileName prog(progName);
199 bool canStart=false;
200 if(prog.IsAbsolute())
201 {
202 canStart=(prog.IsFileExecutable());
203 }
204 else
205 {
207#if defined __WXMSW__ || defined UNIX_SELF_CONTAINED_BUNDLE
208 const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
210#endif
211 pathlist.AddEnvList("PATH");
212 wxString path = pathlist.FindAbsoluteValidPath(progName);
213 if(path.IsEmpty())
214 canStart=false;
215 else
216 {
217 wxFileName prog2(path);
218 canStart=(prog2.IsFileExecutable());
219 };
220 };
221 if(!canStart)
222 CPMessage(wxString::Format(
223 _("Could not find \"%s\" in path.\nMaybe you have not installed it properly or given a wrong path in the settings."),progName.c_str()),
224 _("Error"),parent);
225 return canStart;
226};
227
229{
230 wxString tempDir = wxConfigBase::Get()->Read("tempDir", wxEmptyString);
231 if (!tempDir.IsEmpty())
232 {
233 if (tempDir.Last() != wxFileName::GetPathSeparator())
234 {
235 tempDir.Append(wxFileName::GetPathSeparator());
236 };
237 };
238 return tempDir;
239};
240
247
249 HuginBase::Panorama & pano,
250 const HuginBase::UIntSet & imgs,
251 int nFeatures,
252 int & ret_value,
253 wxWindow *parent)
254{
256 CPDetectorType t = setting.GetType();
257 //check, if the cp generators exists
258 if(!CanStartProg(setting.GetProg(),parent))
259 return cps;
260 if(setting.IsTwoStepDetector())
261 if(!CanStartProg(setting.GetProgMatcher(),parent))
262 return cps;
264 if(!setting.GetProgStack().IsEmpty())
265 if(!CanStartProg(setting.GetProgStack(),parent))
266 return cps;
267 //change locale for correct numeric output
268 char * p = setlocale(LC_NUMERIC,NULL);
269 char * old_locale = strdup(p);
271 switch (t) {
273 {
274 // autopano@kolor
276 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
277 break;
278 }
280 {
281 // autopano-sift
283 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
284 break;
285 }
287 {
288 // autopano-sift with stacks
290 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
291 break;
292 }
294 {
295 // autopano-sift for multi-row panoramas
297 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
298 break;
299 }
301 {
302 // autopano-sift for multi-row panoramas with stacks
304 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
305 break;
306 }
308 {
309 // autopano-sift for panoramas with position information
311 cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
312 break;
313 }
314 default:
315 DEBUG_ERROR("Invalid autopano type");
316 }
319 return cps;
320}
321
323 std::vector<wxString> &keyFiles, wxWindow *parent)
324{
325 if(setting.IsTwoStepDetector())
326 {
327 if(!keyFiles.empty())
328 {
329 for(unsigned int i=0;i<keyFiles.size();i++)
330 {
332 {
333 if(!wxRemoveFile(keyFiles[i]))
334 {
335 DEBUG_DEBUG("could not remove temporary file: " << keyFiles[i].c_str());
336 };
337 };
338 };
339 };
340 }
341 else
342 {
343 if(!setting.IsCleanupPossible())
344 {
345 return;
346 };
347 // create suitable command line..
349 wxString cleanupArgs = setting.GetArgsCleanup();
350 if(cleanupArgs.IsEmpty())
351 {
352 return;
353 };
354
355 wxString ptoinfile_name = wxFileName::CreateTempFileName(GetCheckedTempDir() + ("ap_inproj"));
357 std::ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
358 pano.printPanoramaScript(ptoinstream, pano.getOptimizeVector(), pano.getOptions(), imgs, false);
359
360 int ret_value=CPExecute(cleanupExe, cleanupArgs, _("cleaning up temporary keypoint files"), parent);
361
362 if(ret_value!=0)
363 {
364 DEBUG_DEBUG("could not cleanup temporary keypoint files");
365 };
367 {
368 DEBUG_DEBUG("could not remove temporary file: " << ptoinfile_name.c_str());
369 };
370 };
371};
372
374 int nFeatures, int & ret_value, wxWindow *parent)
375{
377 if (imgs.empty()) {
378 return cps;
379 }
380 // create suitable command line..
381 const wxString autopanoExe = GetProgPath(setting.GetProg());
382 // special cases
383 // geocpset needs other control points to link only unlinked images
384 // linefind needs other control points to correctly ignore nadir/zenit near images
385 // (but only when all images are selected, ignore this limitation when user
386 // selected certain images
387 // cpfind with prealigned setting
388 const bool detectorNeedsOtherCp = (autopanoExe.Find("geocpset") != wxNOT_FOUND) ||
389 (autopanoExe.Find("linefind") != wxNOT_FOUND && pano.getNrOfImages()==imgs.size()) ||
390 (autopanoExe.Find("cpfind") != wxNOT_FOUND && setting.GetArgs().Find("--prealigned") != wxNOT_FOUND);
391 size_t oldCpsSize = -1;
392 if(setting.IsTwoStepDetector())
393 {
394 std::vector<wxString> keyFiles(pano.getNrOfImages());
395 cps=automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
396 Cleanup(setting, pano, imgs, keyFiles, parent);
397 return cps;
398 };
399 wxString autopanoArgs = setting.GetArgs();
400
401 // generate hash for all old cps
402 std::set<std::string> cpsHash;
403 {
404 const HuginBase::CPVector& cps = pano.getCtrlPoints();
405 for (auto& cp : cps)
406 {
407 cpsHash.insert(cp.getCPString());
408 };
409 };
410
411 // TODO: create a secure temporary filename here
412 wxString ptofile = wxFileName::CreateTempFileName(GetCheckedTempDir() + "ap_res");
414 wxString tmp;
415 tmp.Printf("%d", nFeatures);
416 autopanoArgs.Replace("%p", tmp);
417
418 HuginBase::SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
419 tmp.Printf("%f", firstImg.getHFOV());
420 autopanoArgs.Replace("%v", tmp);
421
422 tmp.Printf("%d", (int) firstImg.getProjection());
423 autopanoArgs.Replace("%f", tmp);
424
425 long idx = autopanoArgs.Find("%namefile") ;
426 DEBUG_DEBUG("find %namefile in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
427 bool use_namefile = idx >=0;
428 idx = autopanoArgs.Find("%i");
429 DEBUG_DEBUG("find %i in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
430 bool use_params = idx >=0;
431 idx = autopanoArgs.Find("%s");
432 bool use_inputscript = idx >=0;
433
435 CPMessage(_("Please use %namefile, %i or %s to specify the input files for the control point detector"),
436 _("Error in control point detector command"), parent);
437 return cps;
438 }
439
442 if (use_namefile) {
443 // create temporary file with image names.
444 namefile_name = wxFileName::CreateTempFileName(GetCheckedTempDir() + "ap_imgnames", &namefile);
445 DEBUG_DEBUG("before replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
447 DEBUG_DEBUG("after replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
448 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
449 {
450 namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME));
451 namefile.Write("\r\n");
452 }
453 // close namefile
455 namefile.Close();
456 }
457 } else {
458 std::string imgFiles;
459 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
460 {
461 imgFiles.append(" ").append(hugin_utils::quoteFilename(pano.getImage(*it).getFilename()));
462 }
463 autopanoArgs.Replace("%i", wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
464 }
465
467 if (use_inputscript) {
469 ptoinfile_name = wxFileName::CreateTempFileName(GetCheckedTempDir() + ("ap_inproj"));
471
472 std::ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
473 // create a temporary project with only the selected images
476 {
477 // when the cp generator needs the other cps to work
478 // store the number of cps in the input project
480 }
481 else
482 {
483 // in all other cases delete all cps
485 tempPano.setCtrlPoints(emptyCPV);
486 };
488 fill_set(tempImgSet, 0, tempPano.getNrOfImages() - 1);
489 tempPano.printPanoramaScript(ptoinstream, tempPano.getOptimizeVector(), tempPano.getOptions(), tempImgSet, false);
490 }
491
492#ifdef __WXMSW__
493 if (autopanoArgs.size() > 32000) {
494 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"),
495 _("Too many images selected"), parent );
496 return cps;
497 }
498#endif
499
501 DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal));
502
503 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(autopanoArgs);
504 if (arguments.GetCount() > 127) {
505 DEBUG_ERROR("Too many arguments for call to wxExecute()");
506 DEBUG_ERROR("Try using the %%s parameter in preferences");
507 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);
508 return cps;
509 }
510
511 ret_value = 0;
512 // use MyExternalCmdExecDialog
513 ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
514
516 return cps;
517 } else if (ret_value == -1) {
518 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
519 return cps;
520 } else if (ret_value > 0) {
521 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
522 _("wxExecute Error"), parent);
523 return cps;
524 }
525
526 if (! wxFileExists(ptofile.c_str())) {
527 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()),
528 _("Control point detector failure"), parent );
529 return cps;
530 }
531
532 // read and update control points
533 cps = readUpdatedControlPoints((const char*)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs, !use_inputscript);
535 {
536 // for geocpset/cpfind --prealigned remove all old cps from the vector
537 cps.erase(cps.begin(), cps.begin() + oldCpsSize);
538 };
539 // now check that the new cp are unique
540 if (!cps.empty())
541 {
542 size_t i = cps.size() - 1;
543 for (auto it = cps.rbegin(); it != cps.rend(); ++it, --i)
544 {
545 if (set_contains(cpsHash, it->getCPString()))
546 {
547 // remove duplicates
548 cps.erase(cps.begin() + i);
549 };
550 };
551 };
552
554 namefile.Close();
556 }
557
560 }
561
562 if (!wxRemoveFile(ptofile)) {
563 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
564 }
565
566 return cps;
567}
568
570 int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
571{
573 if (imgs.empty())
574 {
575 return cps;
576 }
577 DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
578 // create suitable command line..
580 wxString matcherExe = GetProgPath(setting.GetProgMatcher());
582 wxString matcherArgs = setting.GetArgsMatcher();
583
584 //check arguments
585 if(generateKeysArgs.Find("%i")==wxNOT_FOUND || generateKeysArgs.Find("%k")==wxNOT_FOUND)
586 {
587 CPMessage(_("Please use %i to specify the input files and %k to specify the keypoint file for the generate keys step"),
588 _("Error in control point detector command"), parent);
589 return cps;
590 };
591 if(matcherArgs.Find("%k")==wxNOT_FOUND || matcherArgs.Find("%o")==wxNOT_FOUND)
592 {
593 CPMessage(_("Please use %k to specify the keypoint files and %o to specify the output project file for the matching step"),
594 _("Error in control point detector command"), parent);
595 return cps;
596 };
597
598 ret_value=0;
600 for (HuginBase::UIntSet::const_iterator img = imgs.begin(); img != imgs.end(); ++img)
601 {
602 if(keyFiles[*img].IsEmpty())
603 {
604 //no key files exists, so generate it
605 wxString keyfile=wxFileName::CreateTempFileName(tempDir+"apk_");
606 keyFiles[*img]=keyfile;
608 wxString tmp;
609 tmp.Printf("%d", nFeatures);
610 cmd.Replace("%p", tmp);
611
613 tmp.Printf("%f", srcImg.getHFOV());
614 cmd.Replace("%v", tmp);
615
616 tmp.Printf("%d", (int) srcImg.getProjection());
617 cmd.Replace("%f", tmp);
618
619 cmd.Replace("%i",hugin_utils::wxQuoteFilename(wxString(srcImg.getFilename().c_str(), HUGIN_CONV_FILENAME)));
621 // use MyExternalCmdExecDialog
622 ret_value = CPExecute(generateKeysExe, cmd, _("generating key file"), parent);
625 return cps;
626 else
627 if (ret_value == -1)
628 {
629 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
630 return cps;
631 }
632 else
633 if (ret_value > 0)
634 {
635 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
636 _("wxExecute Error"), parent);
637 return cps;
638 };
639 };
640 };
641
642 // TODO: create a secure temporary filename here
643 wxString ptofile = wxFileName::CreateTempFileName(GetCheckedTempDir() + "ap_res");
645 wxString tmp;
646 tmp.Printf("%d", nFeatures);
647 matcherArgs.Replace("%p", tmp);
648
649 HuginBase::SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
650 tmp.Printf("%f", firstImg.getHFOV());
651 matcherArgs.Replace("%v", tmp);
652
653 tmp.Printf("%d", (int) firstImg.getProjection());
654 matcherArgs.Replace("%f", tmp);
655
657 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
658 {
659 imgFiles.append(" ").append(hugin_utils::wxQuoteFilename(keyFiles[*it]));
660 };
661 matcherArgs.Replace("%k", wxString (imgFiles.wc_str(), HUGIN_CONV_FILENAME));
662
663#ifdef __WXMSW__
664 if (matcherArgs.size() > 32000) {
665 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"),
666 _("Too many images selected"), parent );
667 return cps;
668 }
669#endif
670
672 DEBUG_DEBUG("Executing: " << matcherExe.mb_str(wxConvLocal) << " " << matcherArgs.mb_str(wxConvLocal));
673
674 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(matcherArgs);
675 if (arguments.GetCount() > 127) {
676 DEBUG_ERROR("Too many arguments for call to wxExecute()");
677 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);
678 return cps;
679 }
680
681 // use MyExternalCmdExecDialog
682 ret_value = CPExecute(matcherExe, matcherArgs, _("finding control points"), parent);
683
685 return cps;
686 else
687 if (ret_value == -1)
688 {
689 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
690 return cps;
691 }
692 else
693 if (ret_value > 0)
694 {
695 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
696 _("wxExecute Error"), parent);
697 return cps;
698 };
699
700 if (! wxFileExists(ptofile.c_str()))
701 {
702 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()),
703 _("Control point detector failure"), parent );
704 return cps;
705 }
706
707 // read and update control points
708 cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs, true);
709
710 if (!wxRemoveFile(ptofile)) {
711 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
712 }
713
714 return cps;
715};
716
718 int nFeatures, int & ret_value, wxWindow *parent)
719{
721 wxString autopanoExe = setting.GetProg();
722
723 // write default autopano.kolor.com flags
724 wxString autopanoArgs = setting.GetArgs();
725
726 std::string imgFiles;
727 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
728 {
729 imgFiles.append(" ").append(hugin_utils::quoteFilename(pano.getImage(*it).getFilename()));
730 }
731
732 wxString ptofilepath = wxFileName::CreateTempFileName(GetCheckedTempDir() + "ap_res");
734 wxString ptofile = ptofn.GetFullName();
736 wxString tmp;
737 tmp.Printf("%d", nFeatures);
738 autopanoArgs.Replace("%p", tmp);
739 HuginBase::SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
740 tmp.Printf("%f", firstImg.getHFOV());
741 autopanoArgs.Replace("%v", tmp);
742
743 tmp.Printf("%d", (int) firstImg.getProjection());
744 autopanoArgs.Replace("%f", tmp);
745
746 autopanoArgs.Replace("%i", wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
747
748 wxString tempdir = ptofn.GetPath();
749 autopanoArgs.Replace("%d", ptofn.GetPath());
752#ifdef __WXMSW__
753 if (cmd.size() > 32766) {
754 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"),
755 _("Too many images selected"), parent);
756 return cps;
757 }
758#endif
759 DEBUG_DEBUG("Executing: " << cmd.c_str());
760
761 wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(cmd);
762 if (arguments.GetCount() > 127) {
763 DEBUG_ERROR("Too many arguments for call to wxExecute()");
764 DEBUG_ERROR("Try using the %s parameter in preferences");
765 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);
766 return cps;
767 }
768
769 ret_value = 0;
770 // use MyExternalCmdExecDialog
771 ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
772
774 return cps;
775 } else if (ret_value == -1) {
776 CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
777 return cps;
778 } else if (ret_value > 0) {
779 CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
780 _("wxExecute Error"), parent);
781 return cps;
782 }
783
784 ptofile = ptofn.GetFullPath();
785 ptofile.append("0.oto");
786 if (! wxFileExists(ptofile.c_str()) ) {
787 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()),
788 _("Control point detector failure"), parent );
789 return cps;
790 }
791 // read and update control points
792 cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs, true);
793
794 if (!wxRemoveFile(ptofile)) {
795 DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
796 }
797 return cps;
798}
799
800struct img_ev
801{
802 unsigned int img_nr;
803 double ev;
804};
806{
807 unsigned int layer_nr;
808 std::vector<img_ev> images;
809};
810bool sort_img_ev (img_ev i1, img_ev i2) { return (i1.ev<i2.ev); };
811
813{
814 for(unsigned int i=0;i<new_cp.size();i++)
815 {
817 bool duplicate=false;
818 for(unsigned int j=0;j<cpv.size();j++)
819 {
820 if(cp==cpv[j])
821 {
822 duplicate=true;
823 break;
824 }
825 };
826 if(!duplicate)
827 {
828 cpv.push_back(cp);
829 if(pano!=NULL)
830 pano->addCtrlPoint(cp);
831 };
832 };
833};
834
836 int nFeatures, int & ret_value, wxWindow *parent)
837{
839 if (imgs.empty()) {
840 return cps;
841 };
842 std::vector<stack_img> stack_images;
844 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
845 {
846 unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
847 //check, if this stack is already in list
848 bool found=false;
849 unsigned int index=0;
850 for(index=0;index<stack_images.size();index++)
851 {
852 found=(stack_images[index].layer_nr==stack_nr);
853 if(found)
854 break;
855 };
856 if(!found)
857 {
858 //new stack
859 stack_images.resize(stack_images.size()+1);
860 index=stack_images.size()-1;
861 //add new stack
862 stack_images[index].layer_nr=stack_nr;
863 };
864 //add new image
865 unsigned int new_image_index=stack_images[index].images.size();
866 stack_images[index].images.resize(new_image_index+1);
867 stack_images[index].images[new_image_index].img_nr=*it;
868 stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
869 };
870 delete variable_groups;
871 //get image with median exposure for search with cp generator
873 for(unsigned int i=0;i<stack_images.size();i++)
874 {
875 std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
876 unsigned int index=0;
877 if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
878 {
879 index=stack_images[i].images.size() / 2;
880 };
881 images_layer.insert(stack_images[i].images[index].img_nr);
882 };
883 //generate cp for median exposure
884 ret_value=0;
885 if(images_layer.size()>1)
886 {
889 if(ret_value!=0)
890 return cps;
891 };
892 //now work on all stacks
893 if(!setting.GetProgStack().IsEmpty())
894 {
897 stack_setting.SetProg(setting.GetProgStack());
898 stack_setting.SetArgs(setting.GetArgsStack());
899
900 for(unsigned int i=0;i<stack_images.size();i++)
901 {
903 images_stack.clear();
904 for(unsigned int j=0;j<stack_images[i].images.size();j++)
905 images_stack.insert(stack_images[i].images[j].img_nr);
906 if(images_stack.size()>1)
907 {
910 if(!new_cps.empty())
912 if(ret_value!=0)
913 return cps;
914 };
915 };
916 }
917 return cps;
918};
919
921 int nFeatures, int & ret_value, wxWindow *parent)
922{
924 if (imgs.size() < 2)
925 {
926 return cps;
927 };
928 std::vector<wxString> keyFiles(pano.getNrOfImages());
929 //generate cp for every consecutive image pair
930 unsigned int counter=0;
931 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end();)
932 {
933 if(counter==imgs.size()-1)
934 break;
935 counter++;
937 ImagePair.clear();
938 ImagePair.insert(*it);
939 ++it;
940 ImagePair.insert(*it);
943 new_cps.clear();
944 if(setting.IsTwoStepDetector())
946 else
948 if(!new_cps.empty())
950 if(ret_value!=0)
951 {
952 Cleanup(setting, pano, imgs, keyFiles, parent);
953 return cps;
954 };
955 };
956 // now connect all image groups
957 // generate temporary panorama to add all found cps
959 fill_set(allImgs, 0, pano.getNrOfImages()-1);
961 for (HuginBase::CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
963
965 const HuginGraph::ImageGraph::Components comps=graph.GetComponents();
966 size_t n = comps.size();
967 if(n>1)
968 {
970 for(size_t i=0;i<n;i++)
971 {
972 ImagesGroups.insert(*(comps[i].begin()));
973 if(comps[i].size()>1)
974 ImagesGroups.insert(*(comps[i].rbegin()));
975 };
978 if(setting.IsTwoStepDetector())
980 else
982 if(!new_cps.empty())
984 if(ret_value!=0)
985 {
986 Cleanup(setting, pano, imgs, keyFiles, parent);
987 return cps;
988 };
990 n = graph2.IsConnected() ? 1 : 2;
991 };
992 if(n==1 && setting.GetOption())
993 {
994 //next steps happens only when all images are connected;
995 //now optimize panorama
998 // calculate proper scaling, 1:1 resolution.
999 // Otherwise optimizer distances are meaningless.
1000 opts.setWidth(30000, false);
1001 opts.setHeight(15000);
1002
1003 optPano.setOptions(opts);
1005
1006 opts.setWidth(w);
1007 opts.setHeight(w/2);
1008 optPano.setOptions(opts);
1009
1010 //generate optimize vector, optimize only yaw and pitch
1013 for (unsigned i=0; i < optPano.getNrOfImages(); i++)
1014 {
1015 std::set<std::string> imgopt;
1016 if(i==opts.optimizeReferenceImage)
1017 {
1018 //optimize only anchors pitch, not yaw
1019 imgopt.insert("p");
1020 }
1021 else
1022 {
1023 // do not optimize anchor image's stack for position.
1024 if(!optPano.getImage(i).YawisLinkedWith(anchorImage))
1025 {
1026 imgopt.insert("p");
1027 imgopt.insert("y");
1028 };
1029 };
1030 optvars.push_back(imgopt);
1031 }
1032 optPano.setOptimizeVector(optvars);
1033
1034 // remove vertical and horizontal control points
1035 HuginBase::CPVector backupOldCPS = optPano.getCtrlPoints();
1037 for (HuginBase::CPVector::const_iterator it = backupOldCPS.begin(); it != backupOldCPS.end(); ++it) {
1038 if (it->mode == HuginBase::ControlPoint::X_Y)
1039 {
1040 backupNewCPS.push_back(*it);
1041 }
1042 }
1043 optPano.setCtrlPoints(backupNewCPS);
1044 // do a first pairwise optimisation step
1047 optPano.setCtrlPoints(backupOldCPS);
1048 //and find cp on overlapping images
1049 //work only on image pairs, which are not yet connected
1052 newSetting.SetProg(setting.GetProg());
1053 newSetting.SetArgs(setting.GetArgs());
1054 if(setting.IsTwoStepDetector())
1055 {
1056 newSetting.SetProgMatcher(setting.GetProgMatcher());
1057 newSetting.SetArgsMatcher(setting.GetArgsMatcher());
1058 };
1059 newSetting.SetOption(true);
1061 if(setting.IsTwoStepDetector())
1063 else
1065 if(!new_cps.empty())
1067 };
1068 Cleanup(setting, pano, imgs, keyFiles, parent);
1069 return cps;
1070};
1071
1073 int nFeatures, int & ret_value, wxWindow *parent)
1074{
1076 if (imgs.empty()) {
1077 return cps;
1078 };
1079 std::vector<stack_img> stack_images;
1081 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
1082 {
1083 unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
1084 //check, if this stack is already in list
1085 bool found=false;
1086 unsigned int index=0;
1087 for(index=0;index<stack_images.size();index++)
1088 {
1089 found=(stack_images[index].layer_nr==stack_nr);
1090 if(found)
1091 break;
1092 };
1093 if(!found)
1094 {
1095 //new stack
1096 stack_images.resize(stack_images.size()+1);
1097 index=stack_images.size()-1;
1098 //add new stack
1099 stack_images[index].layer_nr=stack_nr;
1100 };
1101 //add new image
1102 unsigned int new_image_index=stack_images[index].images.size();
1103 stack_images[index].images.resize(new_image_index+1);
1104 stack_images[index].images[new_image_index].img_nr=*it;
1105 stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
1106 };
1107 delete variable_groups;
1108 //get image with median exposure for search with cp generator
1110 for(unsigned int i=0;i<stack_images.size();i++)
1111 {
1112 std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
1113 unsigned int index=0;
1114 if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
1115 {
1116 index=stack_images[i].images.size() / 2;
1117 };
1118 images_layer.insert(stack_images[i].images[index].img_nr);
1119 };
1120 ret_value=0;
1121 //work on all stacks
1122 if(!setting.GetProgStack().IsEmpty())
1123 {
1126 stack_setting.SetProg(setting.GetProgStack());
1127 stack_setting.SetArgs(setting.GetArgsStack());
1128
1129 for(unsigned int i=0;i<stack_images.size();i++)
1130 {
1132 images_stack.clear();
1133 for(unsigned int j=0;j<stack_images[i].images.size();j++)
1134 images_stack.insert(stack_images[i].images[j].img_nr);
1135 if(images_stack.size()>1)
1136 {
1139 if(!new_cps.empty())
1141 if(ret_value!=0)
1142 {
1143 std::vector<wxString> emptyKeyfiles;
1144 Cleanup(setting, pano, imgs, emptyKeyfiles, parent);
1145 return cps;
1146 };
1147 };
1148 };
1149 }
1150 //generate cp for median exposure with multi-row algorithm
1151 if(images_layer.size()>1)
1152 {
1154 fill_set(allImgs, 0, pano.getNrOfImages()-1);
1155 HuginBase::Panorama newPano = pano.getSubset(allImgs);
1156 if(!cps.empty())
1157 for (HuginBase::CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
1158 newPano.addCtrlPoint(*it);
1159
1162 if(!new_cps.empty())
1164 };
1165 return cps;
1166};
1167
1169 int nFeatures, int & ret_value, wxWindow *parent)
1170{
1171 std::vector<wxString> keyFiles(pano.getNrOfImages());
1172 return automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
1173};
1174
1176 int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
1177{
1179 if (imgs.size()<2)
1180 return cps;
1181 DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
1182
1183 std::vector<HuginBase::UIntSet> usedImages;
1184 usedImages.resize(pano.getNrOfImages());
1185 if(setting.GetOption())
1186 {
1187 //only work on not connected image pairs
1189 for(unsigned i=0;i<oldCps.size();i++)
1190 {
1192 {
1193 usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr);
1194 usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr);
1195 };
1196 };
1197 };
1199 overlap.calculate(10);
1200 for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
1201 {
1202 HuginBase::UIntSet images;
1203 images.clear();
1204 images.insert(*it);
1205 HuginBase::UIntSet::const_iterator it2 = it;
1206 for(++it2;it2!=imgs.end();++it2)
1207 {
1208 //check if this image pair was yet used
1210 continue;
1211 //now check position
1212 if(overlap.getOverlap(*it,*it2)>0)
1213 {
1214 images.insert(*it2);
1215 };
1216 };
1217 if(images.size()<2)
1218 continue;
1219 //remember image pairs for later
1220 for (HuginBase::UIntSet::const_iterator img_it = images.begin(); img_it != images.end(); ++img_it)
1221 for (HuginBase::UIntSet::const_iterator img_it2 = images.begin(); img_it2 != images.end(); ++img_it2)
1222 usedImages[*img_it].insert(*img_it2);
1225 if(setting.IsTwoStepDetector())
1227 else
1228 new_cps=matcher.automatch(setting, pano, images, nFeatures, ret_value, parent);
1229 if(!new_cps.empty())
1231 if(ret_value!=0)
1232 {
1233 Cleanup(setting, pano, imgs, keyFiles, parent);
1234 return cps;
1235 };
1236 };
1237 Cleanup(setting, pano, imgs, keyFiles, parent);
1238 return cps;
1239};
void CPMessage(const wxString message, const wxString caption, wxWindow *parent)
int CPExecute(wxString prog, wxString args, wxString caption, wxWindow *parent)
void AddControlPointsWithCheck(HuginBase::CPVector &cpv, HuginBase::CPVector &new_cp, HuginBase::Panorama *pano=NULL)
bool sort_img_ev(img_ev i1, img_ev i2)
wxString GetProgPath(wxString progName)
bool CanStartProg(wxString progName, wxWindow *parent)
wxString GetCheckedTempDir()
CPDetectorType
@ CPDetector_AutoPanoSiftMultiRow
@ CPDetector_AutoPanoSiftStack
@ CPDetector_AutoPanoSiftMultiRowStack
@ CPDetector_AutoPanoSift
@ CPDetector_AutoPanoSiftPreAlign
@ CPDetector_AutoPano
image1Nr
image2Nr
definitions of classes to calculate overlap between different images
int MyExecuteCommandOnDialog(wxString command, wxString args, wxWindow *parent, wxString title, bool isQuoted)
execute a single command in own dialog, redirect output to frame and allow canceling
const int HUGIN_EXIT_CODE_CANCELLED
!! from PTOptimise.h 1951
Somewhere to specify what variables belong to what.
HuginBase::CPVector readUpdatedControlPoints(const std::string &file, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, bool reordered)
virtual void Cleanup(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, std::vector< wxString > &keyFiles, wxWindow *parent=NULL)
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher that uses Alexandres sift matcher.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher for multi-rows, which considers stacks.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher for multi-row panoramas based on an idea by Bruno Postle.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher that uses the align information in the panorama to generate cp between overlapping images.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher that uses Sebastians Nowozin's excellent sift matcher and considers stacks.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
A matcher that uses Sebastians Nowozin's excellent sift matcher.
virtual HuginBase::CPVector automatch(CPDetectorSetting &setting, HuginBase::Panorama &pano, const HuginBase::UIntSet &imgs, int nFeatures, int &ret_value, wxWindow *parent=NULL)
Do cp matching, calles the right routines, based on the matcher selected.
class, which stores all settings of one cp detector
void SetProg(wxString new_prog)
sets program for one step detector or feature descriptor
void SetType(CPDetectorType new_type)
sets type of this setting
static void autoOptimise(PanoramaData &pano, bool optRoll=true)
class for calculating overlap of images
static double calcOptimalScale(PanoramaData &panorama)
represents a control point
Memento class for a Panorama object.
Definition Panorama.h:50
bool loadPTScript(std::istream &i, int &ptoVersion, const std::string &prefix="")
load a Hugin file
Panorama image options.
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void setHeight(unsigned int h)
set panorama height
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition Panorama.cpp:381
void printPanoramaScript(std::ostream &o, const OptimizeVector &optvars, const PanoramaOptions &options, const UIntSet &imgs, bool forPTOptimizer, const std::string &stripPrefix="") const
create an optimizer script
Definition Panorama.cpp:503
std::size_t getNrOfCtrlPoints() const
number of control points
Definition Panorama.h:306
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition Panorama.h:319
Panorama getSubset(const UIntSet &imgs) const
get a subset of the panorama
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition Panorama.h:454
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
All variables of a source image.
class to work with images graphs created from a HuginBase::Panorama class it creates a graph based on...
Definition ImageGraph.h:45
std::vector< HuginBase::UIntSet > Components
stores the components of the graph
Definition ImageGraph.h:50
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
functions for interaction with the hugin configuration file
platform/compiler specific stuff.
#define DEBUG_ERROR(msg)
Definition utils.h:76
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_DEBUG(msg)
Definition utils.h:68
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
std::vector< ControlPoint > CPVector
std::vector< std::set< std::string > > OptimizeVector
std::set< unsigned int > UIntSet
str quoteFilename(const str &arg)
Quote a filename, so that it is surrounded by "".
Definition platform.h:158
str wxQuoteFilename(const str &arg)
Quote a filename, so that it is surrounded by "".
Definition wxPlatform.h:82
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
int roundi(T x)
Definition hugin_math.h:73
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition utils.cpp:160
include file for the hugin project
include file for the hugin project
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition stl_utils.h:74
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition stl_utils.h:81
unsigned int img_nr
std::vector< img_ev > images
unsigned int layer_nr
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
platform/compiler specific stuff.