~ubuntu-branches/ubuntu/trusty/hugin/trusty-proposed

« back to all changes in this revision

Viewing changes to src/hugin1/icpfind/AutoCtrlPointCreator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2011-01-06 14:28:24 UTC
  • mfrom: (1.1.9 upstream) (0.1.21 experimental)
  • Revision ID: james.westby@ubuntu.com-20110106142824-zn9lxylg5z44dynn
* Drop Cyril Brulebois from Uploaders. Thank you very much for your work.
* Bump package version. (rc3 was re-released as 2010.4.0).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- c-basic-offset: 4 -*-
 
2
 
 
3
/** @file AutoCtrlPointCreator.cpp
 
4
 *
 
5
 *  @brief implementation of AutoCtrlPointCreator Class
 
6
 *
 
7
 *  @author Pablo d'Angelo <pablo.dangelo@web.de>
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
22
 *
 
23
 */
 
24
 
 
25
#include <config.h>
 
26
 
 
27
#include "panoinc_WX.h"
 
28
#include "panoinc.h"
 
29
 
 
30
#include <fstream>
 
31
#ifdef __GNUC__
 
32
#include <ext/stdio_filebuf.h>
 
33
#endif
 
34
 
 
35
#include "PT/Panorama.h"
 
36
#include "PT/ImageGraph.h"
 
37
 
 
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>
 
43
 
 
44
#include "base_wx/MyExternalCmdExecDialog.h"
 
45
#include "base_wx/platform.h"
 
46
#include "base_wx/huginConfig.h"
 
47
#include "common/wxPlatform.h"
 
48
#include <wx/utils.h>
 
49
 
 
50
// somewhere SetDesc gets defined.. this breaks wx/cmdline.h on OSX
 
51
#ifdef SetDesc
 
52
#undef SetDesc
 
53
#endif
 
54
 
 
55
#include <wx/cmdline.h>
 
56
 
 
57
#if defined MAC_SELF_CONTAINED_BUNDLE
 
58
  #include <wx/dir.h>
 
59
  #include <CoreFoundation/CFBundle.h>
 
60
#endif
 
61
 
 
62
using namespace std;
 
63
using namespace PT;
 
64
using namespace utils;
 
65
 
 
66
void CPMessage(const wxString message,const wxString caption, wxWindow *parent)
 
67
{
 
68
    if(parent!=NULL)
 
69
    {
 
70
        wxMessageBox(message,caption,wxOK | wxICON_ERROR,parent);
 
71
    }
 
72
    else
 
73
    {
 
74
        std::cout << message << std::endl;
 
75
    }
 
76
};
 
77
 
 
78
int CPExecute(wxString prog, wxString args, wxString caption, wxWindow *parent)
 
79
{
 
80
    if(parent!=NULL)
 
81
    {
 
82
        return MyExecuteCommandOnDialog(prog, args, parent,  caption);
 
83
    }
 
84
    else
 
85
    {
 
86
        wxString cmdline=prog+wxT(" ")+args;
 
87
        return wxExecute(cmdline,wxEXEC_SYNC | wxEXEC_MAKE_GROUP_LEADER);
 
88
    };
 
89
};
 
90
 
 
91
CPVector AutoCtrlPointCreator::readUpdatedControlPoints(const std::string & file,
 
92
                                                    PT::Panorama & pano)
 
93
{
 
94
    ifstream stream(file.c_str());
 
95
    if (! stream.is_open()) {
 
96
        DEBUG_ERROR("Could not open autopano output: " << file);
 
97
        return CPVector();
 
98
    }
 
99
 
 
100
    Panorama tmpp;
 
101
    PanoramaMemento newPano;
 
102
    int ptoVersion = 0;
 
103
    newPano.loadPTScript(stream, ptoVersion, "");
 
104
    tmpp.setMemento(newPano);
 
105
 
 
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) {
 
113
                // insert image
 
114
                imgMapping[ni] = oi;
 
115
                break;
 
116
            }
 
117
        }
 
118
        if (! set_contains(imgMapping, ni)) {
 
119
            DEBUG_ERROR("Could not find image " << ni << ", name: " << tmpp.getImage(ni).getFilename() << " in autopano output");
 
120
            return CPVector();
 
121
        }
 
122
    }
 
123
 
 
124
 
 
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];
 
131
    }
 
132
 
 
133
    return ctrlPoints;
 
134
}
 
135
 
 
136
#if defined MAC_SELF_CONTAINED_BUNDLE
 
137
wxString GetBundledProg(wxString progName)
 
138
{
 
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;
 
146
}
 
147
#endif
 
148
 
 
149
wxString GetProgPath(wxString progName)
 
