contrib/oxl/osl/internals/droid.cxx
Go to the documentation of this file.
00001 // This is oxl/osl/internals/droid.cxx
00002 #include "droid.h"
00003 
00004 #include <vcl_cmath.h>   // pow()
00005 #include <vcl_cstring.h> // memset()
00006 
00007 #include <osl/osl_roi_window.h>
00008 
00009 //--------------------------------------------------------------------------------
00010 //
00011 // Computes gradient at each pixel.
00012 // Uses the convolution mask [ 2  1 0 -1 -2].
00013 //
00014 void droid::compute_gradx_grady (osl_roi_window                 *window_str,
00015                                  vil1_memory_image_of<vxl_byte>  *image_ptr,
00016                                  vil1_memory_image_of<int> *image_gradx_ptr,
00017                                  vil1_memory_image_of<int> *image_grady_ptr)
00018 
00019 {
00020   int row_start = window_str->row_start_index;
00021   int col_start = window_str->col_start_index;
00022   int row_end   = window_str->row_end_index;
00023   int col_end   = window_str->col_end_index;
00024 
00025   for (int row = row_start; row < row_end; row++) {
00026     for (int col = col_start; col < col_end; col++) {
00027 #if 1
00028       (*image_gradx_ptr)[row][col]
00029         = 2*((*image_ptr)[row][col+2]-(*image_ptr)[row][col-2])
00030         +((*image_ptr)[row][col+1]-(*image_ptr)[row][col-1]);
00031 
00032       (*image_grady_ptr) [row][col]
00033         = 2*((*image_ptr)[row+2][col]-(*image_ptr)[row-2][col])
00034         +((*image_ptr)[row+1][col]-(*image_ptr)[row-1][col]);
00035 #else
00036       (*image_gradx_ptr)[row][col] = (*image_ptr)[row][col+1] - (*image_ptr)[row][col-1];
00037       (*image_grady_ptr)[row][col] = (*image_ptr)[row+1][col] - (*image_ptr)[row-1][col];
00038 #endif
00039     }
00040   }
00041 }
00042 
00043 
00044 //-----------------------------------------------------------------------------
00045 //
00046 // Computes the (singular) second moment matrices of the gradient at each pixel.
00047 // Uses a local sum to estimate the gradient.
00048 // This means that the operator used to compute the gradient in the x-direction
00049 // is :
00050 //     2     1     0    -1    -2
00051 //     2     1     0    -1    -2
00052 //     2     1     0    -1    -2
00053 //     2     1     0    -1    -2
00054 //     2     1     0    -1    -2
00055 //
00056 void droid::compute_fxx_fxy_fyy (osl_roi_window              *window_str,
00057                                  vil1_memory_image_of<int>   *image_gradx_ptr,
00058                                  vil1_memory_image_of<int>   *image_grady_ptr,
00059                                  vil1_memory_image_of<float> *image_fxx_ptr,
00060                                  vil1_memory_image_of<float> *image_fxy_ptr,
00061                                  vil1_memory_image_of<float> *image_fyy_ptr)
00062 {
00063   float gradx,grady;
00064 
00065   int row_start = window_str->row_start_index;
00066   int col_start = window_str->col_start_index;
00067   int row_end   = window_str->row_end_index;
00068   int col_end   = window_str->col_end_index;
00069 
00070   for (int row = row_start; row < row_end; row++) {
00071     for (int col = col_start; col < col_end; col++) {
00072 
00073       gradx = (float) ((*image_gradx_ptr) [row-2][col  ] +
00074                        (*image_gradx_ptr) [row-1][col  ] +
00075                        (*image_gradx_ptr) [row  ][col  ] +
00076                        (*image_gradx_ptr) [row+1][col  ] +
00077                        (*image_gradx_ptr) [row+2][col  ]);
00078 
00079       grady = (float) ((*image_grady_ptr) [row  ][col-2] +
00080                        (*image_grady_ptr) [row  ][col-1] +
00081                        (*image_grady_ptr) [row  ][col  ] +
00082                        (*image_grady_ptr) [row  ][col+1] +
00083                        (*image_grady_ptr) [row  ][col+2]);
00084 
00085       (*image_fxx_ptr) [row][col] = gradx * gradx;
00086       (*image_fxy_ptr) [row][col] = gradx * grady;
00087       (*image_fyy_ptr) [row][col] = grady * grady;
00088     }
00089   }
00090 }
00091 
00092 
00093 //-----------------------------------------------------------------------------
00094 //
00095 // Computes the cornerness for each pixel.
00096 // Returns the maximum overall cornerness.
00097 //
00098 float droid::compute_cornerness (osl_roi_window              *window_str,
00099                                  vil1_memory_image_of<float> *image_fxx_ptr,
00100                                  vil1_memory_image_of<float> *image_fxy_ptr,
00101                                  vil1_memory_image_of<float> *image_fyy_ptr,
00102                                  float scale,
00103                                  vil1_memory_image_of<float> *pixel_cornerness)
00104 {
00105   float corner_max = 0;
00106 
00107   for (int row = window_str->row_start_index; row < window_str->row_end_index; row++) {
00108     for (int col = window_str->col_start_index; col < window_str->col_end_index; col++) {
00109 
00110       // pixel cornerness = (fxx*fyy-fxy^2) - scale*(fxx+fyy)^2
00111 #if 0
00112       float determinant
00113         = (*image_fxx_ptr) [row][col] * (*image_fyy_ptr) [row][col]
00114         - (*image_fxy_ptr) [row][col] * (*image_fxy_ptr) [row][col];
00115       float trace
00116         = (*image_fxx_ptr) [row][col] + (*image_fyy_ptr) [row][col];
00117 #else
00118       float fxx = (*image_fxx_ptr) [row][col];
00119       float fxy = (*image_fxy_ptr) [row][col];
00120       float fyy = (*image_fyy_ptr) [row][col];
00121       float determinant = fxx*fyy - fxy*fxy;
00122       float trace = fxx + fyy;
00123 #endif
00124       (*pixel_cornerness) [row][col] = determinant - scale*trace*trace;
00125 
00126       // update max
00127       if ((*pixel_cornerness) [row][col] > corner_max)
00128         corner_max = (*pixel_cornerness) [row][col];
00129     }
00130   }
00131 
00132   return corner_max;
00133 }
00134 
00135 
00136 //-----------------------------------------------------------------------------
00137 //
00138 // marks those pixels whose cornerness exceed corner_min and
00139 // which are local cornerness maxima in 5x5 windows.
00140 // they are marked by setting the corresponding pixel in
00141 // image_corner_max_ptr to true.
00142 //
00143 int droid::find_corner_maxima (float corner_min,
00144                                osl_roi_window              *window_str,
00145                                vil1_memory_image_of<float> *pixel_cornerness,
00146                                vil1_memory_image_of<bool>  *image_corner_max_ptr)
00147 {
00148   // allow for the spread when setting the loop values - don't explicitly
00149   // update window to be smaller because this routine might be called multiple
00150   // times when trying to get required corner count.
00151   int row, col;
00152 
00153   // zero out the first and last two rows and columns of *image_corner_max_ptr :
00154 
00155   //
00156   row = window_str->row_start_index;
00157   for (col = window_str->col_start_index; col < window_str->col_end_index; col++)
00158     (*image_corner_max_ptr) [row][col] = false;
00159   row++;
00160   for (col = window_str->col_start_index; col < window_str->col_end_index; col++)
00161     (*image_corner_max_ptr) [row][col] = false;
00162 
00163   //
00164   row = window_str->row_end_index-1;
00165   for (col = window_str->col_start_index; col < window_str->col_end_index; col++)
00166     (*image_corner_max_ptr) [row][col] = false;
00167   row--;
00168   for (col = window_str->col_start_index; col < window_str->col_end_index; col++)
00169     (*image_corner_max_ptr) [row][col] = false;
00170 
00171   //
00172   col = window_str->col_start_index;
00173   for (row = window_str->row_start_index; row < window_str->row_end_index; row++)
00174     (*image_corner_max_ptr) [row][col] = false;
00175   col++;
00176   for (row = window_str->row_start_index; row < window_str->row_end_index; row++)
00177     (*image_corner_max_ptr) [row][col] = false;
00178 
00179   //
00180   col = window_str->col_end_index-1;
00181   for (row = window_str->row_start_index; row < window_str->row_end_index; row++)
00182     (*image_corner_max_ptr) [row][col] = false;
00183   col--;
00184   for (row = window_str->row_start_index; row < window_str->row_end_index; row++)
00185     (*image_corner_max_ptr) [row][col] = false;
00186 
00187   // we look for pixels which have cornerness above the threshold
00188   // and which are local maxima in a 5x5 pixel neighbourhood :
00189   //   .....
00190   //   .....
00191   //   ..x..
00192   //   .....
00193   //   .....
00194   int maxima_count = 0;
00195   for (row = window_str->row_start_index+2; row < window_str->row_end_index-2; row++) {
00196     for (col = window_str->col_start_index+2; col < window_str->col_end_index-2; col++) {
00197       // get cornerness at the central pixel :
00198       float pc=(*pixel_cornerness)[row][col];
00199 
00200       // if above threshold and a local maximum, then it counts :
00201       if ((pc > corner_min)
00202 
00203           && (pc >= (*pixel_cornerness) [row-2][col-2])
00204           && (pc >= (*pixel_cornerness) [row-2][col-1])
00205           && (pc >= (*pixel_cornerness) [row-2][col  ])
00206           && (pc >= (*pixel_cornerness) [row-2][col+1])
00207           && (pc >= (*pixel_cornerness) [row-2][col+2])
00208 
00209           && (pc >= (*pixel_cornerness) [row-1][col-2])
00210           && (pc >= (*pixel_cornerness) [row-1][col-1])
00211           && (pc >= (*pixel_cornerness) [row-1][col  ])
00212           && (pc >= (*pixel_cornerness) [row-1][col+1])
00213           && (pc >= (*pixel_cornerness) [row-1][col+2])
00214 
00215           && (pc >= (*pixel_cornerness) [row  ][col-2])
00216           && (pc >= (*pixel_cornerness) [row  ][col-1])
00217           /* --------------------------------------- */
00218           && (pc >  (*pixel_cornerness) [row  ][col+1])
00219           && (pc >  (*pixel_cornerness) [row  ][col+2])
00220 
00221           && (pc >  (*pixel_cornerness) [row+1][col-2])
00222           && (pc >  (*pixel_cornerness) [row+1][col-1])
00223           && (pc >  (*pixel_cornerness) [row+1][col  ])
00224           && (pc >  (*pixel_cornerness) [row+1][col+1])
00225           && (pc >  (*pixel_cornerness) [row+1][col+2])
00226 
00227           && (pc >  (*pixel_cornerness) [row+2][col-2])
00228           && (pc >  (*pixel_cornerness) [row+2][col-1])
00229           && (pc >  (*pixel_cornerness) [row+2][col  ])
00230           && (pc >  (*pixel_cornerness) [row+2][col+1])
00231           && (pc >  (*pixel_cornerness) [row+2][col+2]))
00232         {
00233           (*image_corner_max_ptr) [row][col] = true;
00234           maxima_count++;
00235         }
00236 
00237       else
00238         (*image_corner_max_ptr) [row][col] = false;
00239     }
00240   }
00241   return maxima_count;
00242 }
00243 
00244 
00245 //-----------------------------------------------------------------------------
00246 //
00247 // Change value of "corner_min" to get a more acceptable no of corners.
00248 //
00249 float droid::compute_corner_min (float /*corner_min*/,
00250                                  float corner_max,
00251                                  int corner_count_max,
00252                                  osl_roi_window              *window_str,
00253                                  vil1_memory_image_of<float> *pixel_cornerness,
00254                                  vil1_memory_image_of<bool>  *image_corner_max_ptr)
00255 {
00256 #define DR_BIN_COUNT 200
00257 
00258   float
00259     corner_4throot,
00260     corner_max_4throot;
00261 
00262   int
00263     bin_array [DR_BIN_COUNT],
00264     bin_index,
00265     corner_count;
00266 
00267   vcl_memset (bin_array, 0, sizeof (bin_array));
00268   corner_max_4throot = (float)vcl_pow ((double) corner_max, 0.25);
00269 
00270   for (int row = window_str->row_start_index; row < window_str->row_end_index; row++) {
00271     for (int col = window_str->col_start_index; col < window_str->col_end_index; col++) {
00272       if ((*image_corner_max_ptr) [row][col]) {
00273         corner_4throot = (float)vcl_pow ((double) (*pixel_cornerness) [row][col], 0.25);
00274         bin_index = (int) ((DR_BIN_COUNT-1) * corner_4throot / corner_max_4throot);
00275         bin_array [bin_index]++;
00276       }
00277     }
00278   }
00279 
00280   corner_count = 0;
00281   bin_index = DR_BIN_COUNT-1;
00282   while ((corner_count < corner_count_max) && (bin_index > 0)) {
00283     corner_count += bin_array [bin_index];
00284     bin_index--;
00285   }
00286 
00287   // increment by 2 : one to return to the threshold index, and a further one to
00288   // drop corner count below the threshold.
00289 
00290   bin_index += 2;
00291 
00292   return (float)vcl_pow ((double) bin_index / (double) (DR_BIN_COUNT-1) * corner_max_4throot, 4.0);
00293 
00294 #undef DR_BIN_COUNT
00295 }
00296 
00297 
00298 //-----------------------------------------------------------------------------
00299 
00300 //
00301 // Compute the subpixel location of and value at cornerness maxima.
00302 // Uses a quadratic fit.
00303 //
00304 bool droid::compute_subpixel_max (vil1_memory_image_of<float> *pixel_cornerness,
00305                                   int row, int col,
00306                                   double &x, double &y,
00307                                   bool pab_emulate)
00308 {
00309   // defines to make the code shorter and hence easier to read :
00310 #define DR_P11 (*pixel_cornerness) [row-1][col-1]
00311 #define DR_P12 (*pixel_cornerness) [row-1][col  ]
00312 #define DR_P13 (*pixel_cornerness) [row-1][col+1]
00313 #define DR_P21 (*pixel_cornerness) [row  ][col-1]
00314 #define DR_P22 (*pixel_cornerness) [row  ][col  ]
00315 #define DR_P23 (*pixel_cornerness) [row  ][col+1]
00316 #define DR_P31 (*pixel_cornerness) [row+1][col-1]
00317 #define DR_P32 (*pixel_cornerness) [row+1][col  ]
00318 #define DR_P33 (*pixel_cornerness) [row+1][col+1]
00319 
00320   // Create weighting coefficients for the quadratic fit. They are obtained by
00321   // applying the following masks to the 3x3 window centered on pixel (row,col) :
00322   float b,c,d,e,f;
00323 
00324   if (pab_emulate) { // old pab masks
00325     // 1/8 * [ -1  0 +1 ]
00326     //       [ -2  0 +2 ]
00327     //       [ -1  0 +1 ]
00328     b=0.125f*(-DR_P11 -2*DR_P21 -  DR_P31 +  DR_P13 +2*DR_P23 +  DR_P33);
00329 
00330     // 1/8 * [ -1 -2 -1 ]
00331     //       [  0  0  0 ]
00332     //       [ +1 +2 +1 ]
00333     c=0.125f*(-DR_P11 +  DR_P31 -2*DR_P12 +2*DR_P32 -  DR_P13 +  DR_P33);
00334 
00335     // 1/4 * [ +1 -2 +1 ]
00336     //       [ +2 -4 +2 ]
00337     //       [ +1 -2 +1 ]
00338     d=0.25f*(  DR_P11 +2*DR_P21 +  DR_P31 -2*DR_P12 -4*DR_P22 -2*DR_P32 +DR_P13 +2*DR_P23+DR_P33);
00339 
00340     // 1/4 * [ +1  0 -1 ]
00341     //       [  0  0  0 ]
00342     //       [ -1  0 +1 ]
00343     e=0.25f*(  DR_P11 -  DR_P31 -  DR_P13 +  DR_P33);
00344 
00345     // 1/4 * [ +1 +2 +1 ]
00346     //       [ -2 -4 -2 ]
00347     //       [ +1 +2 +1 ]
00348     f=0.25f*(  DR_P11 -2*DR_P21 +  DR_P31 +2*DR_P12 -4*DR_P22 +2*DR_P32 +DR_P13 -2*DR_P23+DR_P33);
00349   }
00350   else { // new fsm masks
00351     // 1/9 * [ -1 +2 -1 ]
00352     //       [ +2 +5 +2 ]
00353     //       [ -1 +2 -1 ]
00354     //a=....;
00355 
00356     // 1/6 * [ -1  0 +1 ]
00357     //       [ -1  0 +1 ]
00358     //       [ -1  0 +1 ]
00359     b=(-DR_P11 +  DR_P13 -  DR_P21 +  DR_P23 -  DR_P31 +  DR_P33)/6.0f;
00360 
00361     // 1/6 * [ -1 -1 -1 ]
00362     //       [  0  0  0 ]
00363     //       [ +1 +1 +1 ]
00364     c=(-DR_P11 -  DR_P12 -  DR_P13 +  DR_P31 +  DR_P32 +  DR_P33)/6.0f;
00365 
00366     // 1/3 * [ +1 -2 +1 ]
00367     //       [ +1 -2 +1 ]
00368     //       [ +1 -2 +1 ]
00369     d=(  DR_P11 -2*DR_P12 +  DR_P13 +  DR_P21 -2*DR_P22 +  DR_P23 +DR_P31 -2*DR_P32+DR_P33)/3.0f;
00370 
00371     // 1/4 * [ +1  0 -1 ]
00372     //       [  0  0  0 ]
00373     //       [ -1  0 +1 ]
00374     e=(  DR_P11 -  DR_P31 -  DR_P13 +  DR_P33)/4.0f;
00375 
00376     // 1/3 * [ +1 +1 +1 ]
00377     //       [ -2 -2 -2 ]
00378     //       [ +1 +1 +1 ]
00379     f=(  DR_P11 +  DR_P12 +  DR_P13 -2*DR_P21 -2*DR_P22 -2*DR_P23 +DR_P31 +  DR_P32+DR_P33)/3.0f;
00380   }
00381 
00382   //
00383   // The next bit is to find the extremum of the fitted surface by setting its
00384   // partial derivatives to zero. We need to solve the following linear system :
00385   //
00386   //  [ d e ] [ off_x ] + [ b ] = [ 0 ]      (dS/dx = 0)
00387   //  [ e f ] [ off_y ]   [ c ]   [ 0 ]      (dS/dy = 0)
00388   //
00389   // This implies that the fitted surface is
00390   // S(x,y) = a + b x + c y + 1/2 d x^2 + e x y + 1/2 f y^2
00391   // , where we don't need to know the value of a.
00392   //
00393   float det = d*f - e*e;
00394   if ((pab_emulate && (det != 0)) ||
00395       (!pab_emulate && (det > 0))) {
00396     float off_x = (c*e - b*f) / det;
00397     float off_y = (b*e - c*d) / det;
00398 
00399     // more than one pixel away
00400     if (vcl_fabs (off_x) > 1.0 || vcl_fabs (off_y) > 1.0)
00401       return false;
00402     else {
00403       x = col+off_x;
00404       y = row+off_y;
00405       return true;
00406     }
00407   }
00408   // it's a saddle surface, but the corner may be still be good :
00409   else if (!pab_emulate && det<0) {
00410     x = col;
00411     y = row;
00412     return true;
00413   }
00414   // we can\'t solve a singular system :(
00415   else
00416     return false;
00417 
00418 #undef DR_P11
00419 #undef DR_P12
00420 #undef DR_P13
00421 #undef DR_P21
00422 #undef DR_P22
00423 #undef DR_P23
00424 #undef DR_P31
00425 #undef DR_P32
00426 #undef DR_P33
00427 }
00428 
00429 //-----------------------------------------------------------------------------
00430 
00431 //
00432 // window is (2*winsize+1) by (2*winsize+1)
00433 //
00434 int droid::find_local_maxima(float min,int winsize,
00435                              int x1,int y1,
00436                              int x2,int y2,
00437                              vil1_memory_image_of<float>  *bitmap,
00438                              vil1_memory_image_of<bool>  *max_p)
00439 {
00440   //
00441   for (int i=x1;i<x2;i++)
00442     for (int j=y1;j<y2;j++)
00443       (*max_p)[i][j] = (*bitmap)[i][j]>=min;
00444 
00445   //
00446   // k is the step size.
00447   //
00448   for (int k=1;k<=winsize;k++) {
00449     // horizontal scans :
00450     for (int i=x1;i<x2;i++)
00451       for (int j=y1;j<y2-k;j++)
00452         if ((*bitmap)[i][j] < (*bitmap)[i][j+k])
00453           (*max_p)[i][j  ]=false;
00454         else
00455           (*max_p)[i][j+k]=false;
00456 
00457     // vertical scan :
00458     for (int i=x1;i<x2-k;i++)
00459       for (int j=y1;j<y2;j++)
00460         if ((*bitmap)[i][j] < (*bitmap)[i+k][j])
00461           (*max_p)[i  ][j]=false;
00462         else
00463           (*max_p)[i+k][j]=false;
00464   }
00465 
00466   int count=0;
00467   //
00468   // now do the more expensive test :
00469   //
00470   for (int i=x1+winsize;i<x2-winsize;i++) {
00471     for (int j=y1+winsize;j<y2-winsize;j++) {
00472       if (!(*max_p)[i][j])
00473         continue;
00474 
00475       for (int r=1;r<=winsize;r++) {
00476         for (int s=1;s<=winsize;s++) {
00477           if ((*bitmap)[i][j] < (*bitmap)[i+r][j+s] ||
00478               (*bitmap)[i][j] < (*bitmap)[i-r][j+s] ||
00479               (*bitmap)[i][j] < (*bitmap)[i+r][j-s] ||
00480               (*bitmap)[i][j] < (*bitmap)[i-r][j-s]) {
00481             (*max_p)[i][j]=false;
00482             goto skip;
00483           }
00484         }
00485       }
00486       if ((*max_p)[i][j])
00487         count ++;
00488     skip: {;}
00489     }
00490   }
00491   return count;
00492 }