Diff of /APSCmain.c [939879] .. [adbd81]  Maximize  Restore

Switch to unified view

a/APSCmain.c b/APSCmain.c
1
1
2
/* APSCmain.c  06Feb2008 TKSharpless

2
/* APSCmain.c  06Feb2008 TKSharpless
3
 Single-executable form of AutoPano-sift-C for Hugin 0.7

3
 Single-executable form of AutoPano-sift-C for Hugin 0.7
4
 Here, GenerateKeys is a subroutine

4
 Here, GenerateKeys is a subroutine
5
5
6
 * Keypoint file correlation and hugin panorama file creation utility.

6
 * Keypoint file correlation and hugin panorama file creation utility.
7
 *

7
 *
8
 * (C) Copyright 2004 -- Sebastian Nowozin (nowozin@cs.tu-berlin.de)

8
 * (C) Copyright 2004 -- Sebastian Nowozin (nowozin@cs.tu-berlin.de)
9
 *

9
 *
10
 * "The University of British Columbia has applied for a patent on the SIFT

10
 * "The University of British Columbia has applied for a patent on the SIFT
11
 * algorithm in the United States. Commercial applications of this software

11
 * algorithm in the United States. Commercial applications of this software
12
 * may require a license from the University of British Columbia."

12
 * may require a license from the University of British Columbia."
13
 * For more information, see the LICENSE file supplied with the distribution.

13
 * For more information, see the LICENSE file supplied with the distribution.
14
 *

14
 *
15
 * This program is free software released under the GNU General Public

15
 * This program is free software released under the GNU General Public
16
 * License, which is included in this software package (doc/LICENSE).

16
 * License, which is included in this software package (doc/LICENSE).
17
*/

17
*/
18
18
19
#include "AutoPanoSift.h"

19
#include "AutoPanoSift.h"
20
20
21
void Usage ()

21
void Usage ()
22
{

22
{
23
    WriteLine ("APSC: Generate and Match Keypoints giving Hugin project file\n");

23
    WriteLine ("APSC: Generate and Match Keypoints giving Hugin project file\n");
24
    WriteLine ("  Version %s\n", PACKAGE_VERSION);

24
    WriteLine ("  Version %s\n", PACKAGE_VERSION);
25
    WriteLine ("usage: APSC.exe [options] output.pto image1 image2 [..]\n");

25
    WriteLine ("usage: APSC.exe [options] output.pto image1 image2 [..]\n");
26
    WriteLine ("Options");

26
    WriteLine ("Options");
27
    WriteLine ("  --ransac <on|off|1|0>   Switch RANSAC filtration on or off (default: on)");

27
    WriteLine ("  --ransac <on|off|1|0>   Switch RANSAC filtration on or off (default: on)");
28
    WriteLine ("  --maxmatches <matches>  Use no more than the given number of matches");

28
    WriteLine ("  --maxmatches <matches>  Use no more than the given number of matches");
29
    WriteLine ("                          (default: 16, use zero for unlimited)");

29
    WriteLine ("                          (default: 16, use zero for unlimited)");
30
                               

30
                               
31
    WriteLine ("  --disable-areafilter    Do not use max-area filtration, which is default.");

31
    WriteLine ("  --disable-areafilter    Do not use max-area filtration, which is default.");
32
    WriteLine ("                          See manpage for details.");

32
    WriteLine ("                          See manpage for details.");
33
    WriteLine ("  --integer-coordinates   Truncate match coordinates to integer numbers.");

33
    WriteLine ("  --integer-coordinates   Truncate match coordinates to integer numbers.");
34
    WriteLine ("  --absolute-pathnames <on|off|1|0>   Use the absolute pathname of the image");

34
    WriteLine ("  --absolute-pathnames <on|off|1|0>   Use the absolute pathname of the image");
35
    WriteLine ("                          file in the PTO output file. Disabled by default.");

35
    WriteLine ("                          file in the PTO output file. Disabled by default.");
36
    WriteLine ("  --maxdim <integer>      input images are repeatedly halfed in size until");

36
    WriteLine ("  --maxdim <integer>      input images are repeatedly halfed in size until");
37
    WriteLine ("                          both width and height are below 'maxdim' (default: 800).");

37
    WriteLine ("                          both width and height are below 'maxdim' (default: 800).");
38
    WriteLine ("");

38
    WriteLine ("");
39
    

39
    
40
    WriteLine ("Alignment options");

40
    WriteLine ("Alignment options");
41
    WriteLine ("  --align                 Automatically pre-align images in PTO file.");

41
    WriteLine ("  --align                 Automatically pre-align images in PTO file.");
42
    WriteLine ("  --bottom-is-left");

42
    WriteLine ("  --bottom-is-left");
43
    WriteLine ("  --bottom-is-right       Use in case the automatic algorithm fails.");

43
    WriteLine ("  --bottom-is-right       Use in case the automatic algorithm fails.");
44
    WriteLine ("  --generate-horizon <c>  Generate up to 'c' horizon lines.");

44
    WriteLine ("  --generate-horizon <c>  Generate up to 'c' horizon lines.");
45
    WriteLine ("");

45
    WriteLine ("");
46
    

46
    
47
    WriteLine ("Refinement options");

47
    WriteLine ("Refinement options");
48
    WriteLine ("  --refine                Refine the found control points using the");

48
    WriteLine ("  --refine                Refine the found control points using the");
49
    WriteLine ("                          original images.");

49
    WriteLine ("                          original images.");
50
    WriteLine ("  --refine-by-middle      Use the best middle point to refine (default).");

50
    WriteLine ("  --refine-by-middle      Use the best middle point to refine (default).");
51
    WriteLine ("  --refine-by-mean        Use the mean of the patches control points.");

51
    WriteLine ("  --refine-by-mean        Use the mean of the patches control points.");
52
    WriteLine ("  --keep-unrefinable <on|off|1|0>");

52
    WriteLine ("  --keep-unrefinable <on|off|1|0>");
53
    WriteLine ("                          Keep unrefinable matches (default: on).");

53
    WriteLine ("                          Keep unrefinable matches (default: on).");
54
                                        

54
                                        
55
    WriteLine ("output.pto: The output PTO panorama project file.");

55
    WriteLine ("output.pto: The output PTO panorama project file.");
56
    WriteLine ("    The filename can be \"-\", then stdout is used");

56
    WriteLine ("    The filename can be \"-\", then stdout is used");
57
    WriteLine ("image<n>: input image files (any common format: JPEG, PNG, TIFF, ..)");

57
    WriteLine ("image<n>: input image files (any common format: JPEG, PNG, TIFF, ..)");
58
    WriteLine ("Notice: for the aligning to work, the input images shall be");

58
    WriteLine ("Notice: for the aligning to work, the input images shall be");
59
    WriteLine ("  1. All of the same dimension and scale");

59
    WriteLine ("  1. All of the same dimension and scale");
60
    WriteLine ("  2. The first images must be an ordered row. See manpage.");

60
    WriteLine ("  2. The first images must be an ordered row. See manpage.");
61
    WriteLine ("");

61
    WriteLine ("");
62
}

62
}
63
63
64
// subroutine equivalent to GenerateKeys.c

64
// subroutine equivalent to GenerateKeys.c
65
KeypointXMLList * GenerateKeys( char* imgname, int downRes )