150
{
 
151
#if defined MAC_SELF_CONTAINED_BUNDLE
 
152
    wxString bundled=GetBundledProg(progName);
 
153
    if(!bundled.IsEmpty())
 
154
        return bundled;
 
155
#else 
 
156
#ifdef __WXMSW__
 
157
    wxFileName prog(progName);
 
158
    if(prog.IsAbsolute())
 
159
    {
 
160
        return progName;
 
161
    }
 
162
    else
 
163
    {
 
164
        wxPathList pathlist;
 
165
        pathlist.Add(getExePath(wxTheApp->argv[0]));
 
166
        pathlist.AddEnvList(wxT("PATH"));
 
167
        return pathlist.FindAbsoluteValidPath(progName);
 
168
    };
 
169
#endif
 
170
#endif
 
171
    return progName;
 
172
};
 
173
 
 
174
bool CanStartProg(wxString progName,wxWindow* parent)
 
175
{
 
176
#if defined MAC_SELF_CONTAINED_BUNDLE
 
177
    if(!GetBundledProg(progName).IsEmpty())
 
178
        return true;
 
179
#endif
 
180
    wxFileName prog(progName);
 
181
    bool canStart=false; 
 
182
    if(prog.IsAbsolute())
 
183
    {
 
184
        canStart=(prog.IsFileExecutable());
 
185
    }
 
186
    else
 
187
    {
 
188
        wxPathList pathlist;
 
189
#ifdef __WXMSW__
 
190
        pathlist.Add(getExePath(wxTheApp->argv[0]));
 
191
#endif
 
192
        pathlist.AddEnvList(wxT("PATH"));
 
193
        wxString path = pathlist.FindAbsoluteValidPath(progName);
 
194
        if(path.IsEmpty())
 
195
            canStart=false;
 
196
        else
 
197
        {
 
198
            wxFileName prog2(path);
 
199
            canStart=(prog2.IsFileExecutable());
 
200
        };
 
201
    };
 
202
    if(!canStart)
 
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()),
 
205
            _("Error"),parent);
 
206
    return canStart;
 
207
};
 
208
 
 
209
CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
 
210
                           int nFeatures, wxWindow *parent)
 
211
{
 
212
    int return_value;
 
213
    return automatch(setting,pano,imgs,nFeatures,return_value,parent);
 
214
};
 
215
 
 
216
CPVector AutoCtrlPointCreator::automatch(CPDetectorSetting &setting, 
 
217
                                         Panorama & pano,
 
218
                                         const UIntSet & imgs,
 
219
                                         int nFeatures,
 
220
                                         int & ret_value, 
 
221
                                         wxWindow *parent)
 
222
{
 
223
    CPVector cps;
 
224
    CPDetectorType t = setting.GetType();
 
225
    //check, if the cp generators exists
 
226
    if(!CanStartProg(setting.GetProg(),parent))
 
227
        return cps;
 
228
    if(setting.IsTwoStepDetector())
 
229
        if(!CanStartProg(setting.GetProgMatcher(),parent))
 
230
            return cps;
 
231
    if(t==CPDetector_AutoPanoSiftStack || t==CPDetector_AutoPanoSiftMultiRowStack)
 
232
        if(!setting.GetProgStack().IsEmpty())
 
233
            if(!CanStartProg(setting.GetProgStack(),parent))
 
234
                return cps;
 
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");
 
239
    switch (t) {
 
240
    case CPDetector_AutoPano:
 
241
        {
 
242
            // autopano@kolor
 
243
            AutoPanoKolor matcher;
 
244
            cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
245
            break;
 
246
        }
 
247
    case CPDetector_AutoPanoSift:
 
248
        {
 
249
            // autopano-sift
 
250
            AutoPanoSift matcher;
 
251
            cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
252
            break;
 
253
        }
 
254
    case CPDetector_AutoPanoSiftStack:
 
255
    {
 
256
        // autopano-sift with stacks
 
257
        AutoPanoSiftStack matcher;
 
258
        cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
259
        break;
 
260
    }
 
261
    case CPDetector_AutoPanoSiftMultiRow:
 
262
    {
 
263
        // autopano-sift for multi-row panoramas
 
264
        AutoPanoSiftMultiRow matcher;
 
265
        cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
266
        break;
 
267
    }
 
268
    case CPDetector_AutoPanoSiftMultiRowStack:
 
269
    {
 
270
        // autopano-sift for multi-row panoramas with stacks
 
271
        AutoPanoSiftMultiRowStack matcher;
 
272
        cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
273
        break;
 
274
    }
 
275
    case CPDetector_AutoPanoSiftPreAlign:
 
276
    {
 
277
        // autopano-sift for panoramas with position information
 
278
        AutoPanoSiftPreAlign matcher;
 
279
        cps = matcher.automatch(setting, pano, imgs, nFeatures, ret_value, parent);
 
280
        break;
 
281
    }
 
282
        default:
 
283
            DEBUG_ERROR("Invalid autopano type");
 
284
    }
 
285
    setlocale(LC_NUMERIC,old_locale);
 
286
    free(old_locale);
 
287
    return cps;
 
288
}
 
