-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathProject2.cpp
More file actions
executable file
·514 lines (437 loc) · 14.1 KB
/
Project2.cpp
File metadata and controls
executable file
·514 lines (437 loc) · 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
///////////////////////////////////////////////////////////////////////////
//
// NAME
// Project2.cpp -- command-line (shell) interface to project 2 code
//
// SYNOPSIS
// Project2 sphrWarp input.tga output.tga f [k1 k2]
// Project2 alignPair input1.f input2.f nRANSAC RANSACthresh [sift]
// Project2 blendPairs pairlist.txt outfile.tga blendWidth
// Project2 script script.cmd
//
// PARAMTERS
// input.tga input image
// output.tga output image
//
// f focal length in pixels
// k1, k2 radial distortion parameters
//
// input*.f input feature set
//
// nRANSAC number of RANSAC iterations
// RANSACthresh RANSAC distance threshold for inliers
// sift the word "sift"
//
// pairlist.txt file of image pair names and relative translations
// this is usually the concatenation of outputs from alignPair
//
// blendWidth width of the horizontal blending function
//
// script.cmd script file (command line file)
//
// DESCRIPTION
// This file contains a set of simple command line processes from which
// you can build a simple automatic cylindrical stitching application.
//
// Use the programs here to perform a series of operations such as:
// 1. warp all of the images into spherical coordinate (and undo radial distortion)
// 2. align pairs of images using a feature matcher
// 3. read in all of the images and perform pairwise blends
// to obtain a final (rectified and trimmed) mosaic
//
// TIPS
// To become familiar with this code, single-step through a couple of
// examples. Also, if you are running inside the debugger, place
// a breakpoint inside the catch statement and at the last statement
// in main() so you can see the error message before the program exits.
//
// SEE ALSO
// Image.h basic image class documentation
//
// (modified for CSE576 Spring 2005)
///////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <assert.h>
#include <cstring>
#include <fstream>
#include <FL/Fl.H>
#include <FL/Fl_Shared_Image.H>
#include "ImageLib/ImageLib.h"
#include "WarpSpherical.h"
//#include "FeatureMatch.h"
#include "FeatureAlign.h"
#include "BlendImages.h"
int main(int argc, const char *argv[]); // forward declaration
bool LoadImageFile(const char *filename, CByteImage &image);
void convertToByteImage(CFloatImage &floatImage, CByteImage &byteImage);
void convertToFloatImage(CByteImage &byteImage, CFloatImage &floatImage);
bool convertImage(const Fl_Image *image, CByteImage &convertedImage);
int SphrWarp(int argc, const char *argv[])
{
// Warp the input image to correct for radial distortion and/or map to spherical coordinates
if (argc < 5)
{
printf("usage: %s input.tga output.tga f [k1 k2]\n", argv[1]);
return -1;
}
const char *infile = argv[2];
const char *outfile = argv[3];
float f = (float) atof(argv[4]);
float k1 = (argc > 5) ? (float) atof(argv[5]) : 0.0f;
float k2 = (argc > 6) ? (float) atof(argv[6]) : 0.0f;
CByteImage src, dst, temp;
/* Added by Adarsh */
{
bool success = LoadImageFile(infile, src);
if (!success) {
printf("couldn't load image 1\n");
return -1;
}
else
{
printf("Done loading file\n");
}
}
CShape sh = src.Shape();
CTransform3x3 R;
#define THETA 0.0 // 0.1638
R[0][0] = 1.0; R[0][1] = 0.0; R[0][2] = 0.0;
R[1][0] = 0.0; R[1][1] = cos(THETA); R[1][2] = -sin(THETA);
R[2][0] = 0.0; R[2][1] = sin(THETA); R[2][2] = cos(THETA);
// CFloatImage uv = WarpSphericalField(sh, sh, f, k1, k2, CTransform3x3());
CFloatImage uv = WarpSphericalField(sh, sh, f, k1, k2, R);
WarpLocal(src, dst, uv, false, eWarpInterpLinear);
WriteFile(dst, outfile);
return 0;
}
bool ReadFeatureMatches(const char *filename, vector<FeatureMatch> &matches)
{
FILE *f = fopen(filename, "r");
if (f == NULL)
return false;
int num_matches;
fscanf(f, "%d\n", &num_matches);
matches.resize(num_matches);
for (int i = 0; i < num_matches; i++) {
FeatureMatch match;
int id1, id2;
double score;
fscanf(f, "%d %d %lf\n", &id1, &id2, &score);
match.id1 = id1;
match.id2 = id2;
match.score = score;
matches[i] = match;
}
return true;
}
int AlignPair(int argc, const char *argv[])
{
// Align two images using feature matching
if (argc < 7)
{
printf("usage: %s input1.f input2.f matchfile nRANSAC RANSACthresh [sift]\n", argv[1]);
return -1;
}
const char *infile1 = argv[2];
const char *infile2 = argv[3];
const char *matchfile = argv[4];
int nRANSAC = atoi(argv[5]);
double RANSACthresh = atof(argv[6]);
FeatureSet f1, f2;
// Read in the feature sets
if ((argc >= 8) && (strcmp(argv[7], "sift") == 0)) {
f1.load_sift(infile1);
f2.load_sift(infile2);
}
else {
f1.load(infile1);
f2.load(infile2);
}
CTransform3x3 M;
// Read in the feature matches
vector<FeatureMatch> matches;
bool success = ReadFeatureMatches(matchfile, matches);
if (!success) {
printf("Error opening match file %s for reading\n", matchfile);
return -1;
}
#if 0
// Align two images using feature matching
if (argc < 6)
{
printf("usage: %s input1.f input2.f nRANSAC RANSACthresh [sift]\n", argv[1]);
return -1;
}
const char *infile1 = argv[2];
const char *infile2 = argv[3];
int nRANSAC = atoi(argv[4]);
double RANSACthresh = atof(argv[5]);
FeatureSet f1, f2;
//printf("Reading features\n");
// Read in the feature sets
if ((argc >= 7) && (strcmp(argv[6], "sift") == 0)) {
f1.load_sift(infile1);
f2.load_sift(infile2);
} else {
f1.load(infile1);
f2.load(infile2);
}
vector<FeatureMatch> matches;
CTransform3x3 M;
// call your feature matching routine and store the result
// in matches
// printf("Finding matches\n");
fastMatchFeatures(f1, f2, matches);
#endif
// Performs the alignment.
// printf("Aligning pair\n");
// alignPair(f1, f2, matches, eTranslate, 0.0f, nRANSAC, RANSACthresh, M);
alignPair(f1, f2, matches, eTranslate, 0.0f, nRANSAC, RANSACthresh, M);
// Print out the result
if ((argc >= 7) && (strcmp(argv[6], "sift") == 0)) {
printf("%.2f %.2f\n", M[0][2], -M[1][2]);
} else {
printf("%.2f %.2f\n", M[0][2], M[1][2]);
// printf("%0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
// M[0][0], M[0][1], M[0][2],
// M[1][0], M[1][1], M[1][2],
// M[2][0], M[2][1], M[2][2]);
}
return 0;
}
int BlendPairs(int argc, const char *argv[])
{
// Blend a sequence of images given the pairwise transformations
if (argc < 5)
{
printf("usage: %s pairlist.txt outimg.tga blendWidth\n", argv[1]);
return -1;
}
const char *pairlist= argv[2];
const char *outfile = argv[3];
float blendWidth = (float) atof(argv[4]);
// Open the list of image pairs
FILE *stream = fopen(pairlist, "r");
if (stream == 0)
throw CError("%s: could not open the file %s", argv[1], pairlist);
// Construct the list of images and translations
CImagePositionV ipList;
char line[1024], infile1[1024], infile2[1024];
// float rel_t[2];
CTransform3x3 M;
int n;
for (n = 0; fgets(line, 1024, stream); n++)
{
// Compute the position from the PREVIOUS displacement
CImagePosition ip;
if (n == 0) {
ip.position = CTransform3x3::Translation(0.0, 0.0); /* Ident matrix */
// ip.position = CTransform3x3::Rotation(45.0); /* Ident matrix */
} else {
ip.position = ipList[n-1].position * M;
}
// for (int k = 0; k < 2; k++)
// ip.position[k] = (n > 0) ? ipList[n-1].position[k] - rel_t[k] : 0.0f;
// Read the line and push the image onto the list
// if (sscanf(line, "%s %s %f %f", infile1, infile2,
// &rel_t[0], &rel_t[1]) != 4)
// throw CError("%s: error reading %s", argv[1], pairlist);
if (sscanf(line, "%s %s %lf %lf", infile1, infile2,
&(M[0][2]), &(M[1][2])) != 4)
throw CError("%s: error reading %s\n", argv[1], pairlist);
M[1][2] = -M[1][2];
ReadFile(ip.img, infile1);
ipList.push_back(ip);
}
// Read in the last image
CImagePosition ip;
// for (int k = 0; k < 2; k++)
// ip.position[k] = ipList[n-1].position[k] - rel_t[k];
ip.position = ipList[n-1].position * M;
ReadFile(ip.img, infile2);
ipList.push_back(ip);
fclose(stream);
CByteImage result = BlendImages(ipList, blendWidth);
WriteFile(result, outfile);
return 0;
}
int Script(int argc, const char *argv[])
{
// Read a series of commands from a script file
// (an alternative to a shell-level command file)
if (argc < 3)
{
printf("usage: %s script.cmd\n", argv[1]);
return -1;
}
FILE *stream = fopen(argv[2], "r");
if (stream == 0)
throw CError("Could not open %s", argv[2]);
// Process each command line
char line[1024];
while (fgets(line, 1024, stream))
{
fprintf(stderr, line);
if (line[0] == '/' && line[1] == '/')
continue; // skip the comment line
char *ptr = line;
char *argv2[256];
int argc2;
for (argc2 = 0; argc2 < 256 && *ptr; argc2++)
{
while (*ptr && isspace(*ptr)) ptr++;
argv2[argc2] = ptr;
while (*ptr && !isspace(*ptr)) ptr++;
if (*ptr)
*ptr++ = 0; // null terminate the argument
}
if (argc2 < 2)
continue;
// Call the dispatch routine
int code = main(argc2, (const char **) argv2);
if (code)
return code;
}
fclose(stream);
return 0;
}
int main(int argc, const char *argv[])
{
// This lets us load various image formats.
fl_register_images();
try
{
// Branch to processing code based on first argument
if (argc > 1 && strcmp(argv[1], "sphrWarp") == 0)
return SphrWarp(argc, argv);
else if (argc > 1 && strcmp(argv[1], "alignPair") == 0)
return AlignPair(argc, argv);
else if (argc > 1 && strcmp(argv[1], "blendPairs") == 0)
return BlendPairs(argc, argv);
else if (argc > 1 && strcmp(argv[1], "script") == 0)
return Script(argc, argv);
else {
printf("usage: \n");
printf(" %s sphrWarp input.tga output.tga f [k1 k2]\n", argv[0]);
printf(" %s alignPair input1.f input2.f matchfile nRANSAC RANSACthresh [sift]\n", argv[0]);
printf(" %s blendPairs pairlist.txt outimg.tga blendWidth\n", argv[0]);
printf(" %s script script.cmd\n", argv[0]);
}
}
catch (CError &err) {
printf(err.message);
return -1;
}
return 0;
}
bool LoadImageFile(const char *filename, CByteImage &image)
{
// Load the query image.
printf("%s\n", filename);
Fl_Shared_Image *fl_image = Fl_Shared_Image::get(filename);
if (fl_image == NULL) {
printf("TGA\n");
ReadFile(image, filename);
return true;
} else {
printf("Not TGA\n");
CShape sh(fl_image->w(), fl_image->h(), 4);
image = CByteImage(sh);
// Convert the image to the CImage format.
if (!convertImage(fl_image, image)) {
printf("couldn't convert image to RGB format\n");
return false;
}
/* Set the alpha channel to 1 everywhere */
int w = sh.width;
int h = sh.height;
sh = image.Shape();
// printf("shape: %d, %d, %d\n", sh.width, sh.height, sh.nBands);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
image.Pixel(x, y, 3) = 255;
}
}
return true;
}
}
// Convert CFloatImage to CByteImage.
void convertToByteImage(CFloatImage &floatImage, CByteImage &byteImage) {
CShape sh = floatImage.Shape();
//printf("%d\n", floatImage.Shape().nBands);
//printf("%d\n", byteImage.Shape().nBands);
assert(floatImage.Shape().nBands == min(byteImage.Shape().nBands, 3));
for (int y=0; y<sh.height; y++) {
for (int x=0; x<sh.width; x++) {
for (int c=0; c<sh.nBands; c++) {
float value = floor(255*floatImage.Pixel(x,y,c) + 0.5f);
if (value < byteImage.MinVal()) {
value = byteImage.MinVal();
}
else if (value > byteImage.MaxVal()) {
value = byteImage.MaxVal();
}
// We have to flip the image and reverse the color
// channels to get it to come out right. How silly!
byteImage.Pixel(x,sh.height-y-1,sh.nBands-c-1) = (uchar) value;
}
}
}
}
void convertToFloatImage(CByteImage &byteImage, CFloatImage &floatImage) {
CShape sh = byteImage.Shape();
//printf("%d\n", floatImage.Shape().nBands);
//printf("%d\n", byteImage.Shape().nBands);
assert(floatImage.Shape().nBands == min(byteImage.Shape().nBands, 3));
for (int y=0; y<sh.height; y++) {
for (int x=0; x<sh.width; x++) {
for (int c=0; c<min(3,sh.nBands); c++) {
float value = byteImage.Pixel(x,y,c) / 255.0f;
if (value < floatImage.MinVal()) {
value = floatImage.MinVal();
}
else if (value > floatImage.MaxVal()) {
value = floatImage.MaxVal();
}
// We have to flip the image and reverse the color
// channels to get it to come out right. How silly!
floatImage.Pixel(x,sh.height-y-1,min(3,sh.nBands)-c-1) = value;
}
}
}
}
// Convert Fl_Image to CFloatImage.
bool convertImage(const Fl_Image *image, CByteImage &convertedImage) {
if (image == NULL) {
return false;
}
// Let's not handle indexed color images.
if (image->count() != 1) {
return false;
}
int w = image->w();
int h = image->h();
int d = image->d();
// Get the image data.
const char *const *data = image->data();
int index = 0;
for (int y=0; y<h; y++) {
for (int x=0; x<w; x++) {
if (d < 3) {
// If there are fewer than 3 channels, just use the
// first one for all colors.
convertedImage.Pixel(x,y,0) = data[0][index];
convertedImage.Pixel(x,y,1) = data[0][index];
convertedImage.Pixel(x,y,2) = data[0][index];
}
else if (d == 3) {
// Otherwise, use the first 3.
convertedImage.Pixel(x,h-y-1,2) = data[0][index];
convertedImage.Pixel(x,h-y-1,1) = data[0][index+1];
convertedImage.Pixel(x,h-y-1,0) = data[0][index+2];
}
index += d;
}
}
return true;
}