core/vil/algo/vil_corners.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \brief Estimate corner positions using Forstner/Harris approach
00004 // \author Tim Cootes
00005 
00006 #include "vil_corners.h"
00007 #include <vil/vil_fill.h>
00008 #include <vcl_cassert.h>
00009 #include <vil/algo/vil_gauss_filter.h>
00010 #include <vil/vil_math.h>
00011 
00012 //: Compute Forstner/Harris corner strength function given gradient images.
00013 //  grad_i and grad_j are assumed to be the i and j gradient images (single
00014 //  plane), such as produced by vil_sobel_3x3().  At each pixel compute
00015 //  the Forstner/Harris corner function: det(H)-k*sqr(trace(H)), where
00016 //  H is the 2x2 matrix of second derivatives, generated by applying a Sobel
00017 //  operator to the gradient images.
00018 //
00019 //  The local peaks of the output image correspond to corner candidates.
00020 // \relatesalso vil_image_view
00021 void vil_corners(const vil_image_view<float>& grad_i,
00022                  const vil_image_view<float>& grad_j,
00023                  vil_image_view<float>& dest, double k)
00024 {
00025   assert(grad_i.nplanes()==1);
00026   assert(grad_j.nplanes()==1);
00027   unsigned ni = grad_i.ni(), nj = grad_i.nj();
00028   assert(grad_j.ni()==ni && grad_j.nj()==nj );
00029 
00030   dest.set_size(ni,nj);
00031 
00032   // Zero a two pixel border
00033   for (unsigned i=0;i<2;++i)
00034   {
00035     vil_fill_row(dest,i,0.0f);
00036     vil_fill_row(dest,nj-1-i,0.0f);
00037     vil_fill_col(dest,i,0.0f);
00038     vil_fill_col(dest,ni-1-i,0.0f);
00039   }
00040 
00041   const unsigned ni2 = ni-2;
00042   const unsigned nj2 = nj-2;
00043 
00044   // Compute relative grid positions
00045   //  o1 o2 o3
00046   //  o4    o5
00047   //  o6 o7 o8
00048   const vcl_ptrdiff_t oi1 = grad_i.jstep() - grad_i.istep();
00049   const vcl_ptrdiff_t oi2 = grad_i.jstep();
00050   const vcl_ptrdiff_t oi3 = grad_i.istep() + grad_i.jstep();
00051   const vcl_ptrdiff_t oi4 = -grad_i.istep();
00052   const vcl_ptrdiff_t oi5 = grad_i.istep();
00053   const vcl_ptrdiff_t oi6 = -grad_i.istep() - grad_i.jstep();
00054   const vcl_ptrdiff_t oi7 = -grad_i.jstep();
00055   const vcl_ptrdiff_t oi8 = grad_i.istep() - grad_i.jstep();
00056 
00057   const vcl_ptrdiff_t oj1 = grad_j.jstep() - grad_j.istep();
00058   const vcl_ptrdiff_t oj2 = grad_j.jstep();
00059   const vcl_ptrdiff_t oj3 = grad_j.istep() + grad_j.jstep();
00060   const vcl_ptrdiff_t oj6 = -grad_j.istep() - grad_j.jstep();
00061   const vcl_ptrdiff_t oj7 = -grad_j.jstep();
00062   const vcl_ptrdiff_t oj8 = grad_j.istep() - grad_j.jstep();
00063 
00064   float * d_data = &dest(2,2);
00065   const float * gi_data = &grad_i(2,2);
00066   const float * gj_data = &grad_j(2,2);
00067 
00068   for (unsigned j=2;j<nj2;++j)
00069   {
00070     float* d = d_data;
00071     const float* pgi = gi_data;
00072     const float* pgj = gj_data;
00073     for (unsigned i=2;i<ni2;++i)
00074     {
00075       // Compute gradient in i
00076       float dxdx = 0.125f*(pgi[oi3]+pgi[oi8] - (pgi[oi1]+pgi[oi6])) + 0.25f*(pgi[oi5]-pgi[oi4]);
00077       // Compute gradient in j
00078       float dxdy = 0.125f*(pgi[oi1]+pgi[oi3] - (pgi[oi6]+pgi[oi8])) + 0.25f*(pgi[oi2]-pgi[oi7]);
00079       // Compute gradient in j
00080       float dydy = 0.125f*(pgj[oj1]+pgj[oj3] - (pgj[oj6]+pgj[oj8])) + 0.25f*(pgj[oj2]-pgj[oj7]);
00081 
00082       float detH = dxdx*dydy - dxdy*dxdy;
00083       float traceH = dxdx+dydy;
00084 
00085       *d = detH - float(k) * traceH * traceH;
00086 
00087       pgi += grad_i.istep();
00088       pgj += grad_j.istep();
00089       d += dest.istep();
00090     }
00091 
00092     gi_data += grad_i.jstep();
00093     gj_data += grad_j.jstep();
00094     d_data  += dest.jstep();
00095   }
00096 }
00097 
00098 void vil_corners(const vil_image_view<double>& grad_i,
00099                  const vil_image_view<double>& grad_j,
00100                  vil_image_view<double>& dest, double k)
00101 {
00102   assert(grad_i.nplanes()==1);
00103   assert(grad_j.nplanes()==1);
00104   unsigned ni = grad_i.ni(), nj = grad_i.nj();
00105   assert(grad_j.ni()==ni && grad_j.nj()==nj );
00106 
00107   dest.set_size(ni,nj);
00108 
00109   // Zero a two pixel border
00110   for (unsigned i=0;i<2;++i)
00111   {
00112     vil_fill_row(dest,i,0.0);
00113     vil_fill_row(dest,nj-1-i,0.0);
00114     vil_fill_col(dest,i,0.0);
00115     vil_fill_col(dest,ni-1-i,0.0);
00116   }
00117 
00118   const unsigned ni2 = ni-2;
00119   const unsigned nj2 = nj-2;
00120 
00121   // Compute relative grid positions
00122   //  o1 o2 o3
00123   //  o4    o5
00124   //  o6 o7 o8
00125   const vcl_ptrdiff_t oi1 = grad_i.jstep() - grad_i.istep();
00126   const vcl_ptrdiff_t oi2 = grad_i.jstep();
00127   const vcl_ptrdiff_t oi3 = grad_i.istep() + grad_i.jstep();
00128   const vcl_ptrdiff_t oi4 = -grad_i.istep();
00129   const vcl_ptrdiff_t oi5 = grad_i.istep();
00130   const vcl_ptrdiff_t oi6 = -grad_i.istep() - grad_i.jstep();
00131   const vcl_ptrdiff_t oi7 = -grad_i.jstep();
00132   const vcl_ptrdiff_t oi8 = grad_i.istep() - grad_i.jstep();
00133 
00134   const vcl_ptrdiff_t oj1 = grad_j.jstep() - grad_j.istep();
00135   const vcl_ptrdiff_t oj2 = grad_j.jstep();
00136   const vcl_ptrdiff_t oj3 = grad_j.istep() + grad_j.jstep();
00137   const vcl_ptrdiff_t oj6 = -grad_j.istep() - grad_j.jstep();
00138   const vcl_ptrdiff_t oj7 = -grad_j.jstep();
00139   const vcl_ptrdiff_t oj8 = grad_j.istep() - grad_j.jstep();
00140 
00141   double * d_data = &dest(2,2);
00142   const double * gi_data = &grad_i(2,2);
00143   const double * gj_data = &grad_j(2,2);
00144 
00145   for (unsigned j=2;j<nj2;++j)
00146   {
00147     double* d = d_data;
00148     const double* pgi = gi_data;
00149     const double* pgj = gj_data;
00150     for (unsigned i=2;i<ni2;++i)
00151     {
00152       // Compute gradient in i
00153       double dxdx = 0.125f*(pgi[oi3]+pgi[oi8] - (pgi[oi1]+pgi[oi6])) + 0.25f*(pgi[oi5]-pgi[oi4]);
00154       // Compute gradient in j
00155       double dxdy = 0.125f*(pgi[oi1]+pgi[oi3] - (pgi[oi6]+pgi[oi8])) + 0.25f*(pgi[oi2]-pgi[oi7]);
00156       // Compute gradient in j
00157       double dydy = 0.125f*(pgj[oj1]+pgj[oj3] - (pgj[oj6]+pgj[oj8])) + 0.25f*(pgj[oj2]-pgj[oj7]);
00158 
00159       double detH = dxdx*dydy - dxdy*dxdy;
00160       double traceH = dxdx+dydy;
00161 
00162       *d = detH - double(k) * traceH * traceH;
00163 
00164       pgi += grad_i.istep();
00165       pgj += grad_j.istep();
00166       d += dest.istep();
00167     }
00168 
00169     gi_data += grad_i.jstep();
00170     gj_data += grad_j.jstep();
00171     d_data  += dest.jstep();
00172   }
00173 }
00174 
00175 //: Compute corner strength using Rohr's recommended method
00176 //  This computes the determinant of the matrix C=g.g'
00177 //  after the elements of C have been smoothed.
00178 //  g is the vector of first derivatives (gx,gy)'
00179 //  It relies only on first derivatives.
00180 //
00181 //  Currently uses somewhat inefficient multi-pass method.
00182 //  Could be improved.
00183 void vil_corners_rohr(const vil_image_view<float>& gx,
00184                       const vil_image_view<float>& gy,
00185                       vil_image_view<float>& corner_im)
00186 {
00187   vil_image_view<float> tmp_im,work_im, gx2,gy2,gxy;
00188   vil_gauss_filter_5tap_params smooth_params(1.0);
00189 
00190   // Compute smoothed products of gradients
00191   vil_math_image_product(gx,gx,tmp_im);
00192   vil_gauss_filter_5tap(tmp_im,gx2,smooth_params,work_im);
00193 
00194   vil_math_image_product(gy,gy,tmp_im);
00195   vil_gauss_filter_5tap(tmp_im,gy2,smooth_params,work_im);
00196 
00197   vil_math_image_product(gx,gy,tmp_im);
00198   vil_gauss_filter_5tap(tmp_im,gxy,smooth_params,work_im);
00199 
00200   // Compute gx2*gy2 - gxy*gxy at each pixel
00201   vil_math_image_product(gx2,gy2,corner_im);
00202   vil_math_image_product(gxy,gxy,tmp_im);
00203   vil_math_add_image_fraction(corner_im,1.0f,tmp_im,-1.0f);
00204 }