289
 
 
290
void AutoCtrlPointCreator::Cleanup(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
 
291
                           std::vector<wxString> &keyFiles, wxWindow *parent)
 
292
{
 
293
    if(setting.IsTwoStepDetector())
 
294
    {
 
295
        if(keyFiles.size()>0)
 
296
        {
 
297
            for(unsigned int i=0;i<keyFiles.size();i++)
 
298
            {
 
299
                if(wxFileExists(keyFiles[i]))
 
300
                {
 
301
                    if(!wxRemoveFile(keyFiles[i]))
 
302
                    {
 
303
                        DEBUG_DEBUG("could not remove temporary file: " << keyFiles[i].c_str());
 
304
                    };
 
305
                };
 
306
            };
 
307
        };
 
308
    }
 
309
    else
 
310
    {
 
311
        if(!setting.IsCleanupPossible())
 
312
        {
 
313
            return;
 
314
        };
 
315
        // create suitable command line..
 
316
        wxString cleanupExe = GetProgPath(setting.GetProg());
 
317
        wxString cleanupArgs = setting.GetArgsCleanup();
 
318
        if(cleanupArgs.IsEmpty())
 
319
        {
 
320
            return;
 
321
        };
 
322
    
 
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);
 
327
 
 
328
        int ret_value=CPExecute(cleanupExe, cleanupArgs, _("cleaning up temporary keypoint files"), parent);
 
329
 
 
330
        if(ret_value!=0)
 
331
        {
 
332
            DEBUG_DEBUG("could not cleanup temporary keypoint files");
 
333
        };
 
334
        if(!wxRemoveFile(ptoinfile_name))
 
335
        {
 
336
            DEBUG_DEBUG("could not remove temporary file: " << ptoinfile_name.c_str());
 
337
        };
 
338
    };
 
339
};
 
340
        
 
341
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
342
                                     int nFeatures, int & ret_value, wxWindow *parent)
 
343
{
 
344
    CPVector cps;
 
345
    if (imgs.size() == 0) {
 
346
        return cps;
 
347
    }
 
348
    // create suitable command line..
 
349
    wxString autopanoExe = GetProgPath(setting.GetProg());
 
350
    if(setting.IsTwoStepDetector())
 
351
    {
 
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);
 
355
        return cps;
 
356
    };
 
357
    wxString autopanoArgs = setting.GetArgs();
 
358
    
 
359
    // TODO: create a secure temporary filename here
 
360
    wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
 
361
    autopanoArgs.Replace(wxT("%o"), ptofile);
 
362
    wxString tmp;
 
363
    tmp.Printf(wxT("%d"), nFeatures);
 
364
    autopanoArgs.Replace(wxT("%p"), tmp);
 
365
 
 
366
    SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
 
367
    tmp.Printf(wxT("%f"), firstImg.getHFOV());
 
368
    autopanoArgs.Replace(wxT("%v"), tmp);
 
369
 
 
370
    tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
 
371
    autopanoArgs.Replace(wxT("%f"), tmp);
 
372
 
 
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;
 
376
 
 
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;
 
385
 
 
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);
 
389
        return cps;
 
390
    }
 
391
 
 
392
    wxFile namefile;
 
393
    wxString namefile_name;
 
394
    if (use_namefile) {
 
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));
 
400
        int imgNr=0;
 
401
        for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
 
402
        {
 
403
            imgMapping[imgNr] = *it;
 
404
            namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME));
 
405
            namefile.Write(wxT("\r\n"));
 
406
            imgNr++;
 
407
        }
 
408
        // close namefile
 
409
        if (namefile_name != wxString(wxT(""))) {
 
410
            namefile.Close();
 
411
        }
 
412
    } else {
 
413
        string imgFiles;
 
414
        int imgNr=0;
 
415
        for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
 
416
        {
 
417
            imgMapping[imgNr] = *it;
 
418
            imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
 
419
            imgNr++;
 
420
        }
 
421
        autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
 
422
    }
 
423
 
 
424
    wxString ptoinfile_name;
 
