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