65
KeypointXMLList * GenerateKeys( char* imgname, int downRes )
66
{    

66
{    
67
    // 1. load the image file

67
    // 1. load the image file
68
    DisplayImage* pic = DisplayImage_new(imgname);

68
    DisplayImage* pic = DisplayImage_new(imgname);
69
    int pW = pic->width;

69
    int pW = pic->width;
70
    int pH = pic->height;

70
    int pH = pic->height;
71
    ImageMap* picMap;

71
    ImageMap* picMap;
72
    LoweFeatureDetector* lf;

72
    LoweFeatureDetector* lf;
73
    KeypointXMLList* kpp;

73
    KeypointXMLList* kpp;
74
    double startScale = 1.0;

74
    double startScale = 1.0;
75
        

75
        
76
    if (downRes > 0) {

76
    if (downRes > 0) {
77
        startScale = DisplayImage_ScaleWithin(pic, downRes);

77
        startScale = DisplayImage_ScaleWithin(pic, downRes);
78
//      WriteLine ("Scaled picture, starting with scale %0.04f", startScale);

78
//      WriteLine ("Scaled picture, starting with scale %0.04f", startScale);
79
    }

79
    }
80
    picMap = DisplayImage_ConvertToImageMap(pic);

80
    picMap = DisplayImage_ConvertToImageMap(pic);
81
    DisplayImage_delete(pic);

81
    DisplayImage_delete(pic);
82
82
83
    // 2. find the features

83
    // 2. find the features
84
    lf = LoweFeatureDetector_new0();

84
    lf = LoweFeatureDetector_new0();
85
85
86
    if (downRes > 0) {

86
    if (downRes > 0) {
87
        LoweFeatureDetector_DetectFeaturesDownscaled (lf, picMap, 0, 1.0 / startScale);

87
        LoweFeatureDetector_DetectFeaturesDownscaled (lf, picMap, 0, 1.0 / startScale);
88
    } else

88
    } else
89
        LoweFeatureDetector_DetectFeatures (lf, picMap);

89
        LoweFeatureDetector_DetectFeatures (lf, picMap);
90
90
91
  /* build the return value

91
  /* build the return value
92
     We need a new copy of the list held in lf because lf is about to be deleted.

92
     We need a new copy of the list held in lf because lf is about to be deleted.
93
     The following code adapted from LoweFeatureDetector_GlobalNaturalKeypoints() 

93
     The following code adapted from LoweFeatureDetector_GlobalNaturalKeypoints() 
94
     does that, and also a needed format conversion (lucky this is not C++!)

94
     does that, and also a needed format conversion (lucky this is not C++!)
95
 */

95
 */
96
    ArrayList * globalNaturalKeypoints = ArrayList_new0 (KeypointN_delete);

96
    ArrayList * globalNaturalKeypoints = ArrayList_new0 (KeypointN_delete);
97
    int i;

97
    int i;
98
    for(i=0; i < ArrayList_Count(lf->globalKeypoints); i++) {

98
    for(i=0; i < ArrayList_Count(lf->globalKeypoints); i++) {
99
        Keypoint* kp = (Keypoint *) ArrayList_GetItem( lf->globalKeypoints, i );

99
        Keypoint* kp = (Keypoint *) ArrayList_GetItem( lf->globalKeypoints, i );
100
        ArrayList_AddItem ( globalNaturalKeypoints, KeypointN_new( kp ));

100
        ArrayList_AddItem ( globalNaturalKeypoints, KeypointN_new( kp ));
101
    }

101
    }
102
    // package result as a KeypointXMLList

102
    // package result as a KeypointXMLList
103
    kpp = KeypointXMLList_new ( imgname, pW, pH, globalNaturalKeypoints );

103
    kpp = KeypointXMLList_new ( imgname, pW, pH, globalNaturalKeypoints );
104
104
105
    LoweFeatureDetector_delete(lf);

105
    LoweFeatureDetector_delete(lf);
106
106
107
  // disable the patent warning message (for any subsequent images)

107
  // disable the patent warning message (for any subsequent images)
108
    LoweFeatureDetector_SetPrintWarning(false); 

108
    LoweFeatureDetector_SetPrintWarning(false); 
109
109
110
    return kpp;

110
    return kpp;
111
}

111
}
112
112
113
113
114
typedef struct Resolution Resolution;

114
typedef struct Resolution Resolution;
115
struct Resolution

115
struct Resolution
116
{

116
{
117
    int x, y;

117
    int x, y;
118
};

118
};
119
119
120
Resolution* Resolution_new0()

120
Resolution* Resolution_new0()
121
{

121
{
122
    Resolution* self = (Resolution*)malloc(sizeof(Resolution));

122
    Resolution* self = (Resolution*)malloc(sizeof(Resolution));
123
    return self;

123
    return self;
124
}

124
}
125
125
126
Resolution* Resolution_new(int x, int y) 

126
Resolution* Resolution_new(int x, int y) 
127
{

127
{
128
    Resolution* self = Resolution_new0();

128
    Resolution* self = Resolution_new0();
129
    self->x = x;

129
    self->x = x;
130
    self->y = y;

130
    self->y = y;
131
    return self;

131
    return self;
132
}

132
}
133
133
134
void Resolution_delete(Resolution* self) 

134
void Resolution_delete(Resolution* self) 
135
{

135
{
136
    if (self) {

136
    if (self) {
137
        free(self);

137
        free(self);
138
    }

138
    }
139
}

139
}
140
140
141
int Resolution_CompareTo (Resolution* self, int x, int y)

141
int Resolution_CompareTo (Resolution* self, int x, int y)
142
{

142
{
143
    

143
    
144
    if (self->x == x && self->y == y)

144
    if (self->x == x && self->y == y)
145
        return (0);

145
        return (0);
146
    

146
    
147
    return (1);

147
    return (1);
148
}

148
}
149
149
150
150
151
151
152
152
153
// The maximum radius to consider around a keypoint that is refined.  That

153
// The maximum radius to consider around a keypoint that is refined.  That
154
// is, at most a patch of a maximum size of twice this value in both

154
// is, at most a patch of a maximum size of twice this value in both
155
// horizontal and vertical direction is extracted.

155
// horizontal and vertical direction is extracted.
156
int RefinementRadiusMaximum = 96;

156
int RefinementRadiusMaximum = 96;
157
int (*refineHandler)(int index, int total);

157
int (*refineHandler)(int index, int total);
158
158
159
159
160
void RefineKeypoints (ArrayList* msList,

160
void RefineKeypoints (ArrayList* msList,
161
              bool selectMiddlePoint, bool neverLosePoints);

161
              bool selectMiddlePoint, bool neverLosePoints);
162
DisplayImage* ExtractPatch (DisplayImage* large,

162
DisplayImage* ExtractPatch (DisplayImage* large,
163
                int px, int py, double scale, int* radius);

163
                int px, int py, double scale, int* radius);
164
ArrayList* ExtractKeypoints (DisplayImage* pic);

164
ArrayList* ExtractKeypoints (DisplayImage* pic);
165
bool YesNoOption (char* optionName, char* val);

165
bool YesNoOption (char* optionName, char* val);
166
166
167
// selectMiddlePoint: if true, select the middle point in the patch,

167
// selectMiddlePoint: if true, select the middle point in the patch,
168
//   otherwise build the mean

168
//   otherwise build the mean
169
// neverLosePoints: if true, and if we cannot do the refinement, still use

169
// neverLosePoints: if true, and if we cannot do the refinement, still use
170
//   the control point.

170
//   the control point.
171
void RefineKeypoints (ArrayList* msList,

171
void RefineKeypoints (ArrayList* msList,
172
        bool selectMiddlePoint, bool neverLosePoints)

172
        bool selectMiddlePoint, bool neverLosePoints)
173
{

173
{
174
    DisplayImage* pic1 = NULL;

174
    DisplayImage* pic1 = NULL;
175
    DisplayImage* pic2 = NULL;

175
    DisplayImage* pic2 = NULL;
176
    char* pic1Name = NULL;

176
    char* pic1Name = NULL;
177
    char* pic2Name = NULL;

177
    char* pic2Name = NULL;
178
178
179
    /* Keep stats for the refineHandler delegate

179
    /* Keep stats for the refineHandler delegate
180
     */

180
     */
181
    int totalRefines = 0;

181
    int totalRefines = 0;
182
    int doneRefines = 0;

182
    int doneRefines = 0;
183
    int i;

183
    int i;
184
    for(i=0; i<ArrayList_Count(msList); i++) {

184
    for(i=0; i<ArrayList_Count(msList); i++) {
185
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);

185
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);
186
        int j;

186
        int j;
187
        for(j=0; j<ArrayList_Count(ms->matches); j++) {

187
        for(j=0; j<ArrayList_Count(ms->matches); j++) {
188
            ArrayList_GetItem(ms->matches, j);

188
            ArrayList_GetItem(ms->matches, j);
189
            totalRefines += 1;

189
            totalRefines += 1;
190
        }

190
        }
191
    }

191
    }
192
192
193
 

193
 
