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 // \relates 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 unsigned nfrac = fraction.size();
00095   for (unsigned 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 unsigned 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 // \relates 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 // \relates 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 // \relates 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 // \relates 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) = sum / src.nplanes();
00216     }
00217 }
00218 
00219 //: Calc the mean of each pixel over all the planes.
00220 // \relates 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 // \relates 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+=*v;
00251   }
00252 }
00253 
00254 //: Mean of elements in plane p of image
00255 // \relates 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/=(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 the median is half way between two
00271 // values, the result will be the floor of the average.
00272 //
00273 // \relates 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 // \relates 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 // \relates 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/(im.ni()*im.nj());
00313   var = sum_sq/(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 // \relates 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 // \relates 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  private:
00366   double s_;
00367  public:
00368   vil_math_scale_functor(double s) : s_(s) {}
00369   vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x); }
00370   unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x); }
00371   short operator()(short x)   const { double r=s_*x; return short(r<0?r-0.5:r+0.5); }
00372   int operator()(int x)       const { double r=s_*x; return int(r<0?r-0.5:r+0.5); }
00373   float operator()(float x)       const { return float(s_*x); }
00374   double operator()(double x)     const { return s_*x; }
00375   vcl_complex<double> operator()(vcl_complex<double> x) const { return s_*x; }
00376 };
00377 
00378 
00379 //: Functor class to scale by s and translate (offset) by t.
00380 // \note Watch out for overflow, especially for smaller types.
00381 // \sa vil_math_scale_and_offset_values()
00382 class vil_math_scale_and_translate_functor
00383 {
00384  public:
00385   //: Constructor
00386   // \param s Scaling.
00387   // \param t Translation (offset).
00388   vil_math_scale_and_translate_functor(const double s, const double t)
00389     : s_(s), t_(t) {}
00390 
00391   vxl_byte operator()(vxl_byte x) const { return vxl_byte(0.5+s_*x+t_); }
00392   unsigned operator()(unsigned x) const { return unsigned(0.5+s_*x+t_); }
00393   short operator()(short x)       const { double r=s_*x+t_; return short(r<0?r-0.5:r+0.5); }
00394   int operator()(int x)           const { double r=s_*x+t_; return int(r<0?r-0.5:r+0.5); }
00395   float operator()(float x)       const { return float(s_*x+t_); }
00396   double operator()(double x)     const { return s_*x+t_; }
00397   vcl_complex<double> operator()(vcl_complex<double> x) const { return s_*x+t_; } // Not sure if this one makes sense
00398 
00399  private:
00400   double s_;
00401   double t_;
00402 };
00403 
00404 
00405 //: Functor class to compute logarithms (returns zero if x<=0)
00406 class vil_math_log_functor
00407 {
00408  public:
00409   vxl_byte operator()(vxl_byte x) const { return static_cast<vxl_byte>(0.5+vcl_log(double(x))); }
00410   unsigned operator()(unsigned x) const { return static_cast<unsigned int>(0.5+vcl_log(double(x))); }
00411   int operator()(int x)           const { return x>0?static_cast<int>(0.5+vcl_log(double(x))):0; }
00412   short operator()(short x)       const { return x>0?static_cast<short>(0.5+vcl_log(double(x))):0; }
00413   float operator()(float x)       const { return x>0?vcl_log(x):0.0f; }
00414   double operator()(double x)     const { return x>0?vcl_log(x):0.0; }
00415 };
00416 
00417 
00418 //: Multiply values in-place in image view by scale
00419 // \relates vil_image_view
00420 template<class T>
00421 inline void vil_math_scale_values(vil_image_view<T>& image, double scale)
00422 {
00423   vil_transform(image,vil_math_scale_functor(scale));
00424 }
00425 
00426 //: Multiply values in-place in image view by scale and add offset
00427 // \relates vil_image_view
00428 template<class imT, class offsetT>
00429 inline void vil_math_scale_and_offset_values(vil_image_view<imT>& image, double scale, offsetT offset)
00430 {
00431   unsigned ni = image.ni(),nj = image.nj(),np = image.nplanes();
00432   vcl_ptrdiff_t istep=image.istep(),jstep=image.jstep(),pstep = image.planestep();
00433   imT* plane = image.top_left_ptr();
00434   for (unsigned p=0;p<np;++p,plane += pstep)
00435   {
00436     imT* row = plane;
00437     for (unsigned j=0;j<nj;++j,row += jstep)
00438     {
00439       imT* pixel = row;
00440       for (unsigned i=0;i<ni;++i,pixel+=istep) *pixel = imT(scale*(*pixel)+offset);
00441     }
00442   }
00443 }
00444 
00445 //: Scale and offset values so their mean is zero and their variance is one.
00446 //  Only works on signed types!
00447 template<class imT>
00448 inline void vil_math_normalise(vil_image_view<imT>& image)
00449 {
00450   assert(image.nplanes()==1);
00451   double mean,var;
00452   vil_math_mean_and_variance(mean,var,image,0);
00453   double s=0;
00454   if (var>0) s = 1.0/vcl_sqrt(var);
00455   vil_math_scale_and_offset_values(image,s,-s*mean);
00456 }
00457 
00458 //: Computes RMS of each pixel over the planes of src image
00459 // Dest is a single plane image, $dest(i,j)^2 = 1/np sum_p src(i,j,p)^2$
00460 // Summation is performed using type destT
00461 template<class srcT, class destT>
00462 inline
00463 void vil_math_rms(const vil_image_view<srcT>& src,
00464                   vil_image_view<destT>& dest)
00465 {
00466   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00467   dest.set_size(ni,nj,1);
00468 
00469   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00470   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00471   const srcT* rowA = src.top_left_ptr();
00472   destT* rowB = dest.top_left_ptr();
00473   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00474   {
00475     const srcT* pixelA = rowA;
00476     const srcT* end_pixelA = rowA+ni*istepA;
00477     destT* pixelB = rowB;
00478 
00479     if (np==1)
00480     {
00481       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00482         *pixelB = vcl_fabs(destT(*pixelA));
00483     }
00484     else if (np==2)
00485     {
00486       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00487       {
00488         destT sum2 = destT(*pixelA)*(*pixelA)
00489                      + destT(pixelA[pstepA])*(pixelA[pstepA]);
00490         *pixelB = destT(vcl_sqrt(sum2/2));
00491       }
00492     }
00493     else
00494     {
00495       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00496       {
00497         *pixelB = destT(*pixelA)*destT(*pixelA);
00498         const srcT* p=pixelA+pstepA;
00499         const srcT* end_p=pixelA+np*pstepA;
00500         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00501         *pixelB = destT(vcl_sqrt(*pixelB/np));
00502       }
00503     }
00504   }
00505 }
00506 
00507 //: Computes Root Sum of Squares of each pixel over the planes of src image
00508 // Dest is a single plane image, $dest(i,j) = sqrt(sum_p src(i,j,p)^2)$
00509 // Differs from RMS by the scaling factor sqrt(nplanes)
00510 // Summation is performed using type destT
00511 template<class srcT, class destT>
00512 inline
00513 void vil_math_rss(const vil_image_view<srcT>& src,
00514                   vil_image_view<destT>& dest)
00515 {
00516   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00517   dest.set_size(ni,nj,1);
00518 
00519   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00520   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00521   const srcT* rowA = src.top_left_ptr();
00522   destT* rowB = dest.top_left_ptr();
00523   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00524   {
00525     const srcT* pixelA = rowA;
00526     const srcT* end_pixelA = rowA+ni*istepA;
00527     destT* pixelB = rowB;
00528 
00529     if (np==1)
00530     {
00531       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00532         *pixelB = vcl_fabs(destT(*pixelA));
00533     }
00534     else if (np==2)
00535     {
00536       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00537       {
00538         destT sum2 = destT(*pixelA)*(*pixelA)
00539                      + destT(pixelA[pstepA])*(pixelA[pstepA]);
00540         *pixelB = destT(vcl_sqrt(sum2));
00541       }
00542     }
00543     else
00544     {
00545       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00546       {
00547         *pixelB = destT(*pixelA)*destT(*pixelA);
00548         const srcT* p=pixelA+pstepA;
00549         const srcT* end_p=pixelA+np*pstepA;
00550         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00551         *pixelB = destT(vcl_sqrt(*pixelB));
00552       }
00553     }
00554   }
00555 }
00556 
00557 
00558 //: Computes sum of squares of each pixel over the planes of src image
00559 // Dest is a single plane image, $dest(i,j) = sum_p src(i,j,p)^2$
00560 // Summation is performed using type destT
00561 template<class srcT, class destT>
00562 inline
00563 void vil_math_sum_sqr(const vil_image_view<srcT>& src,
00564                       vil_image_view<destT>& dest)
00565 {
00566   unsigned ni = src.ni(),nj = src.nj(),np = src.nplanes();
00567   dest.set_size(ni,nj,1);
00568 
00569   vcl_ptrdiff_t istepA=src.istep(),jstepA=src.jstep(),pstepA = src.planestep();
00570   vcl_ptrdiff_t istepB=dest.istep(),jstepB=dest.jstep();
00571   const srcT* rowA = src.top_left_ptr();
00572   destT* rowB = dest.top_left_ptr();
00573   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00574   {
00575     const srcT* pixelA = rowA;
00576     const srcT* end_pixelA = rowA+ni*istepA;
00577     destT* pixelB = rowB;
00578     if (np==1)
00579     {
00580       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00581         *pixelB = destT(*pixelA)*(*pixelA);
00582     }
00583     else if (np==2)
00584     {
00585       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00586         *pixelB =   destT(*pixelA)*(*pixelA)
00587                   + destT(pixelA[pstepA])*(pixelA[pstepA]);
00588     }
00589     else
00590     {
00591       for (;pixelA!=end_pixelA; pixelA+=istepA,pixelB+=istepB)
00592       {
00593         *pixelB = destT(*pixelA)*destT(*pixelA);
00594         const srcT* p=pixelA+pstepA;
00595         const srcT* end_p=pixelA+np*pstepA;
00596         for (;p!=end_p;p+=pstepA) *pixelB += destT(*p)*destT(*p);
00597       }
00598     }
00599   }
00600 }
00601 
00602 //: Compute sum of two images (im_sum = imA+imB)
00603 // \relates vil_image_view
00604 template<class aT, class bT, class sumT>
00605 inline void vil_math_image_sum(const vil_image_view<aT>& imA,
00606                                const vil_image_view<bT>& imB,
00607                                vil_image_view<sumT>& im_sum)
00608 {
00609   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00610   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00611   im_sum.set_size(ni,nj,np);
00612 
00613   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00614   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00615   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00616   const aT* planeA = imA.top_left_ptr();
00617   const bT* planeB = imB.top_left_ptr();
00618   sumT* planeS     = im_sum.top_left_ptr();
00619   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00620   {
00621     const aT* rowA   = planeA;
00622     const bT* rowB   = planeB;
00623     sumT* rowS = planeS;
00624     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00625     {
00626       const aT* pixelA = rowA;
00627       const bT* pixelB = rowB;
00628       sumT* pixelS = rowS;
00629       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00630         *pixelS = sumT(*pixelA)+sumT(*pixelB);
00631     }
00632   }
00633 }
00634 
00635 //: Compute pixel-wise product of two images (im_prod(i,j) = imA(i,j)*imB(i,j)
00636 //  If images have the same number of planes,
00637 //  then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,p).
00638 //  If imB only has one plane, then im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0).
00639 // \relates vil_image_view
00640 template<class aT, class bT, class sumT>
00641 inline void vil_math_image_product(const vil_image_view<aT>& imA,
00642                                    const vil_image_view<bT>& imB,
00643                                    vil_image_view<sumT>& im_product)
00644 {
00645   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00646   assert(imB.ni()==ni && imB.nj()==nj);
00647   assert(imB.nplanes()==1 || imB.nplanes()==np);
00648   im_product.set_size(ni,nj,np);
00649 
00650   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00651   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00652   vcl_ptrdiff_t istepP=im_product.istep(),jstepP=im_product.jstep(),
00653                 pstepP = im_product.planestep();
00654 
00655   // For one plane case, arrange that im_prod(i,j,p) = imA(i,j,p)*imB(i,j,0)
00656   if (imB.nplanes()==1) pstepB=0;
00657 
00658   const aT* planeA = imA.top_left_ptr();
00659   const bT* planeB = imB.top_left_ptr();
00660   sumT* planeP     = im_product.top_left_ptr();
00661   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeP += pstepP)
00662   {
00663     const aT* rowA   = planeA;
00664     const bT* rowB   = planeB;
00665     sumT* rowP = planeP;
00666     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowP += jstepP)
00667     {
00668       const aT* pixelA = rowA;
00669       const bT* pixelB = rowB;
00670       sumT* pixelP = rowP;
00671       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelP+=istepP)
00672         *pixelP = sumT(*pixelA)*sumT(*pixelB);
00673     }
00674   }
00675 }
00676 
00677 //: Compute the max of two images (im_max = max(imA, imB))
00678 // \relates vil_image_view
00679 template<class aT, class bT, class maxT>
00680 inline void vil_math_image_max(const vil_image_view<aT>& imA,
00681                                const vil_image_view<bT>& imB,
00682                                vil_image_view<maxT>& im_max)
00683 {
00684   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00685   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00686   im_max.set_size(ni,nj,np);
00687 
00688   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00689   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00690   vcl_ptrdiff_t istepS=im_max.istep(),jstepS=im_max.jstep(),pstepS = im_max.planestep();
00691   const aT* planeA = imA.top_left_ptr();
00692   const bT* planeB = imB.top_left_ptr();
00693   maxT* planeS     = im_max.top_left_ptr();
00694   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00695   {
00696     const aT* rowA   = planeA;
00697     const bT* rowB   = planeB;
00698     maxT* rowS = planeS;
00699     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00700     {
00701       const aT* pixelA = rowA;
00702       const bT* pixelB = rowB;
00703       maxT* pixelS = rowS;
00704       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00705         *pixelS = maxT(vcl_max(*pixelA, *pixelB));
00706     }
00707   }
00708 }
00709 
00710 //: Compute the min of two images (im_min = min(imA, imB))
00711 // \relates vil_image_view
00712 template<class aT, class bT, class minT>
00713 inline void vil_math_image_min(const vil_image_view<aT>& imA,
00714                                const vil_image_view<bT>& imB,
00715                                vil_image_view<minT>& im_min)
00716 {
00717   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00718   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00719   im_min.set_size(ni,nj,np);
00720 
00721   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00722   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00723   vcl_ptrdiff_t istepS=im_min.istep(),jstepS=im_min.jstep(),pstepS = im_min.planestep();
00724   const aT* planeA = imA.top_left_ptr();
00725   const bT* planeB = imB.top_left_ptr();
00726   minT* planeS     = im_min.top_left_ptr();
00727   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00728   {
00729     const aT* rowA   = planeA;
00730     const bT* rowB   = planeB;
00731     minT* rowS = planeS;
00732     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00733     {
00734       const aT* pixelA = rowA;
00735       const bT* pixelB = rowB;
00736       minT* pixelS = rowS;
00737       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00738         *pixelS = minT(vcl_min(*pixelA, *pixelB));
00739     }
00740   }
00741 }
00742 
00743 //: Compute pixel-wise ratio of two images : im_ratio(i,j) = imA(i,j)/imB(i,j)
00744 //  Pixels cast to type sumT before calculation.
00745 //  If imB(i,j,p)==0, im_ration(i,j,p)=0
00746 //
00747 //  If images have the same number of planes,
00748 //  then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,p).
00749 //  If imB only has one plane, then im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0).
00750 // \relates vil_image_view
00751 template<class aT, class bT, class sumT>
00752 inline void vil_math_image_ratio(const vil_image_view<aT>& imA,
00753                                  const vil_image_view<bT>& imB,
00754                                  vil_image_view<sumT>& im_ratio)
00755 {
00756   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00757   assert(imB.ni()==ni && imB.nj()==nj);
00758   assert(imB.ni()==ni && imB.nj()==nj);
00759   assert(imB.nplanes()==1 || imB.nplanes()==np);
00760   im_ratio.set_size(ni,nj,np);
00761 
00762   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00763   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00764   vcl_ptrdiff_t istepR=im_ratio.istep(),jstepR=im_ratio.jstep(),
00765                 pstepR = im_ratio.planestep();
00766 
00767   // For one plane case, arrange that im_ratio(i,j,p) = imA(i,j,p)/imB(i,j,0)
00768   if (imB.nplanes()==1) pstepB=0;
00769 
00770   const aT* planeA = imA.top_left_ptr();
00771   const bT* planeB = imB.top_left_ptr();
00772   sumT* planeR     = im_ratio.top_left_ptr();
00773   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeR += pstepR)
00774   {
00775     const aT* rowA   = planeA;
00776     const bT* rowB   = planeB;
00777     sumT* rowR = planeR;
00778     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowR += jstepR)
00779     {
00780       const aT* pixelA = rowA;
00781       const bT* pixelB = rowB;
00782       sumT* pixelR = rowR;
00783       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelR+=istepR)
00784       if (*pixelB==0) *pixelR=0;
00785       else *pixelR = sumT(*pixelA)/sumT(*pixelB);
00786     }
00787   }
00788 }
00789 
00790 //: Compute difference of two images (im_sum = imA-imB)
00791 // \relates vil_image_view
00792 template<class aT, class bT, class sumT>
00793 inline void vil_math_image_difference(const vil_image_view<aT>& imA,
00794                                       const vil_image_view<bT>& imB,
00795                                       vil_image_view<sumT>& im_sum)
00796 {
00797   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00798   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00799   im_sum.set_size(ni,nj,np);
00800 
00801   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00802   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00803   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00804   const aT* planeA = imA.top_left_ptr();
00805   const bT* planeB = imB.top_left_ptr();
00806   sumT* planeS     = im_sum.top_left_ptr();
00807   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00808   {
00809     const aT* rowA   = planeA;
00810     const bT* rowB   = planeB;
00811     sumT* rowS = planeS;
00812     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00813     {
00814       const aT* pixelA = rowA;
00815       const bT* pixelB = rowB;
00816       sumT* pixelS = rowS;
00817       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00818         *pixelS = sumT(*pixelA)-sumT(*pixelB);
00819     }
00820   }
00821 }
00822 
00823 //: Compute absolute difference of two images (im_sum = |imA-imB|)
00824 // \relates vil_image_view
00825 template<class aT, class bT, class sumT>
00826 inline void vil_math_image_abs_difference(const vil_image_view<aT>& imA,
00827                                           const vil_image_view<bT>& imB,
00828                                           vil_image_view<sumT>& im_sum)
00829 {
00830   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00831   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00832   im_sum.set_size(ni,nj,np);
00833 
00834   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00835   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00836   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),pstepS = im_sum.planestep();
00837   const aT* planeA = imA.top_left_ptr();
00838   const bT* planeB = imB.top_left_ptr();
00839   sumT* planeS     = im_sum.top_left_ptr();
00840   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00841   {
00842     const aT* rowA   = planeA;
00843     const bT* rowB   = planeB;
00844     sumT* rowS = planeS;
00845     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00846     {
00847       const aT* pixelA = rowA;
00848       const bT* pixelB = rowB;
00849       sumT* pixelS = rowS;
00850       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00851       {
00852         // The following construction works for all types, including unsigned
00853         *pixelS = (sumT)(*pixelA>*pixelB?(*pixelA-*pixelB):(*pixelB-*pixelA));
00854       }
00855     }
00856   }
00857 }
00858 
00859 //: Compute  sum of absolute difference between two images (|imA-imB|)
00860 // \relates vil_image_view
00861 template<class aT, class bT>
00862 inline double vil_math_image_abs_difference(const vil_image_view<aT>& imA,
00863                                             const vil_image_view<bT>& imB)
00864 {
00865   double sum=0.0;
00866   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00867   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00868 
00869   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00870   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00871   const aT* planeA = imA.top_left_ptr();
00872   const bT* planeB = imB.top_left_ptr();
00873   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
00874   {
00875     const aT* rowA   = planeA;
00876     const bT* rowB   = planeB;
00877     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00878     {
00879       const aT* pixelA = rowA;
00880       const bT* pixelB = rowB;
00881       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
00882       {
00883         // The following construction works for all types, including unsigned
00884         sum += (*pixelA>*pixelB?(*pixelA-*pixelB):(*pixelB-*pixelA));
00885       }
00886     }
00887   }
00888   return sum;
00889 }
00890 
00891 //: Compute magnitude of two images taken as vector components, sqrt(A^2 + B^2)
00892 // \relates vil_image_view
00893 template<class aT, class bT, class magT>
00894 inline void vil_math_image_vector_mag(const vil_image_view<aT>& imA,
00895                                       const vil_image_view<bT>& imB,
00896                                       vil_image_view<magT>& im_mag)
00897 {
00898   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00899   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00900   im_mag.set_size(ni,nj,np);
00901 
00902   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00903   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00904   vcl_ptrdiff_t istepM=im_mag.istep(),jstepM=im_mag.jstep(),pstepM = im_mag.planestep();
00905   const aT* planeA = imA.top_left_ptr();
00906   const bT* planeB = imB.top_left_ptr();
00907   magT* planeM     = im_mag.top_left_ptr();
00908   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeM += pstepM)
00909   {
00910     const aT* rowA   = planeA;
00911     const bT* rowB   = planeB;
00912     magT* rowM = planeM;
00913     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowM += jstepM)
00914     {
00915       const aT* pixelA = rowA;
00916       const bT* pixelB = rowB;
00917       magT* pixelM = rowM;
00918       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelM+=istepM)
00919       {
00920         // The following construction works for all types, including unsigned
00921         magT mag_sqr = static_cast<magT>((*pixelA)*(*pixelA) + (*pixelB)*(*pixelB));
00922         magT mag = vil_math_sqrt_functor()(mag_sqr);
00923         *pixelM = mag;
00924       }
00925     }
00926   }
00927 }
00928 
00929 //: imA = fa*imA + fb*imB  (Useful for moving averages!)
00930 // Can do running sum using vil_add_image_fraction(running_mean,1-f,new_im,f)
00931 // to update current mean by a fraction f of new_im
00932 // \relates vil_image_view
00933 template<class aT, class bT, class scaleT>
00934 inline void vil_math_add_image_fraction(vil_image_view<aT>& imA, scaleT fa,
00935                                         const vil_image_view<bT>& imB, scaleT fb)
00936 {
00937   unsigned ni = imA.ni(),nj = imA.nj(),np = imA.nplanes();
00938   assert(imB.ni()==ni && imB.nj()==nj && imB.nplanes()==np);
00939 
00940   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),pstepA = imA.planestep();
00941   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),pstepB = imB.planestep();
00942   aT* planeA = imA.top_left_ptr();
00943   const bT* planeB = imB.top_left_ptr();
00944   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
00945   {
00946     aT* rowA   = planeA;
00947     const bT* rowB   = planeB;
00948     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00949     {
00950       aT* pixelA = rowA;
00951       const bT* pixelB = rowB;
00952       for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
00953         *pixelA = aT(fa*(*pixelA)+fb*(*pixelB));
00954     }
00955   }
00956 }
00957 
00958 //: Compute integral image im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
00959 //  Useful thing for quickly computing mean over large regions,
00960 //  as demonstrated in Viola and Jones (CVPR01).
00961 // The sum of elements in the ni x nj square with corner (i,j)
00962 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
00963 // \relates vil_image_view
00964 template<class aT, class sumT>
00965 inline void vil_math_integral_image(const vil_image_view<aT>& imA,
00966                                     vil_image_view<sumT>& im_sum)
00967 {
00968   assert(imA.nplanes()==1);
00969   unsigned ni = imA.ni(),nj = imA.nj();
00970   unsigned ni1=ni+1;
00971   unsigned nj1=nj+1;
00972   im_sum.set_size(ni1,nj1,1);
00973 
00974 
00975   // Put zeros along first row of im_sum
00976   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
00977   sumT* rowS     = im_sum.top_left_ptr();
00978   sumT* pixelS = rowS;
00979   for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
00980     *pixelS=0;
00981 
00982   // Now sum from original image (imA)
00983   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
00984   const aT* rowA = imA.top_left_ptr();
00985 
00986   sumT sum;
00987   vcl_ptrdiff_t prev_j = -jstepS;
00988   rowS += jstepS;
00989 
00990   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS)
00991   {
00992     const aT* pixelA = rowA;
00993     pixelS = rowS;
00994     sum = 0;
00995     // set first value at start of each row to zero!
00996     *pixelS = 0;
00997     pixelS+=istepS;
00998     for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS)
00999     { sum+= *pixelA; *pixelS=sum + pixelS[prev_j];}
01000   }
01001 }
01002 
01003 //: Compute integral image im_sum_sq(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)^2
01004 // Also computes sum im_sum(i+1,j+1) = sum (x<=i,y<=j) imA(x,y)
01005 //
01006 //  Useful thing for quickly computing mean and variance over large regions,
01007 //  as demonstrated in Viola and Jones (CVPR01).
01008 //
01009 // The sum of elements in the ni x nj square with corner (i,j)
01010 // is given by im_sum(i,j)+im_sum(i+ni,j+nj)-im_sum(i+ni,j)-im_sum(i,j+nj)
01011 //
01012 // Similar result holds for sum of squares, allowing rapid calculation of variance etc.
01013 // \relates vil_image_view
01014 template<class aT, class sumT>
01015 inline void vil_math_integral_sqr_image(const vil_image_view<aT>& imA,
01016                                         vil_image_view<sumT>& im_sum,
01017                                         vil_image_view<sumT>& im_sum_sq)
01018 {
01019   assert(imA.nplanes()==1);
01020   unsigned ni = imA.ni(),nj = imA.nj();
01021   unsigned ni1=ni+1;
01022   unsigned nj1=nj+1;
01023   im_sum.set_size(ni1,nj1,1);
01024   im_sum_sq.set_size(ni1,nj1,1);
01025 
01026 
01027   // Put zeros along first row of im_sum & im_sum_sq
01028   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep();
01029   vcl_ptrdiff_t istepS2=im_sum_sq.istep(),jstepS2=im_sum_sq.jstep();
01030   sumT* rowS     = im_sum.top_left_ptr();
01031   sumT* rowS2     = im_sum_sq.top_left_ptr();
01032   // im_sum
01033   sumT* pixelS = rowS;
01034   for (unsigned i=0;i<ni1;++i,pixelS+=istepS)
01035     *pixelS=0;
01036 
01037   // im_sum_sq
01038   sumT* pixelS2 = rowS2;
01039   for (unsigned i=0;i<ni1;++i,pixelS2+=istepS2)
01040     *pixelS2=0;
01041 
01042   // Now sum from original image (imA)
01043   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep();
01044   const aT* rowA = imA.top_left_ptr();
01045 
01046   sumT sum,sum2;
01047   vcl_ptrdiff_t prev_j = -jstepS;
01048   vcl_ptrdiff_t prev_j2 = -jstepS2;
01049   rowS += jstepS;
01050   rowS2 += jstepS2;
01051 
01052   for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS,rowS2 += jstepS2)
01053   {
01054     const aT* pixelA = rowA;
01055     pixelS = rowS;
01056     pixelS2 = rowS2;
01057     sum = 0;
01058     sum2 = 0;
01059     // set first value at start of each row to zero!
01060     *pixelS = 0;
01061     *pixelS2 = 0;
01062     pixelS+=istepS;
01063     pixelS2+=istepS2;
01064     for (unsigned i=1;i<ni1;++i,pixelA+=istepA,pixelS+=istepS,pixelS2+=istepS2)
01065     {
01066       sum+= *pixelA;
01067       *pixelS=sum + pixelS[prev_j];
01068       sum2+=sumT(*pixelA)*sumT(*pixelA);
01069       *pixelS2 = sum2 + pixelS2[prev_j2];
01070     }
01071   }
01072 }
01073 
01074 #endif // vil_math_h_

Generated on Mon Nov 23 05:08:37 2009 for core/vil by  doxygen 1.5.1