contrib/mul/ipts/ipts_scale_space_peaks.h
Go to the documentation of this file.
00001 // This is mul/ipts/ipts_scale_space_peaks.h
00002 #ifndef ipts_scale_space_peaks_h_
00003 #define ipts_scale_space_peaks_h_
00004 //:
00005 // \file
00006 // \brief Find peaks in scale-space
00007 // \author Tim Cootes
00008 
00009 #include <vimt/algo/vimt_find_peaks.h>
00010 #include <vgl/vgl_point_2d.h>
00011 #include <vgl/vgl_vector_2d.h>
00012 #include <vgl/vgl_point_3d.h>
00013 #include <vimt/vimt_image_pyramid.h>
00014 #include <vcl_cmath.h> // for sqrt(double)
00015 #include <vcl_cassert.h>
00016 
00017 //: True if value is strictly above *im and its 8 neighbours
00018 template <class T>
00019 inline bool ipts_is_above_3x3(T value, const T* im,
00020                               vcl_ptrdiff_t i_step, vcl_ptrdiff_t j_step)
00021 {
00022   if (value<=im[0]) return false;
00023   if (value<=im[i_step]) return false;
00024   if (value<=im[-i_step]) return false;
00025   if (value<=im[j_step]) return false;
00026   if (value<=im[-j_step]) return false;
00027   if (value<=im[i_step+j_step]) return false;
00028   if (value<=im[i_step-j_step]) return false;
00029   if (value<=im[j_step-i_step]) return false;
00030   if (value<=im[-i_step-j_step]) return false;
00031   return true;
00032 }
00033 
00034 //: Find local maxima in position and scale above given threshold
00035 //  Points returned in a 3D point, given world coords + scale value
00036 template<class T>
00037 inline void ipts_scale_space_peaks_2d(vcl_vector<vgl_point_3d<double> >& peak_pts,
00038                                       const vimt_image_2d_of<T>& image_below,
00039                                       const vimt_image_2d_of<T>& image,
00040                                       const vimt_image_2d_of<T>& image_above,
00041                                       T threshold = 0,
00042                                       bool clear_list = true)
00043 {
00044   if (clear_list) { peak_pts.resize(0); }
00045   unsigned ni=image.image().ni(),nj=image.image().nj();
00046   vcl_ptrdiff_t istep = image.image().istep(),jstep=image.image().jstep();
00047   assert(istep!=0); // strange image if istep would be 0 ... most probably uninitialised!
00048   const T* row = &image.image()(2,2,0);
00049 
00050   const vil_image_view<T>& im_below = image_below.image();
00051   const vil_image_view<T>& im_above = image_above.image();
00052 
00053   vimt_transform_2d to_base  = image.world2im().inverse();
00054   vimt_transform_2d to_above = image_above.world2im() * to_base;
00055   vimt_transform_2d to_below = image_below.world2im() * to_base;
00056 
00057   // Estimate scaling factor between images (assumed isotropic)
00058   vgl_vector_2d<double> dx(1,0),dw;
00059   dw = image.world2im().delta(vgl_point_2d<double>(0,0),dx);
00060   double scale = 1.0/vcl_sqrt(dw.x()*dw.x()+dw.y()*dw.y());
00061 
00062   // Allow 2 pixel border to ensure avoid problems when
00063   // testing level above
00064   for (unsigned j=2;j<nj-2;++j,row+=jstep)
00065   {
00066     const T* pixel = row;
00067     for (unsigned i=2;i<ni-2;++i,pixel+=istep)
00068     {
00069       if (*pixel>threshold && vimt_is_peak_3x3(pixel,istep,jstep))
00070       {
00071         // (i,j) is local maxima at this level
00072         // Check it is also above all pixels nearby in level below
00073         vgl_point_2d<double> p0 = to_below(i,j);
00074 
00075         const T* pixel_below=&im_below(int(p0.x()+0.5),int(p0.y()+0.5));
00076         if (ipts_is_above_3x3(*pixel,pixel_below,
00077                                 im_below.istep(),im_below.jstep())  )
00078         {
00079           // (i,j) is local maxima at the level below
00080           // Check it is also above all pixels nearby in level above
00081           vgl_point_2d<double> p1 = to_above(i,j);
00082           if (p1.x()>0.5 && p1.y()>0.5
00083               && p1.x()<im_above.ni()-2 && p1.y()<im_above.nj()-2)
00084           {
00085             const T* pixel_above=&im_above(int(p1.x()+0.5),int(p1.y()+0.5));
00086             if (ipts_is_above_3x3(*pixel,pixel_above,
00087                                   im_above.istep(),im_above.jstep()))
00088             {
00089               vgl_point_2d<double> p = to_base(i,j);
00090               peak_pts.push_back(vgl_point_3d<double>(p.x(),p.y(),scale));
00091             }
00092           }
00093         }
00094       }
00095     }
00096   }
00097 }
00098 
00099 //: Find local maxima in image0 and check against in image1
00100 //  Returned points will be above all their neighbours and
00101 //  those in nearby positions in image1
00102 template<class T>
00103 inline void ipts_scale_space_peaks_2d(vcl_vector<vgl_point_2d<double> >& peak_pts,
00104                                       vcl_vector<T>& peak_values,
00105                                       const vimt_image_2d_of<T>& image0,
00106                                       const vimt_image_2d_of<T>& image1,
00107                                       T threshold)
00108 {
00109   vcl_vector<vgl_point_2d<double> > peak_pts0;
00110   vcl_vector<T> peak_values0;
00111   vimt_find_world_peaks_3x3(peak_pts0,peak_values0,image0);
00112 
00113   // Check that each point is above equivalent pixels in image1
00114   peak_pts.resize(0);
00115   peak_values.resize(0);
00116   vimt_transform_2d w2i1  = image1.world2im();
00117   unsigned ni2 = image1.image().ni()-2;
00118   unsigned nj2 = image1.image().nj()-2;
00119   vcl_ptrdiff_t istep = image1.image().istep(), jstep=image1.image().jstep();
00120   for (unsigned i=0;i<peak_pts0.size();++i)
00121   {
00122     if (peak_values0[i]>threshold)
00123     {
00124       vgl_point_2d<double> p1 = w2i1(peak_pts0[i]);
00125       if (p1.x()>0.5 && p1.y()>0.5 && p1.x()<ni2 && p1.y()<nj2)
00126       {
00127         const T* pixel=&image1.image()(int(p1.x()+0.5),int(p1.y()+0.5));
00128         if (ipts_is_above_3x3(peak_values0[i],pixel,istep,jstep))
00129         {
00130           peak_pts.push_back(peak_pts0[i]);
00131           peak_values.push_back(peak_values0[i]);
00132         }
00133       }
00134     }
00135   }
00136 }
00137 
00138 //: Find local maxima in image0 and check against in image1
00139 //  Returned points will be above all their neighbours and
00140 //  those in nearby positions in image1
00141 template<class T>
00142 inline void ipts_scale_space_peaks_2d(vcl_vector<vgl_point_3d<double> >& peak_pts,
00143                                       const vimt_image& image0,
00144                                       const vimt_image& image1,
00145                                       T threshold)
00146 {
00147   const vimt_image_2d_of<T>& im0 =
00148                 dynamic_cast<const vimt_image_2d_of<T>&>(image0);
00149   const vimt_image_2d_of<T>& im1 =
00150                 dynamic_cast<const vimt_image_2d_of<T>&>(image1);
00151   vcl_vector<vgl_point_2d<double> > peak_pts0;
00152   vcl_vector<T> peak_values0;
00153 
00154   ipts_scale_space_peaks_2d(peak_pts0,peak_values0,im0,im1,threshold);
00155 
00156   // Estimate scaling factor between images (assumed isotropic)
00157   vgl_vector_2d<double> dx(1,0),dw;
00158   dw = im0.world2im().delta(vgl_point_2d<double>(0,0),dx);
00159   double scale = 1.0/vcl_sqrt(dw.x()*dw.x()+dw.y()*dw.y());
00160 
00161   for (unsigned i=0;i<peak_pts0.size();++i)
00162   {
00163     vgl_point_3d<double> p(peak_pts0[i].x(),peak_pts0[i].y(),scale);
00164     peak_pts.push_back(p);
00165   }
00166 }
00167 
00168 //: Find local maxima in position and scale above a threshold
00169 //  Points returned in a 3D point, given world coords + scale value
00170 //  Note that image_pyr is assumed to contain images of type
00171 //  vimt_image_2d_of<T> - threshold indicates the typing.
00172 template<class T>
00173 inline void ipts_scale_space_peaks_2d(vcl_vector<vgl_point_3d<double> >& peak_pts,
00174                                       const vimt_image_pyramid& image_pyr,
00175                                       T threshold)
00176 {
00177   peak_pts.resize(0);
00178 
00179   // Look for peaks at the finest scale (comparing to those at the scale above)
00180   if (image_pyr.n_levels()>1)
00181     ipts_scale_space_peaks_2d(peak_pts,image_pyr(0),image_pyr(1),threshold);
00182 
00183   for (int L=image_pyr.lo()+1;L<image_pyr.hi();++L)
00184   {
00185     const vimt_image_2d_of<T>& im_below =
00186                 dynamic_cast<const vimt_image_2d_of<T>&>(image_pyr(L-1));
00187     const vimt_image_2d_of<T>& image =
00188                 dynamic_cast<const vimt_image_2d_of<T>&>(image_pyr(L));
00189     const vimt_image_2d_of<T>& im_above =
00190                 dynamic_cast<const vimt_image_2d_of<T>&>(image_pyr(L+1));
00191 
00192     ipts_scale_space_peaks_2d(peak_pts,im_below,image,im_above,threshold,false);
00193   }
00194 }
00195 
00196 #endif // ipts_scale_space_peaks_h_