194
    for(i=0; i<ArrayList_Count(msList); i++) {

194
    for(i=0; i<ArrayList_Count(msList); i++) {
195
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);

195
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, i);
196
        WriteLine ("  between \"%s\" and \"%s\"",

196
        WriteLine ("  between \"%s\" and \"%s\"",
197
               ms->file1, ms->file2);

197
               ms->file1, ms->file2);
198
        

198
        
199
        if (pic1Name != ms->file1) {

199
        if (pic1Name != ms->file1) {
200
            pic1Name = ms->file1;

200
            pic1Name = ms->file1;
201
            pic1 = DisplayImage_new (ms->file1);

201
            pic1 = DisplayImage_new (ms->file1);
202
        }

202
        }
203
        if (pic2Name != ms->file2) {

203
        if (pic2Name != ms->file2) {
204
            pic2Name = ms->file2;

204
            pic2Name = ms->file2;
205
            pic2 = DisplayImage_new (ms->file2);

205
            pic2 = DisplayImage_new (ms->file2);
206
        }

206
        }
207
        /*WriteLine ("pair: %s, %s, %d keypoint matches",

207
        /*WriteLine ("pair: %s, %s, %d keypoint matches",
208
          ms->file1, ms->file2, ArrayList_Count(ms->Matches));*/

208
          ms->file1, ms->file2, ArrayList_Count(ms->Matches));*/
209
        

209
        
210
        ArrayList* refinedMatches = ArrayList_new0 (NULL);

210
        ArrayList* refinedMatches = ArrayList_new0 (NULL);
211
211
212
        int j;

212
        int j;
213
        for(j=0; j<ArrayList_Count(ms->matches); j++) {

213
        for(j=0; j<ArrayList_Count(ms->matches); j++) {
214
            Match* m = (Match*) ArrayList_GetItem(ms->matches, j);

214
            Match* m = (Match*) ArrayList_GetItem(ms->matches, j);
215
215
216
            int p1x = (int) (m->kp1->x + 0.5);

216
            int p1x = (int) (m->kp1->x + 0.5);
217
            int p1y = (int) (m->kp1->y + 0.5);

217
            int p1y = (int) (m->kp1->y + 0.5);
218
            int p1radius;

218
            int p1radius;
219
            DisplayImage* patch1 = ExtractPatch (pic1, p1x, p1y,

219
            DisplayImage* patch1 = ExtractPatch (pic1, p1x, p1y,
220
                                m->kp1->scale, &p1radius);

220
                                m->kp1->scale, &p1radius);
221
221
222
            int p2x = (int) (m->kp2->x + 0.5);

222
            int p2x = (int) (m->kp2->x + 0.5);
223
            int p2y = (int) (m->kp2->y + 0.5);

223
            int p2y = (int) (m->kp2->y + 0.5);
224
            int p2radius;

224
            int p2radius;
225
            DisplayImage* patch2 = ExtractPatch (pic2, p2x, p2y,

225
            DisplayImage* patch2 = ExtractPatch (pic2, p2x, p2y,
226
                                 m->kp2->scale, &p2radius);

226
                                 m->kp2->scale, &p2radius);
227
227
228
            /* Call the refine handler delegate in case there is one to

228
            /* Call the refine handler delegate in case there is one to
229
             * inform the callee of a single refining step (for progress

229
             * inform the callee of a single refining step (for progress
230
             * bar displays and such).

230
             * bar displays and such).
231
             */

231
             */
232
            doneRefines += 1;

232
            doneRefines += 1;
233
            if (refineHandler != NULL)

233
            if (refineHandler != NULL)
234
                refineHandler (doneRefines, totalRefines);

234
                refineHandler (doneRefines, totalRefines);
235
235
236
            // Skip over keypoint matches we cannot refine as part of the

236
            // Skip over keypoint matches we cannot refine as part of the
237
            // image lies outside.

237
            // image lies outside.
238
            if (patch1 == NULL || patch2 == NULL) {

238
            if (patch1 == NULL || patch2 == NULL) {
239
                if (neverLosePoints)

239
                if (neverLosePoints)
240
                    ArrayList_AddItem(refinedMatches, m);

240
                    ArrayList_AddItem(refinedMatches, m);
241
                                DisplayImage_delete(patch1);

241
                                DisplayImage_delete(patch1);
242
                                DisplayImage_delete(patch2);

242
                                DisplayImage_delete(patch2);
243
                continue;

243
                continue;
244
            }

244
            }
245
245
246
            // Otherwise, run the SIFT algorithm on both small patches.

246
            // Otherwise, run the SIFT algorithm on both small patches.
247
            ArrayList* p1kp = ExtractKeypoints (patch1);

247
            ArrayList* p1kp = ExtractKeypoints (patch1);
248
            ArrayList* p2kp = ExtractKeypoints (patch2);

248
            ArrayList* p2kp = ExtractKeypoints (patch2);
249
            /*WriteLine ("p1kp = %d, p2kp = %d", ArrayList_Count(p1kp),

249
            /*WriteLine ("p1kp = %d, p2kp = %d", ArrayList_Count(p1kp),
250
              ArrayList_Count(p2kp));*/

250
              ArrayList_Count(p2kp));*/
251
            

251
            
252
            // Apply the matching, RANSAC enabled.

252
            // Apply the matching, RANSAC enabled.
253
            MultiMatch* mm = MultiMatch_new0 ();

253
            MultiMatch* mm = MultiMatch_new0 ();
254
            mm->verbose = false;

254
            mm->verbose = false;
255
255
256
            ArrayList* matches = NULL;

256
            ArrayList* matches = NULL;
257
            matches = MultiMatch_TwoPatchMatch (mm, p1kp,

257
            matches = MultiMatch_TwoPatchMatch (mm, p1kp,
258
                                patch1->width, patch1->height, p2kp, patch2->width,

258
                                patch1->width, patch1->height, p2kp, patch2->width,
259
                                patch2->height, true);

259
                                patch2->height, true);
260
                        DisplayImage_delete(patch1);

260
                        DisplayImage_delete(patch1);
261
                        DisplayImage_delete(patch2);

261
                        DisplayImage_delete(patch2);
262
262
263
            /* In case there are less than three keypoints in the

263
            /* In case there are less than three keypoints in the
264
             * two patches, we ignore them all.

264
             * two patches, we ignore them all.
265
             */

265
             */
266
            if (0 /*was exception ???*/ ) { 

266
            if (0 /*was exception ???*/ ) { 
267
                matches = NULL;

267
                matches = NULL;
268
            }

268
            }
269
269
270
            if (matches == NULL || ArrayList_Count(matches) != 1) {

270
            if (matches == NULL || ArrayList_Count(matches) != 1) {
271
                if (neverLosePoints)

271
                if (neverLosePoints)
272
                    ArrayList_AddItem(refinedMatches, m);

272
                    ArrayList_AddItem(refinedMatches, m);
273
273
274
                continue;

274
                continue;
275
            }

275
            }
276
276
277
            MatchSet* pSet = (MatchSet*) ArrayList_GetItem(matches, 0);

277
            MatchSet* pSet = (MatchSet*) ArrayList_GetItem(matches, 0);
278
278
279
            // Now get the real new control point coordinates from the

279
            // Now get the real new control point coordinates from the
280
            // patches.  We have two options and assume all points are

280
            // patches.  We have two options and assume all points are
281
            // equal quality-wise:

281
            // equal quality-wise:
282
            //   a) Select the one that is most in the middle

282
            //   a) Select the one that is most in the middle
283
            //      (selectMiddlePoint == true)

283
            //      (selectMiddlePoint == true)
284
            //   b) Build the mean of all the control point matches in the

284
            //   b) Build the mean of all the control point matches in the
285
            //      patches (selectMiddlePoint == false).

285
            //      patches (selectMiddlePoint == false).
286
            double kp1X = 0.0;

286
            double kp1X = 0.0;
287
            double kp1Y = 0.0;

287
            double kp1Y = 0.0;
288
            double kp2X = 0.0;

288
            double kp2X = 0.0;
289
            double kp2Y = 0.0;

289
            double kp2Y = 0.0;
290
            double kpMidDist = Double_PositiveInfinity;

290
            double kpMidDist = Double_PositiveInfinity;
291
291
292
            int k;

292
            int k;
293
            for(k=0; k<ArrayList_Count(pSet->matches); k++) {

293
            for(k=0; k<ArrayList_Count(pSet->matches); k++) {
294
                Match* pM = (Match*) ArrayList_GetItem(pSet->matches, k);

294
                Match* pM = (Match*) ArrayList_GetItem(pSet->matches, k);
295
                if (selectMiddlePoint) {

295
                if (selectMiddlePoint) {
296
                    double dist = sqrt (

296
                    double dist = sqrt (
297
                        pow (pM->kp1->x - p1radius, 2.0) +

297
                        pow (pM->kp1->x - p1radius, 2.0) +
298
                        pow (pM->kp1->y - p1radius, 2.0));

298
                        pow (pM->kp1->y - p1radius, 2.0));
299
                    

299
                    
300
                    if (dist < kpMidDist) {

300
                    if (dist < kpMidDist) {
301
                        kpMidDist = dist;

301
                        kpMidDist = dist;
302
                        

302
                        
303
                        kp1X = pM->kp1->x;

303
                        kp1X = pM->kp1->x;
304
                        kp1Y = pM->kp1->y;

304
                        kp1Y = pM->kp1->y;
305
                        

305
                        
306
                        kp2X = pM->kp2->x;

306
                        kp2X = pM->kp2->x;
307
                        kp2Y = pM->kp2->y;

307
                        kp2Y = pM->kp2->y;
308
                    }

308
                    }
309
                } else {

309
                } else {
310
                    kp1X += pM->kp1->x;

310
                    kp1X += pM->kp1->x;
311
                    kp1Y += pM->kp1->y;

311
                    kp1Y += pM->kp1->y;
312
                    

312
                    
313
                    kp2X += pM->kp2->x;

313
                    kp2X += pM->kp2->x;
314
                    kp2Y += pM->kp2->y;

314
                    kp2Y += pM->kp2->y;
315
                }

315
                }
316
316
317
                /*WriteLine ("(%g, %g) matches (%g, %g)",

317
                /*WriteLine ("(%g, %g) matches (%g, %g)",
318
                  pM->kp1->x, pM->kp1->y, pM->kp2->x, pM->kp2->y);*/

318
                  pM->kp1->x, pM->kp1->y, pM->kp2->x, pM->kp2->y);*/
319
            }

319
            }
