contrib/oxl/osl/osl_harris.cxx
Go to the documentation of this file.
00001 // This is oxl/osl/osl_harris.cxx
00002 #include "osl_harris.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cmath.h>
00007 #include <vcl_cassert.h>
00008 #include <vcl_iostream.h>
00009 #include <vcl_fstream.h>
00010 #include <vcl_vector.h>
00011 #include <vcl_algorithm.h>
00012 
00013 #include <vil1/vil1_image_as.h>
00014 #include <vil1/vil1_copy.h>
00015 #include <vil1/vil1_memory_image_of.h>
00016 
00017 #include <osl/osl_roi_window.h>
00018 #include <osl/osl_convolve.h>
00019 #include <osl/internals/droid.h> //name
00020 
00021 //------------------------------------------------------------
00022 
00023 void osl_harris::prepare_buffers(int w, int h)
00024 {
00025   // remember size.
00026   image_h = h;
00027   image_w = w;
00028 
00029   if (params_.verbose)
00030     vcl_cerr << "Doing harris on image region " << image_h << " by " << image_w << '\n'
00031              << "Maximum no of corners                     = " << params_.corner_count_max << '\n'
00032              << "Gaussian sigma                            = " << params_.gauss_sigma << '\n'
00033              << "Expected ratio lowest/max corner strength = " << params_.relative_minimum << '\n'
00034              << "Auto-correlation scale factor             = " << params_.scale_factor << '\n'
00035              << "Computing cornerness operator response....\n" << vcl_flush;
00036 
00037   // response images (no realloc performed unless size actually changes).
00038   image_buf           .resize(image_w, image_h);
00039   image_gradx_buf     .resize(image_w, image_h);
00040   image_grady_buf     .resize(image_w, image_h);
00041   image_fxx_buf       .resize(image_w, image_h);
00042   image_fxy_buf       .resize(image_w, image_h);
00043   image_fyy_buf       .resize(image_w, image_h);
00044   image_cornerness_buf.resize(image_w, image_h);
00045   image_cornermax_buf .resize(image_w, image_h);
00046 
00047   // set up window
00048   window_str.row_start_index = 0;
00049   window_str.col_start_index = 0;
00050   window_str.row_end_index = image_h-1;
00051   window_str.col_end_index = image_w-1;
00052 }
00053 
00054 void osl_harris::compute_gradients(vil1_image const &image)
00055 {
00056   // copy input image to byte buffer
00057   vil1_image_as_byte(image).get_section(image_buf.get_buffer(), 0, 0, image_w, image_h);
00058 
00059   // compute gradients
00060   if (params_.verbose)
00061     vcl_cerr << " gradient\n" << vcl_flush;
00062 
00063   // trim the window
00064   window_str.row_start_index += 2;
00065   window_str.col_start_index += 2;
00066   window_str.row_end_index   -= 2;
00067   window_str.col_end_index   -= 2;
00068   droid::compute_gradx_grady (&window_str,
00069                               &image_buf,
00070                               &image_gradx_buf,
00071                               &image_grady_buf);
00072 }
00073 
00074 void osl_harris::compute_2nd_moments()
00075 {
00076   // compute 2nd moment matrices
00077   if (params_.verbose)
00078     vcl_cerr << " fxx,fxy,fyy" << vcl_flush;
00079   window_str.row_start_index += 2;
00080   window_str.col_start_index += 2;
00081   window_str.row_end_index   -= 2;
00082   window_str.col_end_index   -= 2;
00083   droid::compute_fxx_fxy_fyy (&window_str,
00084                               &image_gradx_buf,
00085                               &image_grady_buf,
00086                               &image_fxx_buf,
00087                               &image_fxy_buf,
00088                               &image_fyy_buf);
00089 
00090   // create smoothing kernel
00091   osl_1d_half_kernel<double> gauss_mask;
00092   osl_create_gaussian (double(params_.gauss_sigma), &gauss_mask);
00093 
00094   // smoothe the 2nd moment matrix maps
00095   if (params_.verbose)
00096     vcl_cerr << " convolution" << vcl_flush;
00097   { // we use the cornerness map as a temporary scratch area.
00098     vil1_memory_image_of<float> *tmp = &image_cornerness_buf;
00099     osl_convolve(&window_str, &gauss_mask, &image_fxx_buf, tmp);
00100     osl_convolve(&window_str, &gauss_mask, &image_fxy_buf, tmp);
00101     osl_convolve(&window_str, &gauss_mask, &image_fyy_buf, tmp);
00102   }
00103 
00104   // trim the window :
00105   window_str.row_start_index += (gauss_mask.count-1);
00106   window_str.row_end_index   -= (gauss_mask.count-1);
00107   window_str.col_start_index += (gauss_mask.count-1);
00108   window_str.col_end_index   -= (gauss_mask.count-1);
00109 }
00110 
00111 void osl_harris::compute_cornerness()
00112 {
00113   // compute cornerness map
00114   if (params_.verbose)
00115     vcl_cerr << " cornerness" << vcl_flush;
00116   image_cornerness_buf.fill(0);
00117   corner_max = droid::compute_cornerness (&window_str,
00118                                           &image_fxx_buf,
00119                                           &image_fxy_buf,
00120                                           &image_fyy_buf,
00121                                           params_.scale_factor,
00122                                           &image_cornerness_buf);
00123   //
00124   if (params_.verbose)
00125     vcl_cerr << "------\n  done\n" << vcl_flush;
00126 }
00127 
00128 void osl_harris::compute_corners()
00129 {
00130   // do the relevant harris flavours :
00131   double corner_min;
00132   if (params_.adaptive)
00133   {
00134     corner_min = 0.0;
00135     do_adaptive();
00136   }
00137   else
00138   {
00139     corner_min = params_.relative_minimum * corner_max;
00140     do_non_adaptive(&corner_min);
00141   }
00142 
00143 
00144   // store the corners found.
00145   cc.clear();
00146   for (int row = window_str.row_start_index; row < window_str.row_end_index; row++)
00147     for (int col = window_str.col_start_index; col < window_str.col_end_index; col++)
00148       if (image_cornermax_buf[row][col] && image_cornerness_buf[row][col] > corner_min)
00149       {
00150         double x, y;
00151         if (droid::compute_subpixel_max (&image_cornerness_buf, row, col, x,y, params_.pab_emulate))
00152           cc.push_back(vcl_pair<float, float>(float(params_.col_start_index+x),
00153                                               float(params_.row_start_index+y)));
00154       }
00155   vcl_cerr << "osl_harris: Final corner count " << cc.size() << vcl_endl;
00156 }
00157 
00158 //--------------------------------------------------------------------------------
00159 
00160 //: internal
00161 void osl_harris::do_non_adaptive(double *corner_min)
00162 {
00163   int maxima_count = droid::find_corner_maxima (float(*corner_min),
00164                                                 &window_str,
00165                                                 &image_cornerness_buf,
00166                                                 &image_cornermax_buf);
00167 
00168   // iterate if not enough corners.
00169 
00170   if (params_.verbose)
00171     vcl_cerr << "Found " << maxima_count << " corners\n";
00172 
00173   if (maxima_count < (float) params_.corner_count_max * 0.9)
00174     for (int i=0 ; i<10 && maxima_count < (float) params_.corner_count_max * 0.9; i++)
00175     {
00176       params_.relative_minimum *= 0.5f;
00177       *corner_min = params_.relative_minimum * corner_max;
00178       if (params_.verbose)
00179         vcl_cerr << "Found " << maxima_count
00180                  << "... iterating with relmin = " << params_.relative_minimum
00181                  << vcl_endl;
00182       maxima_count = droid::find_corner_maxima (float(*corner_min),
00183                                                 &window_str,
00184                                                 &image_cornerness_buf,
00185                                                 &image_cornermax_buf);
00186     }
00187 
00188   // too many corners - reset parameters to get max number.
00189 
00190   if (maxima_count > params_.corner_count_max)
00191   {
00192     *corner_min = droid::compute_corner_min (float(*corner_min),
00193                                              corner_max,
00194                                              params_.corner_count_max,
00195                                              &window_str,
00196                                              &image_cornerness_buf,
00197                                              &image_cornermax_buf);
00198 
00199     params_.relative_minimum = float(*corner_min / corner_max);
00200     if (params_.verbose)
00201       vcl_cerr << "osl_harris: Too many: " << maxima_count
00202                << "... iterating with relmin = " << params_.relative_minimum
00203                << vcl_endl;
00204   }
00205 }
00206 
00207 //--------------------------------------------------------------------------------
00208 
00209 //: internal
00210 void osl_harris::do_adaptive()
00211 {
00212   if (params_.verbose)
00213     vcl_cerr << "No. of corners before density thresholding= " << params_.corner_count_max << vcl_endl;
00214 
00215   double corner_min = params_.relative_minimum * corner_max;
00216   int maxima_count = droid::find_corner_maxima (float(corner_min),
00217                                                 &window_str,
00218                                                 &image_cornerness_buf,
00219                                                 &image_cornermax_buf);
00220   vcl_cerr << "harris: " << maxima_count << " corners with response above " << corner_min << vcl_endl;
00221 
00222   // Store all corners in an array.
00223   int TILE_WIDTH = params_.adaptive_window_size; // 32
00224   int row_min = window_str.row_start_index;
00225   int col_min = window_str.col_start_index;
00226   int row_max = window_str.row_end_index;
00227   int col_max = window_str.col_end_index;
00228 
00229   // number of tiles to use in the x and y directions.
00230   int n_tiles_x = (int) vcl_ceil(double(col_max-col_min) / TILE_WIDTH);
00231   int n_tiles_y = (int) vcl_ceil(double(row_max-row_min) / TILE_WIDTH);
00232 
00233   double TILE_AREA = TILE_WIDTH*TILE_WIDTH;
00234 
00235   int IDEAL_NUM_PER_TILE = params_.corner_count_max / (n_tiles_x*n_tiles_y);
00236 
00237   if (params_.corner_count_max == 0)
00238     IDEAL_NUM_PER_TILE = params_.corner_count_low;
00239 
00240   vcl_cerr << "Tiles " << n_tiles_x << " x " << n_tiles_y
00241            << ", NUM_PER_TILE " << IDEAL_NUM_PER_TILE;
00242 
00243   vcl_vector<double> cornerness(maxima_count, 0.0);
00244 
00245   vil1_memory_image_of<bool> keep(image_cornermax_buf.width(), image_cornermax_buf.height());
00246   keep.fill(false);
00247 
00248   // Do two passes, overlapping tiles by 1/2
00249   for (int pass = 0; pass < 2; ++pass)
00250   {
00251     int win_offset = pass * TILE_WIDTH / 2;
00252     if (params_.verbose)
00253       vcl_cerr << vcl_endl << "pass " << pass;
00254     for (int tile_y = 0; tile_y < n_tiles_y; ++tile_y)
00255     {
00256       int window_row_start_index = tile_y * TILE_WIDTH + row_min + win_offset;
00257       int window_row_end_index = vcl_min(window_row_start_index+TILE_WIDTH, row_max);
00258 
00259       for (int tile_x = 0; tile_x < n_tiles_x; ++tile_x)
00260       {
00261         int window_col_start_index = tile_x * TILE_WIDTH + col_min + win_offset;
00262         int window_col_end_index = vcl_min(window_col_start_index+TILE_WIDTH, col_max);
00263 
00264         // get corner strengths in this tile :
00265         vil1_memory_image_of<bool>        &corner_present  = image_cornermax_buf;
00266         vil1_memory_image_of<float> const &corner_strength = image_cornerness_buf;
00267         int n = 0;
00268         for (int row = window_row_start_index; row < window_row_end_index; row++)
00269           for (int col = window_col_start_index; col < window_col_end_index; col++)
00270             if (corner_present[row][col])
00271               cornerness[n++] = corner_strength[row][col];
00272 
00273         //
00274         double THIS_TILE_AREA =
00275           (window_row_end_index-window_row_start_index) *
00276           (window_col_end_index-window_col_start_index);
00277 
00278         int NUM_PER_TILE = (int) ( IDEAL_NUM_PER_TILE * (THIS_TILE_AREA/TILE_AREA) );
00279 
00280         double thresh = 0; // Less than NUM on tile, take them all
00281         if (n > NUM_PER_TILE)
00282         {
00283           // Sort corners to get thresholds
00284           vcl_sort(cornerness.begin(), cornerness.begin()+n);
00285           thresh = cornerness[n-1-NUM_PER_TILE];
00286         }
00287 
00288         // Keep corners over thresh
00289         for (int row = window_row_start_index; row < window_row_end_index; row++)
00290           for (int col = window_col_start_index; col < window_col_end_index; col++)
00291             if (corner_present[row][col])
00292               if (corner_strength[row][col] >= thresh)
00293                 keep[row][col] = true;
00294       }
00295     }
00296   }
00297   vcl_cerr << vcl_endl;
00298 
00299   // Copy keep to present
00300   vil1_copy(keep,image_cornermax_buf);
00301 }
00302 
00303 //-----------------------------------------------------------------------------
00304 
00305 // ?? should we append, and not assign ??
00306 void osl_harris::get_corners(vcl_vector<vcl_pair<float, float> > &cor) const
00307 {
00308   cor = cc;
00309 }
00310 
00311 void osl_harris::get_corners(vcl_vector<float> &corx, vcl_vector<float> &cory) const
00312 {
00313   for (unsigned i=0; i<cc.size(); ++i)
00314   {
00315     corx.push_back(cc[i].first);
00316     cory.push_back(cc[i].second);
00317   }
00318 }
00319 
00320 //: convenience method
00321 void osl_harris::save_corners(vcl_ostream &f) const
00322 {
00323   for (unsigned i=0; i<cc.size(); ++i)
00324     f << cc[i].first << ' ' << cc[i].second << vcl_endl;
00325 }
00326 
00327 void osl_harris::save_corners(char const *filename) const
00328 {
00329   vcl_ofstream f(filename);
00330   assert(f.good());
00331   save_corners(f);
00332   f.close();
00333 }
00334 
00335 //-----------------------------------------------------------------------------