00001
00002 #include "osl_harris.h"
00003
00004
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>
00020
00021
00022
00023 void osl_harris::prepare_buffers(int w, int h)
00024 {
00025
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
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
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
00057 vil1_image_as_byte(image).get_section(image_buf.get_buffer(), 0, 0, image_w, image_h);
00058
00059
00060 if (params_.verbose)
00061 vcl_cerr << " gradient\n" << vcl_flush;
00062
00063
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
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
00091 osl_1d_half_kernel<double> gauss_mask;
00092 osl_create_gaussian (double(params_.gauss_sigma), &gauss_mask);
00093
00094
00095 if (params_.verbose)
00096 vcl_cerr << " convolution" << vcl_flush;
00097 {
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
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
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
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
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
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
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
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
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
00223 int TILE_WIDTH = params_.adaptive_window_size;
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
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
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
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;
00281 if (n > NUM_PER_TILE)
00282 {
00283
00284 vcl_sort(cornerness.begin(), cornerness.begin()+n);
00285 thresh = cornerness[n-1-NUM_PER_TILE];
00286 }
00287
00288
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
00300 vil1_copy(keep,image_cornermax_buf);
00301 }
00302
00303
00304
00305
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
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