320
320
321
            if (selectMiddlePoint == false) {

321
            if (selectMiddlePoint == false) {
322
                kp1X /= (double) ArrayList_Count(pSet->matches);

322
                kp1X /= (double) ArrayList_Count(pSet->matches);
323
                kp1Y /= (double) ArrayList_Count(pSet->matches);

323
                kp1Y /= (double) ArrayList_Count(pSet->matches);
324
                kp2X /= (double) ArrayList_Count(pSet->matches);

324
                kp2X /= (double) ArrayList_Count(pSet->matches);
325
                kp2Y /= (double) ArrayList_Count(pSet->matches);

325
                kp2Y /= (double) ArrayList_Count(pSet->matches);
326
            }

326
            }
327
327
328
            kp1X += p1x - p1radius;

328
            kp1X += p1x - p1radius;
329
            kp1Y += p1y - p1radius;

329
            kp1Y += p1y - p1radius;
330
330
331
            kp2X += p2x - p2radius;

331
            kp2X += p2x - p2radius;
332
            kp2Y += p2y - p2radius;

332
            kp2Y += p2y - p2radius;
333
333
334
            Match* mn = Match_clone (m);

334
            Match* mn = Match_clone (m);
335
335
336
            // Adjust the original keypoints location to be the mean of

336
            // Adjust the original keypoints location to be the mean of
337
            // all the highly precise superresolution points.

337
            // all the highly precise superresolution points.
338
            mn->kp1->x = kp1X;

338
            mn->kp1->x = kp1X;
339
            mn->kp1->y = kp1Y;

339
            mn->kp1->y = kp1Y;
340
340
341
            mn->kp2->x = kp2X;

341
            mn->kp2->x = kp2X;
342
            mn->kp2->y = kp2Y;

342
            mn->kp2->y = kp2Y;
343
343
344
            /*WriteLine ("MASTER POINT MATCH: (%g,%g) to (%g,%g)",

344
            /*WriteLine ("MASTER POINT MATCH: (%g,%g) to (%g,%g)",
345
              kp1X, kp1Y, kp2X, kp2Y);*/

345
              kp1X, kp1Y, kp2X, kp2Y);*/
346
346
347
            ArrayList_AddItem(refinedMatches, mn);

347
            ArrayList_AddItem(refinedMatches, mn);
348
            /*

348
            /*
349
              DisplayImage_Save (patch1, "patch-1.jpg");

349
              DisplayImage_Save (patch1, "patch-1.jpg");
350
              DisplayImage_Save (patch2, "patch-2.jpg");

350
              DisplayImage_Save (patch2, "patch-2.jpg");
351
              exit (0);

351
              exit (0);
352
            */

352
            */
353
        }

353
        }
354
354
355
        ms->matches = refinedMatches;

355
        ms->matches = refinedMatches;
356
    }

356
    }
357
}

357
}
358
358
359
/** Extract a small image patch from a larger image, centered at the given

359
/** Extract a small image patch from a larger image, centered at the given
360
 * coordinates.

360
 * coordinates.
361
 */

361
 */
362
DisplayImage* ExtractPatch (DisplayImage* large,

362
DisplayImage* ExtractPatch (DisplayImage* large,
363
                int px, int py, double scale, int* radius)

363
                int px, int py, double scale, int* radius)
364
{

364
{
365
    *radius = (int) (9.0 * scale + 0.5);

365
    *radius = (int) (9.0 * scale + 0.5);
366
    if (*radius > RefinementRadiusMaximum)

366
    if (*radius > RefinementRadiusMaximum)
367
        *radius = RefinementRadiusMaximum;

367
        *radius = RefinementRadiusMaximum;
368
368
369
    /*WriteLine ("patch centered at (%d,%d), scale %g, radius = %d",

369
    /*WriteLine ("patch centered at (%d,%d), scale %g, radius = %d",
370
      px, py, scale, *radius);*/

370
      px, py, scale, *radius);*/
371
371
372
    int pxe = px + *radius;

372
    int pxe = px + *radius;
373
    int pye = py + *radius;

373
    int pye = py + *radius;
374
    px -= *radius;

374
    px -= *radius;
375
    py -= *radius;

375
    py -= *radius;
376
376
377
    if (px < 0 || py < 0 || pxe >= large->width || pye >= large->height) {

377
    if (px < 0 || py < 0 || pxe >= large->width || pye >= large->height) {
378
        /*WriteLine ("   (%d,%d)-(%d,%d) out of (0,0)-(%d,%d)",

378
        /*WriteLine ("   (%d,%d)-(%d,%d) out of (0,0)-(%d,%d)",
379
          px, py, pxe, pye, large->width, large->height);*/

379
          px, py, pxe, pye, large->width, large->height);*/
380
380
381
        return (NULL);

381
        return (NULL);
382
    } else {

382
    } else {
383
        //WriteLine ("   extracting patch");

383
        //WriteLine ("   extracting patch");
384
    }

384
    }
385
    DisplayImage* patch = DisplayImage_Carve (large, px, py, *radius*2, *radius*2);

385
    DisplayImage* patch = DisplayImage_Carve (large, px, py, *radius*2, *radius*2);
386
386
387
    return (patch);

387
    return (patch);
388
}

388
}
389
389
390
/** Produce keypoints for a small image patch.

390
/** Produce keypoints for a small image patch.
391
 */

391
 */
392
ArrayList* ExtractKeypoints (DisplayImage* pic)