425
    if (use_inputscript) {
 
426
        wxFile ptoinfile;
 
427
        ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj"));
 
428
        autopanoArgs.Replace(wxT("%s"), ptoinfile_name);
 
429
 
 
430
        ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile));
 
431
        pano.printPanoramaScript(ptoinstream, pano.getOptimizeVector(), pano.getOptions(), imgs, false);
 
432
    }
 
433
 
 
434
#ifdef __WXMSW__
 
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 );
 
438
        return cps;
 
439
    }
 
440
#endif
 
441
 
 
442
    wxString cmd = autopanoExe + wxT(" ") + autopanoArgs;
 
443
    DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal));
 
444
 
 
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);
 
450
        return cps;
 
451
    }
 
452
 
 
453
    ret_value = 0;
 
454
    // use MyExternalCmdExecDialog
 
455
    ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
 
456
 
 
457
    if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
 
458
        return cps;
 
459
    } else if (ret_value == -1) {
 
460
        CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
 
461
        return cps;
 
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);
 
465
        return cps;
 
466
    }
 
467
 
 
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 );
 
471
        return cps;
 
472
    }
 
473
 
 
474
    // read and update control points
 
475
    cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
 
476
 
 
477
    if (namefile_name != wxString(wxT(""))) {
 
478
        namefile.Close();
 
479
        wxRemoveFile(namefile_name);
 
480
    }
 
481
 
 
482
    if (ptoinfile_name != wxString(wxT(""))) {
 
483
        wxRemoveFile(ptoinfile_name);
 
484
    }
 
485
 
 
486
    if (!wxRemoveFile(ptofile)) {
 
487
        DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
 
488
    }
 
489
 
 
490
    return cps;
 
491
}
 
492
 
 
493
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs,
 
494
                           int nFeatures, vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
 
495
{
 
496
    CPVector cps;
 
497
    if (imgs.size() == 0) 
 
498
    {
 
499
        return cps;
 
500
    }
 
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();
 
507
    
 
508
    wxString tempDir= wxConfigBase::Get()->Read(wxT("tempDir"),wxT(""));
 
509
    if(!tempDir.IsEmpty())
 
510
        if(tempDir.Last()!=wxFileName::GetPathSeparator())
 
511
            tempDir.Append(wxFileName::GetPathSeparator());
 
512
    //check arguments
 
513
    if(generateKeysArgs.Find(wxT("%i"))==wxNOT_FOUND || generateKeysArgs.Find(wxT("%k"))==wxNOT_FOUND)
 
514
    {
 
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);
 
517
        return cps;
 
518
    };
 
519
    if(matcherArgs.Find(wxT("%k"))==wxNOT_FOUND || matcherArgs.Find(wxT("%o"))==wxNOT_FOUND)
 
520
    {
 
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);
 
523
        return cps;
 
524
    };
 
525
 
 
526
    ret_value=0;
 
527
    for(UIntSet::const_iterator img=imgs.begin();img!=imgs.end();img++)
 
528
    {
 
529
        if(keyFiles[*img].IsEmpty())
 
530
        {
 
531
            //no key files exists, so generate it
 
532
            wxString keyfile=wxFileName::CreateTempFileName(tempDir+wxT("apk_"));
 
533
            keyFiles[*img]=keyfile;
 
534
            wxString cmd=generateKeysArgs;
 
535
            wxString tmp;
 
536
            tmp.Printf(wxT("%d"), nFeatures);
 
537
            cmd.Replace(wxT("%p"), tmp);
 
538
 
 
539
            SrcPanoImage srcImg = pano.getSrcImage(*img);
 
540
            tmp.Printf(wxT("%f"), srcImg.getHFOV());
 
541
            cmd.Replace(wxT("%v"), tmp);
 
542
 
 
543
            tmp.Printf(wxT("%d"), (int) srcImg.getProjection());
 
544
            cmd.Replace(wxT("%f"), tmp);
 
545
            
 
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) 
 
552
                return cps;
 
553
            else
 
554
                if (ret_value == -1) 
 
555
                {
 
556
                    CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
 
557
                    return cps;
 
558
                } 
 
559
                else
 
560
                    if (ret_value > 0) 
 
561
                    {
 
562
                        CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
 
563
                            _("wxExecute Error"), parent);
 
564
                        return cps;
 
565
                    };
 
566
        };
 
567
    };
 
568
 
 
569
    // TODO: create a secure temporary filename here
 
570
    wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res"));
 
571
    matcherArgs.Replace(wxT("%o"), ptofile);
 
572
    wxString tmp;
 
573
    tmp.Printf(wxT("%d"), nFeatures);
 
574
    matcherArgs.Replace(wxT("%p"), tmp);
 
