core/vil/vil_math.h
Go to the documentation of this file.
00001 // This is core/vil/vil_math.h
00002 #ifndef vil_math_h_
00003 #define vil_math_h_
00004 //:
00005 // \file
00006 // \brief Various mathematical manipulations of 2D images
00007 // \author Tim Cootes
00008 
00009 #include <vcl_cassert.h>
00010 #include <vcl_vector.h>
00011 #include <vcl_cmath.h>
00012 #include <vcl_algorithm.h>
00013 #include <vil/vil_image_view.h>
00014 #include <vil/vil_view_as.h>
00015 #include <vil/vil_plane.h>
00016 #include <vil/vil_transform.h>
00017 
00018 
00019 //: Compute minimum and maximum values over view
00020 template<class T>
00021 inline void vil_math_value_range(const vil_image_view<T>& view, T& min_value, T& max_value)
00022 {
00023   if (view.size()==0)
00024   {
00025     min_value = 0;
00026     max_value = 0;
00027     return;
00028   }
00029 
00030   min_value = *(view.top_left_ptr());
00031   max_value = min_value;
00032 
00033   unsigned ni = view.ni();
00034   unsigned nj = view.nj();
00035   unsigned np = view.nplanes();
00036 
00037   for (unsigned p=0;p<np;++p)
00038     for (unsigned j=0;j<nj;++j)
00039       for (unsigned i=0;i<ni;++i)
00040       {
00041         const T pixel = view(i,j,p);
00042         if (pixel<min_value)
00043           min_value=pixel;
00044         else if (pixel>max_value)
00045           max_value=pixel;
00046       }
00047 }
00048 
00049 //: Compute minimum and maximum values over view
00050 VCL_DEFINE_SPECIALIZATION
00051 inline void vil_math_value_range(const vil_image_view<vil_rgb<vxl_byte> >& rgb_view,
00052                                  vil_rgb<vxl_byte>& min_value, vil_rgb<vxl_byte>& max_value)
00053 {
00054   vil_image_view<vxl_byte> plane_view = vil_view_as_planes(rgb_view);
00055   // Get range for each plane in turn
00056   vil_math_value_range(vil_plane(plane_view,0),min_value.r,max_value.r);
00057   vil_math_value_range(vil_plane(plane_view,1),min_value.g,max_value.g);
00058   vil_math_value_range(vil_plane(plane_view,2),min_value.b,max_value.b);
00059 }
00060 
00061 //: Compute minimum and maximum values over view
00062 VCL_DEFINE_SPECIALIZATION
00063 inline void vil_math_value_range(const vil_image_view<vil_rgb<float> >& rgb_view,
00064                                  vil_rgb<float>& min_value, vil_rgb<float>& max_value)
00065 {
00066   vil_image_view<float> plane_view = vil_view_as_planes(rgb_view);
00067   // Get range for each plane in turn
00068   vil_math_value_range(vil_plane(plane_view,0),min_value.r,max_value.r);
00069   vil_math_value_range(vil_plane(plane_view,1),min_value.g,max_value.g);
00070   vil_math_value_range(vil_plane(plane_view,2),min_value.b,max_value.b);
00071 }
00072 
00073 
00074 //: Compute the values corresponding to several percentiles of the range of im.
00075 // Percentiles are expressed as fraction, e.g. 0.05, or 0.95.
00076 // \param im The image to examine.
00077 // \param fraction The fractions of the data range (from the lower end).
00078 // \retval value The image data values corresponding to the specified percentiles.
00079 // \relatesalso vil_image_view
00080 // \note This function requires the sorting of large parts of the image data
00081 // and can be very expensive in terms of both processing and memory.
00082 template <class T>
00083 inline void vil_math_value_range_percentiles(const vil_image_view<T>& im,
00084                                              const vcl_vector<double>& fraction,
00085                                              vcl_vector<T>& value)
00086 {
00087   value.clear();
00088 
00089   // Test for invalid inputs
00090   if (im.size()==0)
00091   {
00092     return;
00093   }
00094   const vcl_size_t nfrac = fraction.size();
00095   for (vcl_size_t f=0; f<nfrac; ++f)
00096   {
00097     if (fraction[f]<0.0 || fraction[f]>1.0)
00098       return;
00099   }
00100 
00101   // Copy the pixel values into a list.
00102   unsigned ni = im.ni();
00103   unsigned nj = im.nj();
00104   unsigned np = im.nplanes();
00105   vcl_ptrdiff_t istep = im.istep();
00106   vcl_ptrdiff_t jstep = im.jstep();
00107   vcl_ptrdiff_t pstep = im.planestep();
00108   vcl_vector<T> data(ni*nj*np);
00109 
00110   typename vcl_vector<T>::iterator it = data.begin();
00111   const T* plane = im.top_left_ptr();
00112   for (unsigned int p=0; p<np; ++p, plane+=pstep)
00113   {
00114     const T* row = plane;
00115     for (unsigned int j=0; j<nj; ++j, row+=jstep)
00116     {
00117       const T* pixel = row;
00118       for (unsigned int i=0; i<ni; ++i, pixel+=istep)
00119       {
00120         *it = *pixel;
00121         it++;
00122       }
00123     }
00124   }
00125   const vcl_size_t npix = data.size();
00126 
00127   // Get the nth_element corresponding to the specified fractions
00128   value.resize(nfrac);
00129   for (unsigned f=0; f<nfrac; ++f)
00130   {
00131     unsigned index = static_cast<unsigned>(fraction[f]*npix - 0.5);
00132     typename vcl_vector<T>::iterator index_it = data.begin() + index;
00133     vcl_nth_element(data.begin(), index_it, data.end());
00134     value[f] = *index_it;
00135   }
00136 }
00137 
00138 
00139 //: Compute the value corresponding to a percentile of the range of im.
00140 // Percentile is expressed as fraction, e.g. 0.05, or 0.95.
00141 // \param im The image to examine.
00142 // \param fraction The fraction of the data range (from the lower end).
00143 // \retval value The image data value corresponding to the specified percentile.
00144 // \relatesalso vil_image_view
00145 // \note This function requires the sorting of large parts of the image data
00146 // and can be very expensive in terms of both processing and memory.
00147 template <class T>
00148 inline void vil_math_value_range_percentile(const vil_image_view<T>& im,
00149                                             const double fraction,
00150                                             T& value)
00151 {
00152   vcl_vector<double> fractions(1, fraction);
00153   vcl_vector<T> values;
00154   vil_math_value_range_percentiles(im, fractions, values);
00155   if (values.size() > 0)
00156     value = values[0]; // Bounds-checked access in case previous line failed.
00157 }
00158 
00159 
00160 //: Sum of squared differences between two images
00161 // \relatesalso vil_image_view
00162 template <class imT, class sumT>
00163 inline sumT vil_math_ssd(const vil_image_view<imT>& imA, const vil_image_view<imT>& imB, sumT /*dummy*/)
00164 {
00165   assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() && imA.nplanes() == imB.nplanes());
00166   sumT ssd=0;
00167   for (unsigned p=0;p<imA.nplanes();++p)
00168     for (unsigned j=0;j<imA.nj();++j)
00169       for (unsigned i=0;i<imA.ni();++i)
00170       {
00171         const sumT v = ((sumT)imA(i,j,p) - (sumT)imB(i,j,p));
00172         ssd += v*v;
00173       }
00174   return ssd;
00175 }
00176 
00177 //: Sum squared magnitude differences between two complex images
00178 // \relatesalso vil_image_view
00179 template <class imT, class sumT>
00180 inline sumT
00181 vil_math_ssd_complex(const vil_image_view<vcl_complex<imT> >& imA,
00182                      const vil_image_view<vcl_complex<imT> >& imB,
00183                      sumT /*dummy*/)
00184 {
00185   assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() && imA.nplanes() == imB.nplanes());
00186   sumT ssd=0;
00187   for (unsigned p=0;p<imA.nplanes();++p)
00188     for (unsigned j=0;j<imA.nj();++j)
00189       for (unsigned i=0;i<imA.ni();++i)
00190       {
00191         const vcl_complex<imT> d = imA(i,j,p) - imB(i,j,p);
00192         ssd += sumT( d.real()*d.real() + d.imag()*d.imag() );
00193       }
00194   return ssd;
00195 }
00196 
00197 //: Calc the mean of each pixel over all the planes.
00198 // \relatesalso vil_image_view
00199 template<class aT, class sumT>
00200 inline void vil_math_mean_over_planes(const vil_image_view<aT>& src,
00201                                       vil_image_view<sumT>& dest)
00202 {
00203   if (src.nplanes()==1 && src.is_a()==dest.is_a())
00204   {
00205     dest.deep_copy(src);
00206     return;
00207   }
00208   dest.set_size(src.ni(), src.nj(), 1);
00209   for (unsigned j=0;j<src.nj();++j)
00210     for (unsigned i=0;i<src.ni();++i)
00211     {
00212       sumT sum=0;
00213       for (unsigned p=0;p<src.nplanes();++p)
00214         sum += (sumT) src(i,j,p);
00215       dest(i,j) = (sumT)( sum / src.nplanes() );
00216     }
00217 }
00218 
00219 //: Calc the mean of each pixel over all the planes.
00220 // \relatesalso vil_image_view
00221 template<class inT, class outT, class sumT>
00222 inline void vil_math_mean_over_planes(const vil_image_view<inT>& src,
00223                                       vil_image_view<outT>& dest,
00224                                       sumT /*dummy*/)
00225 {
00226   dest.set_size(src.ni(), src.nj(), 1);
00227   for (unsigned j=0;j<src.nj();++j)
00228     for (unsigned i=0;i<src.ni();++i)
00229     {
00230       sumT sum=0;
00231       for (unsigned p=0;p<src.nplanes();++p)
00232         sum += static_cast<sumT>(src(i,j,p));
00233       dest(i,j) = static_cast<outT>(sum / src.nplanes());
00234     }
00235 }
00236 
00237 //: Sum of elements in plane p of image
00238 // \relatesalso vil_image_view
00239 template<class imT, class sumT>
00240 inline void vil_math_sum(sumT& sum, const vil_image_view<imT>& im, unsigned p)
00241 {
00242   const imT* row = im.top_left_ptr()+p*im.planestep();
00243   vcl_ptrdiff_t istep = im.istep(),jstep=im.jstep();
00244   const imT* row_end = row + im.nj()*jstep;
00245   vcl_ptrdiff_t row_len = im.ni()*im.istep();
00246   sum = 0;
00247   for (;row!=row_end;row+=jstep)
00248   {
00249     const imT* v_end = row + row_len;
00250     for (const imT* v = row;v!=v_end;v+=istep) sum+=(sumT)(*v);
00251   }
00252 }
00253 
00254 //: Mean of elements in plane p of image
00255 // \relatesalso vil_image_view
00256 template<class imT, class sumT>
00257 inline void vil_math_mean(sumT& mean, const vil_image_view<imT>& im, unsigned p)
00258 {
00259   if (im.size()==0) { mean=0; return; }
00260   vil_math_sum(mean,im,p);
00261   mean/=(sumT)(im.ni()*im.nj());
00262 }
00263 
00264 // helper function for reporting an error without cluttering the
00265 // header with unnecessary includes.
00266 void vil_math_median_unimplemented();
00267 
00268 //: Median of elements in plane p of an image.
00269 //
00270 // For integral types, if the median is half way between two
00271 // values, the result will be the floor of the average.
00272 //
00273 // \relatesalso vil_image_view
00274 template<class imT>
00275 inline void vil_math_median(imT& median, const vil_image_view<imT>& im, unsigned p)
00276 {
00277   vil_math_median_unimplemented();
00278 }
00279 // median is unimplemented in the general case (for now).
00280 
00281 // Purposefully not documented via doxygen; let the general template's
00282 // documentation be the documentation.
00283 VCL_DEFINE_SPECIALIZATION
00284 void vil_math_median(vxl_byte& median, const vil_image_view<vxl_byte>& im, unsigned p);
00285 
00286 
00287 //: Sum of squares of elements in plane p of image
00288 // \relatesalso vil_image_view
00289 template<class imT, class sumT>
00290 inline void vil_math_sum_squares(sumT& sum, sumT& sum_sq, const vil_image_view<imT>& im, unsigned p)
00291 {
00292   const imT* row = im.top_left_ptr()+p*im.planestep();
00293   vcl_ptrdiff_t istep = im.istep(),jstep=im.jstep();
00294   const imT* row_end = row + im.nj()*jstep;
00295   vcl_ptrdiff_t row_len = im.ni()*im.istep();
00296   sum = 0; sum_sq = 0;
00297   for (;row!=row_end;row+=jstep)
00298   {
00299     const imT* v_end = row + row_len;
00300     for (const imT* v = row;v!=v_end;v+=istep) { sum+=*v; sum_sq+=sumT(*v)*sumT(*v); }
00301   }
00302 }
00303 
00304 //: Mean and variance of elements in plane p of image
00305 // \relatesalso vil_image_view
00306 template<class imT, class sumT>
00307 inline void vil_math_mean_and_variance(sumT& mean, sumT& var, const vil_image_view<imT>& im, unsigned p)
00308 {
00309   if (im.size()==0) { mean=0; var=0; return; }
00310   sumT sum,sum_sq;
00311   vil_math_sum_squares(sum,sum_sq,im,p);
00312   mean = sum/float(im.ni()*im.nj());
00313   var = sum_sq/float(im.ni()*im.nj()) - mean*mean;
00314 }
00315 
00316 //: Functor class to compute square roots (returns zero if x<0)
00317 class vil_math_sqrt_functor
00318 {
00319  public:
00320   vxl_byte operator()(vxl_byte x) const { return static_cast<vxl_byte>(0.5+vcl_sqrt(double(x))); }
00321   unsigned operator()(unsigned x) const { return static_cast<unsigned int>(0.5+vcl_sqrt(double(x))); }
00322   int operator()(int x)           const { return x>0?static_cast<int>(0.5+vcl_sqrt(double(x))):0; }
00323   short operator()(short x)       const { return x>0?static_cast<short>(0.5+vcl_sqrt(double(x))):0; }
00324   float operator()(float x)       const { return x>0?vcl_sqrt(x):0.0f; }
00325   double operator()(double x)     const { return x>0?vcl_sqrt(x):0.0; }
00326 };
00327 
00328 //: Compute square-root of each pixel element (or zero if negative)
00329 // \relatesalso vil_image_view
00330 template<class T>
00331 inline void vil_math_sqrt(vil_image_view<T>& image)
00332 {
00333   vil_transform(image,vil_math_sqrt_functor());
00334 }
00335 
00336 
00337 //: Truncate each pixel value so it fits into range [min_v,max_v]
00338 //  If value < min_v value=min_v
00339 //  If value > max_v value=max_v
00340 // \relatesalso vil_image_view
00341 template<class T>
00342 inline void vil_math_truncate_range(vil_image_view<T>& image, T min_v, T max_v)
00343 {
00344   unsigned ni = image.ni(),nj = image.nj(),np = image.nplanes();
00345   vcl_ptrdiff_t istep=image.istep(),jstep=image.jstep(),pstep = image.planestep();
00346   T* plane = image.top_left_ptr();
00347   for (unsigned p=0;p<np;++p,plane += pstep)
00348   {
00349     T* row = plane;
00350     for (unsigned j=0;j<nj;++j,row += jstep)
00351     {
00352       T* pixel = row;
00353       for (unsigned i=0;i<ni;++i,pixel+=istep)
00354       {
00355         if (*pixel<min_v) *pixel=min_v;
00356         else if (*pixel>max_v) *pixel=max_v;
00357       }
00358     }
00359   }
00360 }
00361 
00362 //: Functor class to scale by s
00363 class vil_math_scale_functor
00364 {
00365   double s_;
00366  public:
00367   vil_math_scale_functor(double s) : s_(s) {}
00368   vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x); }
00369   unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x); }
00370   short operator()(short x)   const { double r=s_*x; return short(r<0?r-0.5:r+0.5); }
00371   int operator()(int x)       const { double r=s_*x; return int(r<0?r-0.5:r+0.5); }
00372   float operator()(float x)       const { return float(s_*x); }
00373   double operator()(double x)     const { return s_*x; }
00374   vcl_complex<double> operator()(vcl_complex<double> x) const { return s_*x; }
00375 };
00376 
00377 
00378 //: Functor class to scale by s and translate (offset) by t.
00379 // \note Watch out for overflow, especially for smaller types.
00380 // \sa vil_math_scale_and_offset_values()
00381 class vil_math_scale_and_translate_functor
00382 {
00383  public:
00384   //: Constructor
00385   // \param s Scaling.
00386   // \param t Translation (offset).
00387   vil_math_scale_and_translate_functor(const double s, const double t)
00388     : s_(s), t_(t) {}
00389 
00390   vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x+t_); }
00391   unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x+t_); }
00392   short operator()(short x)       const { double r=s_*x+t_; return short(r<0?r-0.5:r+0.5); }
00393   int operator()(int x)           const { double r=s_*x+t_; return int(r<0?r-0.5:r+0.5); }
00394   float operator()(float x)       const { return float(s_*x+t_); }
00395   double operator()(double x)     const { return s_*x+t_; }
00396   vcl_complex<double> operator()(vcl_complex<double> x) const { return s_*x+t_; } // Not sure if this one makes sense
00397 
00398  private:
00399   double s_;
00400   double t_;
00401 };
00402 
00403 
00404 //: Functor class to compute logarithms (returns zero if x<=0)
00405 class vil_math_log_functor
00406 {
00407  public:
00408   vxl_byte operator()(vxl_byte x) const { return static_cast<vxl_byte>(0.5+vcl_log(double(x))); }
00409   unsigned operator()(unsigned x) const { return static_cast<unsigned int>(0.5+vcl_log(double(x))); }
00410   int operator()(int x)           const { return x>0?static_cast<int>(0.5+vcl_log(double(x))):0; }
00411   short operator()(short x)       const { return x>0?static_cast<short>(0.5+vcl_log(double(x))):0; }
00412   float operator()(float x)       const { return x>0?vcl_log(x):0.0f; }
00413   double operator()(double x)     const { return x>0?vcl_log(x):0.0; }
00414 };
00415 
00416 
00417 //: Multiply values in-place in image view by scale
00418 // \relatesalso vil_image_view
00419 template<class T>
00420 inline void vil_math_scale_values(vil_image_view<T>& image, double scale)
00421 {
00422   vil_transform(image,vil_math_scale_functor(scale));
00423 }
00424 
00425 //: Multiply values in-place in image view by scale and add offset
00426 // \relatesalso vil_image_view
00427 template<class imT, class offsetT>
00428 inline void vil_math_scale_and_offset_values(vil_image_view<imT>& image, double scale, offsetT offset)
00429 {
00430   unsigned ni = image.ni(),nj = image.nj(),np = image.nplanes();
00431   vcl_ptrdiff_t istep=image.istep(),jstep=image.jstep(),pstep = image.planestep();
00432   imT* plane = image.top_left_ptr();
00433   for (unsigned p=0;p<np;++p,plane += pstep)
00434   {
00435     imT* row = plane;
00436     for (unsigned j=0;j<nj;++j,row += jstep)
00437     {
00438       imT* pixel = row;
00439       for (unsigned i=0;i<ni;++i,pixel+=istep) *pixel = imT(scale*(*pixel)+offset);
00440     }
00441   }
00442 }
00443 
00444 //: Scale and offset values so their mean is zero and their variance is one.
00445 //  Only works on signed types!
00446 template<class imT>
00447 inline void vil_math_normalise(vil_image_view<imT>& image)
00448 {
00449   assert(image.nplanes()==1);
00450   double mean,var;
00451   vil_math_mean_and_variance(mean,var,image,0);
00452   double s=0;
00453   if (var>0) s = 1.0/vcl_sqrt(var);
00454   vil_math_scale_and_offset_values(image,s,-s*mean);
00455 }
00456 
00457 //: Computes RMS of each pixel over the planes of src image
00458 // Dest is a single plane image, $dest(i,j)^2 = 1/np sum_p src(i,j,p)^2$
00459 // Summation is performed using type destT
00460 template<class srcT, class destT>
00461 inline
00462 void vil_math_rms(const vil_image_view<srcT>& src,
00463                   vil_image_view<destT>& dest)
00464 {
00465   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00466   dest.set_size(ni,nj,1);
00467 
00468   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00469   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00470   const srcT* rowA = src.top_left_ptr();
00471   destT* rowB = dest.top_left_ptr();
00472   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00473   {
00474     const srcT* pixelA = rowA;
00475     const srcT* end_pixelA = rowA+ni*istepA;
00476     destT* pixelB = rowB;
00477 
00478     if (np==1)
00479     {
00480       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00481         *pixelB = vcl_fabs(destT(*pixelA));
00482     }
00483     else if (np==2)
00484     {
00485       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00486       {
00487         destT sum2 = destT(*pixelA)*(*pixelA)
00488                      + destT(pixelA[pstepA])*(pixelA[pstepA]);
00489         *pixelB = destT(vcl_sqrt(sum2/2));
00490       }
00491     }
00492     else
00493     {
00494       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00495       {
00496         *pixelB = destT(*pixelA)*destT(*pixelA);
00497         const srcT* p=pixelA+pstepA;
00498         const srcT* end_p=pixelA+np*pstepA;
00499         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00500         *pixelB = destT(vcl_sqrt(*pixelB/np));
00501       }
00502     }
00503   }
00504 }
00505 
00506 //: Computes Root Sum of Squares of each pixel over the planes of src image
00507 // Dest is a single plane image, $dest(i,j) = sqrt(sum_p src(i,j,p)^2)$
00508 // Differs from RMS by the scaling factor sqrt(nplanes)
00509 // Summation is performed using type destT
00510 template<class srcT, class destT>
00511 inline
00512 void vil_math_rss(const vil_image_view<srcT>& src,
00513                   vil_image_view<destT>& dest)
00514 {
00515   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00516   dest.set_size(ni,nj,1);
00517 
00518   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00519   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00520   const srcT* rowA = src.top_left_ptr();
00521   destT* rowB = dest.top_left_ptr();
00522   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00523   {
00524     const srcT* pixelA = rowA;
00525     const srcT* end_pixelA = rowA+ni*istepA;
00526     destT* pixelB = rowB;
00527 
00528     if (np==1)
00529     {
00530       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00531         *pixelB = vcl_fabs(destT(*pixelA));
00532     }
00533     else if (np==2)
00534     {
00535       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00536       {
00537         destT sum2 = destT(*pixelA)*(*pixelA)
00538                      + destT(pixelA[pstepA])*(pixelA[pstepA]);
00539         *pixelB = destT(vcl_sqrt(sum2));
00540       }
00541     }
00542     else
00543     {
00544       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00545       {
00546         *pixelB = destT(*pixelA)*destT(*pixelA);
00547         const srcT* p=pixelA+pstepA;
00548         const srcT* end_p=pixelA+np*pstepA;
00549         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00550         *pixelB = destT(vcl_sqrt(*pixelB));
00551       }
00552     }
00553   }
00554 }
00555 
00556 
00557 //: Computes sum of squares of each pixel over the planes of src image
00558 // Dest is a single plane image, $dest(i,j) = sum_p src(i,j,p)^2$
00559 // Summation is performed using type destT
00560 template<class srcT, class destT>
00561 inline
00562 void vil_math_sum_sqr(const vil_image_view<srcT>& src,
00563                       vil_image_view<destT>& dest)
00564 {
00565   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00566   dest.set_size(ni,nj,1);
00567 
00568   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00569   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00570   const srcT* rowA = src.top_left_ptr();
00571   destT* rowB = dest.top_left_ptr();
00572   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00573   {
00574     const srcT* pixelA = rowA;
00575     const srcT* end_pixelA = rowA+ni*istepA;
00576     destT* pixelB = rowB;
00577     if (np==1)
00578     {
00579       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00580         *pixelB = destT(*pixelA)*(*pixelA);
00581     }
00582     else if (np==2)
00583     {
00584       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00585         *pixelB =   destT(*pixelA)*(*pixelA)
00586                   + destT(pixelA[pstepA])*(pixelA[pstepA]);
00587     }
00588     else
00589     {
00590       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00591       {
00592         *pixelB = destT(*pixelA)*destT(*pixelA);
00593         const srcT* p=pixelA+pstepA;
00594         const srcT* end_p=pixelA+np*pstepA;
00595         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00596       }
00597     }
00598   }
00599 }
00600 
00601 //: Compute sum of two images (im_sum = imA+imB)
00602 // \relatesalso vil_image_view
00603 template<class aT, class bT, class sumT>
00604 inline void vil_math_image_sum(const vil_image_view<aT>& imA,
00605                                const vil_image_view<bT>& imB,
00606                                vil_image_view<sumT>& im_sum)
00607 {
00608   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00609   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00610   im_sum.set_size(ni,nj,np);
00611 
00612   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00613   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00614   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00615   const aT* planeA = imA.top_left_ptr();
00616   const bT* planeB = imB.top_left_ptr();
00617   sumT* planeS     = im_sum.top_left_ptr();
00618   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00619   {
00620     const aT* rowA   = planeA;
00621     const bT* rowB   = planeB;
00622     sumT* rowS = planeS;
00623     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00624     {
00625       const aT* pixelA = rowA;
00626       const bT* pixelB = rowB;
00627       sumT* pixelS = rowS;
00628       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00629         *pixelS = sumT(*pixelA)+sumT(*pixelB);
00630     }
00631   }
00632 }
00633 
00634 //: Compute pixel-wise product of two images (im_prod(i,j) = imA(i,j)*imB(i,j)
00635 //  If images have the same number of planes,
00636 //  then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,p).
00637 //  If imB only has one plane, then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0).
00638 // \relatesalso vil_image_view
00639 template<class aT, class bT, class sumT>
00640 inline void vil_math_image_product(const vil_image_view<aT>& imA,
00641                                    const vil_image_view<bT>& imB,
00642                                    vil_image_view<sumT>& im_product)
00643 {
00644   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00645   assert(imB.ni()==ni && imB.nj()==nj);
00646   assert(imB.nplanes()==1 || imB.nplanes()==np);
00647   im_product.set_size(ni,nj,np);
00648 
00649   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00650   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00651   vcl_ptrdiff_t istepP=im_product.istep(),jstepP=im_product.jstep(),
00652                 pstepP = im_product.planestep();
00653 
00654   // For one plane case, arrange that im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0)
00655   if (imB.nplanes()==1) pstepB=0;
00656 
00657   const aT* planeA = imA.top_left_ptr();
00658   const bT* planeB = imB.top_left_ptr();
00659   sumT* planeP     = im_product.top_left_ptr();
00660   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeP += pstepP)
00661   {
00662     const aT* rowA   = planeA;
00663     const bT* rowB   = planeB;
00664     sumT* rowP = planeP;
00665     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowP += jstepP)
00666     {
00667       const aT* pixelA = rowA;
00668       const bT* pixelB = rowB;
00669       sumT* pixelP = rowP;
00670       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelP+=istepP)
00671         *pixelP = sumT(*pixelA)*sumT(*pixelB);
00672     }
00673   }
00674 }
00675 
00676 //: Compute the max of two images (im_max = max(imA, imB))
00677 // \relatesalso vil_image_view
00678 template<class aT, class bT, class maxT>
00679 inline void vil_math_image_max(const vil_image_view<aT>& imA,
00680                                const vil_image_view<bT>& imB,
00681                                vil_image_view<maxT>& im_max)
00682 {
00683   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00684   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00685   im_max.set_size(ni,nj,np);
00686 
00687   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00688   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00689   vcl_ptrdiff_t istepS=im_max.istep(),jstepS=im_max.jstep(),pstepS = im_max.planestep();
00690   const aT* planeA = imA.top_left_ptr();
00691   const bT* planeB = imB.top_left_ptr();
00692   maxT* planeS     = im_max.top_left_ptr();
00693   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00694   {
00695     const aT* rowA   = planeA;
00696     const bT* rowB   = planeB;
00697     maxT* rowS = planeS;
00698     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00699     {
00700       const aT* pixelA = rowA;
00701       const bT* pixelB = rowB;
00702       maxT* pixelS = rowS;
00703       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00704         *pixelS = maxT(vcl_max(*pixelA, *pixelB));
00705     }
00706   }
00707 }
00708 
00709 //: Compute the min of two images (im_min = min(imA, imB))
00710 // \relatesalso vil_image_view
00711 template<class aT, class bT, class minT>
00712 inline void vil_math_image_min(const vil_image_view<aT>& imA,
00713                                const vil_image_view<bT>& imB,
00714                                vil_image_view<minT>& im_min)
00715 {
00716   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00717   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00718   im_min.set_size(ni,nj,np);
00719 
00720   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00721   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00722   vcl_ptrdiff_t istepS=im_min.istep(),jstepS=im_min.jstep(),pstepS = im_min.planestep();
00723   const aT* planeA = imA.top_left_ptr();
00724   const bT* planeB = imB.top_left_ptr();
00725   minT* planeS     = im_min.top_left_ptr();
00726   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00727   {
00728     const aT* rowA   = planeA;
00729     const bT* rowB   = planeB;
00730     minT* rowS = planeS;
00731     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00732     {
00733       const aT* pixelA = rowA;
00734       const bT* pixelB = rowB;
00735       minT* pixelS = rowS;
00736       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00737         *pixelS = minT(vcl_min(*pixelA, *pixelB));
00738     }
00739   }
00740 }
00741 
00742 //: Compute pixel-wise ratio of two images : im_ratio(i,j) = imA(i,j)/imB(i,j)
00743 //  Pixels cast to type sumT before calculation.
00744 //  If imB(i,j,p)==0, im_ration(i,j,p)=0
00745 //
00746 //  If images have the same number of planes,
00747 //  then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,p).
00748 //  If imB only has one plane, then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0).
00749 // \relatesalso vil_image_view
00750 template<class aT, class bT, class sumT>
00751 inline void vil_math_image_ratio(const vil_image_view<aT>& imA,
00752                                  const vil_image_view<bT>& imB,
00753                                  vil_image_view<sumT>& im_ratio)
00754 {
00755   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00756   assert(imB.ni()==ni && imB.nj()==nj);
00757   assert(imB.ni()==ni && imB.nj()==nj);
00758   assert(imB.nplanes()==1 || imB.nplanes()==np);
00759   im_ratio.set_size(ni,nj,np);
00760 
00761   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00762   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00763   vcl_ptrdiff_t istepR=im_ratio.istep(),jstepR=im_ratio.jstep(),
00764                 pstepR = im_ratio.planestep();
00765 
00766   // For one plane case, arrange that im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0)
00767   if (imB.nplanes()==1) pstepB=0;
00768 
00769   const aT* planeA = imA.top_left_ptr();
00770   const bT* planeB = imB.top_left_ptr();
00771   sumT* planeR     = im_ratio.top_left_ptr();
00772   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeR += pstepR)
00773   {
00774     const aT* rowA   = planeA;
00775     const bT* rowB   = planeB;
00776     sumT* rowR = planeR;
00777     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowR += jstepR)
00778     {
00779       const aT* pixelA = rowA;
00780       const bT* pixelB = rowB;
00781       sumT* pixelR = rowR;
00782       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelR+=istepR)
00783       if (*pixelB==0) *pixelR=0;
00784       else *pixelR = sumT(*pixelA)/sumT(*pixelB);
00785     }
00786   }
00787 }
00788 
00789 //: Compute difference of two images (im_sum = imA-imB)
00790 // \relatesalso vil_image_view
00791 template<class aT, class bT, class sumT>
00792 inline void vil_math_image_difference(const vil_image_view<aT>& imA,
00793                                       const vil_image_view<bT>& imB,
00794                                       vil_image_view<sumT>& im_sum)
00795 {
00796   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00797   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00798   im_sum.set_size(ni,nj,np);
00799 
00800   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00801   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00802   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00803   const aT* planeA = imA.top_left_ptr();
00804   const bT* planeB = imB.top_left_ptr();
00805   sumT* planeS     = im_sum.top_left_ptr();
00806   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00807   {
00808     const aT* rowA   = planeA;
00809     const bT* rowB   = planeB;
00810     sumT* rowS = planeS;
00811     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00812     {
00813       const aT* pixelA = rowA;
00814       const bT* pixelB = rowB;
00815       sumT* pixelS = rowS;
00816       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00817         *pixelS = sumT(*pixelA)-sumT(*pixelB);
00818     }
00819   }
00820 }
00821 
00822 //: Compute absolute difference of two images (im_sum = |imA-imB|)
00823 // \relatesalso vil_image_view
00824 template<class aT, class bT, class sumT>
00825 inline void vil_math_image_abs_difference(const vil_image_view<aT>& imA,
00826                                           const vil_image_view<bT>& imB,
00827                                           vil_image_view<sumT>& im_sum)
00828 {
00829   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00830   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00831   im_sum.set_size(ni,nj,np);
00832 
00833   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00834   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00835   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00836   const aT* planeA = imA.top_left_ptr();
00837   const bT* planeB = imB.top_left_ptr();
00838   sumT* planeS     = im_sum.top_left_ptr();
00839   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00840   {
00841     const aT* rowA   = planeA;
00842     const bT* rowB   = planeB;
00843     sumT* rowS = planeS;
00844     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00845     {
00846       const aT* pixelA = rowA;
00847       const bT* pixelB = rowB;
00848       sumT* pixelS = rowS;
00849       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00850       {
00851         // The following construction works for all types, including unsigned
00852         *pixelS = (*pixelA>*pixelB)?(sumT)(*pixelA-*pixelB):(sumT)(*pixelB-*pixelA);
00853       }
00854     }
00855   }
00856 }
00857 
00858 //: Compute  sum of absolute difference between two images (|imA-imB|)
00859 // \relatesalso vil_image_view
00860 template<class aT, class bT>
00861 inline double vil_math_image_abs_difference(const vil_image_view<aT>& imA,
00862                                             const vil_image_view<bT>& imB)
00863 {
00864   double sum=0.0;
00865   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00866   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00867 
00868   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00869   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00870   const aT* planeA = imA.top_left_ptr();
00871   const bT* planeB = imB.top_left_ptr();
00872   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
00873   {
00874     const aT* rowA   = planeA;
00875     const bT* rowB   = planeB;
00876     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00877     {
00878       const aT* pixelA = rowA;
00879       const bT* pixelB = rowB;
00880       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
00881       {
00882         // The following construction works for all types, including unsigned
00883         sum += (*pixelA>*pixelB?(*pixelA-*pixelB):(*pixelB-*pixelA));
00884       }
00885     }
00886   }
00887   return sum;
00888 }
00889 
00890 //: Compute magnitude of two images taken as vector components, sqrt(A^2 + B^2)
00891 // \relatesalso vil_image_view
00892 template<class aT, class bT, class magT>
00893 inline void vil_math_image_vector_mag(const vil_image_view<aT>& imA,
00894                                       const vil_image_view<bT>& imB,
00895                                       vil_image_view<magT>& im_mag)
00896 {
00897   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00898   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00899   im_mag.set_size(ni,nj,np);
00900 
00901   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00902   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00903   vcl_ptrdiff_t istepM=im_mag.istep(),jstepM=im_mag.jstep(),pstepM = im_mag.planestep();
00904   const aT* planeA = imA.top_left_ptr();
00905   const bT* planeB = imB.top_left_ptr();
00906   magT* planeM     = im_mag.top_left_ptr();
00907   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeM += pstepM)
00908   {
00909     const aT* rowA   = planeA;
00910     const bT* rowB   = planeB;
00911     magT* rowM = planeM;
00912     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowM += jstepM)
00913     {
00914       const aT* pixelA = rowA;
00915       const bT* pixelB = rowB;
00916       magT* pixelM = rowM;
00917       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelM+=istepM)
00918       {
00919         // The following construction works for all types, including unsigned
00920         magT mag_sqr = static_cast<magT>((*pixelA)*(*pixelA) + (*pixelB)*(*pixelB));
00921         magT mag = vil_math_sqrt_functor()(mag_sqr);
00922         *pixelM = mag;
00923       }
00924     }
00925   }
00926 }
00927 
00928 //: imA = fa*imA + fb*imB  (Useful for moving averages!)
00929 // Can do running sum using vil_add_image_fraction(running_mean,1-f,new_im,f)
00930 // to update current mean by a fraction f of new_im
00931 // \relatesalso vil_image_view
00932 template<class aT, class bT, class scaleT>
00933 inline void vil_math_add_image_fraction(vil_image_view<aT>& imA, scaleT fa,
00934                                         const vil_image_view<bT>& imB, scaleT fb)
00935 {
00936   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00937   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00938 
00939   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00940   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00941   aT* planeA = imA.top_left_ptr();
00942   const bT* planeB = imB.top_left_ptr();
00943   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
00944   {
00945     aT* rowA   = planeA;
00946     const bT* rowB   = planeB;
00947     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00948     {
00949       aT* pixelA = rowA;
00950       const bT* pixelB = rowB;
00951       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
00952         *pixelA = aT(fa*(*pixelA)+fb*(*pixelB));
00953     }
00954   }
00955 }
00956 
00957 //: Compute integral image im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
00958 //  Useful thing for quickly computing mean over large regions,
00959 //  as demonstrated in Viola and Jones (CVPR01).
00960 // The sum of elements in the ni x nj square with corner (i,j)
00961 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
00962 // \relatesalso vil_image_view
00963 template<class aT, class sumT>
00964 inline void vil_math_integral_image(const vil_image_view<aT>& imA,
00965                                     vil_image_view<sumT>& im_sum)
00966 {
00967   assert(imA.nplanes()==1);
00968   unsigned ni = imA.ni(),nj = imA.nj();
00969   unsigned ni1=ni+1;
00970   unsigned nj1=nj+1;
00971   im_sum.set_size(ni1,nj1,1);
00972 
00973   // Put zeros along first row of im_sum
00974   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
00975   sumT* rowS     = im_sum.top_left_ptr();
00976   sumT* pixelS = rowS;
00977   for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
00978     *pixelS=0;
00979 
00980   // Now sum from original image (imA)
00981   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
00982   const aT* rowA = imA.top_left_ptr();
00983 
00984   sumT sum;
00985   vcl_ptrdiff_t prev_j = -jstepS;
00986   rowS += jstepS;
00987 
00988   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS)
00989   {
00990     const aT* pixelA = rowA;
00991     pixelS = rowS;
00992     sum = 0;
00993     // set first value at start of each row to zero!
00994     *pixelS = 0;
00995     pixelS+=istepS;
00996     for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS)
00997     { sum+= (sumT)(*pixelA); *pixelS=sum + pixelS[prev_j];}
00998   }
00999 }
01000 
01001 //: Compute integral image im_sum_sq(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)^2
01002 // Also computes sum im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
01003 //
01004 //  Useful thing for quickly computing mean and variance over large regions,
01005 //  as demonstrated in Viola and Jones (CVPR01).
01006 //
01007 // The sum of elements in the ni x nj square with corner (i,j)
01008 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
01009 //
01010 // Similar result holds for sum of squares, allowing rapid calculation of variance etc.
01011 // \relatesalso vil_image_view
01012 template<class aT, class sumT>
01013 inline void vil_math_integral_sqr_image(const vil_image_view<aT>& imA,
01014                                         vil_image_view<sumT>& im_sum,
01015                                         vil_image_view<sumT>& im_sum_sq)
01016 {
01017   assert(imA.nplanes()==1);
01018   unsigned ni = imA.ni(),nj = imA.nj();
01019   unsigned ni1=ni+1;
01020   unsigned nj1=nj+1;
01021   im_sum.set_size(ni1,nj1,1);
01022   im_sum_sq.set_size(ni1,nj1,1);
01023 
01024   // Put zeros along first row of im_sum & im_sum_sq
01025   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
01026   vcl_ptrdiff_t istepS2=im_sum_sq.istep(),jstepS2=im_sum_sq.jstep();
01027   sumT* rowS     = im_sum.top_left_ptr();
01028   sumT* rowS2     = im_sum_sq.top_left_ptr();
01029   // im_sum
01030   sumT* pixelS = rowS;
01031   for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
01032     *pixelS=0;
01033 
01034   // im_sum_sq
01035   sumT* pixelS2 = rowS2;
01036   for (unsigned i=0;i<ni1;++i,pixelS2+=istepS2)
01037     *pixelS2=0;
01038 
01039   // Now sum from original image (imA)
01040   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
01041   const aT* rowA = imA.top_left_ptr();
01042 
01043   sumT sum,sum2;
01044   vcl_ptrdiff_t prev_j = -jstepS;
01045   vcl_ptrdiff_t prev_j2 = -jstepS2;
01046   rowS += jstepS;
01047   rowS2 += jstepS2;
01048 
01049   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS,rowS2 += jstepS2)
01050   {
01051     const aT* pixelA = rowA;
01052     pixelS = rowS;
01053     pixelS2 = rowS2;
01054     sum = 0;
01055     sum2 = 0;
01056     // set first value at start of each row to zero!
01057     *pixelS = 0;
01058     *pixelS2 = 0;
01059     pixelS+=istepS;
01060     pixelS2+=istepS2;
01061     for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS,pixelS2+=istepS2)
01062     {
01063       sum+= (sumT)(*pixelA);
01064       *pixelS=sum + pixelS[prev_j];
01065       sum2+=sumT(*pixelA)*sumT(*pixelA);
01066       *pixelS2 = sum2 + pixelS2[prev_j2];
01067     }
01068   }
01069 }
01070 
01071 #endif // vil_math_h_