392
ArrayList* ExtractKeypoints (DisplayImage* pic)
393
{

393
{
394
    ImageMap* picMap = DisplayImage_ConvertToImageMap (pic);

394
    ImageMap* picMap = DisplayImage_ConvertToImageMap (pic);
395
    

395
    
396
    LoweFeatureDetector* lf = LoweFeatureDetector_new0 ();

396
    LoweFeatureDetector* lf = LoweFeatureDetector_new0 ();
397
    LoweFeatureDetector_SetPrintWarning(false);

397
    LoweFeatureDetector_SetPrintWarning(false);
398
    LoweFeatureDetector_SetVerbose(false);

398
    LoweFeatureDetector_SetVerbose(false);
399
    LoweFeatureDetector_DetectFeatures (lf, picMap);

399
    LoweFeatureDetector_DetectFeatures (lf, picMap);
400
    

400
    
401
        ArrayList* res = LoweFeatureDetector_GlobalNaturalKeypoints(lf);

401
        ArrayList* res = LoweFeatureDetector_GlobalNaturalKeypoints(lf);
402
        lf->globalNaturalKeypoints = NULL; // Make sure res won't get deleted.

402
        lf->globalNaturalKeypoints = NULL; // Make sure res won't get deleted.
403
        LoweFeatureDetector_delete(lf);

403
        LoweFeatureDetector_delete(lf);
404
        return res;

404
        return res;
405
}

405
}
406
406
407
bool YesNoOption (char* optionName, char* val)

407
bool YesNoOption (char* optionName, char* val)
408
{

408
{
409
    if (strcmp (val, "1") == 0 || strcmp (val, "on") == 0)

409
    if (strcmp (val, "1") == 0 || strcmp (val, "on") == 0)
410
    return (true);

410
    return (true);
411
    else if (strcmp (val, "0") == 0 || strcmp (val, "off") == 0)

411
    else if (strcmp (val, "0") == 0 || strcmp (val, "off") == 0)
412
    return (false);

412
    return (false);
413
    

413
    
414
    FatalError ("'%s' is no valid truth value for option '%s'. Please see manpage for help.",

414
    FatalError ("'%s' is no valid truth value for option '%s'. Please see manpage for help.",
415
        val, optionName);

415
        val, optionName);
416
    return false;

416
    return false;
417
}

417
}
418
418
419
void WritePTOFile (FILE* pto, MultiMatch* mm,

419
void WritePTOFile (FILE* pto, MultiMatch* mm,
420
           ArrayList* msList, BondBall* bb, int generateHorizon, bool integerCoordinates,

420
           ArrayList* msList, BondBall* bb, int generateHorizon, bool integerCoordinates,
421
           bool useAbsolutePathnames)

421
           bool useAbsolutePathnames)
422
{

422
{
423
    fprintf(pto, "# Hugin project file\n");

423
    fprintf(pto, "# Hugin project file\n");
424
    fprintf(pto, "# automatically generated by autopano-sift, available at\n");

424
    fprintf(pto, "# automatically generated by autopano-sift, available at\n");
425
    fprintf(pto, "# http://cs.tu-berlin.de/~nowozin/autopano-sift/\n\n");

425
    fprintf(pto, "# http://cs.tu-berlin.de/~nowozin/autopano-sift/\n\n");
426
    fprintf(pto, "p f2 w3000 h1500 v360  n\"JPEG q90\"\n");

426
    fprintf(pto, "p f2 w3000 h1500 v360  n\"JPEG q90\"\n");
427
    fprintf(pto, "m g1 i0\n\n");

427
    fprintf(pto, "m g1 i0\n\n");
428
    

428
    
429
    int imageIndex = 0;

429
    int imageIndex = 0;
430
    HashTable* imageNameTab = HashTable_new0 (NULL, NULL);

430
    HashTable* imageNameTab = HashTable_new0 (NULL, NULL);
431
    ArrayList* resolutions = ArrayList_new0 (Resolution_delete);

431
    ArrayList* resolutions = ArrayList_new0 (Resolution_delete);
432
    int i;

432
    int i;
433
    for(i=0; i<ArrayList_Count(mm->keySets); i++) {

433
    for(i=0; i<ArrayList_Count(mm->keySets); i++) {
434
        KeypointXMLList* kx = (KeypointXMLList*) ArrayList_GetItem(mm->keySets, i);

434
        KeypointXMLList* kx = (KeypointXMLList*) ArrayList_GetItem(mm->keySets, i);
435
        HashTable_AddItem(imageNameTab, kx->imageFile, (void*)imageIndex);

435
        HashTable_AddItem(imageNameTab, kx->imageFile, (void*)imageIndex);
436
        ArrayList_AddItem(resolutions, Resolution_new (kx->xDim, kx->yDim));

436
        ArrayList_AddItem(resolutions, Resolution_new (kx->xDim, kx->yDim));
437
        

437
        
438
        char*  imageFile = kx->imageFile;

438
        char*  imageFile = kx->imageFile;
439
        

439
        
440
        // If the resolution was already there, use the first image with

440
        // If the resolution was already there, use the first image with
441
        // the exact same resolution as reference for camera-related

441
        // the exact same resolution as reference for camera-related
442
        // values.

442
        // values.
443
        

443
        
444
        int refIdx;

444
        int refIdx;
445
        for (refIdx = 0 ; refIdx < (ArrayList_Count(resolutions) - 1) ; ++refIdx) {

445
        for (refIdx = 0 ; refIdx < (ArrayList_Count(resolutions) - 1) ; ++refIdx) {
446
            if (Resolution_CompareTo((Resolution*) ArrayList_GetItem(resolutions, refIdx), kx->xDim, kx->yDim) == 0)

446
            if (Resolution_CompareTo((Resolution*) ArrayList_GetItem(resolutions, refIdx), kx->xDim, kx->yDim) == 0)
447
                break;

447
                break;
448
        }

448
        }
449
        if (refIdx == (ArrayList_Count(resolutions) - 1))

449
        if (refIdx == (ArrayList_Count(resolutions) - 1))
450
            refIdx = -1;

450
            refIdx = -1;
451
        

451
        
452
        Position* pos = bb == NULL ? NULL :

452
        Position* pos = bb == NULL ? NULL :
453
            (Position*) HashTable_GetItem(bb->positions, imageFile);

453
            (Position*) HashTable_GetItem(bb->positions, imageFile);
454
        /*

454
        /*
455
          if (pos != NULL) {

455
          if (pos != NULL) {
456
          WriteLine ("yaw %g, pitch %g, rotation %g",

456
          WriteLine ("yaw %g, pitch %g, rotation %g",
457
          pos->yaw, pos->pitch, pos->rotation);

457
          pos->yaw, pos->pitch, pos->rotation);
458
          }*/

458
          }*/
459
459
460
        double yaw = 0.0, pitch = 0.0, rotation = 0.0;

460
        double yaw = 0.0, pitch = 0.0, rotation = 0.0;
461
        if (pos != NULL) {

461
        if (pos != NULL) {
462
            yaw = pos->yaw;

462
            yaw = pos->yaw;
463
            pitch = pos->pitch;

463
            pitch = pos->pitch;
464
            rotation = pos->rotation;

464
            rotation = pos->rotation;
465
        }

465
        }
466
        

466
        
467
        if (imageIndex == 0 || refIdx == -1) {

467
        if (imageIndex == 0 || refIdx == -1) {
468
            fprintf(pto, "i w%d h%d f0 a0 b-0.01 c0 d0 e0 p%g r%g v180 y%g  u10 n\"%s\"\n",

468
            fprintf(pto, "i w%d h%d f0 a0 b-0.01 c0 d0 e0 p%g r%g v180 y%g  u10 n\"%s\"\n",
469
                kx->xDim, kx->yDim, pitch, rotation, yaw, imageFile);

469
                kx->xDim, kx->yDim, pitch, rotation, yaw, imageFile);
470
        } else {

470
        } else {
471
            fprintf(pto, "i w%d h%d f0 a=%d b=%d c=%d d0 e0 p%g r%g v=%d y%g  u10 n\"%s\"\n",

471
            fprintf(pto, "i w%d h%d f0 a=%d b=%d c=%d d0 e0 p%g r%g v=%d y%g  u10 n\"%s\"\n",
472
                kx->xDim, kx->yDim, refIdx, refIdx, refIdx, pitch, rotation, refIdx, yaw, imageFile);

472
                kx->xDim, kx->yDim, refIdx, refIdx, refIdx, pitch, rotation, refIdx, yaw, imageFile);
473
        }

473
        }
474
        imageIndex += 1;

474
        imageIndex += 1;
475
    }

475
    }
476
    

476
    
477
    fprintf(pto, "\nv p1 r1 y1\n\n");

477
    fprintf(pto, "\nv p1 r1 y1\n\n");
478
    

478
    
479
    fprintf(pto, "# match list automatically generated\n");

479
    fprintf(pto, "# match list automatically generated\n");
480
    int j;

480
    int j;
481
    for(j=0; j<ArrayList_Count(msList); j++) {

481
    for(j=0; j<ArrayList_Count(msList); j++) {
482
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, j);

482
        MatchSet* ms = (MatchSet*) ArrayList_GetItem(msList, j);
483
        int k;

483
        int k;
484
        for(k=0; k<ArrayList_Count(ms->matches); k++) {

484
        for(k=0; k<ArrayList_Count(ms->matches); k++) {
485
            Match* m = (Match*) ArrayList_GetItem(ms->matches, k);

485
            Match* m = (Match*) ArrayList_GetItem(ms->matches, k);
486
            if (integerCoordinates == false) {

486
            if (integerCoordinates == false) {
487
                fprintf(pto, "c n%d N%d x%.6f y%.6f X%.6f Y%.6f t0\n",

487
                fprintf(pto, "c n%d N%d x%.6f y%.6f X%.6f Y%.6f t0\n",
488
                    (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),

488
                    (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),
489
                    m->kp1->x, m->kp1->y, m->kp2->x, m->kp2->y);

489
                    m->kp1->x, m->kp1->y, m->kp2->x, m->kp2->y);
490
            } else {

490
            } else {
491
                fprintf(pto, "c n%d N%d x%d y%d X%d Y%d t0\n",

491
                fprintf(pto, "c n%d N%d x%d y%d X%d Y%d t0\n",
492
                    (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),

492
                    (int)HashTable_GetItem(imageNameTab, ms->file1), (int)HashTable_GetItem(imageNameTab, ms->file2),
493
                    (int) (m->kp1->x + 0.5), (int) (m->kp1->y + 0.5),

493
                    (int) (m->kp1->x + 0.5), (int) (m->kp1->y + 0.5),
494
                    (int) (m->kp2->x + 0.5), (int) (m->kp2->y + 0.5));

494
                    (int) (m->kp2->x + 0.5), (int) (m->kp2->y + 0.5));
495
            }

495
            }
496
        }

496
        }
497
    }

497
    }