575
 
 
576
    SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin());
 
577
    tmp.Printf(wxT("%f"), firstImg.getHFOV());
 
578
    matcherArgs.Replace(wxT("%v"), tmp);
 
579
 
 
580
    tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
 
581
    matcherArgs.Replace(wxT("%f"), tmp);
 
582
 
 
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;
 
586
 
 
587
    wxString imgFiles;
 
588
    int imgNr=0;
 
589
    for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
 
590
    {
 
591
        imgMapping[imgNr] = *it;
 
592
        imgFiles.append(wxT(" ")).append(wxQuoteFilename(keyFiles[*it]));
 
593
        imgNr++;
 
594
     };
 
595
     matcherArgs.Replace(wxT("%k"), wxString (imgFiles.wc_str(), HUGIN_CONV_FILENAME));
 
596
 
 
597
#ifdef __WXMSW__
 
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 );
 
601
        return cps;
 
602
    }
 
603
#endif
 
604
 
 
605
    wxString cmd = matcherExe + wxT(" ") + matcherArgs;
 
606
    DEBUG_DEBUG("Executing: " << matcherExe.mb_str(wxConvLocal) << " " << matcherArgs.mb_str(wxConvLocal));
 
607
 
 
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);
 
612
        return cps;
 
613
    }
 
614
 
 
615
    // use MyExternalCmdExecDialog
 
616
    ret_value = CPExecute(matcherExe, matcherArgs, _("finding control points"), parent);
 
617
 
 
618
    if (ret_value == HUGIN_EXIT_CODE_CANCELLED) 
 
619
        return cps;
 
620
    else 
 
621
        if (ret_value == -1) 
 
622
        {
 
623
            CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent);
 
624
            return cps;
 
625
        } 
 
626
        else
 
627
            if (ret_value > 0) 
 
628
            {
 
629
                CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value),
 
630
                     _("wxExecute Error"), parent);
 
631
                return cps;
 
632
            };
 
633
 
 
634
    if (! wxFileExists(ptofile.c_str()))
 
635
    {
 
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 );
 
638
        return cps;
 
639
    }
 
640
 
 
641
    // read and update control points
 
642
    cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
 
643
 
 
644
    if (!wxRemoveFile(ptofile)) {
 
645
        DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
 
646
    }
 
647
 
 
648
    return cps;
 
649
};
 
650
 
 
651
CPVector AutoPanoKolor::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
652
                              int nFeatures, int & ret_value, wxWindow *parent)
 
653
{
 
654
    CPVector cps;
 
655
    wxString autopanoExe = setting.GetProg();
 
656
 
 
657
    // write default autopano.kolor.com flags
 
658
    wxString autopanoArgs = setting.GetArgs();
 
659
 
 
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;
 
663
    string imgFiles;
 
664
    int imgNr=0;
 
665
    for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
 
666
    {
 
667
        imgMapping[imgNr] = *it;
 
668
        imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename()));
 
669
        imgNr++;
 
670
    }
 
671
 
 
672
    wxString ptofilepath = wxFileName::CreateTempFileName(wxT("ap_res"));
 
673
    wxFileName ptofn(ptofilepath);
 
674
    wxString ptofile = ptofn.GetFullName();
 
675
    autopanoArgs.Replace(wxT("%o"), ptofile);
 
676
    wxString tmp;
 
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);
 
682
 
 
683
    tmp.Printf(wxT("%d"), (int) firstImg.getProjection());
 
684
    autopanoArgs.Replace(wxT("%f"), tmp);
 
685
 
 
686
    autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME));
 
687
 
 
688
    wxString tempdir = ptofn.GetPath();
 
689
        autopanoArgs.Replace(wxT("%d"), ptofn.GetPath());
 
690
    wxString cmd;
 
691
    cmd.Printf(wxT("%s %s"), utils::wxQuoteFilename(autopanoExe).c_str(), autopanoArgs.c_str());
 
692
#ifdef __WXMSW__
 
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);
 
696
        return cps;
 
697
    }
 
698
#endif
 
699
    DEBUG_DEBUG("Executing: " << cmd.c_str());
 
700
 
 
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);
 
706
        return cps;
 
707
    }
 
708
 
 
709
    ret_value = 0;
 
710
    // use MyExternalCmdExecDialog
 
711
    ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent);
 
712
 
 
713
    if (ret_value == HUGIN_EXIT_CODE_CANCELLED) {
 
714
        return cps;
 
715
    } else if (ret_value == -1) {
 
716
        CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"),  parent);
 
717
        return cps;
 
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);
 
721
        return cps;
 
722
    }
 
