core/vil/algo/vil_normalised_correlation_2d.h
Go to the documentation of this file.
00001 // This is core/vil/algo/vil_normalised_correlation_2d.h
00002 #ifndef vil_normalised_correlation_2d_h_
00003 #define vil_normalised_correlation_2d_h_
00004 //:
00005 // \file
00006 // \brief 2D normalised correlation
00007 // \author Tim Cootes
00008 
00009 #include <vil/vil_image_view.h>
00010 #include <vcl_compiler.h>
00011 #include <vcl_cassert.h>
00012 #include <vcl_cmath.h>    // for std::sqrt()
00013 #include <vcl_cstddef.h>  // for std::ptrdiff_t
00014 
00015 //: Evaluate dot product between kernel and src_im
00016 // Assumes that the kernel has been normalised to have zero mean
00017 // and unit variance
00018 // \relatesalso vil_image_view
00019 template <class srcT, class kernelT, class accumT>
00020 inline accumT vil_norm_corr_2d_at_pt(const srcT *src_im, vcl_ptrdiff_t s_istep,
00021                                      vcl_ptrdiff_t s_jstep, vcl_ptrdiff_t s_pstep,
00022                                      const vil_image_view<kernelT>& kernel,
00023                                      accumT)
00024 {
00025   unsigned ni = kernel.ni();
00026   unsigned nj = kernel.nj();
00027   unsigned np = kernel.nplanes();
00028 
00029   vcl_ptrdiff_t k_istep = kernel.istep(), k_jstep = kernel.jstep();
00030 
00031   accumT sum=0;
00032   accumT mean=0;
00033   accumT sum_sq=0;
00034   for (unsigned p = 0; p<np; ++p)
00035   {
00036     // Select first row of p-th plane
00037     const srcT*  src_row  = src_im + p*s_pstep;
00038     const kernelT* k_row =  kernel.top_left_ptr() + p*kernel.planestep();
00039 
00040     for (unsigned int j=0;j<nj;++j,src_row+=s_jstep,k_row+=k_jstep)
00041     {
00042       const srcT* sp = src_row;
00043       const kernelT* kp = k_row;
00044       // Sum over j-th row
00045       for (unsigned int i=0;i<ni;++i, sp += s_istep, kp += k_istep)
00046       {
00047         sum += accumT(*sp)*accumT(*kp);
00048         mean+= accumT(*sp);
00049         sum_sq += accumT(*sp)*accumT(*sp);
00050       }
00051     }
00052   }
00053 
00054   long n=ni*nj*np;
00055   mean/=(accumT)n;
00056   accumT var = sum_sq/(accumT)n - mean*mean;
00057   return var<=0 ? 0 : sum/vcl_sqrt(var);
00058 }
00059 
00060 //: Normalised cross-correlation of (pre-normalised) kernel with srcT.
00061 // dest is resized to (1+src_im.ni()-kernel.ni())x(1+src_im.nj()-kernel.nj())
00062 // (a one plane image).
00063 // On exit dest(x,y) = sum_ij src_im(x+i,y+j)*kernel(i,j)/sd_under_region
00064 //
00065 // Assumes that the kernel has been normalised to have zero mean
00066 // and unit variance
00067 // \relatesalso vil_image_view
00068 template <class srcT, class destT, class kernelT, class accumT>
00069 inline void vil_normalised_correlation_2d(const vil_image_view<srcT>& src_im,
00070                                           vil_image_view<destT>& dest_im,
00071                                           const vil_image_view<kernelT>& kernel,
00072                                           accumT ac)
00073 {
00074   unsigned ni = 1+src_im.ni()-kernel.ni(); assert(1+src_im.ni() >= kernel.ni());
00075   unsigned nj = 1+src_im.nj()-kernel.nj(); assert(1+src_im.nj() >= kernel.nj());
00076   vcl_ptrdiff_t s_istep = src_im.istep(), s_jstep = src_im.jstep();
00077   vcl_ptrdiff_t s_pstep = src_im.planestep();
00078 
00079   dest_im.set_size(ni,nj,1);
00080   vcl_ptrdiff_t d_istep = dest_im.istep(),d_jstep = dest_im.jstep();
00081 
00082   // Select first row of p-th plane
00083   const srcT*  src_row  = src_im.top_left_ptr();
00084   destT* dest_row = dest_im.top_left_ptr();
00085 
00086   for (unsigned j=0;j<nj;++j,src_row+=s_jstep,dest_row+=d_jstep)
00087   {
00088     const srcT* sp = src_row;
00089     destT* dp = dest_row;
00090     for (unsigned i=0;i<ni;++i, sp += s_istep, dp += d_istep)
00091       *dp =(destT)vil_norm_corr_2d_at_pt(sp,s_istep,s_jstep,s_pstep,kernel,ac);
00092     // Convolve at src(i,j)
00093   }
00094 }
00095 
00096 #endif // vil_normalised_correlation_2d_h_