498
    

498
    
499
    // Generate horizon if we should

499
    // Generate horizon if we should
500
    if (bb != NULL && generateHorizon > 0) {

500
    if (bb != NULL && generateHorizon > 0) {
501
        WriteLine ("Creating horizon...");

501
        WriteLine ("Creating horizon...");
502
        

502
        
503
        int kMain = 2;

503
        int kMain = 2;
504
        int hPoints = generateHorizon;

504
        int hPoints = generateHorizon;
505
        int horizonPointsMade = 0;

505
        int horizonPointsMade = 0;
506
506
507
        bool hasGood = true;

507
        bool hasGood = true;
508
        while (hPoints > 0 && hasGood) {

508
        while (hPoints > 0 && hasGood) {
509
            hasGood = false;

509
            hasGood = false;
510
            int kStep = 2 * kMain;

510
            int kStep = 2 * kMain;
511
511
512
            int p;

512
            int p;
513
            for (p = 0 ; hPoints > 0 && p < kMain ; ++p) {

513
            for (p = 0 ; hPoints > 0 && p < kMain ; ++p) {
514
                double stepSize = ((double) ArrayList_Count(bb->firstRow)) / ((double) kStep);

514
                double stepSize = ((double) ArrayList_Count(bb->firstRow)) / ((double) kStep);
515
                double beginIndex = p * stepSize;

515
                double beginIndex = p * stepSize;
516
                double endIndex = (((double) ArrayList_Count(bb->firstRow)) / (double) kMain) +

516
                double endIndex = (((double) ArrayList_Count(bb->firstRow)) / (double) kMain) +
517
                    p * stepSize;

517
                    p * stepSize;
518
518
519
// Round to next integer and check if their image distance

519
// Round to next integer and check if their image distance
520
// is larger than 1. If its not, we skip over this useless

520
// is larger than 1. If its not, we skip over this useless
521
// horizon point.

521
// horizon point.
522
                int bi = (int) (beginIndex + 0.5);

522
                int bi = (int) (beginIndex + 0.5);
523
                int ei = (int) (endIndex + 0.5);

523
                int ei = (int) (endIndex + 0.5);
524
                if ((ei - bi) <= 1)

524
                if ((ei - bi) <= 1)
525
                    continue;

525
                    continue;
526
526
527
                hasGood = true;

527
                hasGood = true;
528
528
529
                bi %= ArrayList_Count(bb->firstRow);

529
                bi %= ArrayList_Count(bb->firstRow);
530
                ei %= ArrayList_Count(bb->firstRow);

530
                ei %= ArrayList_Count(bb->firstRow);
531
                fprintf(pto, "c n%s N%s x%d y%d X%d Y%d t2\n",

531
                fprintf(pto, "c n%s N%s x%d y%d X%d Y%d t2\n",
532
                    (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, bi)),

532
                    (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, bi)),
533
                    (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, ei)),

533
                    (char*)HashTable_GetItem(imageNameTab, ArrayList_GetItem(bb->firstRow, ei)),
534
                    ((Resolution*) ArrayList_GetItem(resolutions,bi))->x / 2,

534
                    ((Resolution*) ArrayList_GetItem(resolutions,bi))->x / 2,
535
                    ((Resolution*) ArrayList_GetItem(resolutions,bi))->y / 2,

535
                    ((Resolution*) ArrayList_GetItem(resolutions,bi))->y / 2,
536
                    ((Resolution*) ArrayList_GetItem(resolutions,ei))->x / 2,

536
                    ((Resolution*) ArrayList_GetItem(resolutions,ei))->x / 2,
537
                    ((Resolution*) ArrayList_GetItem(resolutions,ei))->y / 2);

537
                    ((Resolution*) ArrayList_GetItem(resolutions,ei))->y / 2);
538
538
539
                horizonPointsMade += 1;

539
                horizonPointsMade += 1;
540
                hPoints -= 1;

540
                hPoints -= 1;
541
            }

541
            }
542
542
543
// Increase density for next generation lines

543
// Increase density for next generation lines
544
            kMain *= 2;

544
            kMain *= 2;
545
        }

545
        }
546
        WriteLine ("  made %d horizon lines.\n", horizonPointsMade);

546
        WriteLine ("  made %d horizon lines.\n", horizonPointsMade);
547
    }

547
    }
548
548
549
    fprintf(pto, "\n# :-)\n\n");

549
    fprintf(pto, "\n# :-)\n\n");
550
    

550
    
551
    WriteLine ("\nYou can now load the output file into hugin.");

551
    WriteLine ("\nYou can now load the output file into hugin.");
552
    WriteLine ("Notice: You absolutely must adjust the field-of-view value for the images");

552
    WriteLine ("Notice: You absolutely must adjust the field-of-view value for the images");
553
553
554
        ArrayList_delete(resolutions);

554
        ArrayList_delete(resolutions);
555
        HashTable_delete(imageNameTab);

555
        HashTable_delete(imageNameTab);
556
}

556
}
557
557
558
558
559
int main (int argc, char* argv[])