723
 
 
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 );
 
729
        return cps;
 
730
    }
 
731
    // read and update control points
 
732
    cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano);
 
733
 
 
734
    if (!wxRemoveFile(ptofile)) {
 
735
        DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str());
 
736
    }
 
737
    return cps;
 
738
}
 
739
 
 
740
struct img_ev
 
741
{
 
742
    unsigned int img_nr;
 
743
    double ev;
 
744
};
 
745
struct stack_img
 
746
{
 
747
    unsigned int layer_nr;
 
748
    std::vector<img_ev> images;
 
749
};
 
750
bool sort_img_ev (img_ev i1, img_ev i2) { return (i1.ev<i2.ev); };
 
751
 
 
752
void AddControlPointsWithCheck(CPVector &cpv, CPVector &new_cp, Panorama *pano=NULL)
 
753
{
 
754
    for(unsigned int i=0;i<new_cp.size();i++)
 
755
    {
 
756
        HuginBase::ControlPoint cp=new_cp[i];
 
757
        bool duplicate=false;
 
758
        for(unsigned int j=0;j<cpv.size();j++)
 
759
        {
 
760
            if(cp==cpv[j])
 
761
            {
 
762
                duplicate=true;
 
763
                break;
 
764
            }
 
765
        };
 
766
        if(!duplicate)
 
767
        {
 
768
            cpv.push_back(cp);
 
769
            if(pano!=NULL)
 
770
                pano->addCtrlPoint(cp);
 
771
        };
 
772
    };
 
773
};
 
774
 
 
775
CPVector AutoPanoSiftStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
776
                                     int nFeatures, int & ret_value, wxWindow *parent)
 
777
{
 
778
    CPVector cps;
 
779
    if (imgs.size() == 0) {
 
780
        return cps;
 
781
    };
 
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++)
 
785
    {
 
786
        unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
 
787
        //check, if this stack is already in list
 
788
        bool found=false;
 
789
        unsigned int index=0;
 
790
        for(index=0;index<stack_images.size();index++)
 
791
        {
 
792
            found=(stack_images[index].layer_nr==stack_nr);
 
793
            if(found)
 
794
                break;
 
795
        };
 
796
        if(!found)
 
797
        {
 
798
            //new stack
 
799
            stack_images.resize(stack_images.size()+1);
 
800
            index=stack_images.size()-1;
 
801
            //add new stack
 
802
            stack_images[index].layer_nr=stack_nr;
 
803
        };
 
804
        //add new image
 
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();
 
809
    };
 
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++)
 
814
    {
 
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)
 
818
        {
 
819
            index=stack_images[i].images.size() / 2;
 
820
        };
 
821
        images_layer.insert(stack_images[i].images[index].img_nr);
 
822
    };
 
823
    //generate cp for median exposure
 
824
    ret_value=0;
 
825
    if(images_layer.size()>1)
 
826
    {
 
827
        AutoPanoSift matcher;
 
828
        cps=matcher.automatch(setting, pano, images_layer, nFeatures, ret_value, parent);
 
829
        if(ret_value!=0)
 
830
            return cps;
 
831
    };
 
832
    //now work on all stacks
 
833
    if(!setting.GetProgStack().IsEmpty())
 
834
    {
 
835
        CPDetectorSetting stack_setting;
 
836
        stack_setting.SetType(CPDetector_AutoPanoSift);
 
837
        stack_setting.SetProg(setting.GetProgStack());
 
838
        stack_setting.SetArgs(setting.GetArgsStack());
 
839
 
 
840
        for(unsigned int i=0;i<stack_images.size();i++)
 
841
        {
 
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)
 
847
            {
 
848
                AutoPanoSift matcher;
 
849
                CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
 
850
                if(new_cps.size()>0)
 
851
                    AddControlPointsWithCheck(cps,new_cps);
 
852
                if(ret_value!=0)
 
853
                    return cps;
 
854
            };
 
855
        };
 
856
    }
 
857
    return cps;
 
858
};
 
859
 
 
860
CPVector AutoPanoSiftMultiRow::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
861
                                     int nFeatures, int & ret_value, wxWindow *parent)
 
862
{
 
863
    CPVector cps;
 
864
    if (imgs.size() < 2) 
 
865
    {
 
866
        return cps;
 
867
    };
 
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(); )
 
872
    {
 
873
        if(counter==imgs.size()-1)
 
874
            break;
 
875
        counter++;
 
876
        UIntSet ImagePair;
 
877
        ImagePair.clear();
 
878
        ImagePair.insert(*it);
 
879
        it++;
 
880
        ImagePair.insert(*it);
 
881
        AutoPanoSift matcher;
 
882
        CPVector new_cps;
 
883
        new_cps.clear();
 
884
        if(setting.IsTwoStepDetector())
 
885
            new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, keyFiles, ret_value, parent);
 
