MathOps.C

Go to the documentation of this file.
00001 /*!@file Image/MathOps.C Mathematical operations on Image               */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/MathOps.C $
00034 // $Id: MathOps.C 14665 2011-03-31 23:34:38Z dberg $
00035 
00036 #ifndef IMAGE_MATHOPS_C_DEFINED
00037 #define IMAGE_MATHOPS_C_DEFINED
00038 
00039 #include "Image/MathOps.H"
00040 
00041 // WARNING: Try not include any other "Image*Ops.H" headers here -- if
00042 // you find that you are needing such a header, then the function
00043 // you're writing probably belongs outside Image_MathOps.C.
00044 #include "Image/Image.H"
00045 #include "Image/Pixels.H"
00046 #include "Image/Range.H"
00047 #include "Image/MatrixOps.H"
00048 #include "Image/CutPaste.H"
00049 #include "Image/FourierEngine.H"
00050 #include "Util/Assert.H"
00051 #include "Util/MathFunctions.H"
00052 #include "Util/safecopy.H"
00053 #include "Util/FileUtil.H"
00054 #include "rutz/trace.h"
00055 
00056 #include <algorithm>
00057 #include <cmath>
00058 #include <climits>
00059 #include <cfloat>
00060 #include <numeric> // for std::accumulate(), etc.
00061 
00062 #if defined(INVT_USE_MMX) || defined(INVT_USE_SSE) || defined(INVT_USE_SSE2)
00063 #include "Util/mmx-sse.H"
00064 #endif
00065 
00066 // ######################################################################
00067 template <class T>
00068 double sum(const Image<T>& a)
00069 {
00070 GVX_TRACE(__PRETTY_FUNCTION__);
00071   return std::accumulate(a.begin(), a.end(), 0.0);
00072 }
00073 
00074 // ######################################################################
00075 // Optimized implementations using SSE2/SSE for some canonical datatypes:
00076 #ifdef INVT_USE_SSE
00077 double sum(const Image<double> &a)
00078 {
00079   double d;
00080   sse_sum((const double *)(a.begin()), &d, a.getSize());
00081   return d;
00082 }
00083 #endif
00084 #ifdef INVT_USE_SSE2
00085 double sum(const Image<float> &a)
00086 {
00087   double d;
00088   sse2_sum((const float *)(a.begin()), &d, a.getSize());
00089   return d;
00090 }
00091 
00092 double sum(const Image<int> &a)
00093 {
00094   double d;
00095   sse2_sum((const int *)(a.begin()), &d, a.getSize());
00096   return d;
00097 }
00098 
00099 double sum(const Image<byte> &a)
00100 {
00101   double d;
00102   sse2_sum((const byte *)(a.begin()), &d, a.getSize());
00103   return d;
00104 }
00105 #endif
00106 
00107 
00108 // ######################################################################
00109 template <class T>
00110 double mean(const Image<T>& a)
00111 {
00112 GVX_TRACE(__PRETTY_FUNCTION__);
00113   ASSERT(a.getSize() > 0);
00114   return sum(a) / double(a.getSize());
00115 }
00116 
00117 // ######################################################################
00118 template<class T>
00119 double stdev(const Image<T>& a)
00120 {
00121 GVX_TRACE(__PRETTY_FUNCTION__);
00122   ASSERT(a.getSize() > 1);
00123 
00124   typename Image<T>::const_iterator aptr = a.begin(), stop = a.end();
00125 
00126   double sum = 0.0;
00127   double avg = mean(a);
00128 
00129   while (aptr != stop)
00130     {
00131       double val = ((double)(*aptr++)) - avg;
00132       sum += val * val;
00133     }
00134   return sqrt(sum / ((double)(a.getSize() - 1)));
00135 }
00136 
00137 // ######################################################################
00138 template <class T>
00139 Range<T> rangeOf(const Image<T>& img)
00140 {
00141 GVX_TRACE(__PRETTY_FUNCTION__);
00142   return std::for_each(img.begin(), img.end(), Range<T>());
00143 }
00144 
00145 // ######################################################################
00146 template <class T>
00147 Image<T> remapRange(const Image<T>& img,
00148                     const Range<T>& from, const Range<T>& to)
00149 {
00150 GVX_TRACE(__PRETTY_FUNCTION__);
00151   Image<T> result(img.getDims(), NO_INIT);
00152 
00153   typename Image<T>::const_iterator sptr = img.begin();
00154   typename Image<T>::iterator dptr = result.beginw(), stop = result.endw();
00155 
00156   double scale = double(to.range()) / double(from.range());
00157 
00158   while (dptr != stop)
00159     {
00160       *dptr = to.min() + T((*sptr - from.min()) * scale);
00161       ++sptr; ++dptr;
00162     }
00163 
00164   return result;
00165 }
00166 
00167 // ######################################################################
00168 template <class T>
00169 Image<T> squared(const Image<T>& a)
00170 {
00171 GVX_TRACE(__PRETTY_FUNCTION__);
00172   Image<T> result(a.getDims(), NO_INIT);
00173 
00174   /* This is more succinct but unfortunately does not seem to get
00175      inlined into efficient code:
00176 
00177      std::transform(a.begin(), a.end(), result.beginw(), squareOf<T>);
00178 
00179      so instead we use an explicit loop
00180   */
00181 
00182   typename Image<T>::const_iterator sptr = a.begin();
00183   typename Image<T>::iterator dptr = result.beginw();
00184   typename Image<T>::iterator stop = result.endw();
00185 
00186   while (dptr != stop)
00187     {
00188       *dptr++ = (*sptr) * (*sptr);
00189       ++sptr;
00190     }
00191   return result;
00192 }
00193 
00194 namespace
00195 {
00196   template <class T>
00197   struct ToPow
00198   {
00199     double pp;
00200     ToPow(double p) : pp(p) {}
00201     T operator()(T x) { return clamped_convert<T>(pow(x, pp)); }
00202   };
00203 
00204   template <class T>
00205   struct EpsInv
00206   {
00207     double ee;
00208     EpsInv(T e) : ee(e) {}
00209     T operator()(T x) {
00210       if (fabs(x) > ee) return clamped_convert<T>(1.0F / x);
00211       else return T();
00212     }
00213   };
00214 }
00215 
00216 // ######################################################################
00217 template <class T>
00218 Image<typename promote_trait<T,float>::TP>
00219 toPower(const Image<T>& a, double pow)
00220 {
00221 GVX_TRACE(__PRETTY_FUNCTION__);
00222   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
00223   std::transform(a.begin(), a.end(), result.beginw(), ToPow<T>(pow));
00224   return result;
00225 }
00226 
00227 // ######################################################################
00228 template <class T>
00229 Image<typename promote_trait<T,float>::TP>
00230 toPowerRegion(const Image<T>& a, double pwr, std::vector<Point2D<int> > region)
00231 {
00232 GVX_TRACE(__PRETTY_FUNCTION__);
00233 
00234   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
00235   result = a;
00236   Point2D<int> temp;
00237   typename std::vector<Point2D<int> >::iterator vptr = region.begin();
00238   while(vptr!=region.end())
00239   {
00240       temp = *vptr++;
00241       result.setVal(temp,pow(result.getVal(temp),pwr));
00242   }
00243 
00244   return result;
00245 }
00246 
00247 // ######################################################################
00248 namespace
00249 {
00250   template <class T> inline T abs_helper(const T& x)
00251   { return (x > 0) ? x : -x; }
00252 }
00253 
00254 template <class T>
00255 Image<T> abs(const Image<T>& a)
00256 {
00257 GVX_TRACE(__PRETTY_FUNCTION__);
00258   Image<T> result(a.getDims(), NO_INIT);
00259   std::transform(a.begin(), a.end(), result.beginw(), abs_helper<T>);
00260   return result;
00261 }
00262 
00263 // ######################################################################
00264 template <class T>
00265 Image<typename promote_trait<T,float>::TP>
00266 hmaxActivation(const Image<T>& a, const float sigma)
00267 {
00268 GVX_TRACE(__PRETTY_FUNCTION__);
00269   typedef typename promote_trait<T, float>::TP TF;
00270   Image<TF> result(a.getDims(), NO_INIT);
00271   float sq = 0.5F / (sigma * sigma);
00272   int siz = a.getSize();
00273   typename Image<T>::const_iterator sptr = a.begin();
00274   typename Image<TF>::iterator dptr = result.beginw();
00275 
00276   for (int i = 0; i < siz; i ++)
00277     *dptr++ = clamped_convert<TF>(exp((*sptr++) * sq));
00278 
00279   return result;
00280 }
00281 
00282 // ######################################################################
00283 namespace
00284 {
00285   template <class T>
00286   inline T scalarAbsDiff(const T& t1,
00287                          const T& t2)
00288   {
00289     if (t1 < t2) return T(t2 - t1);
00290     else return T(t1 - t2);
00291   }
00292 
00293   template <class T>
00294   inline PixRGB<T> scalarAbsDiff(const PixRGB<T>& t1,
00295                                  const PixRGB<T>& t2)
00296   {
00297     return PixRGB<T>(scalarAbsDiff(t1.p[0], t2.p[0]),
00298                      scalarAbsDiff(t1.p[1], t2.p[1]),
00299                      scalarAbsDiff(t1.p[2], t2.p[2]));
00300   }
00301 }
00302 
00303 template <class T>
00304 Image<T> absDiff(const Image<T>& b, const Image<T>& c)
00305 {
00306 GVX_TRACE(__PRETTY_FUNCTION__);
00307   ASSERT(c.isSameSize(b));
00308 
00309   Image<T> result(b.getDims(), NO_INIT);
00310 
00311   typename Image<T>::const_iterator bptr = b.begin();
00312   typename Image<T>::const_iterator cptr = c.begin();
00313   typename Image<T>::iterator dptr = result.beginw();
00314   typename Image<T>::iterator stop = result.endw();
00315 
00316   while (dptr != stop)
00317     *dptr++ = scalarAbsDiff(*bptr++, *cptr++);
00318 
00319   return result;
00320 }
00321 
00322 // ######################################################################
00323 // Optimized absDiff implementations using SSE2 for some canonical datatypes:
00324 #ifdef INVT_USE_SSE2
00325 Image<byte> absDiff(const Image<byte>& b, const Image<byte> &c)
00326 {
00327   Image<byte> result(b.getDims(), NO_INIT);
00328   sse2_absDiff((const byte *)(b.begin()),(const byte *)(c.begin()),
00329               (byte *)(result.beginw()), b.getSize());
00330   return result;
00331 }
00332 
00333 Image<float> absDiff(const Image<float>& b, const Image<float> &c)
00334 {
00335   Image<float> result(b.getDims(), NO_INIT);
00336   sse2_absDiff((const float *)(b.begin()),(float *)(c.begin()),(float *)
00337               (result.beginw()), b.getSize());
00338   return result;
00339 }
00340 
00341 Image<int> absDiff(const Image<int>& b, const Image<int> &c)
00342 {
00343   Image<int> result(b.getDims(), NO_INIT);
00344   sse2_absDiff((const int *)(b.begin()),(const int *)(c.begin()),
00345               (int *)(result.beginw()), b.getSize());
00346   return result;
00347 }
00348 #endif
00349 #ifdef INVT_USE_SSE
00350 Image<double> absDiff(const Image<double>& b, const Image<double> &c)
00351 {
00352   Image<double> result(b.getDims(), NO_INIT);
00353   sse_absDiff((const double *)(b.begin()),(double *)(c.begin()),
00354               (double *)(result.beginw()), b.getSize());
00355   return result;
00356 }
00357 #endif
00358 
00359 
00360 // ######################################################################
00361 namespace
00362 {
00363   template <class T>
00364   inline T scalarClampedDiff(const T& t1,
00365                              const T& t2)
00366   {
00367     if (t1 < t2) return T(0);
00368     else return T(t1 - t2);
00369   }
00370 
00371   template <class T>
00372   inline PixRGB<T> scalarClampedDiff(const PixRGB<T>& t1,
00373                                      const PixRGB<T>& t2)
00374   {
00375     return PixRGB<T>(scalarClampedDiff(t1.p[0], t2.p[0]),
00376                      scalarClampedDiff(t1.p[1], t2.p[1]),
00377                      scalarClampedDiff(t1.p[2], t2.p[2]));
00378   }
00379 }
00380 
00381 template <class T>
00382 Image<T> clampedDiff(const Image<T>& b, const Image<T>& c)
00383 {
00384 GVX_TRACE(__PRETTY_FUNCTION__);
00385   ASSERT(c.isSameSize(b));
00386 
00387   Image<T> result(b.getDims(), NO_INIT);
00388 
00389   typename Image<T>::const_iterator bptr = b.begin();
00390   typename Image<T>::const_iterator cptr = c.begin();
00391   typename Image<T>::iterator dptr = result.beginw();
00392   typename Image<T>::iterator stop = result.endw();
00393 
00394   while (dptr != stop)
00395     *dptr++ = scalarClampedDiff(*bptr++, *cptr++);
00396 
00397   return result;
00398 }
00399 
00400 #ifdef INVT_USE_SSE
00401 
00402 // ######################################################################
00403 
00404 Image<float> clampedDiff(const Image<float>& b, const Image<float>& c)
00405 {
00406 GVX_TRACE(__PRETTY_FUNCTION__);
00407   ASSERT(c.isSameSize(b));
00408 
00409   Image<float> result(b.getDims(), NO_INIT);
00410 
00411   const float *bptr= b.begin();
00412   const float *cptr= c.begin();
00413 
00414   sse_clampedDiff(bptr, cptr,
00415                   (float *) (result.beginw()), b.getSize());
00416 
00417   return result;
00418 }
00419 
00420 
00421 // ######################################################################
00422 
00423 Image<byte> clampedDiff(const Image<byte>& b, const Image<byte>& c)
00424 {
00425 GVX_TRACE(__PRETTY_FUNCTION__);
00426   ASSERT(c.isSameSize(b));
00427 
00428   Image<byte> result(b.getDims(), NO_INIT);
00429 
00430   const byte *aptr = (const_cast <byte *> (b.begin()));
00431   const byte *bptr = (const_cast <byte *> (c.begin()));
00432   byte *dptr= (const_cast <byte *> (result.beginw()));
00433 
00434   sse_clampedDiff( aptr, bptr, dptr, b.getSize());
00435 
00436   return result;
00437 }
00438 
00439 // ######################################################################
00440 
00441 Image<int> clampedDiff(const Image<int>& b, const Image<int>& c)
00442 {
00443 GVX_TRACE(__PRETTY_FUNCTION__);
00444   ASSERT(c.isSameSize(b));
00445 
00446   Image<int> result(b.getDims(), NO_INIT);
00447 
00448   const int *bptr = (const_cast <int *> (b.begin()));
00449   const int *cptr = (const_cast <int *> (c.begin()));
00450   int *dptr = (const_cast <int *> (result.beginw()));
00451 
00452   sse_clampedDiff(bptr, cptr, dptr, b.getSize());
00453 
00454   return result;
00455 }
00456 
00457 
00458 #endif
00459 
00460 // ######################################################################
00461 template <class T>
00462 Image<T> binaryReverse(const Image<T>& a, const T val)
00463 {
00464 GVX_TRACE(__PRETTY_FUNCTION__);
00465   Image<T> result(a.getDims(), NO_INIT);
00466 
00467   typename Image<T>::const_iterator aptr = a.begin();
00468   typename Image<T>::iterator dptr = result.beginw();
00469   typename Image<T>::iterator stop = result.endw();
00470   while (dptr != stop)
00471     {
00472       *dptr++ = val - *aptr++;
00473     }
00474 
00475   return result;
00476 }
00477 
00478 // ######################################################################
00479 template <class T>
00480 Image<T> average(const Image<T>& b, const Image<T>& c)
00481 {
00482 GVX_TRACE(__PRETTY_FUNCTION__);
00483   ASSERT(b.isSameSize(c));
00484   Image<T> result(b.getDims(), NO_INIT);
00485   typename Image<T>::iterator aptr = result.beginw();
00486   typename Image<T>::iterator stop = result.endw();
00487   typename Image<T>::const_iterator bptr = b.begin();
00488   typename Image<T>::const_iterator cptr = c.begin();
00489 
00490   while (aptr != stop)
00491     *aptr++ = (T)( (*bptr++ * 0.5F) + (*cptr++ * 0.5F) );
00492 
00493   return result;
00494 }
00495 
00496 // ######################################################################
00497 
00498 template <class T>
00499 Image<T> averageWeighted(Image<T>& a, const Image<T>& b, T *aWeight)
00500 {
00501 GVX_TRACE(__PRETTY_FUNCTION__);
00502   ASSERT(a.isSameSize(b));
00503   typename Image<T>::iterator aptr;
00504   typename Image<T>::const_iterator bptr = b.begin();
00505   for(aptr = a.beginw();  aptr != a.endw(); ++aptr, ++bptr)
00506     *aptr = (((*aptr)*(*aWeight))+(*bptr))/(1+(*aWeight));
00507   return a;
00508 }
00509 
00510 namespace
00511 {
00512   template <class T>
00513   T element_wise_max(const T& t1, const T& t2)
00514   {
00515     return std::max(t1, t2);
00516   }
00517 
00518   template <class T>
00519   PixRGB<T> element_wise_max(const PixRGB<T>& t1,
00520                              const PixRGB<T>& t2)
00521   {
00522     return PixRGB<T>(std::max(t1.red(), t2.red()),
00523                      std::max(t1.green(), t2.green()),
00524                      std::max(t1.blue(), t2.blue()));
00525   }
00526 }
00527 
00528 // ######################################################################
00529 template <class T>
00530 Image<T> takeMax(const Image<T>& a, const Image<T>& b)
00531 {
00532 GVX_TRACE(__PRETTY_FUNCTION__);
00533   ASSERT(a.isSameSize(b));
00534 
00535   Image<T> result(a.getDims(), NO_INIT);
00536 
00537   typename Image<T>::const_iterator aptr = a.begin();
00538   typename Image<T>::const_iterator bptr = b.begin();
00539   typename Image<T>::iterator dptr = result.beginw();
00540   typename Image<T>::iterator stop = result.endw();
00541 
00542   while (dptr != stop)
00543     {
00544       *dptr++ = element_wise_max(*aptr++, *bptr++);
00545     }
00546 
00547   return result;
00548 }
00549 
00550 
00551 // ######################################################################
00552 template <class T> 
00553 void takeLinkedMax(const Image<T>& a1, const Image<T>& a2, const Image<T>& b1, const Image<T>& b2, Image<T>& aout, Image<T>& bout)
00554 {
00555 GVX_TRACE(__PRETTY_FUNCTION__);
00556   ASSERT(a1.isSameSize(a2));
00557   ASSERT(b1.isSameSize(b2));
00558   ASSERT(a1.isSameSize(aout));
00559   ASSERT(aout.isSameSize(bout));
00560   ASSERT(a1.isSameSize(b1));
00561 
00562   typename Image<T>::const_iterator a1ptr = a1.begin();
00563   typename Image<T>::const_iterator a2ptr = a2.begin();
00564   typename Image<T>::const_iterator b1ptr = b1.begin();
00565   typename Image<T>::const_iterator b2ptr = b2.begin();
00566   typename Image<T>::iterator aoutptr = aout.beginw(), stop = aout.endw();
00567   typename Image<T>::iterator boutptr = bout.beginw();
00568 
00569   while (aoutptr != stop)
00570     {
00571       if(*a1ptr > *a2ptr)
00572         {
00573           *aoutptr=*a1ptr;
00574           *boutptr=*b1ptr;
00575         }
00576       else
00577         {
00578           *aoutptr=*a2ptr;
00579           *boutptr=*b2ptr;
00580         }
00581       a1ptr++; a2ptr++;
00582       b1ptr++; b2ptr++;
00583       aoutptr++; boutptr++;
00584     }
00585 
00586 }
00587 
00588 
00589 
00590 // ######################################################################
00591 template <class T>
00592 Image<T> takeMin(const Image<T>& a, const Image<T>& b)
00593 {
00594 GVX_TRACE(__PRETTY_FUNCTION__);
00595   ASSERT(a.isSameSize(b));
00596 
00597   Image<T> result(a.getDims(), NO_INIT);
00598 
00599   typename Image<T>::const_iterator aptr = a.begin();
00600   typename Image<T>::const_iterator bptr = b.begin();
00601   typename Image<T>::iterator dptr = result.beginw();
00602   typename Image<T>::iterator stop = result.endw();
00603 
00604   while (dptr != stop)
00605     {
00606       *dptr++ = std::min(*aptr++, *bptr++);
00607     }
00608 
00609   return result;
00610 }
00611 
00612 // ######################################################################
00613 template <class T>
00614 Image<T> quadEnergy(const Image<T>& img1, const Image<T>& img2)
00615 {
00616 GVX_TRACE(__PRETTY_FUNCTION__);
00617   ASSERT(img1.isSameSize(img2));
00618 
00619   Image<T> result(img1.getDims(), NO_INIT);
00620 
00621   typename Image<T>::const_iterator s1ptr = img1.begin();
00622   typename Image<T>::const_iterator s2ptr = img2.begin();
00623   typename Image<T>::iterator dptr = result.beginw();
00624   typename Image<T>::iterator stop = result.endw();
00625   typedef typename promote_trait<T, float>::TP TF;
00626   while (dptr != stop)
00627     {
00628       const TF s1( *s1ptr++ );
00629       const TF s2( *s2ptr++ );
00630       *dptr++ = T(sqrt(s1 * s1 + s2 * s2));
00631     }
00632 
00633   return result;
00634 }
00635 
00636 // ######################################################################
00637 template <class T>
00638 double RMSerr(const Image<T>& arr1, const Image<T>& arr2)
00639 {
00640 GVX_TRACE(__PRETTY_FUNCTION__);
00641   ASSERT(arr1.initialized() && arr2.initialized());
00642   ASSERT(arr1.isSameSize(arr2));
00643 
00644   typename Image<T>::const_iterator ap1 = arr1.begin();
00645   typename Image<T>::const_iterator ap2 = arr2.begin();
00646   typename Image<T>::const_iterator stop2 = arr2.end();
00647 
00648   double err = 0.0f;
00649   while (ap2 != stop2)
00650     { double v = *ap1++ - *ap2++; err += v * v;  }
00651   return sqrt(err / double(arr1.getSize()));
00652 }
00653 
00654 // ######################################################################
00655 template <class T>
00656 Image<T> overlay(const Image<T>& top, const Image<T>& bottom,
00657                  const float trans)
00658 {
00659 GVX_TRACE(__PRETTY_FUNCTION__);
00660   // 0 to 100 percent only:
00661   ASSERT((trans >= 0.0F) && (trans <= 100.0F));
00662   // images must be same size:
00663   ASSERT(top.isSameSize(bottom));
00664 
00665   // result is the same size as the input images:
00666   Image<T> result(top.getDims(), NO_INIT);
00667 
00668   typename Image<T>::const_iterator tptr = top.begin();
00669   typename Image<T>::const_iterator bptr = bottom.begin();
00670   typename Image<T>::iterator dptr = result.beginw();
00671   typename Image<T>::iterator stop = result.endw();
00672   float tfac = trans * 0.01F;
00673   while (dptr != stop)
00674     {
00675       *dptr = T((*tptr) - ( (*tptr) - (*bptr) ) * tfac);
00676       ++dptr; ++bptr; ++tptr;
00677     }
00678 
00679   return result;
00680 }
00681 
00682 // ######################################################################
00683 template <class T>
00684 float sumXY(const Image<T>& img, std::vector<float>& sumX,
00685             std::vector<float>& sumY)
00686 {
00687 GVX_TRACE(__PRETTY_FUNCTION__);
00688   int w = img.getWidth(), h = img.getHeight();
00689   sumX.resize(w,0.0F);
00690   sumY.resize(h,0.0F);
00691   std::vector<float>::iterator sX, sY = sumY.begin();
00692   float sum = 0.0F;
00693   typename Image<T>::const_iterator ptr = img.begin();
00694   for (int y = 0; y < h; y++)
00695     {
00696       sX = sumX.begin();
00697       for (int x = 0; x < w; x++)
00698         {
00699           //sumX[x] += (float)*ptr;
00700           //sumY[y] += (float)*ptr;
00701           *sX += (float)*ptr;
00702           *sY += (float)*ptr;
00703           sum += (float)*ptr++;
00704           ++sX;
00705         }
00706       ++sY;
00707     }
00708 
00709   return sum;
00710 }
00711 
00712 // ######################################################################
00713 template <class T>
00714 double distance(const Image<T> &img1, const Image<T> &img2)
00715 {
00716 GVX_TRACE(__PRETTY_FUNCTION__);
00717   ASSERT(img1.isSameSize(img2));
00718   double d = 0.0;
00719   typename Image<T>::const_iterator ptr1 = img1.begin(),
00720     ptr2 = img2.begin(), e = img1.end();
00721   while(ptr1 != e) {
00722     d += (*ptr1 - *ptr2) * (*ptr1 - *ptr2);
00723     ptr1 ++; ptr2 ++;
00724   }
00725   return sqrt(d);
00726 }
00727 
00728 // ######################################################################
00729 template <class T>
00730 double distance(const Image<T> &img1, const Image<T> &img2,
00731                 const Image<float> &weight)
00732 {
00733 GVX_TRACE(__PRETTY_FUNCTION__);
00734   ASSERT(img1.isSameSize(img2) && img1.isSameSize(weight));
00735 
00736   double d = 0.0;
00737   typename Image<T>::const_iterator ptr1 = img1.begin(),
00738     ptr2 = img2.begin(), e = img1.end();
00739   Image<float>::const_iterator w = weight.begin();
00740 
00741   while(ptr1 != e) {
00742     d += *w * (*ptr1 - *ptr2) * (*ptr1 - *ptr2);
00743     ptr1 ++; ptr2 ++; w ++;
00744   }
00745   return sqrt(d);
00746 }
00747 
00748 // ######################################################################
00749 double corrcoef(const Image<float>& img1, const Image<float>& img2)
00750 {
00751 GVX_TRACE(__PRETTY_FUNCTION__);
00752   ASSERT(img1.initialized());
00753   ASSERT(img2.initialized());
00754   ASSERT(img1.isSameSize(img2));
00755 
00756   Image<float>::const_iterator p1 = img1.begin();
00757   Image<float>::const_iterator p2 = img2.begin();
00758   const Image<float>::const_iterator stop1 = img1.end();
00759 
00760   double sum1 = 0.0;
00761   double sum2 = 0.0;
00762 
00763   double sumsq1 = 0.0;
00764   double sumsq2 = 0.0;
00765 
00766   double sumprod = 0.0;
00767 
00768   while (p1 != stop1)
00769     {
00770       sum1    += (*p1);
00771       sum2    += (*p2);
00772       sumsq1  += double(*p1) * double(*p1);
00773       sumsq2  += double(*p2) * double(*p2);
00774       sumprod += double(*p1) * double(*p2);
00775 
00776       ++p1;
00777       ++p2;
00778     }
00779 
00780   const int n = img1.getSize();
00781 
00782   const double avg1 = sum1 / n;
00783   const double avg2 = sum2 / n;
00784 
00785   const double rsq =
00786     ((sumsq1 - n*avg1*avg1) != 0.0 && (sumsq2 - n*avg2*avg2) != 0.0)
00787     ? (squareOf(sumprod - n*avg1*avg2)
00788        /
00789        ( (sumsq1 - n*avg1*avg1) * (sumsq2 - n*avg2*avg2) ))
00790     : 0.0;
00791 
00792   ASSERT(rsq >= 0.0);
00793 
00794   // can't just do ASSERT(rsq<=1.0) because that's susceptible to
00795   // floating-point errors where rsq ends up slightly greater than 1.0
00796   ASSERT(rsq-1.0 < 1.0e-5);
00797 
00798   return rsq;
00799 }
00800 
00801 // ######################################################################
00802 template <class T>
00803 double corrpatch(const Image<T>& img1, const Point2D<int>& topleft1,
00804                  const Dims& patchdims, const Image<T>& img2,
00805                  const Point2D<int>& topleft2, const double eps)
00806 {
00807 GVX_TRACE(__PRETTY_FUNCTION__);
00808 
00809   if (patchdims.sz() == 0) return 0.0;
00810   ASSERT(img1.rectangleOk(Rectangle(topleft1, patchdims)));
00811   ASSERT(img2.rectangleOk(Rectangle(topleft2, patchdims)));
00812 
00813   const int pw = patchdims.w(), ph = patchdims.h();
00814   const int i1w = img1.getWidth(), i2w = img2.getWidth();
00815 
00816   typename Image<T>::const_iterator p1 = img1.begin() + topleft1.j * i1w + topleft1.i;
00817   typename Image<T>::const_iterator p2 = img2.begin() + topleft2.j * i2w + topleft2.i;
00818   const int stride1 = i1w - pw, stride2 = i2w - pw;
00819 
00820   double sum1 = 0.0, sum2 = 0.0, sumsq1 = 0.0, sumsq2 = 0.0, sumprod = 0.0;
00821 
00822   for (int j = 0; j < ph; j ++)
00823     {
00824       for (int i = 0; i < pw; i ++)
00825         {
00826           const double val1 = double(*p1++), val2 = (*p2++);
00827 
00828           sum1    += val1;
00829           sum2    += val2;
00830           sumsq1  += val1 * val1;
00831           sumsq2  += val2 * val2;
00832           sumprod += val1 * val2;
00833         }
00834 
00835       // switch to next row in inputs:
00836       p1 += stride1; p2 += stride2;
00837     }
00838 
00839   const double n = double(pw * ph);
00840   const double avg1 = sum1 / n, avg2 = sum2 / n;
00841 
00842   const double denom1 = sumsq1 - n * avg1 * avg1;
00843   const double denom2 = sumsq2 - n * avg2 * avg2;
00844 
00845   if (fabs(denom1) < eps || fabs(denom2) < eps)
00846     {
00847       if (fabs(denom1) < eps && fabs(denom2) < eps) return 1.0;
00848       return 0.0;
00849     }
00850 
00851   return (sumprod - n * avg1 * avg2) / sqrt(denom1 * denom2);
00852 }
00853 
00854 // ######################################################################
00855 template <class T>
00856 void corrEigenMatrix(const std::vector<std::vector<Image<T> > > &baseImages,
00857                      Image<T> &baseCorr, Image<T> &baseMean,
00858                      Image<T> &baseSTD,  Image<T> &baseSS,
00859                      uint &baseN, bool returnR = false)
00860 {
00861 
00862 
00863   const ushort baseDim = baseImages[0].size();
00864 
00865   baseMean.resize(baseDim,1);
00866   baseSS.resize(baseDim,1);
00867   baseSTD.resize(baseDim,1);
00868   baseCorr.resize(baseDim,baseDim);
00869 
00870   for(ushort i = 0; i < baseDim; i++)
00871   {
00872     baseMean.setVal(i,0,0.0);
00873     baseSS.setVal(i,0,0.0);
00874     baseSTD.setVal(i,0,0.0);
00875     for(ushort j = 0; j < baseDim; j++)
00876     {
00877       baseCorr.setVal(i,j,0.0);
00878     }
00879   }
00880 
00881   baseN = 0;
00882 
00883   typename std::vector<std::vector<Image<T> > >::const_iterator ibaseImages
00884     = baseImages.begin();
00885 
00886   // compute mean and standard deviation over each feature type
00887 
00888   LINFO("Getting base stats");
00889 
00890   // Run over each FRAME
00891   while(ibaseImages != baseImages.end())
00892   {
00893     typename std::vector<Image<T> >::const_iterator iibaseImages
00894       = ibaseImages->begin();
00895     typename Image<T>::iterator ibaseMean = baseMean.beginw();
00896     typename Image<T>::iterator ibaseSS   = baseSS.beginw();
00897     typename Image<T>::iterator ibaseSTD  = baseSTD.beginw();
00898 
00899     baseN += iibaseImages->getHeight() * iibaseImages->getWidth();
00900 
00901     // Run over each FEATURE
00902     while(iibaseImages != ibaseImages->end())
00903     {
00904       typename Image<T>::const_iterator iiibaseImages = iibaseImages->begin();
00905 
00906       // Run over each PIXEL
00907       while(iiibaseImages != iibaseImages->end())
00908       {
00909         *ibaseSS   += static_cast<T>(pow(*iiibaseImages,2));
00910         *ibaseMean += *iiibaseImages;
00911         ++iiibaseImages;
00912       }
00913       ++iibaseImages;
00914       ++ibaseMean; ++ibaseSS; ++ibaseSTD;
00915     }
00916     ++ibaseImages;
00917   }
00918 
00919   LINFO("Getting final base stats");
00920 
00921   typename Image<T>::iterator ibaseMean = baseMean.beginw();
00922   typename Image<T>::iterator ibaseSS   = baseSS.beginw();
00923   typename Image<T>::iterator ibaseSTD  = baseSTD.beginw();
00924   // Run over each FEATURE
00925   while(ibaseMean != baseMean.endw())
00926   {
00927     if((baseN > 0) && (*ibaseSS > 0))
00928     {
00929       // mean
00930       *ibaseMean = *ibaseMean/baseN;
00931       // stddev
00932       *ibaseSTD  = static_cast<T>(sqrt((*ibaseSS/baseN) - pow(*ibaseMean,2)));
00933     }
00934     else
00935     {
00936       *ibaseMean = 0;
00937       *ibaseSTD  = 0;
00938     }
00939     ++ibaseMean; ++baseN; ++ibaseSS; ++ibaseSTD;
00940   }
00941 
00942   ibaseImages = baseImages.begin();
00943 
00944 
00945 
00946   LINFO("computing product covariance");
00947   // compute product covariance
00948   // Run over each FRAME
00949   while(ibaseImages != baseImages.end())
00950   {
00951     typename std::vector<Image<T> >::const_iterator iibaseImages
00952       = ibaseImages->begin();
00953     // Run over each FEATURE
00954     for(ushort i = 0; i < baseDim; i++, ++iibaseImages)
00955     {
00956       // Run over each PIXEL
00957       for(int x = 0; x < iibaseImages->getWidth(); x++)
00958       {
00959         for(int y = 0; y < iibaseImages->getHeight(); y++)
00960         {
00961           const T base = iibaseImages->getVal(x,y);
00962           typename std::vector<Image<T> >::const_iterator iicbaseImages
00963             = ibaseImages->begin();
00964           // Run over each OTHER FEATURE
00965           for(ushort j = 0; j < baseDim; j++, ++iicbaseImages)
00966           {
00967             // compute product sum over each X*Y
00968             T corrVal = baseCorr.getVal(i,j);
00969             corrVal += base * iicbaseImages->getVal(x,y);
00970             baseCorr.setVal(i,j,corrVal);
00971           }
00972         }
00973       }
00974     }
00975     ++ibaseImages;
00976   }
00977 
00978   LINFO("Computing final covariance");
00979 
00980   // compute final covaraince
00981   if(returnR)
00982   {
00983     // Normalized true pearson R correlation
00984     for(uint i = 0; i < baseDim; i++)
00985     {
00986       for(uint j = 0; j < baseDim; j++)
00987       {
00988         // compute (sum(X*Y)/N - Xbar*Ybar) / Xstd*Ystd
00989         T val = baseCorr.getVal(i,j);
00990         val = ((val/baseN) - (baseMean[i] * baseMean[j])) /
00991                (baseSTD[i] * baseSTD[j]);
00992         baseCorr.setVal(i,j,val);
00993       }
00994     }
00995   }
00996   else
00997   {
00998     // Un-normalized eigen matrix for Likelyhood est
00999     // Used in Mahalanobis distance computation as well
01000     for(uint i = 0; i < baseDim; i++)
01001     {
01002       for(uint j = 0; j < baseDim; j++)
01003       {
01004         T val = baseCorr.getVal(i,j);
01005         // compute sum(X*Y)/N - Xbar*Ybar
01006         val = (val/baseN) - (baseMean[i] * baseMean[j]);
01007         baseCorr.setVal(i,j,val);
01008       }
01009     }
01010   }
01011 }
01012 
01013 // ######################################################################
01014 template <class T>
01015 void getLikelyhoodImage(const std::vector<Image<T> > &baseImages,
01016                         const Image<T> &baseCorr, const Image<T> &baseMean,
01017                         const bool returnLogLikelyhood,
01018                         Image<T> &likelyhoodImage,
01019                         Image<T> &nonNormalizedLImage)
01020 {
01021   // matrix must be square
01022   if(baseCorr.getWidth() != baseCorr.getHeight())
01023     LFATAL("ERROR matrix is not square %d x %d",
01024            baseCorr.getWidth(),baseCorr.getHeight());
01025 
01026   // hold the matrix dims
01027   // const T dims           = baseCorr.getWidth();
01028   // first compute the inverse eigen matrix
01029   const Image<T> invCorr = matrixInv(baseCorr);
01030   // compute the determinant of the eigen matrix
01031   // In this case, it is just the product of the eigen values
01032   // WE take the log sum rather than product to keep the number sane
01033 
01034   //const T detCorr        = static_cast<T>(sqrt(matrixDet(baseCorr)));
01035   //T logDetCorr = static_cast<T>(log(sqrt((2*M_PI)/baseCorr.getVal(0,0))));
01036   //T detCorr = static_cast<T>(1/(pow((2*M_PI),(dims/2))));
01037   T logDetCorr = 0;
01038   for(ushort i = 0; i < (ushort)baseCorr.getWidth(); i++)
01039   {
01040     //LINFO("** baseCorr %f",baseCorr.getVal(i,i));
01041     logDetCorr += static_cast<T>(log(1.0/sqrt((2.0*M_PI)*baseCorr.getVal(i,i))));
01042     //LINFO("** logDetCorr %f",logDetCorr);
01043   }
01044 
01045   //LINFO("logDetCorr %f",logDetCorr);
01046   // compute the easy left hand side of the guassian
01047   const T LHS = static_cast<T>(logDetCorr);
01048   //LINFO("LHS computed as %f",LHS);
01049 
01050 
01051   likelyhoodImage.resize(baseImages[0].getWidth(),
01052                          baseImages[0].getHeight());
01053 
01054   nonNormalizedLImage.resize(baseImages[0].getWidth(),
01055                              baseImages[0].getHeight());
01056 
01057   // create column difference x - mu matrix
01058   Image<T> diffMatrix;
01059   diffMatrix.resize(1,baseCorr.getWidth());
01060 
01061   for(uint i = 0; i < (uint)baseImages[0].getWidth(); i++)
01062   {
01063     for(uint j = 0; j < (uint)baseImages[0].getHeight(); j++)
01064     {
01065 
01066       typename Image<T>::iterator                     idiffMatrix =
01067         diffMatrix.beginw();
01068       typename Image<T>::const_iterator               ibaseMean   =
01069         baseMean.begin();
01070       typename std::vector<Image<T> >::const_iterator ibaseImages =
01071         baseImages.begin();
01072 
01073       while(ibaseImages != baseImages.end())
01074       {
01075         // for each feature, compute x - mu
01076         *idiffMatrix = ibaseImages->getVal(i,j) - *ibaseMean;
01077         ++ibaseImages; ++ibaseMean; ++idiffMatrix;
01078       }
01079       // compute Mahalanobis distance (x - mu)*iSIG*(x - mu)
01080       const T RHS = static_cast<T>(sum(matrixMult(
01081                     clamped_convert<Image<T> >
01082                     (vmMult(transpose(diffMatrix),invCorr))
01083                                    ,diffMatrix)));
01084       //LINFO("RHS computed as %f",RHS);
01085       const T newRHS = static_cast<T>((-1.0/2.0) * RHS);
01086       //LINFO("new RHS %f",newRHS);
01087       //LINFO("LHS %f",LHS);
01088 
01089       // compute final p(x)
01090       if(returnLogLikelyhood)
01091       {
01092         nonNormalizedLImage.setVal(i,j,newRHS);
01093         const T Px  = static_cast<T>(LHS + newRHS);
01094         likelyhoodImage.setVal(i,j,Px);
01095       }
01096       else
01097       {
01098         nonNormalizedLImage.setVal(i,j,exp(newRHS));
01099         const T Px  = static_cast<T>(exp(LHS + newRHS));
01100         likelyhoodImage.setVal(i,j,Px);
01101       }
01102     }
01103   }
01104 }
01105 
01106 // ######################################################################
01107 template <class T>
01108 Image<T> getNormalizedBayesImage(const Image<T> classImage1,
01109                                  const Image<T> classImage2,
01110                                  const bool usingLogLikelyhood,
01111                                  const T beta,
01112                                  const T classPrior1,
01113                                  const T classPrior2,
01114                                  const T bias)
01115 {
01116   if(classImage1.getHeight() != classImage2.getHeight())
01117     LFATAL("classImage1 height %d != classImage2 height %d",
01118            classImage1.getHeight(),classImage2.getHeight());
01119   if(classImage1.getWidth() != classImage2.getWidth())
01120     LFATAL("classImage1 width %d != classImage2 width %d",
01121            classImage1.getWidth(),classImage2.getWidth());
01122   Image<T> returnImage;
01123   returnImage.resize(classImage1.getWidth(),
01124                      classImage1.getHeight());
01125 
01126   typename Image<T>::iterator       ireturnImage = returnImage.beginw();
01127   typename Image<T>::const_iterator iclassImage1 = classImage1.begin();
01128   typename Image<T>::const_iterator iclassImage2 = classImage2.begin();
01129 
01130   if(usingLogLikelyhood)
01131   {
01132     while(ireturnImage != returnImage.end())
01133     {
01134       const T a     = static_cast<T>(*iclassImage1 - *iclassImage2 +
01135                                      log(classPrior1/classPrior2));
01136       *ireturnImage = static_cast<T>((1.0/(1.0 + exp(-1.0*a*beta))) * bias);
01137       ++ireturnImage; ++iclassImage1; ++iclassImage2;
01138     }
01139   }
01140   else
01141   {
01142     while(ireturnImage != returnImage.end())
01143     {
01144       const T a     = static_cast<T>(log(((*iclassImage1)*classPrior1)/
01145                                          (*iclassImage2)*classPrior2));
01146       *ireturnImage = static_cast<T>((1.0/(1.0 + exp(-1.0*a*beta))) * bias);
01147       ++ireturnImage; ++iclassImage1; ++iclassImage2;
01148     }
01149   }
01150 
01151   return returnImage;
01152 }
01153 
01154 // ######################################################################
01155 template <class T>
01156 Image<T> getPearsonRMatrix(const Image<T> &eigenMatrix,
01157                            const Image<T> &STDMatrix)
01158 {
01159   if(eigenMatrix.getWidth() != eigenMatrix.getHeight())
01160     LFATAL("eigenMatrix not square width %d != height %d",
01161            eigenMatrix.getWidth(),eigenMatrix.getHeight());
01162 
01163   uint baseDim = eigenMatrix.getWidth();
01164 
01165   Image<T> returnImage;
01166   returnImage.resize(eigenMatrix.getWidth(),eigenMatrix.getHeight());
01167 
01168   // Normalized true pearson R correlation
01169   for(uint i = 0; i < baseDim; i++)
01170   {
01171     for(uint j = 0; j < baseDim; j++)
01172     {
01173       // compute (sum(X*Y)/N - Xbar*Ybar) / Xstd*Ystd from
01174       // the eigen matrix values
01175       T val = eigenMatrix.getVal(i,j);
01176       val = val / (STDMatrix[i] * STDMatrix[j]);
01177       returnImage.setVal(i,j,val);
01178     }
01179   }
01180   return returnImage;
01181 }
01182 
01183 // ######################################################################
01184 template <class T>
01185 void getAugmentedBeliefBayesImage(const Image<T> &bayesImage,
01186                                   const Image<T> &beliefImage1,
01187                                   const Image<T> &beliefImage2,
01188                                   const T medianPoint,
01189                                   Image<T> &beliefImage,
01190                                   Image<T> &beliefValue)
01191 {
01192   beliefImage.resize(bayesImage.getWidth(), bayesImage.getHeight());
01193   beliefValue.resize(bayesImage.getWidth(), bayesImage.getHeight());
01194 
01195   typename Image<T>::const_iterator ibayesImage   = bayesImage.begin();
01196   typename Image<T>::const_iterator ibeliefImage1 = beliefImage1.begin();
01197   typename Image<T>::const_iterator ibeliefImage2 = beliefImage2.begin();
01198   typename Image<T>::iterator       ibeliefImage  = beliefImage.beginw();
01199   typename Image<T>::iterator       ibeliefValue  = beliefValue.beginw();
01200 
01201   float min = FLT_MAX;
01202   float max = FLT_MIN;
01203 
01204 
01205   while(ibeliefValue != beliefValue.endw())
01206   {
01207     *ibeliefValue = static_cast<T>(*ibeliefImage1 + *ibeliefImage2);
01208     if(*ibeliefValue > max)
01209       max = static_cast<float>(*ibeliefValue);
01210     if(*ibeliefValue < min)
01211       min = static_cast<float>(*ibeliefValue);
01212     ++ibeliefImage1; ++ibeliefImage2; ++ibeliefValue;
01213   }
01214 
01215   ibeliefValue  = beliefValue.beginw();
01216 
01217   const T interval = static_cast<T>(max - min);
01218   const T minT     = static_cast<T>(min);
01219 
01220   while(ibeliefValue != beliefValue.endw())
01221   {
01222     *ibeliefValue = static_cast<T>(exp(((*ibeliefValue - minT)/interval)-1));
01223     ++ibeliefValue;
01224   }
01225   ibeliefImage1 = beliefImage1.begin();
01226   ibeliefImage2 = beliefImage2.begin();
01227   ibeliefValue  = beliefValue.beginw();
01228 
01229   while(ibayesImage != bayesImage.end())
01230   {
01231     const T diff = static_cast<T>(
01232                    fabs(static_cast<float>(*ibayesImage - medianPoint)));
01233     const T aug  = diff * *ibeliefValue;
01234 
01235     if(*ibayesImage >= medianPoint)
01236       *ibeliefImage = medianPoint + aug;
01237     else
01238       *ibeliefImage = medianPoint - aug;
01239 
01240     ++ibayesImage; ++ibeliefImage1; ++ibeliefImage2; ++ibeliefImage;
01241     ++ibeliefValue;
01242   }
01243 }
01244 
01245 // ######################################################################
01246 template <class T>
01247 double pSNR(const Image<T> &img1, const Image<T> &img2)
01248 {
01249 GVX_TRACE(__PRETTY_FUNCTION__);
01250   double sigma2 = distance(img1, img2);
01251   sigma2 = sigma2 * sigma2 / double(img1.getSize());
01252   return 10.0 * log10(255.0*255.0 / sigma2);
01253 }
01254 
01255 // ######################################################################
01256 template <class T>
01257 double pSNR(const Image<T> &img1, const Image<T> &img2,
01258             const Image<float>& weight)
01259 {
01260 GVX_TRACE(__PRETTY_FUNCTION__);
01261   double sigma2 = distance(img1, img2, weight);
01262   sigma2 = sigma2 * sigma2 / double(img1.getSize());
01263   return 10.0 * log10(255.0*255.0 / sigma2);
01264 }
01265 
01266 // ######################################################################
01267 template <class T>
01268 Image<typename promote_trait<T,float>::TP> sqrt(const Image<T>& a)
01269 {
01270 GVX_TRACE(__PRETTY_FUNCTION__);
01271   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01272   typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01273   typename Image<typename promote_trait<T,float>::TP>::iterator
01274     dest = result.beginw();
01275   while(src != stop) *dest++ = sqrt(*src++);
01276   return result;
01277 }
01278 
01279 // ######################################################################
01280 template <class T>
01281 Image<typename promote_trait<T,float>::TP> inverse(const Image<T>& a,
01282                                                    const T eps)
01283 {
01284 GVX_TRACE(__PRETTY_FUNCTION__);
01285   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01286   std::transform(a.begin(), a.end(), result.beginw(), EpsInv<T>(eps));
01287   return result;
01288 }
01289 
01290 // ######################################################################
01291 template <class T>
01292 Image<typename promote_trait<T,float>::TP> exp(const Image<T>& a)
01293 {
01294 GVX_TRACE(__PRETTY_FUNCTION__);
01295   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01296   typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01297   typename Image<typename promote_trait<T,float>::TP>::iterator
01298     dest = result.beginw();
01299   while(src != stop) *dest++ = exp(*src++);
01300   return result;
01301 }
01302 
01303 // ######################################################################
01304 template <class T>
01305 Image<typename promote_trait<T,float>::TP> negexp(const Image<T>& a)
01306 {
01307 GVX_TRACE(__PRETTY_FUNCTION__);
01308   Image<typename promote_trait<T,float>::TP> result(a.getDims(), NO_INIT);
01309   typename Image<T>::const_iterator src = a.begin(), stop = a.end();
01310   typename Image<typename promote_trait<T,float>::TP>::iterator
01311     dest = result.beginw();
01312   while(src != stop) *dest++ = exp( - (*src++));
01313   return result;
01314 }
01315 
01316 // ######################################################################
01317 template <class T>
01318 Image<typename promote_trait<T,float>::TP> log(const Image<T>& src)
01319 {
01320 GVX_TRACE(__PRETTY_FUNCTION__);
01321   typedef typename promote_trait<T,float>::TP TF;
01322   Image<TF> result(src.getDims(), NO_INIT);
01323   typename Image<T>::const_iterator sptr = src.begin();
01324   typename Image<TF>::iterator dptr = result.beginw();
01325   typename Image<TF>::iterator stop = result.endw();
01326 
01327   while (dptr != stop)
01328     *dptr++ = log(*sptr++);
01329 
01330   return result;
01331 }
01332 
01333 // ######################################################################
01334 template <class T>
01335 Image<typename promote_trait<T,float>::TP> log10(const Image<T>& src)
01336 {
01337 GVX_TRACE(__PRETTY_FUNCTION__);
01338   typedef typename promote_trait<T,float>::TP TF;
01339   Image<TF> result(src.getDims(), NO_INIT);
01340   typename Image<T>::const_iterator sptr = src.begin();
01341   typename Image<TF>::iterator dptr = result.beginw();
01342   typename Image<TF>::iterator stop = result.endw();
01343 
01344   while (dptr != stop)
01345     *dptr++ = log10(*sptr++);
01346 
01347   return result;
01348 }
01349 
01350 // ######################################################################
01351 template <class T>
01352 bool getCentroidFirstLast(std::vector<T> vect, float& centroid,
01353                           int& first, int& last)
01354 {
01355 GVX_TRACE(__PRETTY_FUNCTION__);
01356   double sum = 0.0;
01357   double mi = 0.0;
01358   bool before = true;
01359   const T zero = T();
01360 
01361   typename std::vector<T>::iterator vit = vect.begin();
01362 
01363   for (uint i = 0; i < vect.size(); ++i, ++vit)
01364     {
01365       //LINFO("vect[%d] = %g",i,vect[i]);
01366       mi  += (*vit * i);
01367       sum += *vit;
01368       if (before) first = i;
01369       if (*vit != zero)
01370         {
01371           before = false;
01372           last = i;
01373         }
01374     }
01375 
01376   // there was nobody at home?
01377   if (before)
01378     {
01379       centroid = -1.0F; first = -1; last = -1;
01380       return false;
01381     }
01382 
01383   if (sum == 0.0)
01384     LFATAL("The sum of non-zero numbers is zero - don't know how "
01385            "to compute the center of mass in this case.");
01386 
01387   centroid = mi / sum;
01388   return true;
01389 }
01390 
01391 // ######################################################################
01392 template <class T>
01393 Point2D<int> centroid(const Image<T>& img, Rectangle& boundingBox,
01394                  float& cenX, float& cenY)
01395 {
01396 GVX_TRACE(__PRETTY_FUNCTION__);
01397   std::vector<float> sumx, sumy;
01398   sumXY(img, sumx, sumy);
01399   int firstX, lastX, firstY, lastY;
01400   cenX = 0.0F; cenY = 0.0F;
01401 
01402   bool success = getCentroidFirstLast(sumx, cenX, firstX, lastX);
01403   success |= getCentroidFirstLast(sumy, cenY, firstY, lastY);
01404 
01405   if (!success)
01406     {
01407       boundingBox = Rectangle();
01408       return Point2D<int>(-1,-1);
01409     }
01410 
01411   boundingBox = Rectangle::tlbrI(firstY, firstX, lastY, lastX);
01412   return Point2D<int>(int(cenX + 0.5F), int(cenY + 0.5F));
01413 }
01414 
01415 // ######################################################################
01416 template <class T>
01417 Point2D<int> centroid(const Image<T>& img)
01418 {
01419 GVX_TRACE(__PRETTY_FUNCTION__);
01420   Rectangle boundingBox;
01421   float cenX, cenY;
01422   return centroid(img, boundingBox, cenX, cenY);
01423 }
01424 
01425 // ######################################################################
01426 template<class T>
01427 Image<T> squash(const Image<T>& ima,
01428                 const T oldmin, const T newmin,
01429                 const T oldmid, const T newmid,
01430                 const T oldmax, const T newmax)
01431 {
01432 GVX_TRACE(__PRETTY_FUNCTION__);
01433   // if the input is blank, let's return blank:
01434   if (oldmin == oldmax) return ima;
01435 
01436   // let's compute the remapping coeffs and do some checking that we
01437   // actually can remap:
01438   float a = float(oldmin), b = float(oldmid), c = float(oldmax);
01439   float d = float(newmin), e = float(newmid), f = float(newmax);
01440 
01441   // here are the polynomial coefficients, straight out of
01442   // Mathematica. They are not optimized for computation speed, but we
01443   // don't really care here as we only need to compute them once. They
01444   // all need to be divided by the denominator below:
01445   float q0 = c*c*(b*(b-c)*(b-c)*(-4.0F*a*a + 3.0F*a*b + 2.0F*a*c - b*c)*d +
01446                   a*a*(a-c)*(a-c)*(a-c)*e) + a*a*(a-b)*(a-b)*b*
01447     (a*(b-2.0F*c) + c*(-3.0F*b + 4.0F*c))*f;
01448   float q1 = 2.0F*a*c*(c*c*c*c*(e-d) - 3.0F*b*b*b*b*(d-f) +
01449                        4.0F*b*b*b*c*(d-f) + 2.0F*a*a*a*c*(e-f) + a*a*a*a*(f-e)+
01450                        2.0F*a*(c*c*c*(d-e) + 2.0F*b*b*b*(d-f) +
01451                                3.0F*b*b*c*(f-d)));
01452   float q2 = a*a*a*a*a*(e-f) + a*a*a*a*c*(e-f) + 8.0F*a*a*a*c*c*(f-e) +
01453     (a+c)*(c*c*c*c*(d-e) + 3.0F*b*b*b*b*(d-f) + 4.0F*b*b*b*c*(f-d)) -
01454     4.0F*a*a*(2.0F*c*c*c*(d-e) + b*b*b*(d-f) + 3.0F*b*c*c*(f-d));
01455   float q3 = 2.0F*(c*c*c*c*(e-d) + 2.0F*a*a*(b-c)*(b-c)*(d-f) +
01456                    2.0F*b*b*c*c*(d-f) + 2.0F*a*a*a*c*(e-f) +
01457                    b*b*b*b*(f-d) + a*a*a*a*(f-e) +
01458                    2.0F*a*c*(c*c*(d-e) + b*b*(d-f) + 2.0F*b*c*(f-d)));
01459   float q4 = -3.0F*a*b*b*d + 2.0F*b*b*b*d + 6.0F*a*b*c*d - 3.0F*b*b*c*d -
01460     3.0F*a*c*c*d + c*c*c*d + a*a*a*e - 3.0F*a*a*c*e + 3.0F*a*c*c*e -
01461     c*c*c*e - (a-b)*(a-b)*(a + 2.0F*b - 3.0F*c)*f;
01462 
01463   float denom = (a-b)*(a-b)*(a-c)*(a-c)*(a-c)*(b-c)*(b-c);
01464   if (fabs(denom) < 1.0e-5F)
01465     { LERROR("Zero denominator - cannot remap - RETURNING INPUT"); return ima;}
01466   q0 /= denom; q1 /= denom; q2 /= denom; q3 /= denom; q4 /= denom;
01467 
01468   Image<T> result(ima.getDims(), NO_INIT);
01469   typename Image<T>::const_iterator src = ima.begin(), stop = ima.end();
01470   typename Image<T>::iterator dest = result.beginw();
01471   while(src != stop) {
01472     float val = float(*src++);
01473     // here we optimize the computation for speed:
01474     val = q0 + val*(q1 + val*(q2 + val*(q3 + val*q4)));
01475     *dest++ = clamped_convert<T>(val);
01476   }
01477   return result;
01478 }
01479 
01480 // ######################################################################
01481 template<class T>
01482 Image<T> squash(const Image<T>& src, const T newmin,
01483                 const T oldmid, const T newmid, const T newmax)
01484 {
01485 GVX_TRACE(__PRETTY_FUNCTION__);
01486   // get oldmin and oldmax from the source image:
01487   T oldmin, oldmax; getMinMax(src, oldmin, oldmax);
01488 
01489   // call the general squash:
01490   return squash(src, oldmin, newmin, oldmid, newmid, oldmax, newmax);
01491 }
01492 
01493 // ######################################################################
01494 template<class T>
01495 Image<T> squash(const Image<T>& src, const T oldmid, const T newmid)
01496 {
01497 GVX_TRACE(__PRETTY_FUNCTION__);
01498   // get oldmin and oldmax from the source image:
01499   T oldmin, oldmax; getMinMax(src, oldmin, oldmax);
01500 
01501   // call the general squash:
01502   return squash(src, oldmin, oldmin, oldmid, newmid, oldmax, oldmax);
01503 }
01504 
01505 // ######################################################################
01506 template <class T, class TT>
01507 Image<TT> thresholdedMix(const Image<T>& mask, const T& thresh,
01508                          const Image<TT>& lower, const Image<TT>& higher)
01509 {
01510 GVX_TRACE(__PRETTY_FUNCTION__);
01511   ASSERT(mask.isSameSize(lower) && mask.isSameSize(higher));
01512 
01513   Image<TT> result(mask.getDims(), NO_INIT);
01514   typename Image<T>::const_iterator msrc = mask.begin(), mstop = mask.end();
01515   typename Image<TT>::const_iterator
01516     lsrc = lower.begin(), hsrc = higher.begin();
01517   typename Image<TT>::iterator dest = result.beginw();
01518 
01519   while(msrc != mstop) {
01520     if (*msrc >= thresh) *dest = *hsrc; else *dest = *lsrc;
01521     msrc ++; lsrc++; hsrc++; dest ++;
01522   }
01523 
01524   return result;
01525 }
01526 
01527 // ######################################################################
01528 Image<float> logSig(const Image<float>& ima, float o, float b)
01529 {
01530 GVX_TRACE(__PRETTY_FUNCTION__);
01531   Image<float> result(ima.getDims(), NO_INIT);
01532   Image<float>::const_iterator ptr = ima.begin();
01533   Image<float>::iterator res = result.beginw();
01534   Image<float>::iterator stop = result.endw();
01535   for ( ; res != stop; ++ptr, ++res)
01536     *res = 1.0f / (1.0f + expf(b*(o-*ptr)));
01537   return result;
01538 }
01539 
01540 // ######################################################################
01541 template <class T>
01542 Image<T> scramble(const Image<T>& ima)
01543 {
01544 GVX_TRACE(__PRETTY_FUNCTION__);
01545   const int siz = ima.getSize(); ASSERT(siz > 0);
01546   Image<T> result = ima; typename Image<T>::iterator a = result.beginw();
01547 
01548   // this is very similar to randShuffle() in saliency.C:
01549   for (int i = 0; i < siz; i ++)
01550     {
01551       T tmp = a[i];
01552       int idx = i + randomUpToNotIncluding(siz - i);
01553       a[i] = a[idx]; a[idx] = tmp;
01554     }
01555 
01556   return result;
01557 }
01558 
01559 // ######################################################################
01560 int32 findMonteMap(Image<float>& ima,
01561                    std::vector<Point2D<int> >* coords,
01562                    int decimation, float bias = 1.0F)
01563 {
01564 GVX_TRACE(__PRETTY_FUNCTION__);
01565   const unsigned int siz = (unsigned)ima.getSize(); ASSERT(siz > 0);
01566   std::vector<Point2D<int> >::iterator itr;
01567   ASSERT(siz <= coords->size());
01568   Image<float>::iterator a = ima.beginw();
01569 
01570   float minVal     = *a;
01571   float maxVal     = 0;
01572 
01573   //First find upper and lower bounds on image values
01574   //apply an exponent bias if needed
01575   if(bias != 1.0F)
01576     for(a = ima.beginw(); a != ima.endw(); ++a)
01577     {
01578       *a = *a * *a;
01579       //*a = pow(*a,bias);
01580     }
01581 
01582   for(a = ima.beginw(); a != ima.endw(); ++a)
01583   {
01584     if(*a > maxVal)
01585       maxVal = *a;
01586     if(*a < minVal)
01587       minVal = *a;
01588   }
01589 
01590   a                 = ima.beginw();
01591   itr               = coords->begin();
01592   int32 counter     = 0;
01593   float salVal      = 0.0F;
01594 
01595   // determin which pixels are selected based upon there
01596   // relation to min/max values
01597   for (unsigned int i = 0; i < siz; i ++)
01598   {
01599     // higher order bits (better)
01600     salVal = ((minVal)+((maxVal)*rand()/(RAND_MAX+1.0)));
01601     // lower order bits (faster)
01602     //salVal = (*minVal)+(rand() % (int)*maxVal);
01603     if(*a > salVal)
01604     {
01605       *itr = Point2D<int>(i % ima.getWidth(), i/ima.getWidth());
01606       ++itr;
01607       counter++;
01608     }
01609     ++a;
01610   }
01611 
01612   return counter;
01613 }
01614 
01615 // ######################################################################
01616 int32 makeSparceMap(std::vector<Point2D<int> >* coords, std::vector<Point2D<int>*>* cmap,
01617                     std::vector<Point2D<int> >* Oldcoords,
01618                     std::vector<bool>* keep, int inPoints, int outPoints)
01619 {
01620 GVX_TRACE(__PRETTY_FUNCTION__);
01621   ASSERT(coords->size() >= cmap->size());
01622   std::vector<Point2D<int>*>::iterator icmap;
01623   std::vector<Point2D<int> >::iterator icoords;
01624   std::vector<Point2D<int> >::iterator iOldcoords;
01625   std::vector<bool>::iterator ikeep;
01626   int interval = inPoints/(outPoints+1);
01627   int mod = 0;
01628   int count = 0;
01629   icoords = coords->begin();
01630   iOldcoords = Oldcoords->begin();
01631   icmap = cmap->begin();
01632   ikeep = keep->begin();
01633   for(int i = 0; i < inPoints; i++)
01634   {
01635     if(mod == 0)
01636     {
01637       if(*ikeep == false)
01638         *icmap = &*icoords;
01639       else
01640         *icmap = &*iOldcoords;
01641       ++icmap;
01642       ++ikeep;
01643       ++iOldcoords;
01644       count++;
01645     }
01646     else
01647     {
01648       if(mod == interval)
01649         mod = -1;
01650     }
01651     mod++;
01652     ++icoords;
01653   }
01654   return count;
01655 }
01656 
01657 // ######################################################################
01658 int32 makeCoordArray(std::vector<Point2D<int> >* coords, unsigned int initX, unsigned int initY, unsigned int sizeX, unsigned int sizeY)
01659 {
01660 GVX_TRACE(__PRETTY_FUNCTION__);
01661   coords->resize(initX*initY);
01662   std::vector<Point2D<int> >::iterator icoords = coords->begin();
01663   float scaleX = sizeX / initX;
01664   float scaleY = sizeY / initY;
01665   for(unsigned int i = 0; i < initX; i++)
01666   {
01667     for(unsigned int j = 0; j < initY; j++)
01668     {
01669       icoords->i = (int)(i*scaleX);
01670       icoords->j = (int)(j*scaleY);
01671     }
01672   }
01673   return initX*initY;
01674 }
01675 
01676 // ######################################################################
01677 template <class T>
01678 void inplaceAddWeighted(Image<T>& a,
01679                         const Image<T>& b, const float coeff)
01680 {
01681 GVX_TRACE(__PRETTY_FUNCTION__);
01682   ASSERT(b.initialized());
01683   if (a.initialized())   // a += b * coeff
01684     {
01685       ASSERT(a.isSameSize(b));
01686       typename Image<T>::iterator aptr = a.beginw();
01687       typename Image<T>::const_iterator bptr = b.begin();
01688       typename Image<T>::const_iterator stop = b.end();
01689 
01690       while (bptr != stop)
01691         *aptr++ += (T)(*bptr++ * coeff);
01692     }
01693   else   // a = b * coeff
01694     {
01695       a = Image<T>(b.getDims(), NO_INIT);
01696       typename Image<T>::iterator aptr = a.beginw();
01697       typename Image<T>::const_iterator bptr = b.begin();
01698       typename Image<T>::const_iterator stop = b.end();
01699 
01700       while (bptr != stop)
01701         *aptr++ = (T)(*bptr++ * coeff);
01702     }
01703 }
01704 
01705 // ######################################################################
01706 template <class T>
01707 void inplaceSquare(Image<T>& a)
01708 {
01709 GVX_TRACE(__PRETTY_FUNCTION__);
01710   typename Image<T>::iterator aptr = a.beginw();
01711   typename Image<T>::iterator stop = a.endw();
01712   while (aptr != stop)
01713     {
01714       (*aptr) *= (*aptr);
01715 
01716       // need to keep the increment in a separate statement; if we do
01717       // "*aptr *= *aptr++", then it's undefined whether the "*="
01718       // happens before or after the "++" (thanks to g++ 4.0 for
01719       // catching this with a warning!)
01720       ++aptr;
01721     }
01722 }
01723 
01724 // ######################################################################
01725 void inplaceReplaceVal(Image<byte>& dest,
01726                        const byte& from, const byte& to)
01727 {
01728 GVX_TRACE(__PRETTY_FUNCTION__);
01729   Image<byte>::iterator
01730     aptr = dest.beginw(),
01731     endptr = dest.endw();
01732 
01733   while (aptr != endptr)
01734     {
01735       if (*aptr == from) *aptr = to;
01736       ++aptr;
01737     }
01738 }
01739 
01740 // ######################################################################
01741 template <class T>
01742 void inplaceAttenuateBorders(Image<T>& a, int size)
01743 {
01744 GVX_TRACE(__PRETTY_FUNCTION__);
01745   ASSERT(a.initialized());
01746 
01747   Dims dims = a.getDims();
01748 
01749   if (size * 2 > dims.w()) size = dims.w() / 2;
01750   if (size * 2 > dims.h()) size = dims.h() / 2;
01751   if (size < 1) return;  // forget it
01752 
01753   float increment = 1.0 / (float)(size + 1);
01754   // top lines:
01755   float coeff = increment;
01756   typename Image<T>::iterator aptr = a.beginw();
01757   for (int y = 0; y < size; y ++)
01758     {
01759       for (int x = 0; x < dims.w(); x ++)
01760         {
01761           *aptr = (T)( (*aptr) * coeff );
01762           ++aptr;
01763         }
01764       coeff += increment;
01765     }
01766   // normal lines: start again from beginning to attenuate corners twice:
01767   aptr = a.beginw();
01768   for (int y = 0; y < dims.h(); y ++)
01769     {
01770       coeff = increment;
01771       for (int x = 0; x < size; x ++)
01772         {
01773           *(aptr + dims.w() - 1 - x * 2) =
01774             (T)(*(aptr + dims.w() - 1 - x * 2) * coeff);
01775 
01776           *aptr = (T)( (*aptr) * coeff );
01777           ++aptr;
01778           coeff += increment;
01779         }
01780       aptr += dims.w() - size;
01781     }
01782   // bottom lines
01783   aptr = a.beginw() + (dims.h() - size) * dims.w();
01784   coeff = increment * (float)size;
01785   for (int y = dims.h() - size; y < dims.h(); y ++)
01786     {
01787       for (int x = 0; x < dims.w(); ++x)
01788         {
01789           *aptr = (T)( (*aptr) * coeff );
01790           ++aptr;
01791         }
01792       coeff -= increment;
01793     }
01794 }
01795 
01796 // ######################################################################
01797 template <class T>
01798 void inplaceSetBorders(Image<T>& a,
01799                        const int size, const T value)
01800 {
01801 GVX_TRACE(__PRETTY_FUNCTION__);
01802   ASSERT(a.initialized());
01803   int siz = size;
01804   if (size * 2 > a.getWidth()) siz = a.getWidth() / 2;
01805   if (size * 2 > a.getHeight()) siz = a.getHeight() / 2;
01806   if (siz < 1) return;  // forget it
01807 
01808   typename Image<T>::iterator const data = a.beginw();
01809 
01810   // do the first line explicitly:
01811   for (int i = 0; i < a.getWidth(); ++i)
01812     data[i] = value;
01813 
01814   // then copy to next lines:
01815   for (int y = 1; y < siz; ++y)
01816     safecopy(data + (y * a.getWidth()),
01817              data,
01818              a.getWidth());
01819 
01820   // then do the vertical borders explicitly:
01821   for (int y = siz; y < a.getHeight() - siz; ++y)
01822     {
01823       typename Image<T>::iterator aptr = data + (y * a.getWidth());
01824       for (int x = 0; x < siz; ++x)
01825         {
01826           aptr[x] = value;
01827           aptr[a.getWidth() - 1 - x] = value;
01828         }
01829     }
01830 
01831   // finally do the bottom lines as a copy of the top lines
01832   safecopy(data + (a.getHeight() - siz) * a.getWidth(),
01833            data,
01834            siz * a.getWidth());
01835 }
01836 
01837 // ######################################################################
01838 void inplaceSpeckleNoise(Image<byte>& dest,
01839                          const float thresh, const int size,
01840                          const byte noise_color, bool random_color)
01841 {
01842 GVX_TRACE(__PRETTY_FUNCTION__);
01843   ASSERT(dest.initialized()); ASSERT(size >= 1);
01844 
01845   if (random_color)
01846     {
01847       for (int j = 0; j <= dest.getHeight() - size; j += size)
01848         for (int i = 0; i <= dest.getWidth() - size; i += size)
01849           if (randomDouble() < thresh) {
01850             byte rcol = clamped_convert<byte>(noise_color * randomDouble());
01851             for (int k = j; k < j + size; k ++)
01852               for (int l = i; l < i + size; l ++)
01853                 dest.setVal(l, k, rcol);
01854           }
01855     }
01856   else
01857     {
01858       for (int j = 0; j <= dest.getHeight() - size; j += size)
01859         for (int i = 0; i <= dest.getWidth() - size; i += size)
01860           if (randomDouble() < thresh)
01861             for (int k = j; k < j + size; k ++)
01862               for (int l = i; l < i + size; l ++)
01863                 dest.setVal(l, k, noise_color);
01864     }
01865 }
01866 
01867 // ######################################################################
01868 template <class T>
01869 Image<typename promote_trait<T,float>::TP>
01870 addPowerNoise(const Image<T>&  src, double beta)
01871 {
01872   //Adds power noise on an input image
01873   //beta =  0 for white noise (flat)
01874   //beta = -1 for pink  noise (1/f)
01875   //beta = -2 fo  brown noise (1/f^2)
01876   
01877   typedef std::complex<float> complexf;
01878 
01879   int inputW = src.getWidth(), inputH = src.getHeight();
01880   const int N = inputW > inputH ? inputW : inputH; //max dimension
01881   
01882   // ifft takes a half plane in the positive x direction
01883   // so we need to pass it coordinates for 
01884   // 0 < x <= N, -N/2 <= y <= N/2 (excluding 0)
01885   std::vector<float> xaxis(N), yaxis(N), u(N*N), v(N*N);
01886   int crnt = 0; 
01887   for(int i = 0; i < N; i++)
01888     {
01889       xaxis[i] = i+1;
01890       if(i < N/2)
01891         yaxis[i] = i+1;
01892       else
01893         yaxis[i] = i-N;
01894     }
01895 
01896   for(int i=0; i<N; i++)
01897     for(int j=0; j<N; j++)
01898       {
01899         u[crnt]  = xaxis[j];
01900         v[crnt]  = yaxis[i];
01901         crnt++;
01902       }
01903 
01904   Image<complexf> tempCmplxImg(N,N,NO_INIT);
01905   typename Image<complexf>::iterator cmplxItr = tempCmplxImg.beginw();
01906   float spectrum, phi;
01907   srand(time(NULL));
01908   for(int i=0; i < N*N; i++)
01909    {
01910      spectrum = pow((u[i]*u[i]) + (v[i]*v[i]),beta);
01911      
01912      phi = 2*M_PI*((double)rand()/((double)(RAND_MAX)+(double)(1)) );     
01913       *cmplxItr++    = complexf(pow(spectrum,0.5),0.0) * 
01914         complexf(cos(phi),sin(phi));
01915    }
01916 
01917   FourierInvEngine<double> ieng(Dims(2*N-1, N)); //twice as wide in the x-direction
01918   const Image<double> fullImg = ieng.ifft(tempCmplxImg); 
01919   //fullImg = remapRange(fullImg,rangeOf(fullImg),Range<T_or_RGB>((T_or_RGB)0,(T_or_RGB)255);
01920   
01921   Image<typename promote_trait<T, double>::TP> mask = crop(fullImg,Point2D<int>(0,0),Dims(inputW,inputH));
01922   
01923   return src + mask;
01924 }
01925 
01926 // ######################################################################
01927 float getLocalMax(const Image<float>& src,
01928                   const Point2D<int>& center, const int radius)
01929 {
01930 GVX_TRACE(__PRETTY_FUNCTION__);
01931   ASSERT(src.initialized());
01932   float val = src.getVal(center); // a bit wasteful but less bogus that numeric_limits
01933   const int r2 = radius * radius, ci = center.i, cj = center.j;
01934   for (int y = -radius; y <= radius; y ++)
01935     {
01936       int bound = int(sqrtf(float(r2 - y*y)));
01937       int sj = y + cj;
01938       for (int x = -bound; x <= bound; x ++)
01939         {
01940           int si = x + ci;
01941           if (src.coordsOk(si, sj))
01942             { float v = src.getVal(si, sj); if (v > val) val = v; }
01943         }
01944     }
01945   return val;
01946 }
01947 
01948 // ######################################################################
01949 float getLocalAvg(const Image<float>& src,
01950                   const Point2D<int>& center, const int radius)
01951 {
01952 GVX_TRACE(__PRETTY_FUNCTION__);
01953   ASSERT(src.initialized());
01954   float val = src.getVal(center); // a bit wasteful but less bogus that numeric_limits
01955   int count = 0;
01956   const int r2 = radius * radius, ci = center.i, cj = center.j;
01957   for (int y = -radius; y <= radius; y ++)
01958     {
01959       int bound = int(sqrtf(float(r2 - y*y)));
01960       int sj = y + cj;
01961       for (int x = -bound; x <= bound; x ++)
01962         {
01963           int si = x + ci;
01964           if (src.coordsOk(si, sj))
01965             { val += src.getVal(si, sj); ++count; }
01966         }
01967     }
01968   return count == 0? 0: val / (float)count;
01969 }
01970 
01971 // ######################################################################
01972 template<class T>
01973 void getMinMax(const Image<T>& src, T& xmini, T& xmaxi)
01974 {
01975 GVX_TRACE(__PRETTY_FUNCTION__);
01976   ASSERT(src.initialized());
01977   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
01978   xmini = *aptr; xmaxi = *aptr++;
01979   while (aptr != stop)
01980     {
01981       if (*aptr < xmini) xmini = *aptr;
01982       else if (*aptr > xmaxi) xmaxi = *aptr;
01983       ++aptr;
01984     }
01985 }
01986 
01987 // ######################################################################
01988 template <class T>
01989 void getMaskedMinMax(const Image<T>& src, const Image<byte>& mask,
01990                      T& min_in, T& max_in, T& min_out, T& max_out)
01991 {
01992 GVX_TRACE(__PRETTY_FUNCTION__);
01993  ASSERT(src.initialized());
01994  ASSERT(mask.initialized());
01995  ASSERT(src.isSameSize(mask));
01996 
01997   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
01998   Image<byte>::const_iterator mptr = mask.begin();
01999 
02000   // we need initial values for the min_in and max_in that come from
02001   // within the mask, and initial values for min_out and max_out that
02002   // come from outside the mask. So in this first loop we just start
02003   // scanning the image until we have found these:
02004 
02005   // let's use the first point, it's either in or out:
02006   if (*mptr++) {
02007     // ok, we got the values for inside, let's look for the outside ones:
02008     min_in = *aptr; max_in = *aptr++;
02009     while (aptr != stop)
02010       {
02011         if (*mptr++) { // inside the mask? update our inside values
02012           if (*aptr < min_in) min_in = *aptr;
02013           else if (*aptr > max_in) max_in = *aptr;
02014         } else {     // outside the mask? initialize outside vals and move on
02015           min_out = *aptr; max_out = *aptr++; break;
02016         }
02017         ++aptr;
02018       }
02019   } else {
02020     // ok, we got the values for outside, let's look for the inside ones:
02021     min_out = *aptr; max_out = *aptr++;
02022     while (aptr != stop)
02023       {
02024         if (*mptr++) { // inside the mask? initialize inside vals and move on
02025           min_in = *aptr; max_in = *aptr++; break;
02026         } else {       // outside the mask? update our values
02027           if (*aptr < min_out) min_out = *aptr;
02028           else if (*aptr > max_out) max_out = *aptr;
02029         }
02030         ++aptr;
02031       }
02032   }
02033 
02034   // we are now ready to finish up the iterations, knowing that both
02035   // the inside and outside values have been initialized and just need
02036   // updating:
02037   while (aptr != stop)
02038     {
02039       if (*mptr++) { // inside the mask?
02040         if (*aptr < min_in) min_in = *aptr;
02041         else if (*aptr > max_in) max_in = *aptr;
02042       } else {     // outside the mask
02043         if (*aptr < min_out) min_out = *aptr;
02044         else if (*aptr > max_out) max_out = *aptr;
02045       }
02046       ++aptr;
02047     }
02048 }
02049 
02050 // ######################################################################
02051 template<class T>
02052 void getMinMaxAvg(const Image<T>& src, T& xmini, T& xmaxi, T& xavg)
02053 {
02054 GVX_TRACE(__PRETTY_FUNCTION__);
02055   ASSERT(src.initialized());
02056   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02057   double avg = 0.0;
02058   xmini = *aptr; xmaxi = *aptr++;
02059   while (aptr != stop)
02060     {
02061       if (*aptr < xmini) xmini = *aptr;
02062       else if (*aptr > xmaxi) xmaxi = *aptr;
02063       avg += (double)(*aptr);
02064       aptr++;
02065     }
02066   xavg = clamped_convert<T>(avg / double(src.getSize()));
02067 }
02068 
02069 // ######################################################################
02070 template <class T>
02071 void getMaskedMinMaxAvg(const Image<T>& src, const Image<byte> &mask,
02072                         T& mi, T& ma, T& avg)
02073 {
02074 GVX_TRACE(__PRETTY_FUNCTION__);
02075   ASSERT(src.initialized());
02076   ASSERT(src.isSameSize(mask));
02077 
02078   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02079   typename Image<byte>::const_iterator mptr = mask.begin();
02080   typedef typename promote_trait<T,T>::TP TF;
02081 
02082   TF sum(0); uint area = 0;
02083 
02084   // we need initial values for mi and ma that come from within the
02085   // mask. So in this first loop we just start scanning the image
02086   // until we hit a non-zero pixel in the mask:
02087   while (aptr != stop && *mptr == 0) { aptr ++; mptr ++; }
02088 
02089   // mask was empty?
02090   if (aptr == stop) { mi = T(0); ma = T(0); avg = T(0); return; }
02091 
02092   // set initial mi/ma/sum values:
02093   mi = *aptr; sum = *aptr; ma = *aptr ++; mptr ++; area ++;
02094 
02095   // loop over the remainder of the image:
02096   while (aptr != stop) {
02097     if (*mptr) {
02098       if (*aptr < mi) mi = *aptr; else if (*aptr > ma) ma = *aptr;
02099       sum += *aptr; area ++;
02100     }
02101     aptr++; mptr++;
02102   }
02103 
02104   if (area) avg = clamped_convert<T>(sum / area); else avg = T(0);
02105 }
02106 
02107 // ######################################################################
02108 template <class T>
02109 void getMaskedMinMaxSumArea(const Image<T>& src, const Image<float> &mask,
02110                             T& mi, T& ma,
02111                             typename promote_trait<T,float>::TP &sum,
02112                             typename promote_trait<T,float>::TP &area)
02113 {
02114 GVX_TRACE(__PRETTY_FUNCTION__);
02115   ASSERT(src.initialized());
02116   ASSERT(src.isSameSize(mask));
02117 
02118   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02119   typename Image<float>::const_iterator mptr = mask.begin();
02120   typedef typename promote_trait<T,float>::TP TF;
02121 
02122   sum = TF(0); area = TF(0);
02123 
02124   // we need initial values for mi and ma that come from within the
02125   // mask. So in this first loop we just start scanning the image
02126   // until we hit a non-zero pixel in the mask:
02127   while (aptr != stop && *mptr <= 0.0F) { aptr ++; mptr ++; }
02128 
02129   // mask was empty?
02130   if (aptr == stop)
02131     { mi = T(0); ma = T(0); sum = TF(0); area = TF(0); return; }
02132 
02133   // set initial mi/ma values:
02134   mi = *aptr; ma = *aptr ++; mptr ++;
02135 
02136   // loop over the remainder of the image:
02137   while (aptr != stop) {
02138     if (*mptr > 0.0F) {
02139       if (*aptr < mi) mi = *aptr; else if (*aptr > ma) ma = *aptr;
02140       sum += *aptr * TF(*mptr); area += TF(*mptr);
02141     }
02142     aptr++; mptr++;
02143   }
02144 }
02145 
02146 // ######################################################################
02147 template<class T>
02148 void getMinMaxAvgEtc(const Image<T>& src, T& xmini, T& xmaxi, T& xavg, T& xstd,
02149                      ushort& minPosX, ushort& minPosY,
02150                      ushort& maxPosX, ushort& maxPosY,
02151                      uint& pixCount)
02152 {
02153 GVX_TRACE(__PRETTY_FUNCTION__);
02154   ASSERT(src.initialized());
02155   typename Image<T>::const_iterator aptr = src.begin();
02156   double avg = 0.0;
02157   double ss  = 0.0;
02158   pixCount   = 0;
02159   const ushort width = src.getWidth();
02160   xmini = *aptr; xmaxi = *aptr++;
02161   while (aptr != src.end())
02162   {
02163     if (*aptr < xmini)
02164     {
02165       xmini   = *aptr;
02166       minPosX = (ushort)(pixCount%width);
02167       minPosY = (ushort)floor(pixCount/width);
02168     }
02169     else if (*aptr > xmaxi)
02170     {
02171       xmaxi   = *aptr;
02172       maxPosX = (ushort)(pixCount%width);
02173       maxPosY = (ushort)floor(pixCount/width);
02174     }
02175     avg += (double)(*aptr);
02176     ss  += (double)(pow(*aptr,2));
02177     aptr++; pixCount++;
02178   }
02179   xavg = clamped_convert<T>(avg / double(src.getSize()));
02180   xstd = clamped_convert<T>(sqrt((ss/double(src.getSize())) - pow(xavg,2)));
02181 }
02182 
02183 // ######################################################################
02184 template<class T>
02185 bool isFinite(const Image<T>& src)
02186 {
02187 GVX_TRACE(__PRETTY_FUNCTION__);
02188   ASSERT(src.initialized());
02189   typename Image<T>::const_iterator aptr = src.begin(), stop = src.end();
02190   while (aptr != stop)
02191     {
02192       if (::isFinite(*aptr) == false) return false;
02193       aptr++;
02194     }
02195   return true;
02196 }
02197 
02198 // ######################################################################
02199 template<class T>
02200 void findMax(const Image<T>& src, Point2D<int>& p, T& maxval)
02201 {
02202 GVX_TRACE(__PRETTY_FUNCTION__);
02203   ASSERT(src.initialized());
02204   typename Image<T>::const_iterator aptr = src.begin();
02205   const int w = src.getWidth(), h = src.getHeight();
02206   p.i = 0; p.j = 0; maxval = *aptr;
02207   for (int j = 0; j < h; j ++)
02208     for (int i = 0; i < w; i ++)
02209       {
02210         if (*aptr > maxval) { maxval = *aptr; p.i = i; p.j = j; }
02211         aptr++;
02212       }
02213 }
02214 
02215 // ######################################################################
02216 template<class T>
02217 void findMin(const Image<T>& src, Point2D<int>& p, T& minval)
02218 {
02219 GVX_TRACE(__PRETTY_FUNCTION__);
02220   ASSERT(src.initialized());
02221   typename Image<T>::const_iterator aptr = src.begin();
02222   const int w = src.getWidth(), h = src.getHeight();
02223   p.i = 0; p.j = 0; minval = *aptr;
02224   for (int j = 0; j < h; j ++)
02225     for (int i = 0; i < w; i ++)
02226       {
02227         if (*aptr < minval) { minval = *aptr; p.i = i; p.j = j; }
02228         aptr++;
02229       }
02230 }
02231 
02232 // ######################################################################
02233 template <class T>
02234 void inplaceClamp(Image<T>& dst, const T cmin, const T cmax)
02235 {
02236 GVX_TRACE(__PRETTY_FUNCTION__);
02237   typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02238   while (aptr != stop)
02239     {
02240       if (*aptr < cmin) *aptr = cmin;
02241       else if (*aptr > cmax) *aptr = cmax;
02242       ++aptr;
02243     }
02244 }
02245 
02246 // ######################################################################
02247 template <class T>
02248 void inplaceNormalize(Image<T>& dst, const T nmin, const T nmax)
02249 {
02250 GVX_TRACE(__PRETTY_FUNCTION__);
02251   T oldmin, oldmax;
02252   inplaceNormalize(dst, nmin, nmax, oldmin, oldmax);
02253 }
02254 
02255 // ######################################################################
02256 template <class T>
02257 void inplaceNormalize(Image<T>& dst, const T nmin, const T nmax,
02258                       T& oldmin, T& oldmax)
02259 {
02260 GVX_TRACE(__PRETTY_FUNCTION__);
02261   if (!dst.initialized()) return;
02262 
02263   typedef typename promote_trait<T, float>::TP TF;
02264 
02265   getMinMax(dst, oldmin, oldmax);
02266 
02267   // check if the original range is empty; NOTE: don't try to check
02268   // (oldmax-oldmin)==0.0 here, because that will fail if oldmin=inf
02269   // and oldmax=inf, since inf-inf=nan, whereas a test of inf==inf
02270   // will still yield true
02271   if (oldmax == oldmin)
02272     {
02273       // OK, the input image was uniform, so let's just change it to
02274       // be uniform at the min of the desired new scale.
02275 
02276       // NOTE: Another sensible approach in this case might be to set
02277       // the new image to the midpoint of the new range, but this
02278       // causes backward-compatibility problems, particularly in cases
02279       // where we expect input images containing all 0's to stay at 0
02280       // rather than shifting to a higher non-zero value after
02281       // rescaling.
02282       dst.clear(nmin);
02283       return;
02284     }
02285   const TF scale = TF(oldmax) - TF(oldmin);
02286   const TF nscale = (TF(nmax) - TF(nmin)) / scale;
02287 
02288   typename Image<T>::iterator aptr = dst.beginw();
02289   typename Image<T>::iterator stop = dst.endw();
02290   const TF oldminf = TF(oldmin);
02291 
02292   while (aptr != stop)
02293     {
02294       *aptr = nmin + T( (TF(*aptr) - oldminf) * nscale );
02295       ++aptr;
02296     }
02297 }
02298 
02299 // ######################################################################
02300 template <class T>
02301 bool isLocalMax(const Image<T>& src, const Point2D<int>& p)
02302 {
02303 GVX_TRACE(__PRETTY_FUNCTION__);
02304   typename Image<T>::const_iterator sptr = src.begin();
02305   const int w = src.getWidth(), h = src.getHeight();
02306   const int i = p.i, j = p.j;
02307   sptr += i + w * j;
02308   T val = *sptr;
02309 
02310   if (src.coordsOk(p) == false) return false; // outside the image
02311   if (i > 0 && sptr[-1] > val) return false;  // (i-1,j) is higher
02312   if (i < w-1 && sptr[1] > val) return false; // (i+1,j) is higher
02313   if (j > 0 && sptr[-w] > val) return false;  // (i,j-1) is higher
02314   if (j < h-1 && sptr[w] > val) return false; // (i,j+1) is higher
02315 
02316   // no neighbor was higher, so we must be the highest:
02317   return true;
02318 }
02319 
02320 // ######################################################################
02321 template <class T>
02322 void inplaceRectify(Image<T>& dst)
02323 {
02324 GVX_TRACE(__PRETTY_FUNCTION__);
02325 
02326   typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02327   T zero = T();
02328   while (aptr != stop)
02329     {
02330       if (*aptr < zero) *aptr = zero;
02331       ++aptr;
02332     }
02333 }
02334 
02335 // ######################################################################
02336 template <class T>
02337 void splitPosNeg(const Image<T>& src,
02338                  Image<T>& pos, Image<T>& neg)
02339 {
02340 GVX_TRACE(__PRETTY_FUNCTION__);
02341   pos.resize(src.getDims(), NO_INIT);
02342   neg.resize(src.getDims(), NO_INIT);
02343   typename Image<T>::const_iterator sptr = src.begin(), stop = src.end();
02344   typename Image<T>::iterator pptr = pos.beginw(), nptr = neg.beginw();
02345 
02346   T zero = T();
02347   while (sptr != stop)
02348     if (*sptr <= zero) { *nptr++ = - (*sptr++); *pptr++ = zero; }
02349     else { *nptr++ = zero; *pptr++ = *sptr++; }
02350 }
02351 
02352 // ######################################################################
02353 template <class T>
02354 void inplaceLowThresh(Image<T>& dst, const T thresh, const T val)
02355 {
02356 GVX_TRACE(__PRETTY_FUNCTION__);
02357   typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02358 
02359   while (aptr != stop)
02360     {
02361       if (*aptr < thresh) *aptr = val;
02362       ++aptr;
02363     }
02364 }
02365 
02366 // ######################################################################
02367 template <class T>
02368 void inplaceLowThreshAbs(Image<T>& dst, const T thresh, const T val)
02369 {
02370 GVX_TRACE(__PRETTY_FUNCTION__);
02371   if (thresh <= T(0))
02372     {
02373       if (thresh == T(0))
02374         // it's still a no-op with thresh = 0 but we won't report an
02375         // LERROR() here since 0 is a convenient default value when no
02376         // threshold should be applied...
02377         return;
02378 
02379       LERROR("With thresh = %f < 0.0, this is a no-op -- IGNORED",
02380              double(thresh));
02381     }
02382 
02383   typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02384 
02385   while (aptr != stop)
02386     {
02387       if (std::abs(*aptr) < thresh) *aptr = val;
02388       ++aptr;
02389     }
02390 }
02391 
02392 // ######################################################################
02393 template <class T>
02394 void inplaceSigmoid(Image<T>& dst,
02395                     const float g, const float h, const float s)
02396 {
02397 GVX_TRACE(__PRETTY_FUNCTION__);
02398   // Sigmoidal normalization: f(x)=x^g/(s+x^h)
02399   typename Image<T>::iterator aptr = dst.beginw(), stop = dst.endw();
02400 
02401   while (aptr != stop) {
02402     T val = clamped_convert<T>(pow(*aptr, g) / (s + pow(*aptr, h)));
02403     *aptr++ = val;
02404   }
02405 }
02406 
02407 // ######################################################################
02408 template <class T>
02409 int emptyArea(const Image<T>& src)
02410 {
02411 GVX_TRACE(__PRETTY_FUNCTION__);
02412   return std::count(src.begin(), src.end(), T());
02413 }
02414 
02415 // ######################################################################
02416 template <class T>
02417 int countThresh(const Image<T>& src, const T thresh, const bool absol)
02418 {
02419 GVX_TRACE(__PRETTY_FUNCTION__);
02420   int nb = 0;
02421   typename Image<T>::const_iterator ap = src.begin(), stop = src.end();
02422 
02423   if (absol)
02424     {
02425       float threshd = (float)thresh;
02426       while (ap != stop)
02427         {
02428           if (fabs(float(*ap)) > threshd) ++nb;
02429           ++ap;
02430         }
02431     }
02432   else
02433     {
02434       while (ap != stop)
02435         if (*ap++ > thresh) ++nb;
02436     }
02437 
02438   return nb;
02439 }
02440 
02441 // ######################################################################
02442 Image<float> meanRow(const Image<float>& inp)
02443 {
02444 GVX_TRACE(__PRETTY_FUNCTION__);
02445   ASSERT(inp.getHeight() > 0);
02446 
02447   Image<float> result(inp.getWidth(), 1, ZEROS);
02448 
02449   const int w = inp.getWidth();
02450   const int h = inp.getHeight();
02451 
02452   Point2D<int> loc;
02453 
02454   for (loc.j = 0; loc.j < h; ++loc.j)
02455     for (loc.i = 0; loc.i < w; ++loc.i)
02456       result[Point2D<int>(loc.i,0)] += inp[loc];
02457 
02458   result /= inp.getHeight();
02459 
02460   return result;
02461 }
02462 
02463 // ######################################################################
02464 Image<float> stdevRow(const Image<float>& M)
02465 {
02466 GVX_TRACE(__PRETTY_FUNCTION__);
02467 
02468   const Image<float> u = meanRow(M);
02469 
02470   const int w = M.getWidth();
02471   const int h = M.getHeight();
02472 
02473   Image<float> ssq(M.getWidth(), 1, ZEROS);
02474 
02475   Image<float>::iterator const dptr = ssq.beginw();
02476   Image<float>::const_iterator const uptr = u.begin();
02477   Image<float>::const_iterator Mptr = M.begin();
02478 
02479   for (int y = 0; y < h; ++y)
02480     for (int x = 0; x < w; ++x)
02481       {
02482         dptr[x] += (*Mptr - uptr[x]) * (*Mptr - uptr[x]);
02483         ++Mptr;
02484       }
02485 
02486   ASSERT(h > 1);
02487   ssq /= float(h - 1);
02488 
02489   return sqrt(ssq);
02490 }
02491 
02492 // ######################################################################
02493 Image<float> addRow(const Image<float>& M, const Image<float>& v)
02494 {
02495 GVX_TRACE(__PRETTY_FUNCTION__);
02496 
02497   ASSERT(M.getWidth() == v.getWidth());
02498   ASSERT(v.getHeight() == 1);
02499 
02500   const int w = M.getWidth();
02501   const int h = M.getHeight();
02502 
02503   Image<float> result(M.getDims(), NO_INIT);
02504 
02505   Image<float>::iterator dptr = result.beginw();
02506   Image<float>::const_iterator Mptr = M.begin();
02507   Image<float>::const_iterator const vptr = v.begin();
02508 
02509   for (int y = 0; y < h; ++y)
02510     for (int x = 0; x < w; ++x)
02511       {
02512         *dptr = (*Mptr) + vptr[x];
02513         ++dptr;
02514         ++Mptr;
02515       }
02516 
02517   return result;
02518 }
02519 
02520 // ######################################################################
02521 Image<float> subtractRow(const Image<float>& M, const Image<float>& v)
02522 {
02523 GVX_TRACE(__PRETTY_FUNCTION__);
02524 
02525   ASSERT(M.getWidth() == v.getWidth());
02526   ASSERT(v.getHeight() == 1);
02527 
02528   const int w = M.getWidth();
02529   const int h = M.getHeight();
02530 
02531   Image<float> result(M.getDims(), NO_INIT);
02532 
02533   Image<float>::iterator dptr = result.beginw();
02534   Image<float>::const_iterator Mptr = M.begin();
02535   Image<float>::const_iterator const vptr = v.begin();
02536 
02537   for (int y = 0; y < h; ++y)
02538     for (int x = 0; x < w; ++x)
02539       {
02540         *dptr = (*Mptr) - vptr[x];
02541         ++dptr;
02542         ++Mptr;
02543       }
02544 
02545   return result;
02546 }
02547 
02548 // ######################################################################
02549 Image<float> multiplyRow(const Image<float>& M, const Image<float>& v)
02550 {
02551 GVX_TRACE(__PRETTY_FUNCTION__);
02552 
02553   ASSERT(M.getWidth() == v.getWidth());
02554   ASSERT(v.getHeight() == 1);
02555 
02556   const int w = M.getWidth();
02557   const int h = M.getHeight();
02558 
02559   Image<float> result(M.getDims(), NO_INIT);
02560 
02561   Image<float>::iterator dptr = result.beginw();
02562   Image<float>::const_iterator Mptr = M.begin();
02563   Image<float>::const_iterator const vptr = v.begin();
02564 
02565   for (int y = 0; y < h; ++y)
02566     for (int x = 0; x < w; ++x)
02567       {
02568         *dptr = (*Mptr) * vptr[x];
02569         ++dptr;
02570         ++Mptr;
02571       }
02572 
02573   return result;
02574 }
02575 
02576 // ######################################################################
02577 Image<float> divideRow(const Image<float>& M, const Image<float>& v)
02578 {
02579 GVX_TRACE(__PRETTY_FUNCTION__);
02580 
02581   ASSERT(M.getWidth() == v.getWidth());
02582   ASSERT(v.getHeight() == 1);
02583 
02584   const int w = M.getWidth();
02585   const int h = M.getHeight();
02586 
02587   Image<float> result(M.getDims(), NO_INIT);
02588 
02589   Image<float>::iterator dptr = result.beginw();
02590   Image<float>::const_iterator Mptr = M.begin();
02591   Image<float>::const_iterator const vptr = v.begin();
02592 
02593   for (int y = 0; y < h; ++y)
02594     for (int x = 0; x < w; ++x)
02595       {
02596         *dptr =
02597           vptr[x] == 0.0f
02598           ? 0.0f
02599           : (*Mptr) / vptr[x];
02600         ++dptr;
02601         ++Mptr;
02602       }
02603 
02604   return result;
02605 }
02606 
02607 // ######################################################################
02608 std::vector<Point2D<int> >  approxPolyDP(std::vector<Point2D<int> >& points, float tol)
02609 {
02610 
02611   std::vector<Point2D<int> > result;
02612 
02613   float tol2 = tol * tol;
02614   uint i,k, pv;
02615 
02616   if (points.size() < 2) //nothing to approximate
02617     return points;
02618 
02619   std::vector<Point2D<int> > vt(points.size());
02620   std::vector<int> mk(points.size(), 0);
02621 
02622   //Vertex reduction within tolerance of prior vertex cluster
02623   vt[0] = points[0];
02624   for(i=k=1, pv = 0; i<points.size(); i++)
02625   {
02626     if (points[i].squdist(points[pv]) < tol2)
02627       continue;
02628     vt[k++] = points[i];
02629     pv = i;
02630   }
02631 
02632   //Douglas-Peucker polyine simplification
02633 
02634   mk[0] = mk[k-1] = 1;
02635   recursePolyDP(tol, vt, 0, k-1, mk);
02636 
02637   //get the output
02638   for(i=0; i<k; i++)
02639   {
02640     if (mk[i])
02641       result.push_back(vt[i]);
02642   }
02643 
02644   return result;
02645 
02646 }
02647 
02648 void recursePolyDP(float tol, std::vector<Point2D<int> >& v, int j, int k, std::vector<int>& mk)
02649 {
02650 
02651   if (k <= j+1) // there is nothing to simplify
02652     return;
02653 
02654   // check for adequate approximation by segment S from v[j] to v[k]
02655   int     maxi = j;          // index of vertex farthest from S
02656   float   maxd2 = 0;         // distance squared of farthest vertex
02657   float   tol2 = tol * tol;  // tolerance squared
02658 
02659   //Segment S = {v[j], v[k]};  // segment from v[j] to v[k]
02660 
02661   //Vector  u = S.P1 - S.P0;   
02662   Point2D<int> SP0 = v[k];
02663   Point2D<int> SP1 = v[j];
02664   Point2D<int> u = SP1 - SP0; // segment direction vector
02665 
02666   double  cu = u.i*u.i + u.j*u.j;     // segment length squared
02667 
02668   // test each vertex v[i] for max distance from S
02669   // compute using the Feb 2001 Algorithm's dist_Point_to_Segment()
02670   // Note: this works in any dimension (2D, 3D, ...)
02671   Point2D<int>  w;
02672   Point2D<int>   Pb;                // base of perpendicular from v[i] to S
02673   double  b, cw, dv2;        // dv2 = distance v[i] to S squared
02674 
02675   for (int i=j+1; i<k; i++)
02676   {
02677     // compute distance squared
02678     w = v[i] - SP0;
02679     cw = w.i*u.i + w.j*u.j; //dot product
02680     if ( cw <= 0 )
02681       dv2 = v[i].squdist(SP0);
02682     else if ( cu <= cw )
02683       dv2 = v[i].squdist(SP1);
02684     else {
02685       b = cw / cu;
02686       Pb = SP0 + Point2D<int>(int(u.i*b), int(u.j*b)); 
02687       dv2 = v[i].squdist(Pb);
02688     }
02689     // test with current max distance squared
02690     if (dv2 <= maxd2)
02691       continue;
02692     // v[i] is a new max vertex
02693     maxi = i;
02694     maxd2 = dv2;
02695   }
02696   if (maxd2 > tol2)        // error is worse than the tolerance
02697   {
02698     // split the polyline at the farthest vertex from S
02699     mk[maxi] = 1;      // mark v[maxi] for the simplified polyline
02700     // recursively simplify the two subpolylines at v[maxi]
02701     recursePolyDP( tol, v, j, maxi, mk );  // polyline v[j] to v[maxi]
02702     recursePolyDP( tol, v, maxi, k, mk );  // polyline v[maxi] to v[k]
02703   }
02704   // else the approximation is OK, so ignore intermediate vertices
02705   return;
02706 }
02707 
02708 
02709 namespace 
02710 {
02711         const int NONE = -1;
02712 
02713         typedef struct range_bin Bin;
02714         struct range_bin {
02715                 int    min;    // index of min point P[] in bin (>=0 or NONE)
02716                 int    max;    // index of max point P[] in bin (>=0 or NONE)
02717         };
02718 
02719 
02720         inline float
02721                 isLeft( Point2D<float> P0, Point2D<float> P1, Point2D<float> P2 )
02722                 {
02723                         return (P1.i - P0.i)*(P2.j - P0.j) - (P2.i - P0.i)*(P1.j - P0.j);
02724                 }
02725 
02726 }
02727 
02728 std::vector<Point2D<float> > approximateHull(std::vector<Point2D<float> > P, int accuracy)
02729 {
02730         std::vector<Point2D<float> >H(P.size());
02731         int n = P.size();
02732         int k = accuracy;
02733         int    minmin=0,  minmax=0;
02734         int    maxmin=0,  maxmax=0;
02735         float  xmin = P[0].i,  xmax = P[0].i;
02736         Point2D<float>* cP;        // the current point being considered
02737         int    bot=0, top=(-1);  // indices for bottom and top of the stack
02738 
02739         // Get the points with (1) min-max x-coord, and (2) min-max y-coord
02740         for (int i=1; i<n; i++) {
02741                 cP = &P[i];
02742                 if (cP->i <= xmin) {
02743                         if (cP->i < xmin) {        // new xmin
02744                                 xmin = cP->i;
02745                                 minmin = minmax = i;
02746                         }
02747                         else {                      // another xmin
02748                                 if (cP->j < P[minmin].j)
02749                                         minmin = i;
02750                                 else if (cP->j > P[minmax].j)
02751                                         minmax = i;
02752                         }
02753                 }
02754                 if (cP->i >= xmax) {
02755                         if (cP->i > xmax) {        // new xmax
02756                                 xmax = cP->i;
02757                                 maxmin = maxmax = i;
02758                         }
02759                         else {                      // another xmax
02760                                 if (cP->j < P[maxmin].j)
02761                                         maxmin = i;
02762                                 else if (cP->j > P[maxmax].j)
02763                                         maxmax = i;
02764                         }
02765                 }
02766         }
02767         if (xmin == xmax) {      // degenerate case: all x-coords == xmin
02768                 H[++top] = P[minmin];           // a point, or
02769                 if (minmax != minmin)           // a nontrivial segment
02770                         H[++top] = P[minmax];
02771                 H.resize(top+1);
02772                 return H;
02773         }
02774 
02775         // Next, get the max and min points in the k range bins
02776         Bin*   B = new Bin[k+2];   // first allocate the bins
02777         B[0].min = minmin;         B[0].max = minmax;        // set bin 0
02778         B[k+1].min = maxmin;       B[k+1].max = maxmax;      // set bin k+1
02779         for (int b=1; b<=k; b++) { // initially nothing is in the other bins
02780                 B[b].min = B[b].max = NONE;
02781         }
02782         for (int b, i=0; i<n; i++) {
02783                 cP = &P[i];
02784                 if (cP->i == xmin || cP->i == xmax) // already have bins 0 and k+1 
02785                         continue;
02786                 // check if a lower or upper point
02787                 if (isLeft( P[minmin], P[maxmin], *cP) < 0) {  // below lower line
02788                         b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1;  // bin #
02789                         if (B[b].min == NONE)       // no min point in this range
02790                                 B[b].min = i;           // first min
02791                         else if (cP->j < P[B[b].min].j)
02792                                 B[b].min = i;           // new min
02793                         continue;
02794                 }
02795                 if (isLeft( P[minmax], P[maxmax], *cP) > 0) {  // above upper line
02796                         b = (int)( k * (cP->i - xmin) / (xmax - xmin) ) + 1;  // bin #
02797                         if (B[b].max == NONE)       // no max point in this range
02798                                 B[b].max = i;           // first max
02799                         else if (cP->j > P[B[b].max].j)
02800                                 B[b].max = i;           // new max
02801                         continue;
02802                 }
02803         }
02804 
02805         // Now, use the chain algorithm to get the lower and upper hulls
02806         // the output array H[] will be used as the stack
02807         // First, compute the lower hull on the stack H
02808         for (int i=0; i <= k+1; ++i)
02809         {
02810                 if (B[i].min == NONE)  // no min point in this range
02811                         continue;
02812                 cP = &P[ B[i].min ];   // select the current min point
02813 
02814                 while (top > 0)        // there are at least 2 points on the stack
02815                 {
02816                         // test if current point is left of the line at the stack top
02817                         if (isLeft( H[top-1], H[top], *cP) > 0)
02818                                 break;         // cP is a new hull vertex
02819                         else
02820                                 top--;         // pop top point off stack
02821                 }
02822                 H[++top] = *cP;        // push current point onto stack
02823         }
02824 
02825         // Next, compute the upper hull on the stack H above the bottom hull
02826         if (maxmax != maxmin)      // if distinct xmax points
02827                 H[++top] = P[maxmax];  // push maxmax point onto stack
02828         bot = top;                 // the bottom point of the upper hull stack
02829         for (int i=k; i >= 0; --i)
02830         {
02831                 if (B[i].max == NONE)  // no max point in this range
02832                         continue;
02833                 cP = &P[ B[i].max ];   // select the current max point
02834 
02835                 while (top > bot)      // at least 2 points on the upper stack
02836                 {
02837                         // test if current point is left of the line at the stack top
02838                         if (isLeft( H[top-1], H[top], *cP) > 0)
02839                                 break;         // current point is a new hull vertex
02840                         else
02841                                 top--;         // pop top point off stack
02842                 }
02843                 H[++top] = *cP;        // push current point onto stack
02844         }
02845         if (minmax != minmin)
02846                 H[++top] = P[minmin];  // push joining endpoint onto stack
02847 
02848         delete B;                  // free bins before returning
02849         H.resize(top+1);
02850         return H;
02851 }
02852 
02853 
02854 // Include the explicit instantiations
02855 #include "inst/Image/MathOps.I"
02856 
02857 // additional explicit instantiations:
02858 template double sum(const Image<double>&);
02859 template double mean(const Image<double>&);
02860 template double stdev(const Image<double>&);
02861 template Range<double> rangeOf(const Image<double>&);
02862 template Image<double> remapRange(const Image<double>&,
02863                                   const Range<double>&, const Range<double>&);
02864 template Image<double> takeMax(const Image<double>& a, const Image<double>& b);
02865 template Image<int> takeMax(const Image<int>& a, const Image<int>& b);
02866 template void findMax(const Image<double>& src, Point2D<int>& p, double& maxval);
02867 template void getMinMax<int>(const Image<int>&, int&, int&);
02868 template void getMinMax<double>(const Image<double>&, double&, double&);
02869 template void inplaceLowThresh(Image<int>& dst, const int thresh, const int val);
02870 template void inplaceLowThreshAbs(Image<int>& dst, const int thresh, const int val);
02871 template void inplaceRectify(Image<int>&);
02872 template void inplaceRectify(Image<double>&);
02873 template void inplaceClamp(Image<double>&, double, double);
02874 template Image<double> abs(const Image<double>&);
02875 template Image<double> exp(const Image<double>&);
02876 template Image<double> log(const Image<double>&);
02877 template Image<double> log10(const Image<double>&);
02878 template Image<byte> thresholdedMix(const Image<float>&,
02879                                     const float&,
02880                                     const Image<byte>&,
02881                                     const Image<byte>&);
02882 template Image<double> toPower(const Image<double>&, double);
02883 template Image<double> addPowerNoise(const Image<double>&, double);
02884 
02885 template double RMSerr(const Image<double>&, const Image<double>&);
02886 template Image<int> absDiff(const Image<int>& b, const Image<int>& c);
02887 template void inplaceNormalize(Image<double>&, double, double);
02888 template void inplaceNormalize(Image<double>&, double, double,
02889                                double&, double&);
02890 
02891 // ######################################################################
02892 /* So things look consistent in everyone's emacs... */
02893 /* Local Variables: */
02894 /* indent-tabs-mode: nil */
02895 /* End: */
02896 
02897 #endif // !IMAGE_MATHOPS_C_DEFINED
Generated on Sun May 8 08:40:56 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3