contrib/gel/vsrl/vsrl_image_correlation.cxx

Go to the documentation of this file.
00001 // This is gel/vsrl/vsrl_image_correlation.cxx
00002 #include "vsrl_image_correlation.h"
00003 
00004 #include <vcl_cmath.h> // for sqrt(double)
00005 #include <vcl_cstdlib.h>
00006 #include <vcl_cassert.h>
00007 #include <vil1/vil1_image.h>
00008 #include <vsrl/vsrl_window_accumulator.h>
00009 #include <vsrl/vsrl_parameters.h>
00010 
00011 // constructor
00012 
00013 vsrl_image_correlation::vsrl_image_correlation(const vil1_image &im1, const vil1_image &im2):
00014   buffer1_(im1),
00015   buffer2_(im2)
00016 {
00017   // initialize the window width and height
00018 
00019   window_width_=vsrl_parameters::instance()->correlation_window_width; // probably 20
00020   window_height_=vsrl_parameters::instance()->correlation_window_height; // probably 20
00021   correlation_range_=vsrl_parameters::instance()->correlation_range; // probably 10
00022 
00023   image_correlations_=0;
00024   mean_x_=0;
00025   mean_y_=0;
00026   std_x_=0;
00027   std_y_=0;
00028 }
00029 
00030 // destructor
00031 vsrl_image_correlation::~vsrl_image_correlation()
00032 {
00033   if (image_correlations_)
00034   {
00035     int i;
00036     for (i=0;i<correlation_range_*2+1;i++)
00037       delete image_correlations_[i];
00038     delete[] image_correlations_;
00039   }
00040   delete mean_x_;
00041   delete mean_y_;
00042   delete std_x_;
00043   delete std_y_;
00044 }
00045 
00046 // set the dimensions of the correlation window
00047 
00048 
00049 void vsrl_image_correlation::set_window_width(int width)
00050 {
00051   window_width_=width;
00052 }
00053 
00054 void vsrl_image_correlation::set_window_height(int height)
00055 {
00056   window_height_=height;
00057 }
00058 
00059 void vsrl_image_correlation::set_correlation_range(int range)
00060 {
00061   correlation_range_ = range;
00062 }
00063 
00064 
00065 int vsrl_image_correlation::get_correlation_range()
00066 {
00067   return correlation_range_;
00068 }
00069 
00070 
00071 // make sure that a point is in the range of the image
00072 
00073 bool vsrl_image_correlation::check_range(vil1_byte_buffer &buf, int x, int y)
00074 {
00075   return x>=0 && x<buf.width() && y>=0 && y<buf.height();
00076 }
00077 
00078 
00079 //***************************************************************************
00080 //** These routines will perform the image correlation in an efficient manner
00081 //***************************************************************************
00082 
00083 void vsrl_image_correlation::compute_local_stats(vnl_matrix<double> &im, vnl_matrix<double> &mean,
00084                                                  vnl_matrix<double> &std)
00085 {
00086   // mean = 1/N * sum X
00087   // var = 1/N * sum (X-mean)(X-mean) = 1/N Sum X*X - mean*mean
00088 
00089   // we want to compute the mean and standard deviation for the im
00090 
00091   // step one get the mean in an efficient manner
00092 
00093   vsrl_window_accumulator ac_mean;
00094 
00095   ac_mean.set_in_matrix(&im);
00096   ac_mean.set_out_matrix(&mean);
00097   ac_mean.set_window_width(this->window_width_);
00098   ac_mean.set_window_height(this->window_height_);
00099   ac_mean.execute();
00100 
00101   // now compute the square values;
00102 
00103   vnl_matrix<double> squares(im.rows(),im.cols());
00104 
00105   shift_multiply_matrix(0,im,im,squares);
00106 
00107   vsrl_window_accumulator ac_std;
00108 
00109   ac_std.set_in_matrix(&squares);
00110   ac_std.set_out_matrix(&std);
00111   ac_std.set_window_width(this->window_width_);
00112   ac_std.set_window_height(this->window_height_);
00113   ac_std.execute();
00114 
00115   for (unsigned int r=0;r<std.rows();r++)
00116     for (unsigned int c=0;c<std.cols();c++)
00117     {
00118       double xx=std(r,c);
00119       double m=mean(r,c);
00120       std(r,c) = vcl_sqrt(xx-m*m);
00121     }
00122 }
00123 
00124 void vsrl_image_correlation::shift_multiply_matrix(int offset, vnl_matrix<double> &X, vnl_matrix<double> &Y,
00125                                                         vnl_matrix<double> &XY)
00126 {
00127   assert(offset >= 0);
00128   assert((unsigned int)offset <= Y.cols());
00129 
00130   // we want to multiply X*(Y shifted by offset);
00131 
00132   XY.fill(0.0);
00133 
00134   // find the start and end columns
00135 
00136   int start_col = 0-offset;
00137   if (start_col<0)
00138     start_col=0;
00139 
00140   unsigned int end_col = Y.cols()-offset; // 1 more than last column
00141   if (end_col>X.cols())
00142     end_col=X.cols();
00143 
00144   for (unsigned int r=0;r<X.rows();r++)
00145     for (unsigned int c=start_col;c<end_col;c++)
00146       XY(r,c) = X(r,c) * Y(r,c+offset);
00147 }
00148 
00149 
00150 void  vsrl_image_correlation::compute_correlation(int x_offset,
00151                                                   vnl_matrix<double> &X,
00152                                                   vnl_matrix<double> &Y,
00153                                                   vnl_matrix<double> &mean_x,
00154                                                   vnl_matrix<double> &mean_y,
00155                                                   vnl_matrix<double> &std_x,
00156                                                   vnl_matrix<double> &std_y,
00157                                                   vnl_matrix<double> &corr_matrix)
00158 {
00159   // the idea is to compute the correlation between X and Y given mean_x and mean_y
00160   // cor = 1/N sum (xi - mean_x)*(yi -mean_y)/(std_x * std_y)
00161   // cor = 1/(stdx * stdy) * (1/N(sum xiyi) - mean_x * mean_y)
00162 
00163   assert(x_offset >= 0);
00164   assert((unsigned int)x_offset <= Y.cols());
00165 
00166   // step 1 compute the matrix XY;
00167 
00168   vnl_matrix<double> XY(X.rows(),X.cols());
00169 
00170   shift_multiply_matrix(x_offset,X,Y,XY);
00171 
00172   // step 2 compute the accumulation of XY ;
00173 
00174   vnl_matrix<double> ac_XY(X.rows(),X.cols());
00175 
00176   vsrl_window_accumulator win_ac;
00177 
00178   win_ac.set_in_matrix(&XY);
00179   win_ac.set_out_matrix(&ac_XY);
00180   win_ac.set_window_width(this->window_width_);
00181   win_ac.set_window_height(this->window_height_);
00182   win_ac.execute();
00183 
00184   // step 3 compute the corr_matrix
00185 
00186   corr_matrix.fill(0.0);
00187 
00188 
00189   // find the start and end columns
00190 
00191   int start_col = 0-x_offset;
00192   if (start_col <0)
00193     start_col=0;
00194 
00195   unsigned int end_col = Y.cols()-x_offset;
00196   if (end_col>X.cols())
00197     end_col=X.cols();
00198 
00199   for (unsigned int r=0;r<X.rows();r++)
00200     for (unsigned int c=start_col;c<end_col;c++)
00201     {
00202       double sx = std_x(r,c);
00203       double sy = std_y(r,c+x_offset);
00204 
00205       double mx = mean_x(r,c);
00206       double my = mean_y(r,c+x_offset);
00207 
00208       double xy = ac_XY(r,c);
00209 
00210       if (sx!=0.0 && sy!=0.0)
00211         corr_matrix(r,c) = (xy-mx*my)/(sx*sy);
00212     }
00213 }
00214 
00215 
00216 void vsrl_image_correlation::initial_calculations()
00217 {
00218   // we want to be able to compute all the possible correlations
00219   // between the two images;
00220 
00221   if (mean_x_)
00222     return; // the initial calculations have already been done
00223 
00224 
00225   // step 1 make a vnl_matrix from the two buffers
00226 
00227   vnl_matrix<double> X(buffer1_.height(),buffer1_.width());
00228 
00229   for (unsigned int r=0;r<X.rows();r++)
00230     for (unsigned int c=0;c<X.cols();c++)
00231       X(r,c)= buffer1_(c,r);
00232 
00233   vnl_matrix<double> Y(buffer2_.height(),buffer2_.width());
00234 
00235 
00236   for (unsigned int r=0;r<Y.rows();r++)
00237     for (unsigned int c=0;c<Y.cols();c++)
00238       Y(r,c)= buffer2_(c,r);
00239 
00240   // Now compute the mean and std for X and Y
00241 
00242 
00243   mean_x_ = new vnl_matrix<double>(X.rows(),X.cols());
00244   mean_y_ = new vnl_matrix<double>(Y.rows(),Y.cols());
00245   std_x_ = new vnl_matrix<double>(X.rows(),X.cols());
00246   std_y_ = new vnl_matrix<double>(Y.rows(),Y.cols());
00247 
00248 
00249   compute_local_stats(X,*mean_x_,*std_x_);
00250   compute_local_stats(Y,*mean_y_,*std_y_);
00251 
00252 
00253   // now allocate memory for the various corelation matrix values
00254 
00255   image_correlations_ = (vnl_matrix<double>**)(vcl_malloc(sizeof(*image_correlations_) * (correlation_range_*2 +1)));
00256 
00257   // now compute each correlation
00258 
00259   for (int i=0;i<correlation_range_*2 + 1;i++)
00260   {
00261     vnl_matrix<double> *corr = new vnl_matrix<double>(X.rows(),X.cols());
00262     image_correlations_[i]=corr;
00263 
00264     int x_offset = i-correlation_range_;
00265 
00266     if (x_offset >= 0)
00267       compute_correlation(x_offset,X,Y,*mean_x_,*mean_y_,*std_x_,*std_y_,*corr);
00268   }
00269 }
00270 
00271 // get local image stats
00272 double vsrl_image_correlation::get_mean_1(int x, int y)
00273 {
00274   return (*mean_x_)(y,x);
00275 }
00276 
00277 double vsrl_image_correlation::get_mean_2(int x, int y)
00278 {
00279   return (*mean_y_)(y,x);
00280 }
00281 
00282 double vsrl_image_correlation::get_std_1(int x, int y)
00283 {
00284   return (*std_x_)(y,x);
00285 }
00286 
00287 double vsrl_image_correlation::get_std_2(int x, int y)
00288 {
00289   return (*std_y_)(y,x);
00290 }
00291 
00292 double vsrl_image_correlation::get_image_value1(int x, int y)
00293 {
00294   return buffer1_(x,y);
00295 }
00296 
00297 
00298 double vsrl_image_correlation::get_image_value2(int x, int y)
00299 {
00300   return buffer2_(x,y);
00301 }
00302 
00303 double vsrl_image_correlation::get_correlation(int x1, int y1, int delta_x)
00304 {
00305   if (!image_correlations_)
00306     return 0.0;
00307 
00308   int index = delta_x + correlation_range_;
00309 
00310   if (index < 0 || index >=(2*correlation_range_ +1))
00311     return 0.0;
00312 
00313   return (*(image_correlations_[index]))(y1,x1);
00314 }
00315 
00316 
00317 int vsrl_image_correlation::get_image1_width()
00318 {
00319   return buffer1_.width();
00320 }
00321 
00322 int vsrl_image_correlation::get_image2_width()
00323 {
00324   return buffer2_.width();
00325 }
00326 
00327 int vsrl_image_correlation::get_image1_height()
00328 {
00329   return buffer1_.height();
00330 }
00331 
00332 int vsrl_image_correlation::get_image2_height()
00333 {
00334   return buffer2_.height();
00335 }
00336 
00337 
00338 // **************************************************
00339 // *** These routines will perform the local corelation in a slow but correct manner
00340 // **************************************************
00341 
00342 
00343 // compute the local stats of a window
00344 // slow
00345 void vsrl_image_correlation::compute_local_stats(vil1_byte_buffer &buf, int x, int y, double &mean, double &std)
00346 {
00347   // find the dimensions of the window;
00348 
00349   int low_x= x- window_width_/2;
00350   int hi_x= x+ window_width_/2;
00351 
00352   if (low_x <0)
00353     low_x=0;
00354 
00355   if (hi_x>buf.width()-1)
00356     hi_x=buf.width()-1;
00357 
00358   int low_y= y- window_height_/2;
00359   int hi_y= y+ window_height_/2;
00360 
00361   if (low_y <0)
00362     low_y=0;
00363 
00364   if (hi_y>buf.height()-1)
00365     hi_y=buf.height()-1;
00366 
00367 
00368   // we want to compute the local stats of the data;
00369 
00370   double sum_x=0.0;
00371   double sum_xx=0.0;
00372   double N=0;
00373 
00374   for (int ix=low_x;ix<= hi_x;ix++)
00375     for (int iy=low_y;iy<=hi_y;iy++)
00376     {
00377       double val = buf(ix,iy);
00378       sum_x=sum_x+val;
00379       sum_xx=sum_xx + val*val;
00380       N++;
00381     }
00382 
00383   // compute the mean
00384 
00385   if (N)
00386   {
00387     mean=sum_x/N;
00388 
00389     double var=sum_xx/N  - mean*mean;
00390 
00391     std= vcl_sqrt(var);
00392   }
00393   else
00394   {
00395     mean=0;
00396     std=0;
00397   }
00398 }
00399 
00400 
00401 // slow
00402 double vsrl_image_correlation::get_correlation(int x1, int y1, int x2, int y2)
00403 {
00404   // we want to compute the correlation
00405 
00406   if (!check_range(buffer1_,x1,y1) || !check_range(buffer2_,x2,y2))
00407     return 0.0;
00408 
00409   // compute the window ranges for the data;
00410 
00411   // first the x component
00412 
00413   int dx = window_width_/2;
00414   if (x1 < dx)
00415     dx=x1;
00416 
00417   if (x2 < dx)
00418     dx=x2;
00419 
00420   int low_x1 = x1-dx;
00421   int low_x2 = x2-dx;
00422 
00423   dx=window_width_/2;
00424   if ((buffer1_.width()-1 -x1) < dx)
00425     dx=(buffer1_.width()-1 -x1);
00426 
00427   if ((buffer2_.width()-1 -x2) < dx)
00428     dx=(buffer2_.width()-1 -x2);
00429 
00430   int hi_x1= x1+dx;
00431 
00432   // now the y component
00433 
00434   int dy = window_height_/2;
00435   if (y1 < dy)
00436     dy=y1;
00437 
00438   if (y2 < dy)
00439     dy=y2;
00440 
00441   int low_y1 = y1-dy;
00442   int low_y2 = y2-dy;
00443 
00444   dy=window_height_/2;
00445   if ((buffer1_.height()-1 -y1) < dy)
00446     dy=(buffer1_.height()-1 -y1);
00447 
00448   if ((buffer2_.height()-1 -y2) < dy)
00449     dy=(buffer2_.height()-1 -y2);
00450 
00451   int hi_y1= y1+dy;
00452 
00453 
00454   // ****** now find the stats of the two windows
00455 
00456   double mean1,std1,mean2,std2;
00457 
00458   compute_local_stats(buffer1_,x1,y1,mean1,std1);
00459   compute_local_stats(buffer2_,x2,y2,mean2,std2);
00460 
00461   // now compute the correlation
00462 
00463   if (std1 && std2)
00464   {
00465     double val1, val2;
00466     double N=0;
00467     double corr=0;
00468 
00469     for (int i1=low_x1, i2=low_x2; i1<= hi_x1;i1++, i2++)
00470       for (int j1=low_y1, j2=low_y2; j1 <= hi_y1;j1++, j2++)
00471       {
00472         val1=buffer1_(i1,j1);
00473         val2=buffer2_(i2,j2);
00474 
00475         corr=corr+((val1-mean1)/std1)*((val2-mean2)/std2);
00476         N++;
00477       }
00478 
00479     if (N != 0)
00480       corr=corr/N;
00481 
00482     // return the correlation value
00483     return corr;
00484   }
00485   else
00486     return 0.0;
00487 }
00488 
00489 
00490 double vsrl_image_correlation::get_sub_pixel_delta(int x1,int y1, int delta_x)
00491 {
00492   // we wish to determine the correct delta_x using sub-pixel accuracy.
00493   // the idea is that we can compute the correlations for delta_x-1, delta_x
00494   // and delta_x +1. let Y= aX^2 + b X + c.
00495   // let X1 = -1, Y1 = corr (delta_x -1),
00496   // let X2 = 0, Y2 = corr (delta_x ),
00497   // let X3 = -1, Y3 = corr (delta_x +1)
00498   // then |X1^2  X1 1| a     |Y1|
00499   // then |X2^2  X2 1| b  =  |Y2|
00500   // then |X3^2  X3 1| c     |Y3|
00501   //           A       S      B
00502   // A^-1 = |.5  -1 .5|
00503   //        |-.5  0 .5|
00504   //        | 0   1 0 |
00505   // there for a = .5 Y1 - Y2 + 0.5 Y3
00506   //           b = -.5 Y1 +0.5 Y3
00507   //           c = Y2
00508   // the derivative  dY/dX = 2aX + b
00509   //  there for maxima/minima occurs at X_hat = -b/2a
00510   // the second derivative is a so if 2a so if
00511   // 2a is poisitive then h_hat is a local minima
00512   // if 2a is negative then X_hat ins a local maxima
00513   // if 2a = 0, we are dealing with  a straigt line
00514 
00515   // first check to see if the correlation range is within
00516   // spec.
00517 
00518   int index = delta_x + correlation_range_;
00519 
00520   if (index <1 || index >= (2*correlation_range_))
00521     return delta_x; // cannot three measurements sending back the original
00522 
00523   // get Y1 , Y2 , Y3
00524 
00525   double Y1 = get_correlation(x1,y1,delta_x -1);
00526   double Y2 = get_correlation(x1,y1,delta_x);
00527   double Y3 = get_correlation(x1,y1,delta_x +1);
00528 
00529   double a = 0.5*Y1 -Y2 + 0.5 *Y3;
00530   double b = 0.5*Y3 - 0.5*Y1;
00531 
00532   double x_hat;
00533   if (a>=0)
00534   {
00535     // this is a straight line or a minumum has
00536     // occurred in the interval
00537 
00538     x_hat =0;
00539 
00540     if (Y1 > Y3)
00541       x_hat = 0.0-0.5;
00542 
00543     if (Y3 > Y1)
00544       x_hat = 0.5;
00545   }
00546   else
00547   {
00548     // we have trapped a local maxima
00549     x_hat = 0.0-b/ (2.0*a);
00550     if (x_hat >0.5)
00551       x_hat = 0.5;
00552 
00553     if (x_hat < (0.0-0.5))
00554       x_hat = (0.0-0.5);
00555   }
00556 
00557   return delta_x + x_hat;
00558 }
00559 
00560 
00561 void vsrl_image_correlation::get_correlation_stats(int x, int y, double &mean, double &std)
00562 {
00563   // we want to determine how the correltaion behaves for the point x, y
00564   // we do this by finding the correlation for every possible offset and
00565   // then recording the mean and standard deviation for this correlation function
00566 
00567   double N=0;
00568   double sum_z=0;
00569   double sum_zz=0;
00570 
00571   // cover all possible correlations
00572 
00573   for (int delta=0-correlation_range_;delta<correlation_range_+1;delta++)
00574   {
00575     double z = this->get_correlation(x,y,delta);
00576     sum_z += z;
00577     sum_zz += z*z;
00578     ++N;
00579   }
00580 
00581   if (N!=0)
00582   {
00583     mean = sum_z/N;
00584     double var = sum_zz/N - mean*mean;
00585     std = vcl_sqrt(var);
00586   }
00587 }

Generated on Mon Mar 8 05:24:39 2010 for contrib/gel/vsrl by  doxygen 1.5.1