886
        else
 
887
            new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, ret_value, parent);
 
888
        if(new_cps.size()>0)
 
889
            AddControlPointsWithCheck(cps,new_cps);
 
890
        if(ret_value!=0)
 
891
        {
 
892
            Cleanup(setting, pano, imgs, keyFiles, parent);
 
893
            return cps;
 
894
        };
 
895
    };
 
896
    // now connect all image groups
 
897
    // generate temporary panorama to add all found cps
 
898
    UIntSet allImgs;
 
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);
 
903
 
 
904
    CPGraph graph;
 
905
    createCPGraph(optPano, graph);
 
906
    CPComponents comps;
 
907
    int n = findCPComponents(graph, comps);
 
908
    if(n>1)
 
909
    {
 
910
        UIntSet ImagesGroups;
 
911
        for(unsigned int i=0;i<n;i++)
 
912
        {
 
913
            ImagesGroups.insert(*(comps[i].begin()));
 
914
            if(comps[i].size()>1)
 
915
                ImagesGroups.insert(*(comps[i].rbegin()));
 
916
        };
 
917
        AutoPanoSift matcher;
 
918
        CPVector new_cps;
 
919
        if(setting.IsTwoStepDetector())
 
920
            new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, keyFiles, ret_value, parent);
 
921
        else
 
922
            new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, ret_value, parent);
 
923
        if(new_cps.size()>0)
 
924
            AddControlPointsWithCheck(cps,new_cps,&optPano);
 
925
        if(ret_value!=0)
 
926
        {
 
927
            Cleanup(setting, pano, imgs, keyFiles, parent);
 
928
            return cps;
 
929
        };
 
930
        createCPGraph(optPano,graph);
 
931
        n=findCPComponents(graph, comps);
 
932
    };
 
933
    if(n==1 && setting.GetOption())
 
934
    {
 
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);
 
943
 
 
944
        optPano.setOptions(opts);
 
945
        int w = optPano.calcOptimalWidth();
 
946
        opts.setWidth(w);
 
947
        opts.setHeight(w/2);
 
948
        optPano.setOptions(opts);
 
949
 
 
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++) 
 
954
        {
 
955
            std::set<std::string> imgopt;
 
956
            if(i==opts.optimizeReferenceImage)
 
957
            {
 
958
                //optimize only anchors pitch, not yaw
 
959
                imgopt.insert("p");
 
960
            }
 
961
            else
 
962
            {
 
963
                // do not optimize anchor image's stack for position.
 
964
                if(!optPano.getImage(i).YawisLinkedWith(anchorImage))
 
965
                {
 
966
                    imgopt.insert("p");
 
967
                    imgopt.insert("y");
 
968
                };
 
969
            };
 
970
            optvars.push_back(imgopt);
 
971
        }
 
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())
 
981
        {
 
982
            newSetting.SetProgMatcher(setting.GetProgMatcher());
 
983
            newSetting.SetArgsMatcher(setting.GetArgsMatcher());
 
984
        };
 
985
        newSetting.SetOption(true);
 
986
        CPVector new_cps;
 
987
        if(setting.IsTwoStepDetector())
 
988
            new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, keyFiles, ret_value, parent);
 
989
        else
 
990
            new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, ret_value, parent);
 
991
        if(new_cps.size()>0)
 
992
            AddControlPointsWithCheck(cps,new_cps);
 
993
    };
 
994
    Cleanup(setting, pano, imgs, keyFiles, parent);
 
995
    return cps;
 
996
};
 
997
 
 
998
CPVector AutoPanoSiftMultiRowStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
999
                                     int nFeatures, int & ret_value, wxWindow *parent)
 
1000
{
 
1001
    CPVector cps;
 
1002
    if (imgs.size() == 0) {
 
1003
        return cps;
 
1004
    };
 
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++)
 
1008
    {
 
1009
        unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
 
1010
        //check, if this stack is already in list
 
1011
        bool found=false;
 
1012
        unsigned int index=0;
 
1013
        for(index=0;index<stack_images.size();index++)
 
1014
        {
 
1015
            found=(stack_images[index].layer_nr==stack_nr);
 
1016
            if(found)
 
1017
                break;
 
1018
        };
 
1019
        if(!found)
 
1020
        {
 
1021
            //new stack
 
1022
            stack_images.resize(stack_images.size()+1);
 
1023
            index=stack_images.size()-1;
 
1024
            //add new stack
 
1025
            stack_images[index].layer_nr=stack_nr;
 
1026
        };
 
1027
        //add new image
 
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();
 
1032
    };
 
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++)
 
