1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // $Id: dbregtest.cpp,v 1.24 2011/06/17 14:04:33 mbansal Exp $
18 #include "stdafx.h"
19 #include "PgmImage.h"
20 #include "../dbreg/dbreg.h"
21 #include "../dbreg/dbstabsmooth.h"
22 #include <db_utilities_camera.h>
23
24 #include <iostream>
25 #include <iomanip>
26
27 #if PROFILE
28 #include <sys/time.h>
29 #endif
30
31
32 using namespace std;
33
34 const int DEFAULT_NR_CORNERS=500;
35 const double DEFAULT_MAX_DISPARITY=0.2;
36 const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_AFFINE;
37 //const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_R_T;
38 //const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_TRANSLATION;
39 const bool DEFAULT_QUARTER_RESOLUTION=false;
40 const unsigned int DEFAULT_REFERENCE_UPDATE_PERIOD=3;
41 const bool DEFAULT_DO_MOTION_SMOOTHING = false;
42 const double DEFAULT_MOTION_SMOOTHING_GAIN = 0.75;
43 const bool DEFAULT_LINEAR_POLISH = false;
44 const int DEFAULT_MAX_ITERATIONS = 10;
45
usage(string name)46 void usage(string name) {
47
48 const char *helpmsg[] = {
49 "Function: point-based frame to reference registration.",
50 " -m [rt,a,p] : motion model, rt = rotation+translation, a = affine (default = affine).",
51 " -c <int> : number of corners (default 1000).",
52 " -d <double>: search disparity as portion of image size (default 0.1).",
53 " -q : quarter the image resolution (i.e. half of each dimension) (default on)",
54 " -r <int> : the period (in nr of frames) for reference frame updates (default = 5)",
55 " -s <0/1> : motion smoothing (1 activates motion smoothing, 0 turns it off - default value = 1)",
56 " -g <double>: motion smoothing gain, only used if smoothing is on (default value =0.75)",
57 NULL
58 };
59
60 cerr << "Usage: " << name << " [options] image_list.txt" << endl;
61
62 const char **p = helpmsg;
63
64 while (*p)
65 {
66 cerr << *p++ << endl;
67 }
68 }
69
70 void parse_cmd_line(stringstream& cmdline,
71 const int argc,
72 const string& progname,
73 string& image_list_file_name,
74 int& nr_corners,
75 double& max_disparity,
76 int& motion_model_type,
77 bool& quarter_resolution,
78 unsigned int& reference_update_period,
79 bool& do_motion_smoothing,
80 double& motion_smoothing_gain
81 );
82
main(int argc,char * argv[])83 int main(int argc, char* argv[])
84 {
85 int nr_corners = DEFAULT_NR_CORNERS;
86 double max_disparity = DEFAULT_MAX_DISPARITY;
87 int motion_model_type = DEFAULT_MOTION_MODEL;
88 bool quarter_resolution = DEFAULT_QUARTER_RESOLUTION;
89
90 unsigned int reference_update_period = DEFAULT_REFERENCE_UPDATE_PERIOD;
91
92 bool do_motion_smoothing = DEFAULT_DO_MOTION_SMOOTHING;
93 double motion_smoothing_gain = DEFAULT_MOTION_SMOOTHING_GAIN;
94 const bool DEFAULT_USE_SMALLER_MATCHING_WINDOW = true;
95
96 int default_nr_samples = DB_DEFAULT_NR_SAMPLES/5;
97
98 bool use_smaller_matching_window = DEFAULT_USE_SMALLER_MATCHING_WINDOW;
99
100
101 bool linear_polish = DEFAULT_LINEAR_POLISH;
102
103 if (argc < 2) {
104 usage(argv[0]);
105 exit(1);
106 }
107
108 stringstream cmdline;
109 string progname(argv[0]);
110 string image_list_file_name;
111
112 #if PROFILE
113 timeval ts1, ts2, ts3, ts4;
114 #endif
115
116 // put the options and image list file name into the cmdline stringstream
117 for (int c = 1; c < argc; c++)
118 {
119 cmdline << argv[c] << " ";
120 }
121
122 parse_cmd_line(cmdline, argc, progname, image_list_file_name, nr_corners, max_disparity, motion_model_type,quarter_resolution,reference_update_period,do_motion_smoothing,motion_smoothing_gain);
123
124 ifstream in(image_list_file_name.c_str(),ios::in);
125
126 if ( !in.is_open() )
127 {
128 cerr << "Could not open file " << image_list_file_name << ". Exiting" << endl;
129
130 return false;
131 }
132
133 // feature-based image registration class:
134 db_FrameToReferenceRegistration reg;
135 // db_StabilizationSmoother stab_smoother;
136
137 // input file name:
138 string file_name;
139
140 // look-up tables for image warping:
141 float ** lut_x = NULL, **lut_y = NULL;
142
143 // if the images are color, the input is saved in color_ref:
144 PgmImage color_ref(0,0);
145
146 // image width, height:
147 int w,h;
148
149 int frame_number = 0;
150
151 while ( !in.eof() )
152 {
153 getline(in,file_name);
154
155 PgmImage ref(file_name);
156
157 if ( ref.GetDataPointer() == NULL )
158 {
159 cerr << "Could not open image" << file_name << ". Exiting." << endl;
160 return -1;
161 }
162
163 cout << ref << endl;
164
165 // color format:
166 int format = ref.GetFormat();
167
168 // is the input image color?:
169 bool color = format == PgmImage::PGM_BINARY_PIXMAP;
170
171 w = ref.GetWidth();
172 h = ref.GetHeight();
173
174 if ( !reg.Initialized() )
175 {
176 reg.Init(w,h,motion_model_type,DEFAULT_MAX_ITERATIONS,linear_polish,quarter_resolution,DB_POINT_STANDARDDEV,reference_update_period,do_motion_smoothing,motion_smoothing_gain,default_nr_samples,DB_DEFAULT_CHUNK_SIZE,nr_corners,max_disparity,use_smaller_matching_window);
177 lut_x = db_AllocImage_f(w,h);
178 lut_y = db_AllocImage_f(w,h);
179
180 }
181
182 if ( color )
183 {
184 // save the color image:
185 color_ref = ref;
186 }
187
188 // make a grayscale image:
189 ref.ConvertToGray();
190
191 // compute the homography:
192 double H[9],Hinv[9];
193 db_Identity3x3(Hinv);
194 db_Identity3x3(H);
195
196 bool force_reference = false;
197
198 #if PROFILE
199 gettimeofday(&ts1, NULL);
200 #endif
201
202 reg.AddFrame(ref.GetRowPointers(),H,false,false);
203 cout << reg.profile_string << std::endl;
204
205 #if PROFILE
206 gettimeofday(&ts2, NULL);
207
208 double elapsedTime = (ts2.tv_sec - ts1.tv_sec)*1000.0; // sec to ms
209 elapsedTime += (ts2.tv_usec - ts1.tv_usec)/1000.0; // us to ms
210 cout <<"\nelapsedTime for Reg<< "<<elapsedTime<<" ms >>>>>>>>>>>>>\n";
211 #endif
212
213 if (frame_number == 0)
214 {
215 reg.UpdateReference(ref.GetRowPointers());
216 }
217
218
219 //std::vector<int> &inlier_indices = reg.GetInliers();
220 int *inlier_indices = reg.GetInliers();
221 int num_inlier_indices = reg.GetNrInliers();
222 printf("[%d] #Inliers = %d\n",frame_number,num_inlier_indices);
223
224 reg.Get_H_dref_to_ins(H);
225
226 db_GenerateHomographyLut(lut_x,lut_y,w,h,H);
227
228 // create a new image and warp:
229 PgmImage warped(w,h,format);
230
231 #if PROFILE
232 gettimeofday(&ts3, NULL);
233 #endif
234
235 if ( color )
236 db_WarpImageLutBilinear_rgb(color_ref.GetRowPointers(),warped.GetRowPointers(),w,h,lut_x,lut_y);
237 else
238 db_WarpImageLut_u(ref.GetRowPointers(),warped.GetRowPointers(),w,h,lut_x,lut_y,DB_WARP_FAST);
239
240 #if PROFILE
241 gettimeofday(&ts4, NULL);
242 elapsedTime = (ts4.tv_sec - ts3.tv_sec)*1000.0; // sec to ms
243 elapsedTime += (ts4.tv_usec - ts3.tv_usec)/1000.0; // us to ms
244 cout <<"\nelapsedTime for Warp <<"<<elapsedTime<<" ms >>>>>>>>>>>>>\n";
245 #endif
246
247 // write aligned image: name is aligned_<corresponding input file name>
248 stringstream s;
249 s << "aligned_" << file_name;
250 warped.WritePGM(s.str());
251
252 /*
253 // Get the reference and inspection corners to write to file
254 double *ref_corners = reg.GetRefCorners();
255 double *ins_corners = reg.GetInsCorners();
256
257 // get the image file name (without extension), so we
258 // can generate the corresponding filenames for matches
259 // and inliers
260 string file_name_root(file_name.substr(0,file_name.rfind(".")));
261
262 // write matches to file
263 s.str(string(""));
264 s << "Matches_" << file_name_root << ".txt";
265
266 ofstream match_file(s.str().c_str());
267
268 for (int i = 0; i < reg.GetNrMatches(); i++)
269 {
270 match_file << ref_corners[3*i] << " " << ref_corners[3*i+1] << " " << ins_corners[3*i] << " " << ins_corners[3*i+1] << endl;
271 }
272
273 match_file.close();
274
275 // write the inlier matches to file
276 s.str(string(""));
277 s << "InlierMatches_" << file_name_root << ".txt";
278
279 ofstream inlier_match_file(s.str().c_str());
280
281 for(int i=0; i<num_inlier_indices; i++)
282 {
283 int k = inlier_indices[i];
284 inlier_match_file << ref_corners[3*k] << " "
285 << ref_corners[3*k+1] << " "
286 << ins_corners[3*k] << " "
287 << ins_corners[3*k+1] << endl;
288 }
289 inlier_match_file.close();
290 */
291
292 frame_number++;
293 }
294
295 if ( reg.Initialized() )
296 {
297 db_FreeImage_f(lut_x,h);
298 db_FreeImage_f(lut_y,h);
299 }
300
301 return 0;
302 }
303
parse_cmd_line(stringstream & cmdline,const int argc,const string & progname,string & image_list_file_name,int & nr_corners,double & max_disparity,int & motion_model_type,bool & quarter_resolution,unsigned int & reference_update_period,bool & do_motion_smoothing,double & motion_smoothing_gain)304 void parse_cmd_line(stringstream& cmdline,
305 const int argc,
306 const string& progname,
307 string& image_list_file_name,
308 int& nr_corners,
309 double& max_disparity,
310 int& motion_model_type,
311 bool& quarter_resolution,
312 unsigned int& reference_update_period,
313 bool& do_motion_smoothing,
314 double& motion_smoothing_gain)
315 {
316 // for counting down the parsed arguments.
317 int c = argc;
318
319 // a holder
320 string token;
321
322 while (cmdline >> token)
323 {
324 --c;
325
326 int pos = token.find("-");
327
328 if (pos == 0)
329 {
330 switch (token[1])
331 {
332 case 'm':
333 --c; cmdline >> token;
334 if (token.compare("rt") == 0)
335 {
336 motion_model_type = DB_HOMOGRAPHY_TYPE_R_T;
337 }
338 else if (token.compare("a") == 0)
339 {
340 motion_model_type = DB_HOMOGRAPHY_TYPE_AFFINE;
341 }
342 else if (token.compare("p") == 0)
343 {
344 motion_model_type = DB_HOMOGRAPHY_TYPE_PROJECTIVE;
345 }
346 else
347 {
348 usage(progname);
349 exit(1);
350 }
351 break;
352 case 'c':
353 --c; cmdline >> nr_corners;
354 break;
355 case 'd':
356 --c; cmdline >> max_disparity;
357 break;
358 case 'q':
359 quarter_resolution = true;
360 break;
361 case 'r':
362 --c; cmdline >> reference_update_period;
363 break;
364 case 's':
365 --c; cmdline >> do_motion_smoothing;
366 break;
367 case 'g':
368 --c; cmdline >> motion_smoothing_gain;
369 break;
370 default:
371 cerr << progname << "illegal option " << token << endl;
372 case 'h':
373 usage(progname);
374 exit(1);
375 break;
376 }
377 }
378 else
379 {
380 if (c != 1)
381 {
382 usage(progname);
383 exit(1);
384 }
385 else
386 {
387 --c;
388 image_list_file_name = token;
389 }
390 }
391 }
392
393 if (c != 0)
394 {
395 usage(progname);
396 exit(1);
397 }
398 }
399
400