contrib/mul/vil3d/vil3d_math.h
Go to the documentation of this file.
00001 // This is mul/vil3d/vil3d_math.h
00002 #ifndef vil3d_math_h_
00003 #define vil3d_math_h_
00004 //:
00005 // \file
00006 // \brief Various mathematical manipulations of 3D images
00007 // \author Tim Cootes
00008 
00009 #include <vcl_cassert.h>
00010 #include <vcl_vector.h>
00011 // not used? #include <vcl_functional.h> // for std::less<T>
00012 #include <vil3d/vil3d_image_view.h>
00013 #include <vil3d/vil3d_plane.h>
00014 #include <vcl_algorithm.h>
00015 
00016 
00017 //: Compute minimum and maximum values over im
00018 // \relatesalso vil3d_image_view
00019 template <class T>
00020 inline void vil3d_math_value_range(const vil3d_image_view<T>& im,
00021                                    T& min_value, T& max_value)
00022 {
00023   if (im.size()==0)
00024   {
00025     min_value = 0;
00026     max_value = 0;
00027     return;
00028   }
00029 
00030   const T* plane = im.origin_ptr();
00031   min_value = *plane;
00032   max_value = min_value;
00033 
00034   unsigned ni = im.ni();
00035   unsigned nj = im.nj();
00036   unsigned nk = im.nk();
00037   unsigned np = im.nplanes();
00038   vcl_ptrdiff_t istep = im.istep(), jstep=im.jstep(), kstep=im.kstep();
00039 
00040   for (unsigned int p=0;p<np;++p, plane += im.planestep())
00041   {
00042     const T* slice = plane;
00043     for (unsigned int k=0;k<nk;++k, slice += kstep)
00044     {
00045       const T* row = slice;
00046       for (unsigned int j=0;j<nj;++j, row += jstep)
00047       {
00048         const T* pixel = row;
00049         for (unsigned int i=0;i<ni;++i, pixel+=istep)
00050         {
00051           if (*pixel<min_value)      min_value = *pixel;
00052           else if (*pixel>max_value) max_value = *pixel;
00053         }
00054       }
00055     }
00056   }
00057 }
00058 
00059 
00060 //: Compute value corresponding to a percentile of the range of im.
00061 // Percentiles expressed as fraction, e.g. 0.05, or 0.95.
00062 // \param im The image to examine.
00063 // \param fraction The fraction of the data range (from the lower end).
00064 // \retval value The image data value corresponding to the specified percentile.
00065 // \relatesalso vil3d_image_view
00066 // \note This function requires the sorting of large parts of the image data
00067 // and can be very expensive in terms of both processing and memory.
00068 // \sa vil3d_math_value_range_percentiles()
00069 template <class T>
00070 inline void vil3d_math_value_range_percentile(const vil3d_image_view<T>& im,
00071                                               const double fraction,
00072                                               T& value)
00073 {
00074   vcl_vector<double> fractions(1, fraction);
00075   vcl_vector<T> values;
00076   vil3d_math_value_range_percentiles(im, fractions, values);
00077   if (values.size() > 0)
00078     value = values[0]; // Bounds-checked access in case previous line failed.
00079 }
00080 
00081 
00082 //: Compute value corresponding to several percentiles of the range of im.
00083 // Percentiles expressed as fraction, e.g. 0.05, or 0.95.
00084 // \param im The image to examine.
00085 // \param fraction The fraction of the data range (from the lower end).
00086 // \retval value The image data value corresponding to the specified percentiles.
00087 // \relatesalso vil3d_image_view
00088 // \note This function requires the sorting of large parts of the image data
00089 // and can be very expensive in terms of both processing and memory.
00090 template <class T>
00091 inline void vil3d_math_value_range_percentiles(const vil3d_image_view<T>& im,
00092                                                const vcl_vector<double> fraction,
00093                                                vcl_vector<T>& value)
00094 {
00095   value.clear();
00096 
00097   // Test for invalid inputs
00098   if (im.size()==0)
00099   {
00100     return;
00101   }
00102   unsigned nfrac = fraction.size();
00103   for (unsigned f=0; f<nfrac; ++f)
00104   {
00105     if (fraction[f]<0.0 || fraction[f]>1.0)
00106       return;
00107   }
00108 
00109   // Copy the pixel values into a local list.
00110   unsigned ni = im.ni();
00111   unsigned nj = im.nj();
00112   unsigned nk = im.nk();
00113   unsigned np = im.nplanes();
00114   vcl_ptrdiff_t istep = im.istep();
00115   vcl_ptrdiff_t jstep=im.jstep();
00116   vcl_ptrdiff_t kstep=im.kstep();
00117   vcl_ptrdiff_t pstep = im.planestep();
00118   vcl_vector<T> data(ni*nj*nk*np);
00119 
00120   typename vcl_vector<T>::iterator it = data.begin();
00121   const T* plane = im.origin_ptr();
00122   for (unsigned int p=0;p<np;++p, plane += pstep)
00123   {
00124     const T* slice = plane;
00125     for (unsigned int k=0;k<nk;++k, slice += kstep)
00126     {
00127       const T* row = slice;
00128       for (unsigned int j=0;j<nj;++j, row += jstep)
00129       {
00130         const T* pixel = row;
00131         for (unsigned int i=0;i<ni;++i, pixel+=istep)
00132         {
00133           *it = *pixel;
00134           it++;
00135         }
00136       }
00137     }
00138   }
00139   unsigned npix = data.size();
00140 
00141   // Get the nth_element corresponding to the specified fractions
00142   value.resize(nfrac);
00143   for (unsigned f=0; f<nfrac; ++f)
00144   {
00145     unsigned index = static_cast<unsigned>(fraction[f]*npix - 0.5);
00146     typename vcl_vector<T>::iterator index_it = data.begin() + index;
00147     vcl_nth_element(data.begin(), index_it, data.end());
00148     value[f] = *index_it;
00149   }
00150 }
00151 
00152 
00153 //: Calc the mean of each pixel over all the planes.
00154 // \relatesalso vil3d_image_view
00155 template<class aT, class sumT>
00156 inline void vil3d_math_mean_over_planes(const vil3d_image_view<aT>& src,
00157                                         vil3d_image_view<sumT>& dest)
00158 {
00159   dest.set_size(src.ni(), src.nj(), src.nk(), 1);
00160   for (unsigned k=0;k<src.nk();++k)
00161     for (unsigned j=0;j<src.nj();++j)
00162       for (unsigned i=0;i<src.ni();++i)
00163       {
00164         sumT sum=0;
00165         for (unsigned p=0;p<src.nplanes();++p)
00166           sum += (sumT) src(i,j,k,p);
00167         dest(i,j,k) = sum / src.nplanes();
00168       }
00169 }
00170 
00171 //: Calc the mean of each pixel over all the planes.
00172 // \relatesalso vil3d_image_view
00173 template<class inT, class outT, class sumT>
00174 inline void vil3d_math_mean_over_planes(const vil3d_image_view<inT>& src,
00175                                         vil3d_image_view<outT>& dest,
00176                                         sumT /*dummy*/)
00177 {
00178   dest.set_size(src.ni(), src.nj(), src.nk(), 1);
00179   for (unsigned k=0;k<src.nk();++k)
00180     for (unsigned j=0;j<src.nj();++j)
00181       for (unsigned i=0;i<src.ni();++i)
00182       {
00183         sumT sum=0;
00184         for (unsigned p=0;p<src.nplanes();++p)
00185           sum += static_cast<sumT>(src(i,j,k,p));
00186         dest(i,j,k) = static_cast<outT>(sum / src.nplanes());
00187       }
00188 }
00189 
00190 //: Calculate the rms of each pixel over all the planes.
00191 // \relatesalso vil3d_image_view
00192 template<class inT, class outT, class sumT>
00193 inline void vil3d_math_rms(const vil3d_image_view<inT>& src,
00194                            vil3d_image_view<outT>& dest,
00195                            sumT /*dummy*/)
00196 {
00197   dest.set_size(src.ni(), src.nj(), src.nk(), 1);
00198   for (unsigned k=0;k<src.nk();++k)
00199     for (unsigned j=0;j<src.nj();++j)
00200       for (unsigned i=0;i<src.ni();++i)
00201       {
00202         sumT sum_sqr=0;
00203         for (unsigned p=0;p<src.nplanes();++p)
00204           sum_sqr += static_cast<sumT>(src(i,j,k,p))*static_cast<sumT>(src(i,j,k,p));
00205         dest(i,j,k) = static_cast<outT>(vcl_sqrt(sum_sqr / src.nplanes()));
00206       }
00207 }
00208 
00209 
00210 //: Compute sum of values in plane p
00211 // \relatesalso vil3d_image_view
00212 template <class imT, class sumT>
00213 inline void vil3d_math_sum(sumT& sum, const vil3d_image_view<imT>& im,
00214                            unsigned p)
00215 {
00216   assert(p<im.nplanes());
00217   sum=0;
00218   if (im.size()==0)
00219   {
00220     return;
00221   }
00222 
00223   const imT* plane = im.origin_ptr();
00224   unsigned ni = im.ni();
00225   unsigned nj = im.nj();
00226   unsigned nk = im.nk();
00227   vcl_ptrdiff_t istep = im.istep(), jstep=im.jstep(), kstep=im.kstep();
00228 
00229   const imT* slice = plane + p*im.planestep();
00230   for (unsigned int k=0;k<nk;++k, slice += kstep)
00231   {
00232     const imT* row = slice;
00233     for (unsigned int j=0;j<nj;++j, row += jstep)
00234     {
00235       const imT* pixel = row;
00236       for (unsigned int i=0;i<ni;++i, pixel+=istep) sum += sumT(*pixel);
00237     }
00238   }
00239 }
00240 
00241 //: Mean of elements in plane p of image
00242 // \relatesalso vil3d_image_view
00243 template <class imT, class sumT>
00244 inline void vil3d_math_mean(sumT& mean, const vil3d_image_view<imT>& im,
00245                             unsigned p)
00246 {
00247   if (im.size()==0) { mean=0; return; }
00248   vil3d_math_sum(mean,im,p);
00249   mean/=(im.ni()*im.nj()*im.nk());
00250 }
00251 
00252 
00253 //: Sum of squares of elements in plane p of image
00254 // \relatesalso vil3d_image_view
00255 template <class imT, class sumT>
00256 inline void vil3d_math_sum_squares(sumT& sum, sumT& sum_sq,
00257                                    const vil3d_image_view<imT>& im, unsigned p)
00258 {
00259   assert(p<im.nplanes());
00260   sum = 0; sum_sq=0;
00261   if (im.size()==0)
00262   {
00263     return;
00264   }
00265 
00266   const imT* plane = im.origin_ptr();
00267   unsigned ni = im.ni();
00268   unsigned nj = im.nj();
00269   unsigned nk = im.nk();
00270   vcl_ptrdiff_t istep = im.istep(), jstep=im.jstep(), kstep=im.kstep();
00271 
00272   const imT* slice = plane + p*im.planestep();
00273   for (unsigned int k=0;k<nk;++k, slice += kstep)
00274   {
00275     const imT* row = slice;
00276     for (unsigned int j=0;j<nj;++j, row += jstep)
00277     {
00278       const imT* r = row;
00279       for (unsigned int i=0;i<ni;++i, r+=istep)
00280       { sum += *r; sum_sq+=sumT(*r)*sumT(*r); }
00281     }
00282   }
00283 }
00284 
00285 
00286 //: Sum of squared differences between two images
00287 // \relatesalso vil_image_view
00288 template <class imT, class sumT>
00289 inline sumT vil3d_math_ssd(const vil3d_image_view<imT>& imA,
00290                            const vil3d_image_view<imT>& imB, sumT /*dummy*/)
00291 {
00292   assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() &&
00293          imB.nk() == imB.nk() && imA.nplanes() == imB.nplanes());
00294   sumT ssd=0;
00295   for (unsigned p=0;p<imA.nplanes();++p)
00296     for (unsigned k=0;k<imA.nk();++k)
00297       for (unsigned j=0;j<imA.nj();++j)
00298         for (unsigned i=0;i<imA.ni();++i)
00299         {
00300           const sumT v = ((sumT)imA(i,j,k,p) - (sumT)imB(i,j,k,p));
00301           ssd += v*v;
00302         }
00303   return ssd;
00304 }
00305 
00306 
00307 //: Multiply values in-place in image view by scale and add offset
00308 // \relatesalso vil3d_image_view
00309 template<class imT, class offsetT>
00310 inline void vil3d_math_scale_and_offset_values(vil3d_image_view<imT>& image,
00311                                                double scale, offsetT offset)
00312 {
00313   unsigned ni = image.ni(), nj = image.nj(),
00314     nk = image.nk(), np = image.nplanes();
00315   vcl_ptrdiff_t istep=image.istep(), jstep=image.jstep(),
00316     kstep = image.kstep(), pstep = image.planestep();
00317   imT* plane = image.origin_ptr();
00318   for (unsigned p=0;p<np;++p,plane += pstep)
00319   {
00320     imT* slice = plane;
00321     for (unsigned k=0;k<nk;++k,slice += kstep)
00322     {
00323       imT* row = slice;
00324       for (unsigned j=0;j<nj;++j,row += jstep)
00325       {
00326         imT* pixel = row;
00327         for (unsigned i=0;i<ni;++i,pixel+=istep)
00328           *pixel = imT(scale*(*pixel)+offset);
00329       }
00330     }
00331   }
00332 }
00333 
00334 
00335 //: Mean and variance of elements in plane p of image
00336 // \relatesalso vil3d_image_view
00337 template <class imT, class sumT>
00338 inline void vil3d_math_mean_and_variance(sumT& mean, sumT& var,
00339                                          const vil3d_image_view<imT>& im,
00340                                          unsigned p)
00341 {
00342   if (im.size()==0) { mean=0; var=0; return; }
00343   sumT sum, sum_sq;
00344   vil3d_math_sum_squares(sum,sum_sq,im,p);
00345   mean = sum/(im.ni()*im.nj()*im.nk());
00346   var = sum_sq/(im.ni()*im.nj()*im.nk()) - mean*mean;
00347 }
00348 
00349 
00350 //: Mean and variance of elements in plane p of image
00351 // \relatesalso vil3d_image_view
00352 template <class imT, class sumT>
00353 inline sumT vil3d_math_dot_product(const vil3d_image_view<imT>& imA,
00354                                    const vil3d_image_view<imT>& imB, sumT)
00355 {
00356   assert(imA.ni() == imB.ni() && imB.nj() == imB.nj() &&
00357          imB.nk() == imB.nk() && imA.nplanes() == imB.nplanes());
00358   sumT dp=0;
00359   for (unsigned p=0;p<imA.nplanes();++p)
00360     for (unsigned k=0;k<imA.nk();++k)
00361       for (unsigned j=0;j<imA.nj();++j)
00362         for (unsigned i=0;i<imA.ni();++i)
00363           dp += (sumT)imA(i,j,k,p) * (sumT)imB(i,j,k,p);
00364   return dp;
00365 }
00366 
00367 
00368 //: Compute difference of two images (im_sum = imA-imB)
00369 // \relatesalso vil_image_view
00370 template<class aT, class bT, class sumT>
00371 inline void vil3d_math_image_difference(const vil3d_image_view<aT>& imA,
00372                                         const vil3d_image_view<bT>& imB,
00373                                         vil3d_image_view<sumT>& im_sum)
00374 {
00375   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk(),np = imA.nplanes();
00376   assert(imB.ni()==ni && imB.nj()==nj && imB.nk()==nk && imB.nplanes()==np);
00377   im_sum.set_size(ni,nj,nk,np);
00378 
00379   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),kstepA=imA.kstep(),pstepA = imA.planestep();
00380   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),kstepB=imB.kstep(),pstepB = imB.planestep();
00381   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),kstepS=im_sum.kstep(),pstepS = im_sum.planestep();
00382   const aT* planeA = imA.origin_ptr();
00383   const bT* planeB = imB.origin_ptr();
00384   sumT* planeS     = im_sum.origin_ptr();
00385   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00386   {
00387     const aT* sliceA   = planeA;
00388     const bT* sliceB   = planeB;
00389     sumT* sliceS = planeS;
00390     for (unsigned k=0;k<nk;++k,sliceA += kstepA,sliceB += kstepB,sliceS += kstepS)
00391     {
00392       const aT* rowA = sliceA;
00393       const bT* rowB = sliceB;
00394       sumT* rowS = sliceS;
00395       for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00396       {
00397         const aT* pixelA = rowA;
00398         const bT* pixelB = rowB;
00399         sumT* pixelS = rowS;
00400         for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00401           *pixelS = sumT(*pixelA)-sumT(*pixelB);
00402       }
00403     }
00404   }
00405 }
00406 
00407 //: Compute sum of two images (im_sum = imA+imB)
00408 // \relatesalso vil_image_view
00409 template<class aT, class bT, class sumT>
00410 inline void vil3d_math_image_sum(const vil3d_image_view<aT>& imA,
00411                                  const vil3d_image_view<bT>& imB,
00412                                  vil3d_image_view<sumT>& im_sum)
00413 {
00414   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk(),np = imA.nplanes();
00415   assert(imB.ni()==ni && imB.nj()==nj && imB.nk()==nk && imB.nplanes()==np);
00416   im_sum.set_size(ni,nj,nk,np);
00417 
00418   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),kstepA=imA.kstep(),pstepA = imA.planestep();
00419   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),kstepB=imB.kstep(),pstepB = imB.planestep();
00420   vcl_ptrdiff_t istepS=im_sum.istep(),jstepS=im_sum.jstep(),kstepS=im_sum.kstep(),pstepS = im_sum.planestep();
00421   const aT* planeA = imA.origin_ptr();
00422   const bT* planeB = imB.origin_ptr();
00423   sumT* planeS     = im_sum.origin_ptr();
00424   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00425   {
00426     const aT* sliceA   = planeA;
00427     const bT* sliceB   = planeB;
00428     sumT* sliceS = planeS;
00429     for (unsigned k=0;k<nk;++k,sliceA += kstepA,sliceB += kstepB,sliceS += kstepS)
00430     {
00431       const aT* rowA = sliceA;
00432       const bT* rowB = sliceB;
00433       sumT* rowS = sliceS;
00434       for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00435       {
00436         const aT* pixelA = rowA;
00437         const bT* pixelB = rowB;
00438         sumT* pixelS = rowS;
00439         for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00440           *pixelS = sumT(*pixelA)+sumT(*pixelB);
00441       }
00442     }
00443   }
00444 }
00445 
00446 //: Compute pixel-wise product of two images (im_prod = imA*imB)
00447 // \relatesalso vil_image_view
00448 template<class aT, class bT, class prodT>
00449 inline void vil3d_math_image_product(const vil3d_image_view<aT>& imA,
00450                                      const vil3d_image_view<bT>& imB,
00451                                      vil3d_image_view<prodT>& im_prod)
00452 {
00453   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk(),np = imA.nplanes();
00454   assert(imB.ni()==ni && imB.nj()==nj && imB.nk()==nk && imB.nplanes()==np);
00455   im_prod.set_size(ni,nj,nk,np);
00456 
00457   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),kstepA=imA.kstep(),pstepA = imA.planestep();
00458   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),kstepB=imB.kstep(),pstepB = imB.planestep();
00459   vcl_ptrdiff_t istepS=im_prod.istep(),jstepS=im_prod.jstep(),kstepS=im_prod.kstep(),pstepS = im_prod.planestep();
00460   const aT* planeA = imA.origin_ptr();
00461   const bT* planeB = imB.origin_ptr();
00462   prodT* planeS     = im_prod.origin_ptr();
00463   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB,planeS += pstepS)
00464   {
00465     const aT* sliceA   = planeA;
00466     const bT* sliceB   = planeB;
00467     prodT* sliceS = planeS;
00468     for (unsigned k=0;k<nk;++k,sliceA += kstepA,sliceB += kstepB,sliceS += kstepS)
00469     {
00470       const aT* rowA = sliceA;
00471       const bT* rowB = sliceB;
00472       prodT* rowS = sliceS;
00473       for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB,rowS += jstepS)
00474       {
00475         const aT* pixelA = rowA;
00476         const bT* pixelB = rowB;
00477         prodT* pixelS = rowS;
00478         for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB,pixelS+=istepS)
00479           *pixelS = prodT(*pixelA)*prodT(*pixelB);
00480       }
00481     }
00482   }
00483 }
00484 
00485 
00486 //: imA = fa*imA + fb*imB  (Useful for moving averages!)
00487 // Can do running sum using vil_add_image_fraction(running_mean,1-f,new_im,f)
00488 // to update current mean by a fraction f of new_im
00489 // \relatesalso vil_image_view
00490 template<class aT, class bT, class scaleT>
00491 inline void vil3d_math_add_image_fraction(vil3d_image_view<aT>& imA, scaleT fa,
00492                                           const vil3d_image_view<bT>& imB, scaleT fb)
00493 {
00494   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk(),np = imA.nplanes();
00495   assert(imB.ni()==ni && imB.nj()==nj && imB.nk()==nk && imB.nplanes()==np);
00496 
00497   vcl_ptrdiff_t istepA=imA.istep(),jstepA=imA.jstep(),kstepA=imA.kstep(),pstepA = imA.planestep();
00498   vcl_ptrdiff_t istepB=imB.istep(),jstepB=imB.jstep(),kstepB=imB.kstep(),pstepB = imB.planestep();
00499   aT* planeA = imA.origin_ptr();
00500   const bT* planeB = imB.origin_ptr();
00501   for (unsigned p=0;p<np;++p,planeA += pstepA,planeB += pstepB)
00502   {
00503     aT* sliceA   = planeA;
00504     const bT* sliceB   = planeB;
00505     for (unsigned k=0;k<nk;++k,sliceA += kstepA,sliceB += kstepB)
00506     {
00507       aT* rowA = sliceA;
00508       const bT* rowB = sliceB;
00509       for (unsigned j=0;j<nj;++j,rowA += jstepA,rowB += jstepB)
00510       {
00511         aT* pixelA = rowA;
00512         const bT* pixelB = rowB;
00513         for (unsigned i=0;i<ni;++i,pixelA+=istepA,pixelB+=istepB)
00514           *pixelA = aT(fa*(*pixelA)+fb*(*pixelB));
00515       }
00516     }
00517   }
00518 }
00519 
00520 //: Truncate each pixel value so it fits into range [min_v,max_v]
00521 //  If value < min_v value=min_v
00522 //  If value > max_v value=max_v
00523 // \relatesalso vil3d_image_view
00524 template<class T>
00525 inline void vil3d_math_truncate_range(vil3d_image_view<T>& image,
00526                                       T min_v, T max_v)
00527 {
00528   unsigned ni=image.ni(), nj=image.nj(), nk=image.nk(), np=image.nplanes();
00529   vcl_ptrdiff_t istep=image.istep(), jstep=image.jstep(),
00530                 kstep=image.kstep(), pstep=image.planestep();
00531   T* plane = image.origin_ptr();
00532   for (unsigned p=0; p<np; ++p, plane+=pstep)
00533   {
00534     T* slice = plane;
00535     for (unsigned k=0; k<nk; ++k, slice+=kstep)
00536     {
00537       T* row = slice;
00538       for (unsigned j=0; j<nj; ++j, row+=jstep)
00539       {
00540         T* pixel = row;
00541         for (unsigned i=0; i<ni; ++i, pixel+=istep)
00542         {
00543           if (*pixel<min_v) *pixel=min_v;
00544           else if (*pixel>max_v) *pixel=max_v;
00545         }
00546       }
00547     }
00548   }
00549 }
00550 
00551 //: Calc integral image im_sum(i+1,j+1,k+1)= sum (x<=i,y<=j,z<=k) imA(x,y,z)
00552 //  Useful thing for quickly computing mean over large regions,
00553 //  as demonstrated in Viola and Jones (CVPR01).
00554 // The sum of elements in the ni x nj x nk volume with corner (i,j,k)
00555 // is given by
00556 // im_sum(i,j,k+nk)+im_sum(i+ni,j+nj,j+nk)+im_sum(i,j+nj,k)+im_sum(i+ni,j,k)
00557 // -im_sum(i,j,k)-im_sum(i+ni,j+nj,k)-im_sum(i+ni,n,k_nk)-im_sum(i,j+nj,k+nk
00558 // \relatesalso vil_image_view
00559 template<class aT, class sumT>
00560 inline void vil3d_math_integral_image(const vil3d_image_view<aT>& imA,
00561                                     vil3d_image_view<sumT>& im_sum)
00562 {
00563   assert(imA.nplanes()==1);
00564   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk();
00565   unsigned ni1=ni+1;
00566   unsigned nj1=nj+1;
00567   unsigned nk1=nk+1;
00568   im_sum.set_size(ni1,nj1,nk1,1);
00569 
00570   // Put zeros along first plane of im_sum
00571   vcl_ptrdiff_t istepS=im_sum.istep();
00572   vcl_ptrdiff_t jstepS=im_sum.jstep();
00573   vcl_ptrdiff_t kstepS=im_sum.kstep();
00574   sumT* planeS = im_sum.origin_ptr();
00575   sumT* rowS = planeS;
00576   sumT* voxelS;
00577   for (unsigned j=0;j<nj1;++j,rowS += jstepS)
00578   {
00579     voxelS = rowS;
00580     for (unsigned i=0;i<ni1;++i,voxelS+=istepS)
00581       *voxelS=0;
00582   }
00583 
00584   // Now sum from original image (imA)
00585   vcl_ptrdiff_t istepA=imA.istep();
00586   vcl_ptrdiff_t jstepA=imA.jstep();
00587   vcl_ptrdiff_t kstepA=imA.kstep();
00588 
00589   const aT* planeA = imA.origin_ptr();
00590 
00591   sumT sum;
00592   vcl_ptrdiff_t prev_j = -jstepS;
00593   vcl_ptrdiff_t prev_k = -kstepS;
00594   planeS += kstepS;
00595 
00596   // for each plane, do a 2D integral image first
00597   for (unsigned k=0;k<nk;++k,planeA += kstepA,planeS += kstepS)
00598   {
00599     const aT* rowA = planeA;
00600     rowS = planeS;
00601 
00602     // Put zeros along first row in plane
00603     voxelS = rowS;
00604     for (unsigned i=0;i<ni1;++i,voxelS += istepS)
00605       *voxelS = 0;
00606     rowS += jstepS;
00607 
00608     // Compute integral sums for rest of plane
00609     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS)
00610     {
00611       const aT* voxelA = rowA;
00612       voxelS = rowS;
00613       sum = 0;
00614 
00615       // set value at first column of each row to zero!
00616       *voxelS = 0;
00617       voxelS += istepS;
00618 
00619       // compute the 2D integral image
00620       for (unsigned i=1; i<ni1;++i,voxelA+=istepA,voxelS+=istepS)
00621       {
00622         sum += *voxelA;
00623         *voxelS = sum + voxelS[prev_j];
00624       }
00625     }    
00626   }
00627  
00628   // Go through from plane 2 to end and add values of voxels in plane
00629   // above to get the 3D integral image
00630   planeS = im_sum.origin_ptr() + 2*kstepS;
00631   for (unsigned k=2;k<nk1;k++,planeS += kstepS)
00632   {
00633     // Skip first row in each plane
00634     rowS = planeS+jstepS;
00635     for (unsigned j=1;j<nj1;j++,rowS += jstepS)
00636     {
00637       // Skip first col in each row
00638       voxelS = rowS+istepS;
00639       for (unsigned i=1;i<ni1;i++,voxelS += istepS)
00640         *voxelS += voxelS[prev_k];
00641     }
00642   }
00643 
00644 }
00645 
00646 
00647 //: Calc integral image im_sum_sq(i+1,j+1,k+1) = sum (x<=i,y<=j,z<=k) imA^2
00648 //  Also calcs integral image, im_sum(i+1,j+1,k+1 = sum (x=i,y<=j,z<=kk) imA
00649 //  Useful thing for quickly computing mean and variance over large regions,
00650 //  as demonstrated in Viola and Jones (CVPR01).
00651 // The sum of elements in the ni x nj x nk volume with corner (i,j,k)
00652 // is given by:
00653 // im_sum(i,j,k+nk)+im_sum(i+ni,j+nj,j+nk)+im_sum(i,j+nj,k)+im_sum(i+ni,j,k)
00654 // -im_sum(i,j,k)-im_sum(i+ni,j+nj,k)-im_sum(i+ni,n,k_nk)-im_sum(i,j+nj,k+nk
00655 // \relatesalso vil_image_view
00656 template<class aT, class sumT>
00657 inline void vil3d_math_integral_sqr_image(const vil3d_image_view<aT>& imA,
00658                                     vil3d_image_view<sumT>& im_sum,
00659                                     vil3d_image_view<sumT>& im_sum_sq)
00660 {
00661   assert(imA.nplanes()==1);
00662   unsigned ni = imA.ni(),nj = imA.nj(),nk = imA.nk();
00663   unsigned ni1=ni+1;
00664   unsigned nj1=nj+1;
00665   unsigned nk1=nk+1;
00666   im_sum.set_size(ni1,nj1,nk1,1);
00667   im_sum_sq.set_size(ni1,nj1,nk1,1);
00668 
00669   // Put zeros along first plane of im_sum & im_sum_sq
00670   vcl_ptrdiff_t istepS=im_sum.istep();
00671   vcl_ptrdiff_t istepS2=im_sum_sq.istep();
00672   vcl_ptrdiff_t jstepS=im_sum.jstep();
00673   vcl_ptrdiff_t jstepS2=im_sum_sq.jstep();
00674   vcl_ptrdiff_t kstepS=im_sum.kstep();
00675   vcl_ptrdiff_t kstepS2=im_sum_sq.kstep();
00676   sumT* planeS = im_sum.origin_ptr();
00677   sumT* planeS2 = im_sum_sq.origin_ptr();
00678   sumT* rowS = planeS;
00679   sumT* rowS2 = planeS2;
00680   sumT *voxelS, *voxelS2;
00681 
00682   // im_sum
00683   for (unsigned j=0;j<nj1;++j,rowS += jstepS)
00684   {
00685     voxelS = rowS;
00686     for (unsigned i=0;i<ni1;++i,voxelS+=istepS)
00687       *voxelS=0;
00688   }
00689 
00690   // im_sum_sq
00691   for (unsigned j=0;j<nj1;++j,rowS2 += jstepS2)
00692   {
00693     voxelS2 = rowS2;
00694     for (unsigned i=0;i<ni1;++i,voxelS2+=istepS2)
00695       *voxelS2=0;
00696   }
00697 
00698   // Now sum from original image (imA)
00699   vcl_ptrdiff_t istepA=imA.istep();
00700   vcl_ptrdiff_t jstepA=imA.jstep();
00701   vcl_ptrdiff_t kstepA=imA.kstep();
00702 
00703   const aT* planeA = imA.origin_ptr();
00704 
00705   sumT sum, sum2;
00706   vcl_ptrdiff_t prev_j = -jstepS;
00707   vcl_ptrdiff_t prev_k = -kstepS;
00708   vcl_ptrdiff_t prev_j2 = -jstepS2;
00709   vcl_ptrdiff_t prev_k2 = -kstepS2;
00710   planeS += kstepS;
00711   planeS2 += kstepS2;
00712 
00713   // for each plane, do a 2D integral image first
00714   for (unsigned k=0;k<nk;++k,planeA+=kstepA,planeS+=kstepS,planeS2+=kstepS2)
00715   {
00716     const aT* rowA = planeA;
00717     rowS = planeS;
00718     rowS2 = planeS2;
00719 
00720     // Put zeros along first row in plane
00721     voxelS = rowS;
00722     voxelS2 = rowS2;
00723     for (unsigned i=0;i<ni1;++i,voxelS += istepS, voxelS2 += istepS2)
00724     {
00725       *voxelS = 0;
00726       *voxelS2 = 0;
00727     }
00728     rowS += jstepS;
00729     rowS2 += jstepS2;
00730 
00731     // Compute integral sums for rest of plane
00732     for (unsigned j=0;j<nj;++j,rowA += jstepA,rowS += jstepS,rowS2+=jstepS2)
00733     {
00734       const aT* voxelA = rowA;
00735       voxelS = rowS;
00736       voxelS2 = rowS2;
00737       sum = 0;
00738       sum2 = 0;
00739 
00740       // set value at first column of each row to zero!
00741       *voxelS = 0;
00742       *voxelS2 = 0;
00743       voxelS += istepS;
00744       voxelS2 += istepS2;
00745 
00746       // compute the 2D integral image
00747       for (unsigned i=1;i<ni1;++i,voxelA+=istepA,
00748                                   voxelS+=istepS,voxelS2+=istepS2)
00749       {
00750         sum += *voxelA;
00751         *voxelS = sum + voxelS[prev_j];
00752         sum2 += sumT(*voxelA)*sumT(*voxelA);
00753         *voxelS2 = sum2 + voxelS2[prev_j2];
00754       }
00755     }    
00756   }
00757  
00758   // Go through from plane 2 to end and add values of voxels in plane
00759   // above to get the 3D integral image
00760   planeS = im_sum.origin_ptr() + 2*kstepS;
00761   planeS2 = im_sum_sq.origin_ptr() + 2*kstepS2;
00762   for (unsigned k=2;k<nk1;k++,planeS += kstepS, planeS2 += kstepS2)
00763   {
00764     // Skip first row in each plane
00765     rowS = planeS+jstepS;
00766     rowS2 = planeS2+jstepS2;
00767     for (unsigned j=1;j<nj1;j++,rowS += jstepS,rowS2 += jstepS2)
00768     {
00769       // Skip first col in each row
00770       voxelS = rowS+istepS;
00771       voxelS2 = rowS2+istepS2;
00772       for (unsigned i=1;i<ni1;i++,voxelS += istepS,voxelS2 += istepS2)
00773       {
00774         *voxelS += voxelS[prev_k];
00775         *voxelS2 += voxelS2[prev_k2];
00776       }
00777     }
00778   }
00779 
00780 }
00781 
00782 
00783 #endif