1037
    {
 
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)
 
1041
        {
 
1042
            index=stack_images[i].images.size() / 2;
 
1043
        };
 
1044
        images_layer.insert(stack_images[i].images[index].img_nr);
 
1045
    };
 
1046
    ret_value=0;
 
1047
    //work on all stacks
 
1048
    if(!setting.GetProgStack().IsEmpty())
 
1049
    {
 
1050
        CPDetectorSetting stack_setting;
 
1051
        stack_setting.SetType(CPDetector_AutoPanoSift);
 
1052
        stack_setting.SetProg(setting.GetProgStack());
 
1053
        stack_setting.SetArgs(setting.GetArgsStack());
 
1054
 
 
1055
        for(unsigned int i=0;i<stack_images.size();i++)
 
1056
        {
 
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)
 
1062
            {
 
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);
 
1067
                if(ret_value!=0)
 
1068
                {
 
1069
                    std::vector<wxString> emptyKeyfiles;
 
1070
                    Cleanup(setting, pano, imgs, emptyKeyfiles, parent);
 
1071
                    return cps;
 
1072
                };
 
1073
            };
 
1074
        };
 
1075
    }
 
1076
    //generate cp for median exposure with multi-row algorithm
 
1077
    if(images_layer.size()>1)
 
1078
    {
 
1079
        UIntSet allImgs;
 
1080
        fill_set(allImgs, 0, pano.getNrOfImages()-1);
 
1081
        Panorama newPano=pano.getSubset(allImgs);
 
1082
        if(cps.size()>0)
 
1083
            for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
 
1084
                newPano.addCtrlPoint(*it);
 
1085
 
 
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);
 
1090
    };
 
1091
    return cps;
 
1092
};
 
1093
 
 
1094
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
1095
                                     int nFeatures, int & ret_value, wxWindow *parent)
 
1096
{
 
1097
    std::vector<wxString> keyFiles(pano.getNrOfImages());
 
1098
    return automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent);
 
1099
};
 
1100
 
 
1101
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
 
1102
                                         int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent)
 
1103
{
 
1104
    CPVector cps;
 
1105
    if (imgs.size()<2) 
 
1106
        return cps;
 
1107
    DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages());
 
1108
 
 
1109
    vector<UIntSet> usedImages;
 
1110
    usedImages.resize(pano.getNrOfImages());
 
1111
    if(setting.GetOption())
 
1112
    {
 
1113
        //only work on not connected image pairs
 
1114
        CPVector oldCps=pano.getCtrlPoints();
 
1115
        for(unsigned i=0;i<oldCps.size();i++)
 
1116
        {
 
1117
            if(oldCps[i].mode==ControlPoint::X_Y)
 
1118
            {
 
1119
                usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr);
 
1120
                usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr);
 
1121
            };
 
1122
        };
 
1123
    };
 
1124
    HuginBase::CalculateImageOverlap overlap(&pano);
 
1125
    overlap.calculate(10);
 
1126
    for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
 
1127
    {
 
1128
        UIntSet images;
 
1129
        images.clear();
 
1130
        images.insert(*it);
 
1131
        UIntSet::const_iterator it2=it;
 
1132
        for(++it2;it2!=imgs.end();it2++)
 
1133
        {
 
1134
            //check if this image pair was yet used
 
1135
            if(set_contains(usedImages[*it2],*it))
 
1136
                continue;
 
1137
            //now check position
 
1138
            if(overlap.getOverlap(*it,*it2)>0)
 
1139
            {
 
1140
                images.insert(*it2);
 
1141
            };
 
1142
        };
 
1143
        if(images.size()<2)
 
1144
            continue;
 
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;
 
1150
        CPVector new_cps;
 
1151
        if(setting.IsTwoStepDetector())
 
1152
            new_cps=matcher.automatch(setting, pano, images, nFeatures, keyFiles, ret_value, parent);
 
1153
        else
 
1154
            new_cps=matcher.automatch(setting, pano, images, nFeatures, ret_value, parent);
 
1155
        if(new_cps.size()>0)
 
1156
            AddControlPointsWithCheck(cps,new_cps);
 
1157
        if(ret_value!=0)
 
1158
        {
 
1159
            Cleanup(setting, pano, imgs, keyFiles, parent);
 
1160
            return cps;
 
1161
        };
 
1162
    };
 
1163
    Cleanup(setting, pano, imgs, keyFiles, parent);
 
1164
    return cps;
 
1165
};