LowPass.C

Go to the documentation of this file.
00001 /*!@file Image/LowPass.C low-pass filtering and smoothing functions */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/LowPass.C $
00035 // $Id: LowPass.C 12962 2010-03-06 02:13:53Z irock $
00036 //
00037 
00038 #ifndef IMAGE_LOWPASS_C_DEFINED
00039 #define IMAGE_LOWPASS_C_DEFINED
00040 
00041 #include "Image/LowPass.H"
00042 
00043 #include "Image/Convolutions.H"
00044 #include "Image/Image.H"
00045 #include "Image/Kernels.H"
00046 #include "Image/Pixels.H"
00047 #include "rutz/trace.h"
00048 
00049 namespace
00050 {
00051   // helper function for median3x()/median3y()/median3()
00052   template <class T>
00053   T median3scalar(T a, T b, T c)
00054   {
00055     if (b < a) { T t = b; b = a; a = t; }
00056     if (c < b) { T t = c; c = b; b = t; }
00057     if (b < a) { T t = b; b = a; a = t; }
00058 
00059     return b;
00060   }
00061 
00062   // helper function for median3x()/median3y()/median3()
00063   template <class T>
00064   PixRGB<T> median3scalar(PixRGB<T> a, PixRGB<T> b, PixRGB<T> c)
00065   {
00066     return PixRGB<T>(median3scalar(a.p[0], b.p[0], c.p[0]),
00067                      median3scalar(a.p[1], b.p[1], c.p[1]),
00068                      median3scalar(a.p[2], b.p[2], c.p[2]));
00069   }
00070 
00071   Image<PixRGB<float> > lowPass3x_rgb(const Image<PixRGB<float> >& src)
00072   {
00073     const int w = src.getWidth(), h = src.getHeight();
00074     if (w < 2) return src; // nothing to smooth
00075     Image<PixRGB<float> > result(w, h, NO_INIT);
00076     Image<PixRGB<float> >::const_iterator sptr = src.begin();
00077     Image<PixRGB<float> >::iterator dptr = result.beginw();
00078 
00079     // *** unfolded version (all particular cases treated) for max speed.
00080     // do not use access overload since can access the C array directly.
00081     // the bet is: float computations are faster than int (true for most
00082     // float copros), and int2float converts fast->do not have to divide
00083     // by the coeff sum since we directly use float coeffs.
00084     // notations: in () is the position of dest ptr, and ^ is src ptr
00085     // ########## horizontal pass
00086     for (int j = 0; j < h; j ++)
00087       {
00088         // leftmost point  [ (2^) 1 ] / 3
00089         dptr->setRed(sptr[0].red() * (2.0F / 3.0F)
00090           + sptr[1].red() * (1.0F / 3.0F));
00091         dptr->setGreen(sptr[0].green() * (2.0F / 3.0F)
00092           + sptr[1].green() * (1.0F / 3.0F));
00093         dptr->setBlue(sptr[0].blue() * (2.0F / 3.0F)
00094           + sptr[1].blue() * (1.0F / 3.0F));
00095         ++dptr;
00096 
00097         // rest of the line except last point  [ 1^ (2) 1 ] / 4
00098         for (int i = 0; i < w - 2; i ++)
00099           {
00100             dptr->setRed((sptr[0].red() + sptr[2].red())
00101               * 0.25F + sptr[1].red() * 0.5F);
00102             dptr->setGreen((sptr[0].green() + sptr[2].green())
00103               * 0.25F + sptr[1].green() * 0.5F);
00104             dptr->setBlue((sptr[0].blue() + sptr[2].blue())
00105               * 0.25F + sptr[1].blue() * 0.5F);
00106             ++dptr;
00107             ++sptr;
00108           }
00109 
00110         // last point [ 1^ (2) ] / 3
00111         dptr->setRed(sptr[0].red() * (1.0F / 3.0f)
00112           + sptr[1].red() * (2.0F / 3.0F));
00113         dptr->setGreen(sptr[0].green() * (1.0F / 3.0f)
00114           + sptr[1].green() * (2.0F / 3.0F));
00115         dptr->setBlue(sptr[0].blue() * (1.0F / 3.0f)
00116           + sptr[1].blue() * (2.0F / 3.0F));
00117         ++dptr;
00118         sptr += 2;  // sptr back to same position as dptr
00119       }
00120     return result;
00121   }
00122 
00123   Image<PixRGB<float> > lowPass3y_rgb(const Image<PixRGB<float> >& src)
00124   {
00125     const int w = src.getWidth(), h = src.getHeight();
00126     if (h < 2) return src; // nothing to smooth
00127     Image<PixRGB<float> > result(w, h, NO_INIT);
00128     Image<PixRGB<float> >::const_iterator sptr = src.begin();
00129     Image<PixRGB<float> >::iterator dptr = result.beginw();
00130     const int w2 = w * 2; // speedup
00131 
00132     // ########## vertical pass  (even though we scan horiz for speedup)
00133     // topmost points  ( [ (2^) 1 ] / 3 )^T
00134     for (int i = 0; i < w; i ++)
00135       {
00136         //*dptr = sptr[0] * (2.0F / 3.0F) + sptr[w] * (1.0F / 3.0F);
00137         dptr->setRed(sptr[0].red() * (2.0F / 3.0F)
00138           + sptr[w].red() * (1.0F / 3.0F));
00139         dptr->setGreen(sptr[0].green() * (2.0F / 3.0F)
00140           + sptr[w].green() * (1.0F / 3.0F));
00141         dptr->setBlue(sptr[0].blue() * (2.0F / 3.0F)
00142           + sptr[w].blue() * (1.0F / 3.0F));
00143         ++dptr;
00144         ++sptr;
00145       }
00146     sptr -= w;  // go back to top-left
00147 
00148     // rest of the column except last point ( [ 1^ (2) 1 ] / 4.0 )^T
00149     for (int j = 0; j < h - 2; j ++)
00150       for (int i = 0; i < w; i ++)
00151         {
00152           //*dptr = (sptr[0] + sptr[w2]) * 0.25F + sptr[w] * 0.5F;
00153           dptr->setRed((sptr[0].red() + sptr[w2].red())
00154             * 0.25F + sptr[w].red() * 0.5F);
00155           dptr->setGreen((sptr[0].green() + sptr[w2].green())
00156             * 0.25F + sptr[w].green() * 0.5F);
00157           dptr->setBlue((sptr[0].blue() + sptr[w2].blue())
00158             * 0.25F + sptr[w].blue() * 0.5F);
00159           ++dptr;
00160           ++sptr;
00161         }
00162 
00163     // last points ( [ 1^ (2) ] / 3 )^T
00164     for (int i = 0; i < w; i ++)
00165       {
00166         //*dptr = sptr[0] * (1.0F / 3.0F) + sptr[w] * (2.0F / 3.0F);
00167         dptr->setRed(sptr[0].red() * (1.0F / 3.0F) + sptr[w].red()
00168           * (2.0F / 3.0F));
00169         dptr->setGreen(sptr[0].green() * (1.0F / 3.0F) + sptr[w].green()
00170           * (2.0F / 3.0F));
00171         dptr->setBlue(sptr[0].blue() * (1.0F / 3.0F) + sptr[w].blue()
00172           * (2.0F / 3.0F));
00173         ++dptr;
00174         ++sptr;
00175       }
00176 
00177     // finished. here, sptr is one line before the end of array.
00178     return result;
00179   }
00180 }
00181 
00182 // ######################################################################
00183 template <>
00184 Image<promote_trait<PixRGB<float>, float>::TP>
00185 lowPass3x(const Image<PixRGB<float> >& src)
00186 {
00187 GVX_TRACE(__PRETTY_FUNCTION__);
00188   return lowPass3x_rgb(src);
00189 }
00190 
00191 // ######################################################################
00192 template <class T>
00193 Image<typename promote_trait<T, float>::TP>
00194 lowPass3x(const Image<T>& src)
00195 {
00196 GVX_TRACE(__PRETTY_FUNCTION__);
00197   const int w = src.getWidth(), h = src.getHeight();
00198   // promote the source image to float if necessary, so that we do the
00199   // promotion only once for all, rather than many times as we access
00200   // the pixels of the image; if no promotion is necessary, "source"
00201   // will just point to the original data of "src" through the
00202   // copy-on-write/ref-counting behavior of Image:
00203   typedef typename promote_trait<T, float>::TP TF;
00204   const Image<TF> source = src;
00205   if (w < 2) return source; // nothing to smooth
00206   Image<TF> result(w, h, NO_INIT);
00207   typename Image<TF>::const_iterator sptr = source.begin();
00208   typename Image<TF>::iterator dptr = result.beginw();
00209 
00210   // *** unfolded version (all particular cases treated) for max speed.
00211   // do not use access overload since can access the C array directly.
00212   // the bet is: float computations are faster than int (true for most
00213   // float copros), and int2float converts fast->do not have to divide
00214   // by the coeff sum since we directly use float coeffs.
00215   // notations: in () is the position of dest ptr, and ^ is src ptr
00216   // ########## horizontal pass
00217   for (int j = 0; j < h; j ++)
00218     {
00219       // leftmost point  [ (2^) 1 ] / 3
00220       *dptr++ = sptr[0] * (2.0F / 3.0F) + sptr[1] * (1.0F / 3.0F);
00221 
00222       // rest of the line except last point  [ 1^ (2) 1 ] / 4
00223       for (int i = 0; i < w - 2; i ++)
00224         {
00225           *dptr++ = (sptr[0] + sptr[2]) * 0.25F + sptr[1] * 0.5F;
00226           sptr++;
00227         }
00228 
00229       // last point [ 1^ (2) ] / 3
00230       *dptr++ = sptr[0] * (1.0F / 3.0F) + sptr[1] * (2.0F / 3.0F);
00231       sptr += 2;  // sptr back to same position as dptr
00232     }
00233   return result;
00234 }
00235 
00236 // ######################################################################
00237 template <>
00238 Image<promote_trait<PixRGB<float>, float>::TP>
00239 lowPass3y(const Image<PixRGB<float> >& src)
00240 {
00241 GVX_TRACE(__PRETTY_FUNCTION__);
00242   return lowPass3y_rgb(src);
00243 }
00244 
00245 // ######################################################################
00246 template <class T>
00247 Image<typename promote_trait<T, float>::TP>
00248 lowPass3y(const Image<T>& src)
00249 {
00250 GVX_TRACE(__PRETTY_FUNCTION__);
00251   const int w = src.getWidth(), h = src.getHeight();
00252   // promote the source image to float if necessary, so that we do the
00253   // promotion only once for all, rather than many times as we access
00254   // the pixels of the image; if no promotion is necessary, "source"
00255   // will just point to the original data of "src" through the
00256   // copy-on-write/ref-counting behavior of Image:
00257   typedef typename promote_trait<T, float>::TP TF;
00258   const Image<TF> source = src;
00259   if (h < 2) return source; // nothing to smooth
00260   Image<TF> result(w, h, NO_INIT);
00261   typename Image<TF>::const_iterator sptr = source.begin();
00262   typename Image<TF>::iterator dptr = result.beginw();
00263   const int w2 = w * 2; // speedup
00264 
00265   // ########## vertical pass  (even though we scan horiz for speedup)
00266   // topmost points  ( [ (2^) 1 ] / 3 )^T
00267   for (int i = 0; i < w; i ++)
00268     {
00269       *dptr++ = sptr[0] * (2.0F / 3.0F) + sptr[w] * (1.0F / 3.0F);
00270       sptr++;
00271     }
00272   sptr -= w;  // go back to top-left
00273 
00274   // rest of the column except last point ( [ 1^ (2) 1 ] / 4.0 )^T
00275   for (int j = 0; j < h - 2; j ++)
00276     for (int i = 0; i < w; i ++)
00277       {
00278         *dptr++ = (sptr[0] + sptr[w2]) * 0.25F + sptr[w] * 0.5F;
00279         sptr++;
00280       }
00281 
00282   // last points ( [ 1^ (2) ] / 3 )^T
00283   for (int i = 0; i < w; i ++)
00284     {
00285       *dptr++ = sptr[0] * (1.0F / 3.0F) + sptr[w] * (2.0F / 3.0F);
00286       sptr++;
00287     }
00288 
00289   // finished. here, sptr is one line before the end of array.
00290   return result;
00291 }
00292 
00293 // ######################################################################
00294 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1]
00295 Image<typename promote_trait<T, float>::TP>
00296 lowPass5x(const Image<T>& src)
00297 {
00298 GVX_TRACE(__PRETTY_FUNCTION__);
00299   const int w = src.getWidth(), h = src.getHeight();
00300   // promote the source image to float if necessary, so that we do the
00301   // promotion only once for all, rather than many times as we access
00302   // the pixels of the image; if no promotion is necessary, "source"
00303   // will just point to the original data of "src" through the
00304   // copy-on-write/ref-counting behavior of Image:
00305   typedef typename promote_trait<T, float>::TP TF;
00306   const Image<TF> source = src;
00307   if (w < 2) return source; // nothing to smooth
00308   Image<TF> result(w, h, NO_INIT);
00309   typename Image<TF>::const_iterator sptr = source.begin();
00310   typename Image<TF>::iterator dptr = result.beginw();
00311 
00312   if (w == 2) //////////////////////////////////////////////////
00313     for (int j = 0; j < h; j ++)
00314       {
00315         // leftmost point  [ (6^) 4 ] / 10
00316         *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[1] * (4.0F / 10.0F);
00317 
00318         // rightmost point  [ 4^ (6) ] / 10
00319         *dptr++ = sptr[0] * (4.0F / 10.0F) + sptr[1] * (6.0F / 10.0F);
00320 
00321         sptr += 2;  // sptr back to same position as dptr
00322       }
00323   else if (w == 3) //////////////////////////////////////////////////
00324     for (int j = 0; j < h; j ++)
00325       {
00326         // leftmost point  [ (6^) 4 1 ] / 11
00327         *dptr++ = sptr[0] * (6.0F / 11.0F) +
00328           sptr[1] * (4.0F / 11.0F) +
00329           sptr[2] * (1.0F / 11.0F);
00330 
00331         // middle point    [ 4^ (6) 4 ] / 14
00332         *dptr++ = (sptr[0] + sptr[2]) * (4.0F / 14.0F) +
00333           sptr[1] * (6.0F / 14.0F);
00334 
00335         // rightmost point  [ 1^ 4 (6) ] / 11
00336         *dptr++ = sptr[0] * (1.0F / 11.0F) +
00337           sptr[1] * (4.0F / 11.0F) +
00338           sptr[2] * (6.0F / 11.0F);
00339 
00340         sptr += 3;  // sptr back to same position as dptr
00341       }
00342   else  ////////////////////////////// general case for width() >= 4
00343         // *** unfolded version (all particular cases treated) for
00344         // max speed.  do not use access overloading since can
00345         // access the C array directly.  the bet is: float
00346         // computations are faster than int (true for most float
00347         // copros), and int2float convert is fast -> do not have to
00348         // divide by the coeff sum since we directly use float
00349         // coeffs.
00350         // notations: in () is the position of dest ptr, and ^ is src ptr
00351         // ########## horizontal pass
00352     for (int j = 0; j < h; j ++)
00353       {
00354         // leftmost point  [ (6^) 4 1 ] / 11
00355         *dptr++ = sptr[0] * (6.0F / 11.0F) +
00356           sptr[1] * (4.0F / 11.0F) +
00357           sptr[2] * (1.0F / 11.0F);
00358 
00359         // second point    [ 4^ (6) 4 1 ] / 15
00360         *dptr++ = (sptr[0] + sptr[2]) * (4.0F / 15.0F) +
00361           sptr[1] * (6.0F / 15.0F) +
00362           sptr[3] * (1.0F / 15.0F);
00363 
00364         // rest of the line except last 2 points  [ 1^ 4 (6) 4 1 ] / 16.0
00365         for (int i = 0; i < w - 4; i ++)
00366           {
00367             *dptr++ = (sptr[0] + sptr[4]) * (1.0F / 16.0F) +
00368               (sptr[1] + sptr[3]) * (4.0F / 16.0F) +
00369               sptr[2]  * (6.0F / 16.0F);
00370             sptr++;
00371           }
00372 
00373         // before last point [ 1^ 4 (6) 4 ] / 15
00374         *dptr++ = sptr[0] * (1.0F / 15.0F) +
00375           (sptr[1] + sptr[3]) * (4.0F / 15.0F) +
00376           sptr[2] * (6.0F / 15.0F);
00377         sptr++;
00378 
00379         // last point [ 1^ 4 (6) ] / 11
00380         *dptr++ = sptr[0] * (1.0F / 11.0F) +
00381           sptr[1] * (4.0F / 11.0F) +
00382           sptr[2] * (6.0F / 11.0F);
00383         sptr += 3;  // sptr back to same position as dptr
00384       }
00385   return result;
00386 }
00387 
00388 // ######################################################################
00389 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1]
00390 Image<typename promote_trait<T, float>::TP>
00391 lowPass5y(const Image<T>& src)
00392 {
00393 GVX_TRACE(__PRETTY_FUNCTION__);
00394   const int w = src.getWidth(), h = src.getHeight();
00395   // promote the source image to float if necessary, so that we do the
00396   // promotion only once for all, rather than many times as we access
00397   // the pixels of the image; if no promotion is necessary, "source"
00398   // will just point to the original data of "src" through the
00399   // copy-on-write/ref-counting behavior of Image:
00400   typedef typename promote_trait<T, float>::TP TF;
00401   const Image<TF> source = src;
00402   if (h < 2) return source; // nothing to smooth
00403   Image<TF> result(w, h, NO_INIT);
00404   typename Image<TF>::const_iterator sptr = source.begin();
00405   typename Image<TF>::iterator dptr = result.beginw();
00406 
00407   // ########## vertical pass  (even though we scan horiz for speedup)
00408   const int w2 = w * 2, w3 = w * 3, w4 = w * 4; // speedup
00409 
00410   if (h == 2) //////////////////////////////////////////////////
00411     {
00412       // topmost points  ( [ (6^) 4 ] / 10 )^T
00413       for (int i = 0; i < w; i ++)
00414         {
00415           *dptr++ = sptr[0] * (6.0F / 10.0F) +
00416             sptr[w] * (4.0F / 10.0F);
00417           sptr++;
00418         }
00419       sptr -= w;  // go back to top-left
00420 
00421       // bottommost points  ( [ 4^ (6) ] / 10 )^T
00422       for (int i = 0; i < w; i ++)
00423         {
00424           *dptr++ = sptr[0] * (4.0F / 10.0F) +
00425             sptr[w] * (6.0F / 10.0F);
00426           sptr++;
00427         }
00428     }
00429   else if (h == 3) //////////////////////////////////////////////////
00430     {
00431       // topmost points  ( [ (6^) 4 1 ] / 11 )^T
00432       for (int i = 0; i < w; i ++)
00433         {
00434           *dptr++ = sptr[ 0] * (6.0F / 11.0F) +
00435             sptr[ w] * (4.0F / 11.0F) +
00436             sptr[w2] * (1.0F / 11.0F);
00437           sptr++;
00438         }
00439       sptr -= w;  // go back to top-left
00440 
00441       // middle points  ( [ 4^ (6) 4 ] / 14 )^T
00442       for (int i = 0; i < w; i ++)
00443         {
00444           *dptr++ = (sptr[ 0] + sptr[w2]) * (4.0F / 14.0F) +
00445             sptr[ w] * (6.0F / 14.0F);
00446           sptr++;
00447         }
00448       sptr -= w;  // go back to top-left
00449 
00450       // bottommost points  ( [ 1^ 4 (6) ] / 11 )^T
00451       for (int i = 0; i < w; i ++)
00452         {
00453           *dptr++ = sptr[ 0] * (1.0F / 11.0F) +
00454             sptr[ w] * (4.0F / 11.0F) +
00455             sptr[w2] * (6.0F / 11.0F);
00456           sptr++;
00457         }
00458     }
00459   else  ///////////////////////////////// general case for height >= 4
00460     {
00461       // topmost points  ( [ (6^) 4 1 ] / 11 )^T
00462       for (int i = 0; i < w; i ++)
00463         {
00464           *dptr++ = sptr[ 0] * (6.0F / 11.0F) +
00465             sptr[ w] * (4.0F / 11.0F) +
00466             sptr[w2] * (1.0F / 11.0F);
00467           sptr++;
00468         }
00469       sptr -= w;  // go back to top-left
00470 
00471       // second topmost points  ( [ 4^ (6) 4 1 ] / 15 )^T
00472       for (int i = 0; i < w; i ++)
00473         {
00474           *dptr++ = (sptr[ 0] + sptr[w2]) * (4.0F / 15.0F) +
00475             sptr[ w] * (6.0F / 15.0F) +
00476             sptr[w3] * (1.0F / 15.0F);
00477           sptr++;
00478         }
00479       sptr -= w;  // go back to top-left
00480 
00481       // rest of the column except last 2 points ( [ 1^ 4 (6) 4 1 ] / 16 )T
00482       for (int j = 0; j < h - 4; j ++)
00483         for (int i = 0; i < w; i ++)
00484           {
00485             *dptr++ = (sptr[ 0] + sptr[w4]) * (1.0F / 16.0F) +
00486               (sptr[ w] + sptr[w3]) * (4.0F / 16.0F) +
00487               sptr[w2]  * (6.0F / 16.0F);
00488             sptr++;
00489           }
00490 
00491       // before last points ( [ 1^ 4 (6) 4 ] / 15 )T
00492       for (int i = 0; i < w; i ++)
00493         {
00494           *dptr++ = sptr[ 0] * (1.0F / 15.0F) +
00495             (sptr[ w] + sptr[w3]) * (4.0F / 15.0F) +
00496             sptr[w2] * (6.0F / 15.0F);
00497           sptr++;
00498         }
00499 
00500       // last points ( [ 1^ 4 (6) ] / 11 )T
00501       for (int i = 0; i < w; i ++)
00502         {
00503           *dptr++ = sptr[ 0] * (1.0F / 11.0F) +
00504             sptr[ w] * (4.0F / 11.0F) +
00505             sptr[w2] * (6.0F / 11.0F);
00506           sptr++;
00507         }
00508       // finished. here, sptr is two lines before the end of array.
00509     }
00510   return result;
00511 }
00512 
00513 // ######################################################################
00514 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1]
00515 Image<typename promote_trait<T, float>::TP>
00516 lowPass5xDecX(const Image<T>& src, const int factor)
00517 {
00518 GVX_TRACE(__PRETTY_FUNCTION__);
00519   ASSERT(factor > 0);
00520 
00521   // if factor == 1 then we don't decimate:
00522   if (factor == 1) return lowPass5x(src);
00523 
00524   // now factor is guaranteed to be >= 2
00525   const int w = src.getWidth(), h = src.getHeight();
00526   int w2 = w / factor;
00527   if (w2 == 0) w2 = 1; // do not go smaller than 1 pixel
00528 
00529   // promote the source image to float if necessary, so that we do the
00530   // promotion only once for all, rather than many times as we access
00531   // the pixels of the image; if no promotion is necessary, "source"
00532   // will just point to the original data of "src" through the
00533   // copy-on-write/ref-counting behavior of Image:
00534   typedef typename promote_trait<T, float>::TP TF;
00535   const Image<TF> source = src;
00536   if (w < 2) return source; // nothing to smooth
00537 
00538   Image<TF> result(w2, h, NO_INIT);
00539   typename Image<TF>::const_iterator sptr = source.begin();
00540   typename Image<TF>::iterator dptr = result.beginw();
00541 
00542   if (w == 2) //////////////////////////////////////////////////
00543     for (int j = 0; j < h; j ++)
00544       {
00545         // leftmost point  [ (6^) 4 ] / 10
00546         *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[1] * (4.0F / 10.0F);
00547 
00548         sptr += 2;  // sptr back to same position as dptr
00549       }
00550   else if (w == 3) //////////////////////////////////////////////////
00551     for (int j = 0; j < h; j ++)
00552       {
00553         // need the left most point in any case
00554         // leftmost point  [ (6^) 4 1 ] / 11
00555         *dptr++ = sptr[0] * (6.0F / 11.0F) +
00556           sptr[1] * (4.0F / 11.0F) +
00557           sptr[2] * (1.0F / 11.0F);
00558 
00559         // since factor >= 2 we don't need any other point.
00560 
00561         sptr += 3;  // sptr back to same position as dptr
00562       }
00563   else  ////////////////////////////// general case for width() >= 4
00564         // *** unfolded version (all particular cases treated) for
00565         // max speed.  do not use access overloading since can
00566         // access the C array directly.  the bet is: float
00567         // computations are faster than int (true for most float
00568         // copros), and int2float convert is fast -> do not have to
00569         // divide by the coeff sum since we directly use float
00570         // coeffs.
00571         // notations: in () is the position of dest ptr, and ^ is src ptr
00572         // ########## horizontal pass
00573     for (int j = 0; j < h; j ++)
00574       {
00575         int i1 = 0, i2 = 0;
00576         typename Image<TF>::const_iterator sptr2 = sptr;
00577 
00578 
00579         // leftmost point  [ (6^) 4 1 ] / 11
00580         *dptr++ = sptr2[0] * (6.0F / 11.0F) +
00581           sptr2[1] * (4.0F / 11.0F) +
00582           sptr2[2] * (1.0F / 11.0F);
00583         ++i2;
00584         i1 += factor;
00585 
00586         // skip second point since factor >= 2:
00587         sptr2 += (factor-2);
00588 
00589         // rest of the line except last 2 points  [ 1^ 4 (6) 4 1 ] / 16.0
00590         while ((i1 < (w-2)) && (i2 < w2))
00591           {
00592             *dptr++ = (sptr2[0] + sptr2[4]) * (1.0F / 16.0F) +
00593               (sptr2[1] + sptr2[3]) * (4.0F / 16.0F) +
00594               sptr2[2]  * (6.0F / 16.0F);
00595             i1 += factor; sptr2 += factor;
00596             ++i2;
00597           }
00598 
00599         // need special case for second to last point?
00600         if ((i2 < w2) && (i1 == (w-2)))
00601           {
00602             sptr2 = sptr + w - 4;
00603             // before last point [ 1^ 4 (6) 4 ] / 15
00604             *dptr++ = sptr2[0] * (1.0F / 15.0F) +
00605               (sptr2[1] + sptr2[3]) * (4.0F / 15.0F) +
00606               sptr2[2] * (6.0F / 15.0F);
00607             i1 += factor;
00608             ++i2;
00609           }
00610 
00611         // need special case for last point?
00612         if ((i2 < w2) && (i1 == (w-1)))
00613           {
00614             sptr2 = sptr + w - 3;
00615             // last point [ 1^ 4 (6) ] / 11
00616             *dptr++ = sptr2[0] * (1.0F / 11.0F) +
00617               sptr2[1] * (4.0F / 11.0F) +
00618               sptr2[2] * (6.0F / 11.0F);
00619             ++i2;
00620           }
00621         sptr += w;
00622       }
00623   return result;
00624 }
00625 
00626 // ######################################################################
00627 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1]
00628 Image<typename promote_trait<T, float>::TP>
00629 lowPass5yDecY(const Image<T>& src, const int factor)
00630 {
00631 GVX_TRACE(__PRETTY_FUNCTION__);
00632   ASSERT(factor > 0);
00633 
00634   // if factor == 1 then we don't decimate:
00635   if (factor == 1) return lowPass5y(src);
00636 
00637   // now factor is guaranteed to be >= 2
00638   const int w = src.getWidth(), h = src.getHeight();
00639   int h2 = h / factor;
00640   if (h2 == 0) h2 = 1; // do not go smaller than 1 pixel
00641 
00642   // promote the source image to float if necessary, so that we do the
00643   // promotion only once for all, rather than many times as we access
00644   // the pixels of the image; if no promotion is necessary, "source"
00645   // will just point to the original data of "src" through the
00646   // copy-on-write/ref-counting behavior of Image:
00647   typedef typename promote_trait<T, float>::TP TF;
00648   const Image<TF> source = src;
00649   if (h < 2) return source; // nothing to smooth
00650 
00651   Image<TF> result(w, h2, NO_INIT);
00652   typename Image<TF>::const_iterator sptr = source.begin();
00653   typename Image<TF>::iterator dptr = result.beginw();
00654 
00655   // ########## vertical pass  (even though we scan horiz for speedup)
00656   const int w2 = w * 2, w3 = w * 3, w4 = w * 4; // speedup
00657 
00658   if (h == 2) //////////////////////////////////////////////////
00659     {
00660       // topmost points  ( [ (6^) 4 ] / 10 )^T
00661       for (int i = 0; i < w; i ++)
00662         {
00663           *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[w] * (4.0F / 10.0F);
00664           sptr++;
00665         }
00666       sptr -= w;  // go back to top-left
00667     }
00668   else if (h == 3) //////////////////////////////////////////////////
00669     {
00670       // topmost points  ( [ (6^) 4 1 ] / 11 )^T
00671       for (int i = 0; i < w; i ++)
00672         {
00673           *dptr++ = sptr[ 0] * (6.0F / 11.0F) +
00674             sptr[ w] * (4.0F / 11.0F) +
00675             sptr[w2] * (1.0F / 11.0F);
00676           sptr++;
00677         }
00678       sptr -= w;  // go back to top-left
00679 
00680       // since factor >= 2 we don't need any other point.
00681     }
00682   else  ///////////////////////////////// general case for height >= 4
00683     {
00684       int i1 = 0, i2 = 0;
00685       const int skip = (factor - 1) * w;
00686 
00687       // topmost points  ( [ (6^) 4 1 ] / 11 )^T
00688       for (int i = 0; i < w; i ++)
00689         {
00690           *dptr++ = sptr[ 0] * (6.0F / 11.0F) +
00691             sptr[ w] * (4.0F / 11.0F) +
00692             sptr[w2] * (1.0F / 11.0F);
00693           sptr++;
00694         }
00695       sptr -= w;  // go back to top-left
00696       ++i2;
00697       i1 += factor;
00698 
00699       // second point skipped since factor >= 2
00700       sptr += (skip - w);
00701 
00702       // rest of the column except last 2 points ( [ 1^ 4 (6) 4 1 ] / 16 )T
00703       while((i1 < (h-2)) && (i2 < h2))
00704         {
00705           for (int i = 0; i < w; i ++)
00706             {
00707               *dptr++ = (sptr[ 0] + sptr[w4]) * (1.0F / 16.0F) +
00708                 (sptr[ w] + sptr[w3]) * (4.0F / 16.0F) +
00709                 sptr[w2]  * (6.0F / 16.0F);
00710               sptr++;
00711             }
00712           sptr += skip;
00713           i1 += factor;
00714           ++ i2;
00715         }
00716 
00717       // need special case for second to last point?
00718       if ((i2 < h2) && (i1 == (h-2)))
00719         {
00720           sptr = source.end() - w4;
00721           // before last points ( [ 1^ 4 (6) 4 ] / 15 )T
00722           for (int i = 0; i < w; i ++)
00723             {
00724               *dptr++ = sptr[ 0] * (1.0F / 15.0F) +
00725                 (sptr[ w] + sptr[w3]) * (4.0F / 15.0F) +
00726                 sptr[w2] * (6.0F / 15.0F);
00727               sptr++;
00728             }
00729           i1 += factor;
00730           ++i2;
00731         }
00732 
00733       // need special case for last point?
00734       if ((i2 < h2) && (i1 == (h-1)))
00735         {
00736           sptr = source.end() - w3;
00737           // last points ( [ 1^ 4 (6) ] / 11 )T
00738           for (int i = 0; i < w; i ++)
00739             {
00740               *dptr++ = sptr[ 0] * (1.0F / 11.0F) +
00741                 sptr[ w] * (4.0F / 11.0F) +
00742                 sptr[w2] * (6.0F / 11.0F);
00743               sptr++;
00744             }
00745         }
00746     }
00747   return result;
00748 }
00749 
00750 // ######################################################################
00751 template <class T>
00752 Image<typename promote_trait<T, float>::TP>
00753 lowPass9x(const Image<T>& src)
00754 {
00755 GVX_TRACE(__PRETTY_FUNCTION__);
00756   const int w = src.getWidth(), h = src.getHeight();
00757   // promote the source image to float if necessary, so that we do the
00758   // promotion only once for all, rather than many times as we access
00759   // the pixels of the image; if no promotion is necessary, "source"
00760   // will just point to the original data of "src" through the
00761   // copy-on-write/ref-counting behavior of Image:
00762   typedef typename promote_trait<T, float>::TP TF;
00763   const Image<TF> source = src;
00764   if (w < 2) return source; // nothing to smooth
00765   Image<TF> result(w, h, NO_INIT);
00766   typename Image<TF>::const_iterator sptr = source.begin();
00767   typename Image<TF>::iterator dptr = result.beginw();
00768 
00769   if (w < 9)  // use inefficient implementation for small images
00770     {
00771       float kernel[9] = { 1.0F / 256.0F, 8.0F / 256.0F, 28.0F / 256.0F,
00772                           56.0F / 256.0F, 70.0F / 256.0F, 56.0F / 256.0F,
00773                           28.0F / 256.0F, 8.0F / 256.0F, 1.0F / 256.0F };
00774       return sepFilter(src, kernel, NULL, 9, 0,
00775                        CONV_BOUNDARY_CLEAN);
00776     }
00777 
00778   // boundary conditions: truncated filter
00779   for (int j = 0; j < h; j ++)
00780     {
00781       // leftmost points
00782       *dptr++ = sptr[0] * (70.0F / 163.0F) +
00783         sptr[1] * (56.0F / 163.0F) +
00784         sptr[2] * (28.0F / 163.0F) +
00785         sptr[3] * ( 8.0F / 163.0F) +
00786         sptr[4] * ( 1.0F / 163.0F);
00787       *dptr++ = (sptr[0] + sptr[2]) * (56.0F / 219.0F) +
00788         sptr[1] * (70.0F / 219.0F) +
00789         sptr[3] * (28.0F / 219.0F) +
00790         sptr[4] * ( 8.0F / 219.0F) +
00791         sptr[5] * ( 1.0F / 219.0F);
00792       *dptr++ = (sptr[0] + sptr[4]) * (28.0F / 247.0F) +
00793         (sptr[1] + sptr[3]) * (56.0F / 247.0F) +
00794         sptr[2] * (70.0F / 247.0F) +
00795         sptr[5] * ( 8.0F / 247.0F) +
00796         sptr[6] * ( 1.0F / 247.0F);
00797       *dptr++ = (sptr[0] + sptr[6]) * ( 8.0F / 255.0F) +
00798         (sptr[1] + sptr[5]) * (28.0F / 255.0F) +
00799         (sptr[2] + sptr[4]) * (56.0F / 255.0F) +
00800         sptr[3] * (70.0F / 255.0F) +
00801         sptr[7] * ( 1.0F / 255.0F);
00802 
00803       // far from the borders
00804       for (int i = 0; i < w - 8; i ++)
00805         {
00806           *dptr++ = (sptr[0] + sptr[8]) * ( 1.0F / 256.0F) +
00807             (sptr[1] + sptr[7]) * ( 8.0F / 256.0F) +
00808             (sptr[2] + sptr[6]) * (28.0F / 256.0F) +
00809             (sptr[3] + sptr[5]) * (56.0F / 256.0F) +
00810             sptr[4] * (70.0F / 256.0F);
00811           sptr ++;
00812         }
00813 
00814       // rightmost points
00815       *dptr++ = sptr[0] * ( 1.0F / 255.0F) +
00816         (sptr[1] + sptr[7]) * ( 8.0F / 255.0F) +
00817         (sptr[2] + sptr[6]) * (28.0F / 255.0F) +
00818         (sptr[3] + sptr[5]) * (56.0F / 255.0F) +
00819         sptr[4] * (70.0F / 255.0F);
00820       sptr ++;
00821       *dptr++ = sptr[0] * ( 1.0F / 247.0F) +
00822         sptr[1] * ( 8.0F / 247.0F) +
00823         (sptr[2] + sptr[6]) * (28.0F / 247.0F) +
00824         (sptr[3] + sptr[5]) * (56.0F / 247.0F) +
00825         sptr[4] * (70.0F / 247.0F);
00826       sptr ++;
00827       *dptr++ = sptr[0] * ( 1.0F / 219.0F) +
00828         sptr[1] * ( 8.0F / 219.0F) +
00829         sptr[2] * (28.0F / 219.0F) +
00830         (sptr[3] + sptr[5]) * (56.0F / 219.0F) +
00831         sptr[4] * (70.0F / 219.0F);
00832       sptr ++;
00833       *dptr++ = sptr[0] * ( 1.0F / 163.0F) +
00834         sptr[1] * ( 8.0F / 163.0F) +
00835         sptr[2] * (28.0F / 163.0F) +
00836         sptr[3] * (56.0F / 163.0F) +
00837         sptr[4] * (70.0F / 163.0F);
00838       sptr += 5;  // sptr back to same as dptr (start of next line)
00839     }
00840   return result;
00841 }
00842 
00843 // ######################################################################
00844 template <class T>
00845 Image<typename promote_trait<T, float>::TP>
00846 lowPass9y(const Image<T>& src)
00847 {
00848 GVX_TRACE(__PRETTY_FUNCTION__);
00849   const int w = src.getWidth(), h = src.getHeight();
00850   // promote the source image to float if necessary, so that we do the
00851   // promotion only once for all, rather than many times as we access
00852   // the pixels of the image; if no promotion is necessary, "source"
00853   // will just point to the original data of "src" through the
00854   // copy-on-write/ref-counting behavior of Image:
00855   typedef typename promote_trait<T, float>::TP TF;
00856   const Image<TF> source = src;
00857   if (h < 2) return source; // nothing to smooth
00858   Image<TF> result(w, h, NO_INIT);
00859   typename Image<TF>::const_iterator sptr = source.begin();
00860   typename Image<TF>::iterator dptr = result.beginw();
00861 
00862   if (h < 9)  // use inefficient implementation for small images
00863     {
00864       float kernel[9] = { 1.0F / 256.0F, 8.0F / 256.0F, 28.0F / 256.0F,
00865                           56.0F / 256.0F, 70.0F / 256.0F, 56.0F / 256.0F,
00866                           28.0F / 256.0F, 8.0F / 256.0F, 1.0F / 256.0F };
00867       return sepFilter(src, NULL, kernel, 0, 9,
00868                        CONV_BOUNDARY_CLEAN);
00869     }
00870 
00871   // *** vertical pass ***
00872   const int w2 = w + w, w3 = w2 + w, w4 = w3 + w, w5 = w4 + w, w6 = w5 + w,
00873     w7 = w6 + w,  w8 = w7 + w;  // index computation speedup
00874   for (int i = 0; i < w; i ++)
00875     {
00876       *dptr++ = sptr[ 0] * (70.0F / 163.0F) +
00877         sptr[ w] * (56.0F / 163.0F) +
00878         sptr[w2] * (28.0F / 163.0F) +
00879         sptr[w3] * ( 8.0F / 163.0F) +
00880         sptr[w4] * ( 1.0F / 163.0F);
00881       sptr ++;
00882     }
00883   sptr -= w; // back to top-left
00884   for (int i = 0; i < w; i ++)
00885     {
00886       *dptr++ = (sptr[ 0] + sptr[w2]) * (56.0F / 219.0F) +
00887         sptr[ w] * (70.0F / 219.0F) +
00888         sptr[w3] * (28.0F / 219.0F) +
00889         sptr[w4] * ( 8.0F / 219.0F) +
00890         sptr[w5] * ( 1.0F / 219.0F);
00891       sptr ++;
00892     }
00893   sptr -= w; // back to top-left
00894   for (int i = 0; i < w; i ++)
00895     {
00896       *dptr++ = (sptr[ 0] + sptr[w4]) * (28.0F / 247.0F) +
00897         (sptr[ w] + sptr[w3]) * (56.0F / 247.0F) +
00898         sptr[w2] * (70.0F / 247.0F) +
00899         sptr[w5] * ( 8.0F / 247.0F) +
00900         sptr[w6] * ( 1.0F / 247.0F);
00901       sptr ++;
00902     }
00903   sptr -= w; // back to top-left
00904   for (int i = 0; i < w; i ++)
00905     {
00906       *dptr++ = (sptr[ 0] + sptr[w6]) * ( 8.0F / 255.0F) +
00907         (sptr[ w] + sptr[w5]) * (28.0F / 255.0F) +
00908         (sptr[w2] + sptr[w4]) * (56.0F / 255.0F) +
00909         sptr[w3] * (70.0F / 255.0F) +
00910         sptr[w7] * ( 1.0F / 255.0F);
00911       sptr ++;
00912     }
00913   sptr -= w;   // back to top-left
00914   for (int j = 0; j < h - 8; j ++)
00915     for (int i = 0; i < w; i ++)
00916       {
00917         *dptr++ = (sptr[ 0] + sptr[w8]) * ( 1.0F / 256.0F) +
00918           (sptr[ w] + sptr[w7]) * ( 8.0F / 256.0F) +
00919           (sptr[w2] + sptr[w6]) * (28.0F / 256.0F) +
00920           (sptr[w3] + sptr[w5]) * (56.0F / 256.0F) +
00921           sptr[w4]  * (70.0F / 256.0F);
00922         sptr ++;
00923       }
00924   for (int i = 0; i < w; i ++)
00925     {
00926       *dptr++ = sptr[ 0] * ( 1.0F / 255.0F) +
00927         (sptr[ w] + sptr[w7]) * ( 8.0F / 255.0F) +
00928         (sptr[w2] + sptr[w6]) * (28.0F / 255.0F) +
00929         (sptr[w3] + sptr[w5]) * (56.0F / 255.0F) +
00930         sptr[w4] * (70.0F / 255.0F);
00931       sptr ++;
00932     }
00933   for (int i = 0; i < w; i ++)
00934     {
00935       *dptr++ = sptr[ 0] * ( 1.0F / 247.0F) +
00936         sptr[ w] * ( 8.0F / 247.0F) +
00937         (sptr[w2] + sptr[w6]) * (28.0F / 247.0F) +
00938         (sptr[w3] + sptr[w5]) * (56.0F / 247.0F) +
00939         sptr[w4] * (70.0F / 247.0F);
00940       sptr ++;
00941     }
00942   for (int i = 0; i < w; i ++)
00943     {
00944       *dptr++ = sptr[ 0] * ( 1.0F / 219.0F) +
00945         sptr[ w] * ( 8.0F / 219.0F) +
00946         sptr[w2] * (28.0F / 219.0F) +
00947         (sptr[w3] + sptr[w5]) * (56.0F / 219.0F) +
00948         sptr[w4] * (70.0F / 219.0F);
00949       sptr ++;
00950     }
00951   for (int i = 0; i < w; i ++)
00952     {
00953       *dptr++ = sptr[ 0] * ( 1.0F / 163.0F) +
00954         sptr[ w] * ( 8.0F / 163.0F) +
00955         sptr[w2] * (28.0F / 163.0F) +
00956         sptr[w3] * (56.0F / 163.0F) +
00957         sptr[w4] * (70.0F / 163.0F);
00958       sptr ++;
00959     }
00960   return result;
00961 }
00962 
00963 // ######################################################################
00964 template <class T>
00965 Image<typename promote_trait<T, float>::TP>
00966 lowPass3(const Image<T>& src, const bool go_x, const bool go_y)
00967 {
00968   Image<typename promote_trait<T, float>::TP> result = src;
00969   if (go_x) result = lowPass3x(result);
00970   if (go_y) result = lowPass3y(result);
00971   return result;
00972 }
00973 
00974 // ######################################################################
00975 template <class T>
00976 Image<typename promote_trait<T, float>::TP>
00977 lowPass5(const Image<T>& src, const bool go_x, const bool go_y)
00978 {
00979   Image<typename promote_trait<T, float>::TP> result = src;
00980   if (go_x) result = lowPass5x(result);
00981   if (go_y) result = lowPass5y(result);
00982   return result;
00983 }
00984 
00985 // ######################################################################
00986 template <class T>
00987 Image<typename promote_trait<T, float>::TP>
00988 lowPass9(const Image<T>& src, const bool go_x, const bool go_y)
00989 {
00990   Image<typename promote_trait<T, float>::TP> result = src;
00991   if (go_x) result = lowPass9x(result);
00992   if (go_y) result = lowPass9y(result);
00993   return result;
00994 }
00995 
00996 // ######################################################################
00997 template <class T>
00998 Image<typename promote_trait<T, float>::TP>
00999 lowPass(const int N, const Image<T>& src,
01000         const bool go_x = true, const bool go_y = true)
01001 {
01002   Image<typename promote_trait<T, float>::TP> result = src;
01003   if (go_x) result = lowPassX(N, result);
01004   if (go_y) result = lowPassY(N, result);
01005   return result;
01006 }
01007 
01008 // ######################################################################
01009 template <class T>
01010 Image<typename promote_trait<T, float>::TP>
01011 lowPassX(const int N, const Image<T>& src)
01012 {
01013 GVX_TRACE(__PRETTY_FUNCTION__);
01014   switch (N)
01015     {
01016     case 3: return lowPass3x(src);
01017     case 5: return lowPass5x(src);
01018     case 9: return lowPass9x(src);
01019     default: break;
01020     }
01021 
01022   const Image<float> kern = binomialKernel(N);
01023   ASSERT(kern.getWidth() == N);
01024   ASSERT(kern.getHeight() == 1);
01025   return sepFilter(src, kern.getArrayPtr(), NULL, N, 0,
01026                    CONV_BOUNDARY_CLEAN);
01027 }
01028 
01029 // ######################################################################
01030 template <class T>
01031 Image<typename promote_trait<T, float>::TP>
01032 lowPassY(const int N, const Image<T>& src)
01033 {
01034 GVX_TRACE(__PRETTY_FUNCTION__);
01035   switch (N)
01036     {
01037     case 3: return lowPass3y(src);
01038     case 5: return lowPass5y(src);
01039     case 9: return lowPass9y(src);
01040     default: break;
01041     }
01042 
01043   const Image<float> kern = binomialKernel(N);
01044   ASSERT(kern.getWidth() == N);
01045   ASSERT(kern.getHeight() == 1);
01046   return sepFilter(src, NULL, kern.getArrayPtr(), 0, N,
01047                    CONV_BOUNDARY_CLEAN);
01048 }
01049 
01050 // ######################################################################
01051 template <class T>
01052 Image<T> median3x(const Image<T>& in)
01053 {
01054   if (in.getWidth() < 3) return in;
01055 
01056   const int w = in.getWidth();
01057   const int h = in.getHeight();
01058 
01059   Image<T> result(in.getDims(), NO_INIT);
01060 
01061   typename Image<T>::const_iterator sptr = in.begin();
01062   typename Image<T>::iterator dptr = result.beginw();
01063 
01064   for (int y = 0; y < h; ++y)
01065     for (int x = 0; x < w; ++x)
01066       {
01067         if (x == 0 || x == w-1)
01068           *dptr = *sptr;
01069         else
01070           *dptr = median3scalar(sptr[-1], sptr[0], sptr[1]);
01071 
01072         ++dptr;
01073         ++sptr;
01074       }
01075 
01076   return result;
01077 }
01078 
01079 // ######################################################################
01080 template <class T>
01081 Image<T> median3y(const Image<T>& in)
01082 {
01083   if (in.getHeight() < 3) return in;
01084 
01085   const int w = in.getWidth();
01086   const int h = in.getHeight();
01087 
01088   Image<T> result(in.getDims(), NO_INIT);
01089 
01090   typename Image<T>::const_iterator sptr = in.begin();
01091   typename Image<T>::iterator dptr = result.beginw();
01092 
01093   for (int y = 0; y < h; ++y)
01094     {
01095       if (y == 0 || y == h-1)
01096         for (int x = 0; x < w; ++x)
01097             *dptr++ = *sptr++;
01098       else
01099         for (int x = 0; x < w; ++x)
01100           {
01101             *dptr = median3scalar(sptr[-w], sptr[0], sptr[w]);
01102 
01103             ++dptr;
01104             ++sptr;
01105           }
01106     }
01107 
01108   return result;
01109 }
01110 
01111 // ######################################################################
01112 template <class T>
01113 Image<T> median3(const Image<T>& in, bool go_x, bool go_y)
01114 {
01115   Image<T> result = in;
01116   if (go_x) result = median3x(result);
01117   if (go_y) result = median3y(result);
01118   return result;
01119 }
01120 
01121 // ######################################################################
01122 template <class T>
01123 Image<typename promote_trait<T, float>::TP>
01124 convGauss(const Image<T>& src, const float sigmaX, const float sigmaY,
01125           const float threshperc)
01126 {
01127 GVX_TRACE(__PRETTY_FUNCTION__);
01128   Image<typename promote_trait<T, float>::TP> result = src;
01129   Image <float> kernel;
01130   if (sigmaX > 0.0)
01131     {
01132       kernel = gaussian<float>(0.0F, sigmaX, result.getWidth(),threshperc);
01133       result = sepFilter(result, kernel, Image<float>(),
01134                          CONV_BOUNDARY_CLEAN);
01135     }
01136   if (sigmaY > 0.0)
01137     {
01138       kernel = gaussian<float>(0.0F, sigmaY, src.getHeight(), threshperc);
01139       result = sepFilter(result, Image<float>(), kernel,
01140                          CONV_BOUNDARY_CLEAN);
01141     }
01142   return result;
01143 }
01144 
01145 // Include the explicit instantiations
01146 #include "inst/Image/LowPass.I"
01147 
01148 template
01149 Image<promote_trait<double, float>::TP>
01150 lowPass3(const Image<double>& src, const bool, const bool);
01151 
01152 template
01153 Image<promote_trait<double, float>::TP>
01154 lowPass5(const Image<double>& src, const bool, const bool);
01155 
01156 template
01157 Image<promote_trait<double, float>::TP>
01158 lowPass3x(const Image<double>& src);
01159 
01160 template
01161 Image<promote_trait<double, float>::TP>
01162 lowPass3y(const Image<double>& src);
01163 
01164 template
01165 Image<promote_trait<double, float>::TP>
01166 lowPass5x(const Image<double>& src);
01167 
01168 template
01169 Image<promote_trait<double, float>::TP>
01170 lowPass5y(const Image<double>& src);
01171 
01172 // ######################################################################
01173 /* So things look consistent in everyone's emacs... */
01174 /* Local Variables: */
01175 /* mode: c++ */
01176 /* indent-tabs-mode: nil */
01177 /* End: */
01178 
01179 #endif // IMAGE_LOWPASS_C_DEFINED
Generated on Sun May 8 08:40:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3