559
int main (int argc, char* argv[])
560
{

560
{
561
    WriteLine ("autopano-sift, Automatic panorama generation program\n");

561
    WriteLine ("autopano-sift, Automatic panorama generation program\n");
562
  

562
  
563
    if (argc+1 < 3) {

563
    if (argc+1 < 3) {
564
        Usage ();

564
        Usage ();
565
        exit (1);

565
        exit (1);
566
    }

566
    }
567
567
568
    // downscale option for GenerteKeys

568
    // downscale option for GenerteKeys
569
    int mindim = 800; // default maxdim = 800

569
    int mindim = 800; // default maxdim = 800
570
570
571
    // output to stdout flag

571
    // output to stdout flag
572
    bool streamout = false;

572
    bool streamout = false;
573
573
574
    // Automatic pre-aligning of images

574
    // Automatic pre-aligning of images
575
    bool preAlign = false;

575
    bool preAlign = false;
576
    int bottomDefault = -1;

576
    int bottomDefault = -1;
577
    int generateHorizon = 0;

577
    int generateHorizon = 0;
578
  

578
  
579
    // Use RANSAC algorithm match filtration.

579
    // Use RANSAC algorithm match filtration.
580
    bool useRansac = true;

580
    bool useRansac = true;
581
  

581
  
582
    // Use area based weighting for final match selection.

582
    // Use area based weighting for final match selection.
583
    bool useAreaFiltration = true;

583
    bool useAreaFiltration = true;
584
  

584
  
585
    // Truncate match coordinates to integer numbers.

585
    // Truncate match coordinates to integer numbers.
586
    bool useIntegerCoordinates = false;

586
    bool useIntegerCoordinates = false;
587
  

587
  
588
    // Use the absolute pathname of the image files in the output PTO

588
    // Use the absolute pathname of the image files in the output PTO
589
    // file.

589
    // file.
590
    bool useAbsolutePathnames = false;

590
    bool useAbsolutePathnames = false;
591
  

591
  
592
    // Use "keep-best" filtration, keep the maxMatches best.

592
    // Use "keep-best" filtration, keep the maxMatches best.
593
    int maxMatches = 16;    // default: 16

593
    int maxMatches = 16;    // default: 16
594
  

594
  
595
    // Refinement options

595
    // Refinement options
596
    bool refine = false;

596
    bool refine = false;
597
    bool refineMiddle = true;

597
    bool refineMiddle = true;
598
    bool keepUnrefinable = true;

598
    bool keepUnrefinable = true;
599
  

599
  
600
    int optionCount = 0;

600
    int optionCount = 0;
601
    int optionN = 1;

601
    int optionN = 1;
602
    while (optionN < argc &&

602
    while (optionN < argc &&
603
           strlen(argv[optionN]) >= 2 

603
           strlen(argv[optionN]) >= 2 
604
           && argv[optionN][0] == '-'

604
           && argv[optionN][0] == '-'
605
           && argv[optionN][1] == '-')

605
           && argv[optionN][1] == '-')
606
        {

606
        {
607
            char* optionStr = argv[optionN];

607
            char* optionStr = argv[optionN];
608
608
609
            if (strcmp (optionStr, "--maxdim") == 0) {

609
            if (strcmp (optionStr, "--maxdim") == 0) {
610
                mindim = atoi(argv[optionN + 1]);

610
                mindim = atoi(argv[optionN + 1]);
611
                optionN += 2;

611
                optionN += 2;
612
            } else if (strcmp (optionStr, "--ransac") == 0) {

612
            } else if (strcmp (optionStr, "--ransac") == 0) {
613
                useRansac = YesNoOption ("--ransac", argv[optionN + 1]);

613
                useRansac = YesNoOption ("--ransac", argv[optionN + 1]);
614
                optionN += 2;

614
                optionN += 2;
615
            } else if (strcmp (optionStr, "--maxmatches") == 0) {

615
            } else if (strcmp (optionStr, "--maxmatches") == 0) {
616
                if (sscanf(argv[optionN + 1], "%d",  &maxMatches) != 1) {

616
                if (sscanf(argv[optionN + 1], "%d",  &maxMatches) != 1) {
617
                    WriteLine ("Parameter to maxmatches option invalid. See the usage help.");

617
                    WriteLine ("Parameter to maxmatches option invalid. See the usage help.");
618
                    exit (1);

618
                    exit (1);
619
                }

619
                }
620
                if (maxMatches < 0) {

620
                if (maxMatches < 0) {
621
                    WriteLine ("Maximum number of matches must be positive or zero (unlimited).");

621
                    WriteLine ("Maximum number of matches must be positive or zero (unlimited).");
622
                    exit (1);

622
                    exit (1);
623
                }

623
                }
624
                optionN += 2;

624
                optionN += 2;
625
            } else if (strcmp (optionStr, "--disable-areafilter") == 0) {

625
            } else if (strcmp (optionStr, "--disable-areafilter") == 0) {
626
                useAreaFiltration = false;

626
                useAreaFiltration = false;
627
                optionN += 1;

627
                optionN += 1;
628
            } else if (strcmp (optionStr, "--integer-coordinates") == 0) {

628
            } else if (strcmp (optionStr, "--integer-coordinates") == 0) {
629
                useIntegerCoordinates = true;

629
                useIntegerCoordinates = true;
630
                optionN += 1;

630
                optionN += 1;
631
            } else if (strcmp (optionStr, "--absolute-pathnames") == 0) {

631
            } else if (strcmp (optionStr, "--absolute-pathnames") == 0) {
632
                useAbsolutePathnames = YesNoOption ("--absolute-pathnames", argv[optionN + 1]);

632
                useAbsolutePathnames = YesNoOption ("--absolute-pathnames", argv[optionN + 1]);
633
                optionN += 2;

633
                optionN += 2;
634
            } else if (strcmp (optionStr, "--align") == 0) {

634
            } else if (strcmp (optionStr, "--align") == 0) {
635
                preAlign = true;

635
                preAlign = true;
636
                optionN += 1;

636
                optionN += 1;
637
            } else if (strcmp (optionStr, "--bottom-is-left") == 0) {

637
            } else if (strcmp (optionStr, "--bottom-is-left") == 0) {
638
                bottomDefault = 0;

638
                bottomDefault = 0;
639
                optionN += 1;

639
                optionN += 1;
640
            } else if (strcmp (optionStr, "--bottom-is-right") == 0) {

640
            } else if (strcmp (optionStr, "--bottom-is-right") == 0) {
641
                bottomDefault = 1;

641
                bottomDefault = 1;
642
                optionN += 1;

642
                optionN += 1;
643
            } else if (strcmp (optionStr, "--generate-horizon") == 0) {

643
            } else if (strcmp (optionStr, "--generate-horizon") == 0) {
644
                if (sscanf(argv[optionN + 1], "%d", &generateHorizon) != 1) {

644
                if (sscanf(argv[optionN + 1], "%d", &generateHorizon) != 1) {
645
                    WriteLine ("Parameter to generate-horizon option invalid. See the usage help.");

645
                    WriteLine ("Parameter to generate-horizon option invalid. See the usage help.");
646
                    exit (1);

646
                    exit (1);
647
                }

647
                }
648
                if (generateHorizon < 0) {

648
                if (generateHorizon < 0) {
649
                    WriteLine ("The number of horizon lines to generate must be positive.");

649
                    WriteLine ("The number of horizon lines to generate must be positive.");
650
                    exit (1);

650
                    exit (1);
651
                }

651
                }
652
652
653
                optionN += 2;

653
                optionN += 2;
654
            } else if (strcmp (optionStr, "--refine") == 0) {

654
            } else if (strcmp (optionStr, "--refine") == 0) {
655
                refine = true;

655
                refine = true;
656
                optionN += 1;

656
                optionN += 1;
657
            } else if (strcmp (optionStr, "--refine-by-middle") == 0) {

657
            } else if (strcmp (optionStr, "--refine-by-middle") == 0) {
658
                refineMiddle = true;

658
                refineMiddle = true;
659
                optionN += 1;

659
                optionN += 1;
660
            } else if (strcmp (optionStr, "--refine-by-mean") == 0) {

660
            } else if (strcmp (optionStr, "--refine-by-mean") == 0) {
661
                refineMiddle = false;

661
                refineMiddle = false;
662
                optionN += 1;

662
                optionN += 1;
663
            } else if (strcmp (optionStr, "--keep-unrefinable") == 0) {

663
            } else if (strcmp (optionStr, "--keep-unrefinable") == 0) {
664
                keepUnrefinable = YesNoOption ("--keep-unrefinable", argv[optionN + 1]);

664
                keepUnrefinable = YesNoOption ("--keep-unrefinable", argv[optionN + 1]);
665
                optionN += 2;

665
                optionN += 2;
666
            } else {

666
            } else {
667
                WriteLine ("Option error. Run without arguments for help.");

667
                WriteLine ("Option error. Run without arguments for help.");
668
                exit (1);

668
                exit (1);
669
            }

669
            }
670
        }

670
        }
671
    optionCount = optionN;

671
    optionCount = optionN;
672
    // is there an output name and at least one input name?

672
    // is there an output name and at least one input name?
673
    if( argc - optionN < 2 ){

673
    if( argc - optionN < 2 ){
674
        WriteLine ("Error. Output name and at least one image name required.");

674
        WriteLine ("Error. Output name and at least one image name required.");
675
        Usage();

675
        Usage();
676
        exit(1);

676
        exit(1);
677
    }

677
    }
678
    // next arg is either output file name or "-" for stdout

678
    // next arg is either output file name or "-" for stdout
679
    // anything else beginning with '-' is an error

679
    // anything else beginning with '-' is an error
680
    if( argv[optionCount][0] == '-' ){

680
    if( argv[optionCount][0] == '-' ){
681
        if( strcmp( argv[optionCount], "-" ) == 0 )streamout = true;

681
        if( strcmp( argv[optionCount], "-" ) == 0 )streamout = true;
682
        else {

682
        else {
683
            WriteLine ("Option error. Run without arguments for help.");

683
            WriteLine ("Option error. Run without arguments for help.");
684
            exit (1);

684
            exit (1);
685
        }

685
        }
686
    }

686
    }
687
    

687
    
688
    if (bottomDefault != -1 && preAlign == false) {

688
    if (bottomDefault != -1 && preAlign == false) {
689
        WriteLine ("Please enable automatic alignment (\"--align\") before using the");

689
        WriteLine ("Please enable automatic alignment (\"--align\") before using the");
690
        WriteLine ("--bottom-is-* options. Run without arguments for help.");

690
        WriteLine ("--bottom-is-* options. Run without arguments for help.");
691
691
692
        exit (1);

692
        exit (1);
693
    }

693
    }
694
694
695
    if (generateHorizon > 0 && preAlign == false) {

695
    if (generateHorizon > 0 && preAlign == false) {
696
        WriteLine ("Please enable automatic alignment (\"--align\") before using the");

696
        WriteLine ("Please enable automatic alignment (\"--align\") before using the");
697
        WriteLine ("--generate-horizon option. Run without arguments for help.");

697
        WriteLine ("--generate-horizon option. Run without arguments for help.");
698
698
699
        exit (1);

699
        exit (1);
700
    }

700
    }
701
701
702
    MultiMatch* mm = MultiMatch_new0 ();

702
    MultiMatch* mm = MultiMatch_new0 ();
703
//------------

703
//------------
704
    ArrayList* keylists = ArrayList_new0(NULL);

704
    ArrayList* keylists = ArrayList_new0(NULL);
705
    int i;

705
    int i;
706
    for( i=0; i<argc - 1 - optionCount; i++) {

706
    for( i=0; i<argc - 1 - optionCount; i++) {
707
        ArrayList_AddItem(keylists, GenerateKeys( argv[i+optionCount+1], mindim ) );

707
        ArrayList_AddItem(keylists, GenerateKeys( argv[i+optionCount+1], mindim ) );
708
    }

708
    }
709
    MultiMatch_LoadKeysetsFromMemory (mm, keylists);

709
    MultiMatch_LoadKeysetsFromMemory (mm, keylists);
710
    // note mm now owns keylists and will delete it when destroyed

710
    // note mm now owns keylists and will delete it when destroyed
711
//-------------

711
//-------------
712
712
713
    WriteLine ("\nMatching...%s", useRansac == true ? " RANSAC enabled" : "");

713
    WriteLine ("\nMatching...%s", useRansac == true ? " RANSAC enabled" : "");
714
    ArrayList* msList = MultiMatch_LocateMatchSets (mm, 3, maxMatches,

714
    ArrayList* msList = MultiMatch_LocateMatchSets (mm, 3, maxMatches,
715
                            useRansac, useAreaFiltration);

715
                            useRansac, useAreaFiltration);
716
716
717
    // Connected component check

717
    // Connected component check
718
    WriteLine ("\nConnected component check...");

718
    WriteLine ("\nConnected component check...");
719
    ArrayList* components = MultiMatch_ComponentCheck (mm, msList);

719
    ArrayList* components = MultiMatch_ComponentCheck (mm, msList);
720
    WriteLine ("Connected component identification resulted in %d component%s:",

720
    WriteLine ("Connected component identification resulted in %d component%s:",
721
           ArrayList_Count(components), ArrayList_Count(components) > 1 ? "s" : "");

721
           ArrayList_Count(components), ArrayList_Count(components) > 1 ? "s" : "");
722
722
723
    int compN = 1;

723
    int compN = 1;
724
    int j;

724
    int j;
725
    for(j=0; j<ArrayList_Count(components); j++) {

725
    for(j=0; j<ArrayList_Count(components); j++) {
726
        Component* comp = (Component*) ArrayList_GetItem(components, j);

726
        Component* comp = (Component*) ArrayList_GetItem(components, j);
727
                char* compstr = Component_ToString(comp);

727
                char* compstr = Component_ToString(comp);
728
                WriteLine ("component %d: %s", compN++, compstr);

728
                WriteLine ("component %d: %s", compN++, compstr);
729
                free(compstr);

729
                free(compstr);
730
    }

730
    }
731
731
732
    if (ArrayList_Count(components) > 1) {

732
    if (ArrayList_Count(components) > 1) {
733
        WriteLine ("");

733
        WriteLine ("");
734
        WriteLine ("Warning: There is one or more components that are not connected through control");

734
        WriteLine ("Warning: There is one or more components that are not connected through control");
735
        WriteLine ("         points. An optimization of the resulting PTO will not be possible");

735
        WriteLine ("         points. An optimization of the resulting PTO will not be possible");
736
        WriteLine ("         without prior adding of control points between the components listed");

736
        WriteLine ("         without prior adding of control points between the components listed");
737
        WriteLine ("         above. Please see the manual page for autopano(1) for details.");

737
        WriteLine ("         above. Please see the manual page for autopano(1) for details.");
738
        WriteLine ("");

738
        WriteLine ("");
739
    } else

739
    } else
740
        WriteLine ("");

740
        WriteLine ("");
741
741
742
    // BondBall algorithm

742
    // BondBall algorithm
743
    BondBall* bb = NULL;

743
    BondBall* bb = NULL;
744
    if (preAlign) {

744
    if (preAlign) {
745
        bb = MultiMatch_BuildBondBall (mm, msList, bottomDefault);

745
        bb = MultiMatch_BuildBondBall (mm, msList, bottomDefault);
746
746
747
        if (bb == NULL) {

747
        if (bb == NULL) {
748
            WriteLine ("WARNING: Failed to build bondball as requested. No pre-aligning of images");

748
            WriteLine ("WARNING: Failed to build bondball as requested. No pre-aligning of images");
749
            WriteLine ("         takes place.\n");

749
            WriteLine ("         takes place.\n");
750
        }

750
        }
751
    }

751
    }
752
752
753
    if (refine) {

753
    if (refine) {
754
        WriteLine ("Refining keypoints");

754
        WriteLine ("Refining keypoints");
755
        RefineKeypoints (msList, refineMiddle, keepUnrefinable);

755
        RefineKeypoints (msList, refineMiddle, keepUnrefinable);
756
    }

756
    }
757
757
758
    FILE* pto;

758
    FILE* pto;
759
    if ( streamout ) {

759
    if ( streamout ) {
760
        pto = stdout;

760
        pto = stdout;
761
    } else {

761
    } else {
762
        WriteLine ("Creating output file \"%s\"", argv[optionCount]);

762
        WriteLine ("Creating output file \"%s\"", argv[optionCount]);
763
        pto = fopen(argv[optionCount], "w");

763
        pto = fopen(argv[optionCount], "w");
764
    }

764
    }
765
765
766
    WritePTOFile (pto, mm, msList, bb, generateHorizon, useIntegerCoordinates,

766
    WritePTOFile (pto, mm, msList, bb, generateHorizon, useIntegerCoordinates,
767
              useAbsolutePathnames);

767
              useAbsolutePathnames);
768
768
769
    ArrayList_delete(components);

769
    ArrayList_delete(components);
770
    BondBall_delete(bb);

770
    BondBall_delete(bb);
771
    MultiMatch_delete(mm);

771
    MultiMatch_delete(mm);
772
    if ( !streamout )

772
    if ( !streamout )
773
        fclose(pto);

773
        fclose(pto);
774
    return 0;

774
    return 0;
775
}

775
}
776
776

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks