1
// -*- c-basic-offset: 4 -*-
3
/** @file AutoCtrlPointCreator.cpp
5
* @brief implementation of AutoCtrlPointCreator Class
7
* @author Pablo d'Angelo <pablo.dangelo@web.de>
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public
11
* License as published by the Free Software Foundation; either
12
* version 2 of the License, or (at your option) any later version.
14
* This software is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* General Public License for more details.
19
* You should have received a copy of the GNU General Public
20
* License along with this software; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
#include "panoinc_WX.h"
32
#include <ext/stdio_filebuf.h>
35
#include "PT/Panorama.h"
36
#include "PT/ImageGraph.h"
38
#include "hugin/huginApp.h"
39
#include "hugin/config_defaults.h"
40
#include "icpfind/AutoCtrlPointCreator.h"
41
#include <algorithms/optimizer/PTOptimizer.h>
42
#include <algorithms/basic/CalculateOverlap.h>
44
#include "base_wx/MyExternalCmdExecDialog.h"
45
#include "base_wx/platform.h"
46
#include "base_wx/huginConfig.h"
47
#include "common/wxPlatform.h"
50
// somewhere SetDesc gets defined.. this breaks wx/cmdline.h on OSX
55
#include <wx/cmdline.h>
57
#if defined MAC_SELF_CONTAINED_BUNDLE
59
#include <CoreFoundation/CFBundle.h>
64
using namespace utils;
66
void CPMessage(const wxString message,const wxString caption, wxWindow *parent)
70
wxMessageBox(message,caption,wxOK | wxICON_ERROR,parent);
74
std::cout << message << std::endl;
78
int CPExecute(wxString prog, wxString args, wxString caption, wxWindow *parent)
82
return MyExecuteCommandOnDialog(prog, args, parent, caption);
86
wxString cmdline=prog+wxT(" ")+args;
87
return wxExecute(cmdline,wxEXEC_SYNC | wxEXEC_MAKE_GROUP_LEADER);
91
CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file,
94
ifstream stream(file.c_str());
95
if (! stream.is_open()) {
96
DEBUG_ERROR("Could not open autopano output: " << file);
101
PanoramaMemento newPano;
103
newPano.loadPTScript(stream, ptoVersion, "");
104
tmpp.setMemento(newPano);
106
// create mapping between the panorama images.
107
map<unsigned int, unsigned int> imgMapping;
108
for (unsigned int ni = 0; ni < tmpp.getNrOfImages(); ni++) {
109
std::string nname = stripPath(tmpp.getImage(ni).getFilename());
110
for (unsigned int oi=0; oi < pano.getNrOfImages(); oi++) {
111
std::string oname = stripPath(pano.getImage(oi).getFilename());
112
if (nname == oname) {
118
if (! set_contains(imgMapping, ni)) {
119
DEBUG_ERROR("Could not find image " << ni << ", name: " << tmpp.getImage(ni).getFilename() << " in autopano output");
125
// get control points
126
CPVector ctrlPoints = tmpp.getCtrlPoints();
127
// make sure they are in correct order
128
for (CPVector::iterator it= ctrlPoints.begin(); it != ctrlPoints.end(); ++it) {
129
(*it).image1Nr = imgMapping[(*it).image1Nr];
130
(*it).image2Nr = imgMapping[(*it).image2Nr];
136
#if defined MAC_SELF_CONTAINED_BUNDLE
137
wxString GetBundledProg(wxString progName)
139
// First check inside the bundle for (AutoCP generator "without path"), e.g. binary name with path stripped off
140
wxFileName file(progName);
141
// if executable contains no path, look inside bundle, if program can be found there
142
if(file.GetPath().IsEmpty())
143
//return MacGetPathToBundledResourceFile(MacCreateCFStringWithWxString(progName));
144
return MacGetPathToBundledExecutableFile(MacCreateCFStringWithWxString(progName));
145
return wxEmptyString;
149
wxString GetProgPath(wxString progName)
151
#if defined MAC_SELF_CONTAINED_BUNDLE
152
wxString bundled=GetBundledProg(progName);
153
if(!bundled.IsEmpty())
157
wxFileName prog(progName);
158
if(prog.IsAbsolute())
165
pathlist.Add(getExePath(wxTheApp->argv[0]));
166
pathlist.AddEnvList(wxT("PATH"));
167
return pathlist.FindAbsoluteValidPath(progName);
174
bool CanStartProg(wxString progName,wxWindow* parent)
176
#if defined MAC_SELF_CONTAINED_BUNDLE
177
if(!GetBundledProg(progName).IsEmpty())
180
wxFileName prog(progName);
182
if(prog.IsAbsolute())
184
canStart=(prog.IsFileExecutable());
190
pathlist.Add(getExePath(wxTheApp->argv[0]));
192
pathlist.AddEnvList(wxT("PATH"));
193
wxString path = pathlist.FindAbsoluteValidPath(progName);
198
wxFileName prog2(path);
199
canStart=(prog2.IsFileExecutable());
203
CPMessage(wxString::Format(
204
_("Could not find \"%s\" in path.\nMaybe you have not installed it properly or given a wrong path in the settings."),progName.c_str()),
209
CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
210
int nFeatures, wxWindow *parent)
213
return automatch(setting,pano,imgs,nFeatures,return_value,parent);
216
CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting,
218
const UIntSet & imgs,
224
CPDetectorType t = setting.GetType();
225
//check, if the cp generators exists
226
if(!CanStartProg(setting.GetProg(),parent))
228
if(setting.IsTwoStepDetector())
229
if(!CanStartProg(setting.GetProgMatcher(),parent))
231
if(t==CPDetector_AutoPanoSiftStack || t==CPDetector_AutoPanoSiftMultiRowStack)
232
if(!setting.GetProgStack().IsEmpty())
233
if(!CanStartProg(setting.GetProgStack(),parent))
235
//change locale for correct numeric output
236
char * p = setlocale(LC_NUMERIC,NULL);
237
char * old_locale = strdup(p);
238
setlocale(LC_NUMERIC,"C");
240
case CPDetector_AutoPano:
243
AutoPanoKolor matcher;
244
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
247
case CPDetector_AutoPanoSift:
250
AutoPanoSift matcher;
251
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
254
case CPDetector_AutoPanoSiftStack:
256
// autopano-sift with stacks
257
AutoPanoSiftStack matcher;
258
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
261
case CPDetector_AutoPanoSiftMultiRow:
263
// autopano-sift for multi-row panoramas
264
AutoPanoSiftMultiRow matcher;
265
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
268
case CPDetector_AutoPanoSiftMultiRowStack:
270
// autopano-sift for multi-row panoramas with stacks
271
AutoPanoSiftMultiRowStack matcher;
272
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
275
case CPDetector_AutoPanoSiftPreAlign:
277
// autopano-sift for panoramas with position information
278
AutoPanoSiftPreAlign matcher;
279
cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
283
DEBUG_ERROR("Invalid autopano type");
285
setlocale(LC_NUMERIC,old_locale);
290
void AutoCtrlPointCreator::Cleanup(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
291
std::vector<wxString> &keyFiles, wxWindow *parent)
293
if(setting.IsTwoStepDetector())
295
if(keyFiles.size()>0)
297
for(unsigned int i=0;i<keyFiles.size();i++)
299
if(wxFileExists(keyFiles[i]))
301
if(!wxRemoveFile(keyFiles[i]))
303
DEBUG_DEBUG("could not remove temporary file: " << keyFiles[i].c_str());
311
if(!setting.IsCleanupPossible())
315
// create suitable command line..
316
wxString cleanupExe = GetProgPath(setting.GetProg());
317
wxString cleanupArgs = setting.GetArgsCleanup();
318
if(cleanupArgs.IsEmpty())
323
wxString ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj"));
324
cleanupArgs.Replace(wxT("%s"), ptoinfile_name);
325
ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
326
pano.printPanoramaScript(ptoinstream, pano.getOptimizeVector(), pano.getOptions(), imgs, false);
328
int ret_value=CPExecute(cleanupExe, cleanupArgs, _("cleaning up temporary keypoint files"), parent);
332
DEBUG_DEBUG("could not cleanup temporary keypoint files");
334
if(!wxRemoveFile(ptoinfile_name))
336
DEBUG_DEBUG("could not remove temporary file: " << ptoinfile_name.c_str());
341
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
342
int nFeatures, int & ret_value, wxWindow *parent)
345
if (imgs.size() == 0) {
348
// create suitable command line..
349
wxString autopanoExe = GetProgPath(setting.GetProg());
350
if(setting.IsTwoStepDetector())
352
std::vector<wxString> keyFiles(pano.getNrOfImages());
353
cps=automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
354
Cleanup(setting, pano, imgs, keyFiles, parent);
357
wxString autopanoArgs = setting.GetArgs();
359
// TODO: create a secure temporary filename here
360
wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
361
autopanoArgs.Replace(wxT("%o"), ptofile);
363
tmp.Printf(wxT("%d"), nFeatures);
364
autopanoArgs.Replace(wxT("%p"), tmp);
366
SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
367
tmp.Printf(wxT("%f"), firstImg.getHFOV());
368
autopanoArgs.Replace(wxT("%v"), tmp);
370
tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
371
autopanoArgs.Replace(wxT("%f"), tmp);
373
// build a list of all image files, and a corrosponding connection map.
374
// local img nr -> global (panorama) img number
375
std::map<int,int> imgMapping;
377
long idx = autopanoArgs.Find(wxT("%namefile")) ;
378
DEBUG_DEBUG("find %namefile in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
379
bool use_namefile = idx >=0;
380
idx = autopanoArgs.Find(wxT("%i"));
381
DEBUG_DEBUG("find %i in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx);
382
bool use_params = idx >=0;
383
idx = autopanoArgs.Find(wxT("%s"));
384
bool use_inputscript = idx >=0;
386
if (! (use_namefile || use_params || use_inputscript)) {
387
CPMessage(_("Please use %namefile, %i or %s to specify the input files for control point detector"),
388
_("Error in control point detector command"), parent);
393
wxString namefile_name;
395
// create temporary file with image names.
396
namefile_name = wxFileName::CreateTempFileName(wxT("ap_imgnames"), &namefile);
397
DEBUG_DEBUG("before replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
398
autopanoArgs.Replace(wxT("%namefile"), namefile_name);
399
DEBUG_DEBUG("after replace %namefile: " << autopanoArgs.mb_str(wxConvLocal));
401
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
403
imgMapping[imgNr] = *it;
404
namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME));
405
namefile.Write(wxT("\r\n"));
409
if (namefile_name != wxString(wxT(""))) {
415
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
417
imgMapping[imgNr] = *it;
418
imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
421
autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
424
wxString ptoinfile_name;
425
if (use_inputscript) {
427
ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj"));
428
autopanoArgs.Replace(wxT("%s"), ptoinfile_name);
430
ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
431
pano.printPanoramaScript(ptoinstream, pano.getOptimizeVector(), pano.getOptions(), imgs, false);
435
if (autopanoArgs.size() > 32000) {
436
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"),
437
_("Too many images selected"), parent );
442
wxString cmd = autopanoExe + wxT(" ") + autopanoArgs;
443
DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal));
445
wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(autopanoArgs);
446
if (arguments.GetCount() > 127) {
447
DEBUG_ERROR("Too many arguments for call to wxExecute()");
448
DEBUG_ERROR("Try using the %%s parameter in preferences");
449
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);
454
// use MyExternalCmdExecDialog
455
ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
457
if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
459
} else if (ret_value == -1) {
460
CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
462
} else if (ret_value > 0) {
463
CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
464
_("wxExecute Error"), parent);
468
if (! wxFileExists(ptofile.c_str())) {
469
CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor wrong command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
470
_("Control point detector failure"), parent );
474
// read and update control points
475
cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
477
if (namefile_name != wxString(wxT(""))) {
479
wxRemoveFile(namefile_name);
482
if (ptoinfile_name != wxString(wxT(""))) {
483
wxRemoveFile(ptoinfile_name);
486
if (!wxRemoveFile(ptofile)) {
487
DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
493
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
494
int nFeatures, vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
497
if (imgs.size() == 0)
501
DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
502
// create suitable command line..
503
wxString generateKeysExe=GetProgPath(setting.GetProg());
504
wxString matcherExe = GetProgPath(setting.GetProgMatcher());
505
wxString generateKeysArgs=setting.GetArgs();
506
wxString matcherArgs = setting.GetArgsMatcher();
508
wxString tempDir= wxConfigBase::Get()->Read(wxT("tempDir"),wxT(""));
509
if(!tempDir.IsEmpty())
510
if(tempDir.Last()!=wxFileName::GetPathSeparator())
511
tempDir.Append(wxFileName::GetPathSeparator());
513
if(generateKeysArgs.Find(wxT("%i"))==wxNOT_FOUND || generateKeysArgs.Find(wxT("%k"))==wxNOT_FOUND)
515
CPMessage(_("Please use %i to specify the input files and %k to specify the keypoint file for generate keys step"),
516
_("Error in control point detector command"), parent);
519
if(matcherArgs.Find(wxT("%k"))==wxNOT_FOUND || matcherArgs.Find(wxT("%o"))==wxNOT_FOUND)
521
CPMessage(_("Please use %k to specify the keypoint files and %o to specify the output project file for the matching step"),
522
_("Error in control point detector command"), parent);
527
for(UIntSet::const_iterator img=imgs.begin();img!=imgs.end();img++)
529
if(keyFiles[*img].IsEmpty())
531
//no key files exists, so generate it
532
wxString keyfile=wxFileName::CreateTempFileName(tempDir+wxT("apk_"));
533
keyFiles[*img]=keyfile;
534
wxString cmd=generateKeysArgs;
536
tmp.Printf(wxT("%d"), nFeatures);
537
cmd.Replace(wxT("%p"), tmp);
539
SrcPanoImage srcImg = pano.getSrcImage(*img);
540
tmp.Printf(wxT("%f"), srcImg.getHFOV());
541
cmd.Replace(wxT("%v"), tmp);
543
tmp.Printf(wxT("%d"), (int) srcImg.getProjection());
544
cmd.Replace(wxT("%f"), tmp);
546
cmd.Replace(wxT("%i"),wxQuoteFilename(wxString(srcImg.getFilename().c_str(), HUGIN_CONV_FILENAME)));
547
cmd.Replace(wxT("%k"),wxQuoteFilename(keyfile));
548
// use MyExternalCmdExecDialog
549
ret_value = CPExecute(generateKeysExe, cmd, _("generating key file"), parent);
550
cmd=generateKeysExe+wxT(" ")+cmd;
551
if (ret_value == HUGIN_EXIT_CODE_CANCELLED)
556
CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
562
CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
563
_("wxExecute Error"), parent);
569
// TODO: create a secure temporary filename here
570
wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
571
matcherArgs.Replace(wxT("%o"), ptofile);
573
tmp.Printf(wxT("%d"), nFeatures);
574
matcherArgs.Replace(wxT("%p"), tmp);
576
SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
577
tmp.Printf(wxT("%f"), firstImg.getHFOV());
578
matcherArgs.Replace(wxT("%v"), tmp);
580
tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
581
matcherArgs.Replace(wxT("%f"), tmp);
583
// build a list of all image files, and a corrosponding connection map.
584
// local img nr -> global (panorama) img number
585
std::map<int,int> imgMapping;
589
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
591
imgMapping[imgNr] = *it;
592
imgFiles.append(wxT(" ")).append(wxQuoteFilename(keyFiles[*it]));
595
matcherArgs.Replace(wxT("%k"), wxString (imgFiles.wc_str(), HUGIN_CONV_FILENAME));
598
if (matcherArgs.size() > 32000) {
599
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"),
600
_("Too many images selected"), parent );
605
wxString cmd = matcherExe + wxT(" ") + matcherArgs;
606
DEBUG_DEBUG("Executing: " << matcherExe.mb_str(wxConvLocal) << " " << matcherArgs.mb_str(wxConvLocal));
608
wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(matcherArgs);
609
if (arguments.GetCount() > 127) {
610
DEBUG_ERROR("Too many arguments for call to wxExecute()");
611
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);
615
// use MyExternalCmdExecDialog
616
ret_value = CPExecute(matcherExe, matcherArgs, _("finding control points"), parent);
618
if (ret_value == HUGIN_EXIT_CODE_CANCELLED)
623
CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
629
CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
630
_("wxExecute Error"), parent);
634
if (! wxFileExists(ptofile.c_str()))
636
CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor wrong command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
637
_("Control point detector failure"), parent );
641
// read and update control points
642
cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
644
if (!wxRemoveFile(ptofile)) {
645
DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
651
CPVector AutoPanoKolor::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
652
int nFeatures, int & ret_value, wxWindow *parent)
655
wxString autopanoExe = setting.GetProg();
657
// write default autopano.kolor.com flags
658
wxString autopanoArgs = setting.GetArgs();
660
// build a list of all image files, and a corrosponding connection map.
661
// local img nr -> global (panorama) img number
662
std::map<int,int> imgMapping;
665
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
667
imgMapping[imgNr] = *it;
668
imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
672
wxString ptofilepath = wxFileName::CreateTempFileName(wxT("ap_res"));
673
wxFileName ptofn(ptofilepath);
674
wxString ptofile = ptofn.GetFullName();
675
autopanoArgs.Replace(wxT("%o"), ptofile);
677
tmp.Printf(wxT("%d"), nFeatures);
678
autopanoArgs.Replace(wxT("%p"), tmp);
679
SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
680
tmp.Printf(wxT("%f"), firstImg.getHFOV());
681
autopanoArgs.Replace(wxT("%v"), tmp);
683
tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
684
autopanoArgs.Replace(wxT("%f"), tmp);
686
autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
688
wxString tempdir = ptofn.GetPath();
689
autopanoArgs.Replace(wxT("%d"), ptofn.GetPath());
691
cmd.Printf(wxT("%s %s"), utils::wxQuoteFilename(autopanoExe).c_str(), autopanoArgs.c_str());
693
if (cmd.size() > 32766) {
694
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"),
695
_("Too many images selected"), parent);
699
DEBUG_DEBUG("Executing: " << cmd.c_str());
701
wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(cmd);
702
if (arguments.GetCount() > 127) {
703
DEBUG_ERROR("Too many arguments for call to wxExecute()");
704
DEBUG_ERROR("Try using the %s parameter in preferences");
705
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);
710
// use MyExternalCmdExecDialog
711
ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
713
if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
715
} else if (ret_value == -1) {
716
CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
718
} else if (ret_value > 0) {
719
CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
720
_("wxExecute Error"), parent);
724
ptofile = ptofn.GetFullPath();
725
ptofile.append(wxT("0.oto"));
726
if (! wxFileExists(ptofile.c_str()) ) {
727
CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor wrong command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()),
728
_("Control point detector failure"), parent );
731
// read and update control points
732
cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
734
if (!wxRemoveFile(ptofile)) {
735
DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
747
unsigned int layer_nr;
748
std::vector<img_ev> images;
750
bool sort_img_ev (img_ev i1, img_ev i2) { return (i1.ev<i2.ev); };
752
void AddControlPointsWithCheck(CPVector &cpv, CPVector &new_cp, Panorama *pano=NULL)
754
for(unsigned int i=0;i<new_cp.size();i++)
756
HuginBase::ControlPoint cp=new_cp[i];
757
bool duplicate=false;
758
for(unsigned int j=0;j<cpv.size();j++)
770
pano->addCtrlPoint(cp);
775
CPVector AutoPanoSiftStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
776
int nFeatures, int & ret_value, wxWindow *parent)
779
if (imgs.size() == 0) {
782
std::vector<stack_img> stack_images;
783
HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano);
784
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
786
unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
787
//check, if this stack is already in list
789
unsigned int index=0;
790
for(index=0;index<stack_images.size();index++)
792
found=(stack_images[index].layer_nr==stack_nr);
799
stack_images.resize(stack_images.size()+1);
800
index=stack_images.size()-1;
802
stack_images[index].layer_nr=stack_nr;
805
unsigned int new_image_index=stack_images[index].images.size();
806
stack_images[index].images.resize(new_image_index+1);
807
stack_images[index].images[new_image_index].img_nr=*it;
808
stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
810
delete variable_groups;
811
//get image with median exposure for search with cp generator
812
UIntSet images_layer;
813
for(unsigned int i=0;i<stack_images.size();i++)
815
std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
816
unsigned int index=0;
817
if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
819
index=stack_images[i].images.size() / 2;
821
images_layer.insert(stack_images[i].images[index].img_nr);
823
//generate cp for median exposure
825
if(images_layer.size()>1)
827
AutoPanoSift matcher;
828
cps=matcher.automatch(setting, pano, images_layer, nFeatures, ret_value, parent);
832
//now work on all stacks
833
if(!setting.GetProgStack().IsEmpty())
835
CPDetectorSetting stack_setting;
836
stack_setting.SetType(CPDetector_AutoPanoSift);
837
stack_setting.SetProg(setting.GetProgStack());
838
stack_setting.SetArgs(setting.GetArgsStack());
840
for(unsigned int i=0;i<stack_images.size();i++)
842
UIntSet images_stack;
843
images_stack.clear();
844
for(unsigned int j=0;j<stack_images[i].images.size();j++)
845
images_stack.insert(stack_images[i].images[j].img_nr);
846
if(images_stack.size()>1)
848
AutoPanoSift matcher;
849
CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
851
AddControlPointsWithCheck(cps,new_cps);
860
CPVector AutoPanoSiftMultiRow::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
861
int nFeatures, int & ret_value, wxWindow *parent)
868
std::vector<wxString> keyFiles(pano.getNrOfImages());
869
//generate cp for every consecutive image pair
870
unsigned int counter=0;
871
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); )
873
if(counter==imgs.size()-1)
878
ImagePair.insert(*it);
880
ImagePair.insert(*it);
881
AutoPanoSift matcher;
884
if(setting.IsTwoStepDetector())
885
new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, keyFiles, ret_value, parent);
887
new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, ret_value, parent);
889
AddControlPointsWithCheck(cps,new_cps);
892
Cleanup(setting, pano, imgs, keyFiles, parent);
896
// now connect all image groups
897
// generate temporary panorama to add all found cps
899
fill_set(allImgs, 0, pano.getNrOfImages()-1);
900
Panorama optPano=pano.getSubset(allImgs);
901
for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
902
optPano.addCtrlPoint(*it);
905
createCPGraph(optPano, graph);
907
int n = findCPComponents(graph, comps);
910
UIntSet ImagesGroups;
911
for(unsigned int i=0;i<n;i++)
913
ImagesGroups.insert(*(comps[i].begin()));
914
if(comps[i].size()>1)
915
ImagesGroups.insert(*(comps[i].rbegin()));
917
AutoPanoSift matcher;
919
if(setting.IsTwoStepDetector())
920
new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, keyFiles, ret_value, parent);
922
new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, ret_value, parent);
924
AddControlPointsWithCheck(cps,new_cps,&optPano);
927
Cleanup(setting, pano, imgs, keyFiles, parent);
930
createCPGraph(optPano,graph);
931
n=findCPComponents(graph, comps);
933
if(n==1 && setting.GetOption())
935
//next steps happens only when all images are connected;
936
//now optimize panorama
937
PanoramaOptions opts = pano.getOptions();
938
opts.setProjection(PanoramaOptions::EQUIRECTANGULAR);
939
// calculate proper scaling, 1:1 resolution.
940
// Otherwise optimizer distances are meaningless.
941
opts.setWidth(30000, false);
942
opts.setHeight(15000);
944
optPano.setOptions(opts);
945
int w = optPano.calcOptimalWidth();
948
optPano.setOptions(opts);
950
//generate optimize vector, optimize only yaw and pitch
951
OptimizeVector optvars;
952
const SrcPanoImage & anchorImage = optPano.getImage(opts.optimizeReferenceImage);
953
for (unsigned i=0; i < optPano.getNrOfImages(); i++)
955
std::set<std::string> imgopt;
956
if(i==opts.optimizeReferenceImage)
958
//optimize only anchors pitch, not yaw
963
// do not optimize anchor image's stack for position.
964
if(!optPano.getImage(i).YawisLinkedWith(anchorImage))
970
optvars.push_back(imgopt);
972
optPano.setOptimizeVector(optvars);
973
HuginBase::PTools::optimize(optPano);
974
//and find cp on overlapping images
975
//work only on image pairs, which are not yet connected
976
AutoPanoSiftPreAlign matcher;
977
CPDetectorSetting newSetting;
978
newSetting.SetProg(setting.GetProg());
979
newSetting.SetArgs(setting.GetArgs());
980
if(setting.IsTwoStepDetector())
982
newSetting.SetProgMatcher(setting.GetProgMatcher());
983
newSetting.SetArgsMatcher(setting.GetArgsMatcher());
985
newSetting.SetOption(true);
987
if(setting.IsTwoStepDetector())
988
new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, keyFiles, ret_value, parent);
990
new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, ret_value, parent);
992
AddControlPointsWithCheck(cps,new_cps);
994
Cleanup(setting, pano, imgs, keyFiles, parent);
998
CPVector AutoPanoSiftMultiRowStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
999
int nFeatures, int & ret_value, wxWindow *parent)
1002
if (imgs.size() == 0) {
1005
std::vector<stack_img> stack_images;
1006
HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano);
1007
for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
1009
unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
1010
//check, if this stack is already in list
1012
unsigned int index=0;
1013
for(index=0;index<stack_images.size();index++)
1015
found=(stack_images[index].layer_nr==stack_nr);
1022
stack_images.resize(stack_images.size()+1);
1023
index=stack_images.size()-1;
1025
stack_images[index].layer_nr=stack_nr;
1028
unsigned int new_image_index=stack_images[index].images.size();
1029
stack_images[index].images.resize(new_image_index+1);
1030
stack_images[index].images[new_image_index].img_nr=*it;
1031
stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
1033
delete variable_groups;
1034
//get image with median exposure for search with cp generator
1035
UIntSet images_layer;
1036
for(unsigned int i=0;i<stack_images.size();i++)
1038
std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
1039
unsigned int index=0;
1040
if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
1042
index=stack_images[i].images.size() / 2;
1044
images_layer.insert(stack_images[i].images[index].img_nr);
1047
//work on all stacks
1048
if(!setting.GetProgStack().IsEmpty())
1050
CPDetectorSetting stack_setting;
1051
stack_setting.SetType(CPDetector_AutoPanoSift);
1052
stack_setting.SetProg(setting.GetProgStack());
1053
stack_setting.SetArgs(setting.GetArgsStack());
1055
for(unsigned int i=0;i<stack_images.size();i++)
1057
UIntSet images_stack;
1058
images_stack.clear();
1059
for(unsigned int j=0;j<stack_images[i].images.size();j++)
1060
images_stack.insert(stack_images[i].images[j].img_nr);
1061
if(images_stack.size()>1)
1063
AutoPanoSift matcher;
1064
CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
1065
if(new_cps.size()>0)
1066
AddControlPointsWithCheck(cps,new_cps);
1069
std::vector<wxString> emptyKeyfiles;
1070
Cleanup(setting, pano, imgs, emptyKeyfiles, parent);
1076
//generate cp for median exposure with multi-row algorithm
1077
if(images_layer.size()>1)
1080
fill_set(allImgs, 0, pano.getNrOfImages()-1);
1081
Panorama newPano=pano.getSubset(allImgs);
1083
for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
1084
newPano.addCtrlPoint(*it);
1086
AutoPanoSiftMultiRow matcher;
1087
CPVector new_cps=matcher.automatch(setting, newPano, images_layer, nFeatures, ret_value, parent);
1088
if(new_cps.size()>0)
1089
AddControlPointsWithCheck(cps,new_cps);
1094
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
1095
int nFeatures, int & ret_value, wxWindow *parent)
1097
std::vector<wxString> keyFiles(pano.getNrOfImages());
1098
return automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
1101
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
1102
int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
1107
DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
1109
vector<UIntSet> usedImages;
1110
usedImages.resize(pano.getNrOfImages());
1111
if(setting.GetOption())
1113
//only work on not connected image pairs
1114
CPVector oldCps=pano.getCtrlPoints();
1115
for(unsigned i=0;i<oldCps.size();i++)
1117
if(oldCps[i].mode==ControlPoint::X_Y)
1119
usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr);
1120
usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr);
1124
HuginBase::CalculateImageOverlap overlap(&pano);
1125
overlap.calculate(10);
1126
for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
1131
UIntSet::const_iterator it2=it;
1132
for(++it2;it2!=imgs.end();it2++)
1134
//check if this image pair was yet used
1135
if(set_contains(usedImages[*it2],*it))
1137
//now check position
1138
if(overlap.getOverlap(*it,*it2)>0)
1140
images.insert(*it2);
1145
//remember image pairs for later
1146
for(UIntSet::const_iterator img_it=images.begin();img_it!=images.end();img_it++)
1147
for(UIntSet::const_iterator img_it2=images.begin();img_it2!=images.end();img_it2++)
1148
usedImages[*img_it].insert(*img_it2);
1149
AutoPanoSift matcher;
1151
if(setting.IsTwoStepDetector())
1152
new_cps=matcher.automatch(setting, pano, images, nFeatures, keyFiles, ret_value, parent);
1154
new_cps=matcher.automatch(setting, pano, images, nFeatures, ret_value, parent);
1155
if(new_cps.size()>0)
1156
AddControlPointsWithCheck(cps,new_cps);
1159
Cleanup(setting, pano, imgs, keyFiles, parent);
1163
Cleanup(setting, pano, imgs, keyFiles, parent);