Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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