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 32using namespace std; 33 34const int DEFAULT_NR_CORNERS=500; 35const double DEFAULT_MAX_DISPARITY=0.2; 36const 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; 39const bool DEFAULT_QUARTER_RESOLUTION=false; 40const unsigned int DEFAULT_REFERENCE_UPDATE_PERIOD=3; 41const bool DEFAULT_DO_MOTION_SMOOTHING = false; 42const double DEFAULT_MOTION_SMOOTHING_GAIN = 0.75; 43const bool DEFAULT_LINEAR_POLISH = false; 44const int DEFAULT_MAX_ITERATIONS = 10; 45 46void 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 70void 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 83int 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 304void 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