FilterOps.C

Go to the documentation of this file.
00001 /*!@file Image/FilterOps.C Filtering operations on Image */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/FilterOps.C $
00035 // $Id: FilterOps.C 13815 2010-08-22 17:58:48Z lior $
00036 //
00037 
00038 #include "Image/FilterOps.H"
00039 
00040 #include "Image/Image.H"
00041 #include "Image/Kernels.H"
00042 #include "Image/MathOps.H"
00043 #include "Image/Pixels.H"
00044 #include "Util/Assert.H"
00045 #include "Util/MathFunctions.H"
00046 #include "Util/Promotions.H"
00047 #include "Util/log.H"
00048 #include "rutz/trace.h"
00049 
00050 #include <algorithm>
00051 #include <cmath>
00052 #include <limits>
00053 
00054 // ######################################################################
00055 template <class T>
00056   Image<typename promote_trait<T, float>::TP>
00057 correlation(const Image<T>& src, const Image<float>& filter)
00058 {
00059   ASSERT(src.initialized());
00060   ASSERT(filter.initialized());
00061   const int src_w = src.getWidth();
00062   const int src_h = src.getHeight();
00063 
00064   Image<float>::const_iterator fptrBegin = filter.begin();
00065   const int fil_w = filter.getWidth();
00066   const int fil_h = filter.getHeight();
00067   ASSERT((fil_w & 1) && (fil_h & 1)); //check if the filter is odd size
00068 
00069   // promote the source image to float if necessary, so that we do the
00070   // promotion only once for all, rather than many times as we access
00071   // the pixels of the image; if no promotion is necessary, "source"
00072   // will just point to the original data of "src" through the
00073   // copy-on-write/ref-counting behavior of Image:
00074 
00075   typedef typename promote_trait<T, float>::TP TF;
00076   const Image<TF> source = src;
00077   Image<TF> result(src_w, src_h, NO_INIT);
00078   typename Image<TF>::const_iterator sptr = source.begin();
00079   typename Image<TF>::iterator dptr = result.beginw();
00080 
00081   //const int fil_end = fil_w * fil_h - 1;
00082   // const int Nx2 = (fil_w - 1) / 2;
00083   // const int Ny2 = (fil_h - 1) / 2;
00084 
00085   const int srow_skip = src_w-fil_w;
00086 
00087 
00088   for (int dst_y = 0; dst_y < src_h-fil_h; dst_y++) {
00089 
00090          for (int dst_x = 0; dst_x < src_w-fil_w; dst_x++, dptr++) {
00091 
00092                 float dst_val = 0.0f;
00093 
00094                 Image<float>::const_iterator fptr = fptrBegin;
00095 
00096                 // Image<float>::const_iterator srow_ptr =
00097                 //          sptr + src_w*(dst_y-Ny2) + (dst_x - Nx2);
00098 
00099                 Image<float>::const_iterator srow_ptr =
00100                   sptr + (src_w*dst_y) + dst_x;
00101 
00102                 // LINFO("DD:%ix%i %i", dst_x,dst_y, src_w*(dst_y) + (dst_x));
00103 
00104 
00105                 for (int f_y = 0; f_y < fil_h; ++f_y)
00106                 {
00107                   for (int f_x = 0; f_x < fil_w; ++f_x){
00108                          dst_val += fabs((*srow_ptr++) - (*fptr++));
00109                   }
00110 
00111                   srow_ptr += srow_skip;
00112 
00113                 }
00114                 *dptr = dst_val;
00115                 continue;
00116          }
00117   }
00118 
00119   return result;
00120 
00121 }
00122 
00123 // ######################################################################
00124 template <class T>
00125   Image<typename promote_trait<T, float>::TP>
00126 templMatch(const Image<T>& src, const Image<float>& filter, int method)
00127 {
00128   ASSERT(src.initialized());
00129   ASSERT(filter.initialized());
00130   const int src_w = src.getWidth();
00131   const int src_h = src.getHeight();
00132 
00133 
00134   // promote the source image to float if necessary, so that we do the
00135   // promotion only once for all, rather than many times as we access
00136   // the pixels of the image; if no promotion is necessary, "source"
00137   // will just point to the original data of "src" through the
00138   // copy-on-write/ref-counting behavior of Image:
00139 
00140   const int fil_w = filter.getWidth();
00141   const int fil_h = filter.getHeight();
00142 
00143   typedef typename promote_trait<T, float>::TP TF;
00144   const Image<TF> source = src;
00145   Image<TF> result(src_w-fil_w+1, src_h-fil_h+1, NO_INIT);
00146 
00147   result = correlation(source, filter);
00148 
00149   return result;
00150 }
00151 
00152 
00153 
00154 // ######################################################################
00155 template <class T>
00156 Image<typename promote_trait<T, float>::TP>
00157 spatialPoolMax(const Image<T>& src, const int si, const int sj,
00158                const int sti, const int stj)
00159 {
00160 GVX_TRACE(__PRETTY_FUNCTION__);
00161   const int w = src.getWidth(), h = src.getHeight();
00162   // promote the source image to float if necessary, so that we do the
00163   // promotion only once for all, rather than many times as we access
00164   // the pixels of the image; if no promotion is necessary, "source"
00165   // will just point to the original data of "src" through the
00166   // copy-on-write/ref-counting behavior of Image:
00167   typedef typename promote_trait<T, float>::TP TF;
00168   const Image<TF> source = src;
00169   Image<TF> result((int)ceil((float)w / (float)si),
00170                   (int)ceil((float)h / (float)sj),
00171                   NO_INIT);
00172   typename Image<TF>::const_iterator sptr = source.begin();
00173   typename Image<TF>::iterator dptr = result.beginw();
00174 
00175   // very inefficient implementation, ha ha
00176   for (int j = 0; j < h; j += sj)
00177     {
00178       int jmax = std::min(j + stj, h);
00179       for (int i = 0; i < w; i += si)
00180         {
00181           TF val = std::numeric_limits<TF>::min();
00182           int imax = std::min(i + sti, w);
00183 
00184           for (int jj = j; jj < jmax; jj ++)
00185             for (int ii = i; ii < imax; ii ++)
00186               if (sptr[jj * w + ii] > val) val = sptr[jj * w + ii];
00187           *dptr++ = val;
00188         }
00189     }
00190   return result;
00191 }
00192 
00193 // ######################################################################
00194 template<class T>
00195 float featurePoolHmax(const Image<T>& img1, const Image<T>& img2,
00196                       const Image<T>& img3, const Image<T>& img4,
00197                       const int si, const int sj, const float s2t)
00198 {
00199 GVX_TRACE(__PRETTY_FUNCTION__);
00200   ASSERT(img1.isSameSize(img2)&&img1.isSameSize(img3)&&img1.isSameSize(img4));
00201 
00202   float res = std::numeric_limits<float>::min();
00203   int w = img1.getWidth(), h = img1.getHeight();
00204   typename Image<T>::const_iterator i1 = img1.begin() + si + w * sj;
00205   typename Image<T>::const_iterator i2 = img2.begin() + si;
00206   typename Image<T>::const_iterator i3 = img3.begin() + w * sj;
00207   typename Image<T>::const_iterator i4 = img4.begin();
00208 
00209   for (int y = sj; y < h; y++)
00210     {
00211       for (int x = si; x < w; x++)
00212         {
00213           float s2r = (*i1 - s2t) * (*i1 - s2t) + (*i2 - s2t) * (*i2 - s2t) +
00214             (*i3 - s2t) * (*i3 - s2t) + (*i4 - s2t) * (*i4 - s2t);
00215           if (s2r > res) res = s2r;
00216           i1++; i2++; i3++; i4++;
00217         }
00218       i1 += si; i2 += si; i3 += si; i4 += si;
00219     }
00220   return res;
00221 }
00222 
00223 namespace
00224 {
00225   pthread_once_t trigtab_init_once = PTHREAD_ONCE_INIT;
00226 
00227   const int TRIGTAB_SIZE = 256;
00228 
00229   double sintab[TRIGTAB_SIZE];
00230   double costab[TRIGTAB_SIZE];
00231 
00232   void trigtab_init()
00233   {
00234     for (int i = 0; i < 256; ++i)
00235       {
00236         const double arg = (2.0*M_PI*i) / 256.0;
00237 
00238 #if defined(HAVE_ASM_FSINCOS)
00239         asm("fsincos"
00240             :"=t"(costab[i]), "=u"(sintab[i])
00241             :"0"(arg));
00242 #elif defined(HAVE_SINCOS)
00243         sincos(arg, &sintab[i], &costab[i]);
00244 #else
00245         sintab[i] = sin(arg);
00246         costab[i] = cos(arg);
00247 #endif
00248       }
00249   }
00250 }
00251 
00252 // ######################################################################
00253 template <class T>
00254 Image<typename promote_trait<T, float>::TP>
00255 orientedFilter(const Image<T>& src, const float k,
00256                const float theta, const float intensity,
00257                const bool usetab)
00258 {
00259 GVX_TRACE(__PRETTY_FUNCTION__);
00260   double kx = double(k) * cos((theta + 90.0) * M_PI / 180.0);
00261   double ky = double(k) * sin((theta + 90.0) * M_PI / 180.0);
00262 
00263   typedef typename promote_trait<T, float>::TP TF;
00264   Image<TF> re(src.getDims(), NO_INIT), im(src.getDims(), NO_INIT);
00265   typename Image<T>::const_iterator sptr = src.begin();
00266   typename Image<TF>::iterator reptr = re.beginw(), imptr = im.beginw();
00267 
00268   // (x,y) = (0,0) at center of image:
00269   int w2l = src.getWidth() / 2, w2r = src.getWidth() - w2l;
00270   int h2l = src.getHeight() / 2, h2r = src.getHeight() - h2l;
00271 
00272   if (usetab)
00273     {
00274       pthread_once(&trigtab_init_once, &trigtab_init);
00275 
00276       const double kx2 = (256.0 * kx) / (2.0*M_PI);
00277       const double ky2 = (256.0 * ky) / (2.0*M_PI);
00278 
00279       for (int j = -h2l; j < h2r; ++j)
00280         for (int i = -w2l; i < w2r; ++i)
00281           {
00282             const double arg2 = kx2 * i + ky2 * j;
00283             int idx = int(arg2) % 256;
00284             if (idx < 0) idx += 256;
00285             const TF val = (*sptr++) * intensity;
00286 
00287             const double sinarg = sintab[idx];
00288             const double cosarg = costab[idx];
00289 
00290             *reptr++ = TF(val * cosarg);
00291             *imptr++ = TF(val * sinarg);
00292           }
00293     }
00294   else
00295     {
00296       for (int j = -h2l; j < h2r; ++j)
00297         for (int i = -w2l; i < w2r; ++i)
00298           {
00299             const double arg = kx * i + ky * j;
00300             const TF val = (*sptr++) * intensity;
00301 
00302 #if defined(HAVE_ASM_FSINCOS)
00303             // If we the asm "fsincos" instruction is available, then
00304             // that will be the fastest way to compute paired sin and
00305             // cos calls.
00306             double sinarg, cosarg;
00307             asm("fsincos"
00308                 :"=t"(cosarg), "=u"(sinarg)
00309                 :"0"(arg));
00310 
00311 #elif defined(HAVE_SINCOS)
00312             // Otherwise we use a sincos() library function if it is
00313             // available as an extension (it's present at least in GNU
00314             // libc, maybe on other systems as well) then it is faster
00315             // (~30% overall speedup of orientedFilter()) to compute
00316             // both sin+cos at once rather than doing separate calls
00317             // -- this allows the use of the x87 assembly instruction
00318             // fsincos (see /usr/include/bits/mathinline.h for the
00319             // glibc sincos()).
00320             double sinarg, cosarg;
00321             sincos(arg, &sinarg, &cosarg);
00322 
00323 #else
00324             // Otherwise we resort to explicit separate sin() and
00325             // cos() calls.
00326             double sinarg = sin(arg);
00327             double cosarg = cos(arg);
00328 #endif
00329 
00330             *reptr++ = TF(val * cosarg);
00331             *imptr++ = TF(val * sinarg);
00332           }
00333     }
00334 
00335   re = ::lowPass9(re);
00336   im = ::lowPass9(im);
00337 
00338   return quadEnergy(re, im);
00339 }
00340 
00341 // ######################################################################
00342 template <class T>
00343 Image<T> centerSurround(const Image<T>& center,
00344                         const Image<T>& surround,
00345                         const bool absol)
00346 {
00347 GVX_TRACE(__PRETTY_FUNCTION__);
00348   const int lw = center.getWidth(), lh = center.getHeight();
00349   const int sw = surround.getWidth(), sh = surround.getHeight();
00350 
00351   if (sw > lw || sh > lh) LFATAL("center must be larger than surround");
00352 
00353   int scalex = lw / sw, remx = lw - 1 - (lw % sw);
00354   int scaley = lh / sh, remy = lh - 1 - (lh % sh);
00355 
00356   // result has the size of the larger image:
00357   Image<T> result(center.getDims(), NO_INIT);
00358 
00359   // scan large image and subtract corresponding pixel from small image:
00360   int ci = 0, cj = 0;
00361   typename Image<T>::const_iterator lptr = center.begin();
00362   typename Image<T>::const_iterator sptr = surround.begin();
00363   typename Image<T>::iterator dptr = result.beginw();
00364   T zero = T();
00365 
00366   if (absol == true)  // compute abs(hires - lowres):
00367     {
00368       for (int j = 0; j < lh; ++j)
00369         {
00370           for (int i = 0; i < lw; ++i)
00371             {
00372               if (*lptr > *sptr)
00373                 *dptr++ = T(*lptr++ - *sptr);
00374               else
00375                 *dptr++ = T(*sptr - *lptr++);
00376 
00377               if ((++ci) == scalex && i != remx) { ci = 0; ++sptr; }
00378             }
00379           if (ci) { ci = 0; ++sptr; }  // in case the reduction is not round
00380           if ((++cj) == scaley && j != remy) cj = 0; else sptr -= sw;
00381         }
00382     }
00383   else  // compute hires - lowres, clamped to 0:
00384     {
00385       for (int j = 0; j < lh; ++j)
00386         {
00387           for (int i = 0; i < lw; ++i)
00388             {
00389               if (*lptr > *sptr)
00390                 *dptr++ = T(*lptr++ - *sptr);
00391               else
00392                 { *dptr++ = zero; lptr++; }
00393 
00394               if ((++ci) == scalex && i != remx) { ci = 0; ++sptr; }
00395             }
00396           if (ci) { ci = 0; ++sptr; } // in case the reduction is not round
00397           if ((++cj) == scaley && j != remy) cj = 0; else sptr -= sw;
00398         }
00399     }
00400 
00401   // attenuate borders:
00402   inplaceAttenuateBorders(result, result.getDims().max() / 20);
00403 
00404   return result;
00405 }
00406 
00407 // ######################################################################
00408 template <class T>
00409 void centerSurround(const Image<T>& center, const Image<T>& surround,
00410                     Image<T>& pos, Image<T>& neg)
00411 {
00412 GVX_TRACE(__PRETTY_FUNCTION__);
00413   const int lw = center.getWidth(), lh = center.getHeight();
00414   const int sw = surround.getWidth(), sh = surround.getHeight();
00415 
00416   if (sw > lw || sh > lh) LFATAL("center must be larger than surround");
00417 
00418   int scalex = lw / sw, remx = lw - 1 - (lw % sw);
00419   int scaley = lh / sh, remy = lh - 1 - (lh % sh);
00420 
00421   // result has the size of the larger image:
00422   pos.resize(center.getDims(), NO_INIT);
00423   neg.resize(center.getDims(), NO_INIT);
00424 
00425   // scan large image and subtract corresponding pixel from small image:
00426   int ci = 0, cj = 0;
00427   typename Image<T>::const_iterator lptr = center.begin();
00428   typename Image<T>::const_iterator sptr = surround.begin();
00429   typename Image<T>::iterator pptr = pos.beginw(), nptr = neg.beginw();
00430   T zero = T();
00431 
00432   for (int j = 0; j < lh; ++j)
00433     {
00434       for (int i = 0; i < lw; ++i)
00435         {
00436           if (*lptr > *sptr) { *pptr++ = T(*lptr++ - *sptr); *nptr++ = zero; }
00437           else { *pptr++ = zero; *nptr++ = T(*sptr - *lptr++); }
00438 
00439           if ((++ci) == scalex && i != remx) { ci = 0; ++sptr; }
00440         }
00441       if (ci) { ci = 0; ++sptr; }  // in case the reduction is not round
00442       if ((++cj) == scaley && j != remy) cj = 0; else sptr -= sw;
00443     }
00444 
00445   // attenuate borders:
00446   inplaceAttenuateBorders(pos, pos.getDims().max() / 20);
00447   inplaceAttenuateBorders(neg, neg.getDims().max() / 20);
00448 }
00449 
00450 // ######################################################################
00451 template <class T>
00452 Image<typename promote_trait<T, float>::TP>
00453 doubleOpp(const Image<T>& cplus, const Image<T>& cminus,
00454           const Image<T>& splus, const Image<T>& sminus)
00455 {
00456 GVX_TRACE(__PRETTY_FUNCTION__);
00457   ASSERT(cplus.isSameSize(cminus)); ASSERT(splus.isSameSize(sminus));
00458 
00459   typedef typename promote_trait<T, float>::TP TF;
00460 
00461   // compute difference between both center arrays
00462   Image<TF> cdiff = cplus; cdiff -= cminus;
00463 
00464   // compute difference between both surround arrays
00465   Image<TF> sdiff = splus; sdiff -= sminus;
00466 
00467   // compute center-surround cdiff - sdiff = (cp - cm) [-] (sp - sm)
00468   return centerSurround(cdiff, sdiff, true);  // take abs
00469 }
00470 
00471 // ######################################################################
00472 template <class T>
00473 void avgOrient(const Image<T>& src,
00474                Image<float>& orient, Image<float>& strength)
00475 {
00476 GVX_TRACE(__PRETTY_FUNCTION__);
00477   float Gf1[9] = { 0.0094, 0.1148, 0.3964, -0.0601, -0.9213,  -0.0601,
00478                    0.3964, 0.1148, 0.0094 };
00479   float Gf2[9] = { 0.0008, 0.0176, 0.1660, 0.6383, 1.0, 0.6383, 0.1660,
00480                    0.0176, 0.0008 };
00481   float Gf3[9] = { -0.0028, -0.0480, -0.3020, -0.5806, 0.0, 0.5806, 0.3020,
00482                    0.0480, 0.0028 };
00483   float Hf1[9] = { -0.0098, -0.0618, 0.0998, 0.7551, 0.0, -0.7551, -0.0998,
00484                    0.0618, 0.0098 };
00485   float Hf2[9] = { 0.0008, 0.0176, 0.1660, 0.6383, 1.0, 0.6383, 0.1660,
00486                    0.0176, 0.0008 };
00487   float Hf3[9] = { -0.0020, -0.0354, -0.2225, -0.4277, 0.0, 0.4277, 0.2225,
00488                    0.0354, 0.0020 };
00489   float Hf4[9] = { 0.0048, 0.0566, 0.1695, -0.1889, -0.7349, -0.1889, 0.1695,
00490                    0.0566, 0.0048 };
00491 
00492   Image<float> fima = src;
00493 
00494   // apply Nine-Tap filters to create the separable bases of G2 and H2
00495   Image<float> G2a = sepFilter(fima, Gf1, Gf2, 9, 9, CONV_BOUNDARY_ZERO);
00496   Image<float> G2b = sepFilter(fima, Gf3, Gf3, 9, 9, CONV_BOUNDARY_ZERO);
00497   Image<float> G2c = sepFilter(fima, Gf2, Gf1, 9, 9, CONV_BOUNDARY_ZERO);
00498   Image<float> H2a = sepFilter(fima, Hf1, Hf2, 9, 9, CONV_BOUNDARY_ZERO);
00499   Image<float> H2b = sepFilter(fima, Hf4, Hf3, 9, 9, CONV_BOUNDARY_ZERO);
00500   Image<float> H2c = sepFilter(fima, Hf3, Hf4, 9, 9, CONV_BOUNDARY_ZERO);
00501   Image<float> H2d = sepFilter(fima, Hf2, Hf1, 9, 9, CONV_BOUNDARY_ZERO);
00502 
00503   // combine the basis-filtered images:
00504   orient = Image<float>(src.getDims(), NO_INIT);
00505   strength = Image<float>(src.getDims(), NO_INIT);
00506 
00507   const int siz = src.getSize();
00508 
00509   typename Image<float>::const_iterator
00510     pG2a = G2a.begin(),
00511     pG2b = G2b.begin(),
00512     pG2c = G2c.begin(),
00513     pH2a = H2a.begin(),
00514     pH2b = H2b.begin(),
00515     pH2c = H2c.begin(),
00516     pH2d = H2d.begin();
00517 
00518   Image<float>::iterator porient = orient.beginw();
00519   Image<float>::iterator pstrength = strength.beginw();
00520 
00521   for (int k = 0; k < siz; ++k)
00522     {
00523       const float c2 = 0.5 * (squareOf(pG2a[k]) - squareOf(pG2c[k]))
00524         + 0.46875 * (squareOf(pH2a[k]) - squareOf(pH2d[k]))
00525         + 0.28125 * (squareOf(pH2b[k]) - squareOf(pH2c[k]))
00526         + 0.1875 * (pH2a[k] * pH2c[k] - pH2b[k] * pH2d[k]);
00527       const float c3 =
00528         - pG2a[k] * pG2b[k]
00529         - pG2b[k] * pG2c[k]
00530         - 0.9375 * (pH2c[k] * pH2d[k] + pH2a[k] * pH2b[k])
00531         - 1.6875 * pH2b[k] * pH2c[k]
00532         - 0.1875 * pH2a[k] * pH2d[k];
00533       porient[k] = (atan2(c3, c2) + M_PI)/ 2.0;  // between 0 and PI
00534       pstrength[k] = sqrt(squareOf(c2) + squareOf(c3));
00535     }
00536 }
00537 
00538 // ######################################################################
00539 template <class T>
00540 Image<T> energyNorm(const Image<T>& img)
00541 {
00542 GVX_TRACE(__PRETTY_FUNCTION__);
00543   // Need to bump everything above zero here so that we don't have
00544   // divide-by-zero problems when we later divide by the energy. FIXME
00545   // should be a better way???
00546   Image<float> result = img + 1.0f;
00547 
00548   // Compute the local image energy
00549   const Image<float> energy = sqrt(lowPass9(result * result));
00550 
00551   // Normalize by the local image energy
00552   result = result / energy; // watch divbyzero here!!!
00553 
00554   // Set to zero-mean
00555   result -= mean(result);
00556 
00557   return result;
00558 }
00559 
00560 // ######################################################################
00561 template <class T>
00562 Image<T> junctionFilterFull(const Image<T>& i0,  const Image<T>& i45,
00563                             const Image<T>& i90, const Image<T>& i135,
00564                             const bool r[8],     const int dx = 6,
00565                             const int dy = 6,
00566                             const bool useEuclidDiag = true)
00567 {
00568 GVX_TRACE(__PRETTY_FUNCTION__);
00569 
00570  ASSERT(i0.isSameSize(i45));
00571  ASSERT(i0.isSameSize(i90));
00572  ASSERT(i0.isSameSize(i135));
00573 
00574   Image<T> result(i0.getDims(), ZEROS);
00575 
00576   const int w = i0.getWidth(), h = i0.getHeight();
00577 
00578   /* example L junction: upright L(x,y) = |(x, y-1) and (NOT
00579      /(x+1,y-1)) and -(x+1, y) and (NOT \(x+1,y+1)) and (NOT |(x,
00580      y+1)) and (NOT /(x-1,y+1)) and (NOT -(x-1, y)) and (NOT
00581      \(x-1,y-1))
00582 
00583      To find NOT of an irrelevant feature, just consider how strong it
00584      is in comparison to the weakest relevant feature, i.e. d =
00585      min(all Rel responses)/2 - Irr. response
00586 
00587      d is high <=> the absence of this Irr. feature
00588      d is low <=> the presence of this Irr. feature
00589 
00590      *******
00591 
00592      3rd party comment:
00593 
00594      Nathan: This filter basically will give either a proportional
00595              response to a proper feature set or should return
00596              zero given 1 or more irr features. That is, notice
00597              that for any feature <= min rel feature is tacked
00598              into the multiplication. Thus, weak irr features still
00599              add to the strength. So this filter is sensitive to noise.
00600              However, it is simple and will brutally weed out any
00601              response given a strong irr feature.
00602  */
00603 
00604   // pixel offsets for (x+dx, y), (x+dx, y-dy), (x, y-dy), etc. going
00605   // counterclockwise:
00606 
00607   int dx_diag, dy_diag;
00608 
00609   // Compute the diagonal offsets if needed as a euclidian distance
00610   // from the center in dx,dy or should we just put it on a "grid"
00611   if(useEuclidDiag)
00612   {
00613     dx_diag = (int)round(sqrt(pow(dx,2)/2.0f));
00614     dy_diag = (int)round(sqrt(pow(dy,2)/2.0f));
00615   }
00616   else
00617   {
00618     dx_diag = dx;
00619     dy_diag = dy;
00620   }
00621 
00622   // non diagonal elements
00623   const int o0 =  dx;
00624   const int o2 = -dy*w;
00625   const int o4 = -dx;
00626   const int o6 =  dy*w;
00627 
00628   // diagonal elements
00629   const int o1 =  dx_diag - dy_diag*w;
00630   const int o3 = -dx_diag - dy_diag*w;
00631   const int o5 = -dx_diag + dy_diag*w;
00632   const int o7 =  dx_diag + dy_diag*w;
00633 
00634   // get pointers to the image pixel data:
00635   typename Image<T>::const_iterator
00636     ip0  = i0.begin()  + dx + dy*w, ip45  = i45.begin()  + dx + dy*w,
00637     ip90 = i90.begin() + dx + dy*w, ip135 = i135.begin() + dx + dy*w;
00638   typename Image<T>::iterator rp = result.beginw() + dx + dy*w;
00639 
00640   // loop over the bulk of the images (i.e., all except a border of
00641   // width dx and height dy):
00642 
00643   const T max = std::numeric_limits<T>::max();
00644 
00645   for (int j = (dy*2); j < h; j ++)
00646   {
00647     for (int i = (dx*2); i < w; i ++)
00648     {
00649 
00650       // get the various feature values:
00651       const T r0 = ip0[o0],   r4 = ip0[o4];   ++ip0;
00652       const T r1 = ip45[o1],  r5 = ip45[o5];  ++ip45;
00653       const T r2 = ip90[o2],  r6 = ip90[o6];  ++ip90;
00654       const T r3 = ip135[o3], r7 = ip135[o7]; ++ip135;
00655 
00656       // for this full implementation, let's start by finding out the
00657       // minimum relevant response, so that we can then check the
00658       // irrelevant responses against that baseline:
00659       T minRel = max;
00660       if (r[0] && r0 < minRel) minRel = r0;
00661       if (r[1] && r1 < minRel) minRel = r1;
00662       if (r[2] && r2 < minRel) minRel = r2;
00663       if (r[3] && r3 < minRel) minRel = r3;
00664       if (r[4] && r4 < minRel) minRel = r4;
00665       if (r[5] && r5 < minRel) minRel = r5;
00666       if (r[6] && r6 < minRel) minRel = r6;
00667       if (r[7] && r7 < minRel) minRel = r7;
00668       minRel /= 2;
00669 
00670       // now let's compute the response of the junction:
00671       float resp = 1.0f;
00672 
00673       // One at a time we test to see if an irr feature is stronger
00674       // than one of our rel features. If so, we return a zero reponse
00675       // and quit. Otherwise we keep going and normalize the final response.
00676       // Notice we only get a non-zero reponse of all irr features are
00677       // less than 1/2 of the minimum rel feature.
00678 
00679       if (r[0]) resp *= r0; else resp *= (minRel - r0);
00680       if (resp <= 0.0f) resp = 0.0f;
00681       else
00682       {
00683         if (r[1]) resp *= r1; else resp *= (minRel - r1);
00684         if (resp <= 0.0f) resp = 0.0f;
00685         else
00686         {
00687           if (r[2]) resp *= r2; else resp *= (minRel - r2);
00688           if (resp <= 0.0f) resp = 0.0f;
00689           else
00690           {
00691             if (r[3]) resp *= r3; else resp *= (minRel - r3);
00692             if (resp <= 0.0f) resp = 0.0f;
00693             else
00694             {
00695               if (r[4]) resp *= r4; else resp *= (minRel - r4);
00696               if (resp <= 0.0f) resp = 0.0f;
00697               else
00698               {
00699                 if (r[5]) resp *= r5; else resp *= (minRel - r5);
00700                 if (resp <= 0.0f) resp = 0.0f;
00701                 else
00702                 {
00703                   if (r[6]) resp *= r6; else resp *= (minRel - r6);
00704                   if (resp <= 0.0f) resp = 0.0f;
00705                   else
00706                   {
00707                     if (r[7]) resp *= r7; else resp *= (minRel - r7);
00708                     if (resp <= 0.0f) resp = 0.0f;
00709                     else
00710                     {
00711                       // normalize it by the number of features:
00712                       resp = pow(resp, 1.0/8.0);
00713                     }
00714                   }
00715                 }
00716               }
00717             }
00718           }
00719         }
00720       }
00721 
00722       // store the response
00723       *rp++ = T(resp);
00724     }
00725     // skip border and go to next row of pixels:
00726     ip0 += dx*2; ip45 += dx*2; ip90 += dx*2; ip135 += dx*2; rp += dx*2;
00727   }
00728 
00729   return result;
00730 }
00731 
00732 // ######################################################################
00733 namespace
00734 {
00735   // Trivial helper function for junctionFilterPartial()
00736   template <class DstItr, class SrcItr>
00737   inline void JFILT(DstItr dptr, SrcItr sptr,
00738                     const int w, const int jmax, const int imax)
00739   {
00740     for(int j = 0; j < jmax; ++j)
00741     {
00742       for (int i = 0; i < imax; ++i)
00743         dptr[i] *= sptr[i];
00744 
00745       sptr += w; dptr += w;
00746     }
00747   }
00748 }
00749 
00750 template <class T>
00751 Image<T> junctionFilterPartial(const Image<T>& i0,  const Image<T>& i45,
00752                                const Image<T>& i90, const Image<T>& i135,
00753                                const bool r[8],     const int dx = 6,
00754                                const int dy = 6,
00755                                const bool useEuclidDiag = false)
00756 {
00757 GVX_TRACE(__PRETTY_FUNCTION__);
00758   // the preamble is identical to junctionFilterFull:
00759 
00760   ASSERT(i0.isSameSize(i45) && i0.isSameSize(i90) && i0.isSameSize(i135));
00761   Image<T> result(i0.getDims(), ZEROS);
00762 
00763   const int w = i0.getWidth(), h = i0.getHeight();
00764 
00765   int dx_diag, dy_diag;
00766 
00767   // Compute the diagonal offsets if needed as a euclidian distance
00768   // from the center in dx,dy or should we just put it on a "grid"
00769   if(useEuclidDiag)
00770   {
00771     dx_diag = (int)round(fastSqrt((dx*dx)/2.0f));
00772     dy_diag = (int)round(fastSqrt((dy*dy)/2.0f));
00773   }
00774   else
00775   {
00776     dx_diag = dx;
00777     dy_diag = dy;
00778   }
00779 
00780   // non diagonal elements
00781   const int o0 =  dx;
00782   const int o2 = -dy*w;
00783   const int o4 = -dx;
00784   const int o6 =  dy*w;
00785 
00786   // diagonal elements
00787   const int o1 =  dx_diag - dy_diag*w;
00788   const int o3 = -dx_diag - dy_diag*w;
00789   const int o5 = -dx_diag + dy_diag*w;
00790   const int o7 =  dx_diag + dy_diag*w;
00791 
00792   const int offset = dx + dy*w;
00793 
00794   typename Image<T>::iterator const rpp = result.beginw() + offset;
00795 
00796   // compute the number of relevant features (for normalization):
00797   int nr = 0; for (int i = 0; i < 8; i++) if (r[i]) nr++;
00798 
00799   const int imax = w - dx*2;
00800   const int jmax = h - dy*2;
00801 
00802   // initialize the valid portion of the response array to 1.0's
00803   {
00804     typename Image<T>::iterator rp = rpp;
00805     for (int j = 0; j < jmax; ++j)
00806     {
00807       for (int i = 0; i < imax; ++i)
00808         rp[i] = T(1.0);
00809       rp += w;
00810     }
00811   }
00812 
00813   // loop over the bulk of the images, computing the responses of
00814   // the junction filter:
00815   {
00816     if (r[0]) JFILT(rpp, i0.begin()   + o0 + offset, w, jmax, imax);
00817     if (r[1]) JFILT(rpp, i45.begin()  + o1 + offset, w, jmax, imax);
00818     if (r[2]) JFILT(rpp, i90.begin()  + o2 + offset, w, jmax, imax);
00819     if (r[3]) JFILT(rpp, i135.begin() + o3 + offset, w, jmax, imax);
00820     if (r[4]) JFILT(rpp, i0.begin()   + o4 + offset, w, jmax, imax);
00821     if (r[5]) JFILT(rpp, i45.begin()  + o5 + offset, w, jmax, imax);
00822     if (r[6]) JFILT(rpp, i90.begin()  + o6 + offset, w, jmax, imax);
00823     if (r[7]) JFILT(rpp, i135.begin() + o7 + offset, w, jmax, imax);
00824   }
00825 
00826   // normalize the responses by the number of relevant features,
00827   // optimizing by using sqrt() or cbrt() where possible (this gives
00828   // an average speedup of ~3x across all junction filter types):
00829   {
00830     typename Image<T>::iterator rp = rpp;
00831     if (nr == 1)
00832     {
00833       // nothing to do here
00834     }
00835     else if (nr == 2)
00836     {
00837       for (int j = 0; j < jmax; ++j)
00838       {
00839         for (int i = 0; i < imax; ++i)
00840           rp[i] = T(fastSqrt(rp[i]));
00841         rp += w;
00842       }
00843     }
00844     else if (nr == 3)
00845     {
00846       for (int j = 0; j < jmax; ++j)
00847       {
00848         for (int i = 0; i < imax; ++i)
00849           rp[i] = T(cbrt(rp[i]));
00850         rp += w;
00851       }
00852     }
00853     else if (nr == 4)
00854     {
00855       for (int j = 0; j < jmax; ++j)
00856       {
00857         for (int i = 0; i < imax; ++i)
00858           rp[i] = T(fastSqrt(fastSqrt(rp[i])));
00859         rp += w;
00860       }
00861     }
00862     else
00863     {
00864       const double power = 1.0 / nr;
00865       for (int j = 0; j < jmax; ++j)
00866       {
00867         for (int i = 0; i < imax; ++i)
00868           rp[i] = T(pow(rp[i], power));
00869         rp += w;
00870       }
00871     }
00872   }
00873   return result;
00874 }
00875 
00876 // ######################################################################
00877 
00878 // ######################################################################
00879 template <class T>
00880 Image<T> MSTFilterFull(const Image<T>& i0,  const Image<T>& i45,
00881                             const Image<T>& i90, const Image<T>& i135,
00882                             const bool r[8],     const int dx = 6,
00883                             const int dy = 6,
00884                             const bool useEuclidDiag = true)
00885 {
00886 GVX_TRACE(__PRETTY_FUNCTION__);
00887 
00888  ASSERT(i0.isSameSize(i45));
00889  ASSERT(i0.isSameSize(i90));
00890  ASSERT(i0.isSameSize(i135));
00891 
00892   Image<T> result(i0.getDims(), ZEROS);
00893 
00894   const int w = i0.getWidth(), h = i0.getHeight();
00895 
00896   /* example star MST: star star(x,y) = |(x, y-1) and (
00897      /(x+1,y-1)) and -(x+1, y) and  \(x+1,y+1) and ( |(x,
00898      y+1)) and ( /(x-1,y+1)) and ( -(x-1, y)) and (
00899      \(x-1,y-1))
00900 
00901      To find NOT of an irrelevant feature, just consider how strong it
00902      is in comparison to the weakest relevant feature, i.e. d =
00903      min(all Rel responses)/2 - Irr. response
00904 
00905      d is high <=> the absence of this Irr. feature
00906      d is low <=> the presence of this Irr. feature
00907 
00908      *******
00909 
00910  */
00911 
00912   // pixel offsets for (x+dx, y), (x+dx, y-dy), (x, y-dy), etc. going
00913   // counterclockwise:
00914 
00915   int dx_diag, dy_diag;
00916 
00917   // Compute the diagonal offsets if needed as a euclidian distance
00918   // from the center in dx,dy or should we just put it on a "grid"
00919   if(useEuclidDiag)
00920   {
00921     dx_diag = (int)round(sqrt(pow(dx,2)/2.0f));
00922     dy_diag = (int)round(sqrt(pow(dy,2)/2.0f));
00923   }
00924   else
00925   {
00926     dx_diag = dx;
00927     dy_diag = dy;
00928   }
00929 
00930   // non diagonal elements
00931   const int o0 =  dx;
00932   const int o2 = -dy*w;
00933   const int o4 = -dx;
00934   const int o6 =  dy*w;
00935 
00936   const int o8 =  dx*2;
00937   const int o10 = -dy*w*2;
00938   const int o12 = -dx*2;
00939   const int o14 =  dy*w*2;
00940 
00941   // diagonal elements
00942   const int o1 =  dx_diag - dy_diag*w;
00943   const int o3 = -dx_diag - dy_diag*w;
00944   const int o5 = -dx_diag + dy_diag*w;
00945   const int o7 =  dx_diag + dy_diag*w;
00946 
00947   const int o9 =  (dx_diag - dy_diag*w)*2;
00948   const int o11 = (-dx_diag - dy_diag*w)*2;
00949   const int o13 = (-dx_diag + dy_diag*w)*2;
00950   const int o15 =  (dx_diag + dy_diag*w)*2;
00951 
00952   // get pointers to the image pixel data:
00953   typename Image<T>::const_iterator
00954     ip0  = i0.begin()  + dx + dy*w, ip45  = i45.begin()  + dx + dy*w,
00955     ip90 = i90.begin() + dx + dy*w, ip135 = i135.begin() + dx + dy*w;
00956   typename Image<T>::iterator rp = result.beginw() + dx + dy*w;
00957 
00958   // loop over the bulk of the images (i.e., all except a border of
00959   // width dx and height dy):
00960 
00961   const T max = std::numeric_limits<T>::max();
00962 
00963   for (int j = (dy*2); j < h; j ++)
00964   {
00965     for (int i = (dx*2); i < w; i ++)
00966     {
00967 
00968       // get the various feature values:
00969       const T r0 = ip0[o0],   r4 = ip0[o4], r8 = ip0[o8],   r12 = ip0[o12];  ++ip0;
00970       const T r1 = ip45[o1],  r5 = ip45[o5], r9 = ip45[o9],  r13 = ip45[o13];  ++ip45;
00971       const T r2 = ip90[o2],  r6 = ip90[o6], r10 = ip90[o10],  r14 = ip90[o14];  ++ip90;
00972       const T r3 = ip135[o3], r7 = ip135[o7], r11 = ip135[o11], r15 = ip135[o15]; ++ip135;
00973 
00974       // for this full implementation, let's start by finding out the
00975       // minimum relevant response, so that we can then check the
00976       // irrelevant responses against that baseline:
00977       T minRel = max;
00978       if (r[0] && r0 < minRel) minRel = r0;
00979       if (r[1] && r1 < minRel) minRel = r1;
00980       if (r[2] && r2 < minRel) minRel = r2;
00981       if (r[3] && r3 < minRel) minRel = r3;
00982       if (r[4] && r4 < minRel) minRel = r4;
00983       if (r[5] && r5 < minRel) minRel = r5;
00984       if (r[6] && r6 < minRel) minRel = r6;
00985       if (r[7] && r7 < minRel) minRel = r7;
00986 
00987       if (r[0] && r8 < minRel) minRel = r8;
00988       if (r[1] && r9 < minRel) minRel = r9;
00989       if (r[2] && r10 < minRel) minRel = r10;
00990       if (r[3] && r11 < minRel) minRel = r11;
00991       if (r[4] && r12 < minRel) minRel = r12;
00992       if (r[5] && r13 < minRel) minRel = r13;
00993       if (r[6] && r14 < minRel) minRel = r14;
00994       if (r[7] && r15 < minRel) minRel = r15;
00995       minRel /= 2;
00996 
00997       // now let's compute the response of the MST:
00998       float resp = 1.0f;
00999 
01000       // One at a time we test to see if an irr feature is stronger
01001       // than one of our rel features. If so, we return a zero reponse
01002       // and quit. Otherwise we keep going and normalize the final response.
01003       // Notice we only get a non-zero reponse of all irr features are
01004       // less than 1/2 of the minimum rel feature.
01005 
01006       if (r[0]) resp *= r0; else resp *= (minRel - r0);
01007       if (resp <= 0.0f)
01008         resp = 0.0f;
01009       else
01010       {
01011         if (r[1]) resp *= r1; else resp *= (minRel - r1);
01012         if (resp <= 0.0f)
01013           resp = 0.0f;
01014         else
01015         {
01016           if (r[2]) resp *= r2;  else resp *= (minRel - r2);
01017           if (resp <= 0.0f)
01018             resp = 0.0f;
01019           else
01020           {
01021             if (r[3]) resp *= r3;  else resp *= (minRel - r3);
01022             if (resp <= 0.0f)
01023               resp = 0.0f;
01024             else
01025             {
01026               if (r[4]) resp *= r4; else resp *= (minRel - r4);
01027               if (resp <= 0.0f) resp = 0.0f;
01028               else
01029               {
01030                 if (r[5]) resp *= r5; else resp *= (minRel - r5);
01031                 if (resp <= 0.0f) resp = 0.0f;
01032                 else
01033                 {
01034                   if (r[6]) resp *= r6; else resp *= (minRel - r6);
01035                   if (resp <= 0.0f) resp = 0.0f;
01036                   else
01037                   {
01038                     if (r[7]) resp *= r7; else resp *= (minRel - r7);
01039                     if (resp <= 0.0f) resp = 0.0f;
01040                     else
01041                     {
01042                       if (r[0]) resp *= r8; else resp *= (minRel - r8);
01043                       if (resp <= 0.0f && r8<r0)
01044                         resp = 0.0f;
01045                       else
01046                       {
01047                           if (r[1]) resp *= r9; else resp *= (minRel - r9);
01048                           if (resp <= 0.0f && r9<r1)
01049                             resp = 0.0f;
01050                           else
01051                           {
01052                             if (r[2]) resp *= r10;  else resp *= (minRel - r10);
01053                             if (resp <= 0.0f && r10<r2)
01054                               resp = 0.0f;
01055                             else
01056                             {
01057                               if (r[3]) resp *= r11;  else resp *= (minRel - r11);
01058                               if (resp <= 0.0f && r11<r3)
01059                                 resp = 0.0f;
01060                               else
01061                               {
01062                                   if (r[4]) resp *= r12; else resp *= (minRel - r12);
01063                                   if (resp <= 0.0f && r12<r4) resp = 0.0f;
01064                                   else
01065                                   {
01066                                     if (r[5]) resp *= r13; else resp *= (minRel - r13);
01067                                     if (resp <= 0.0f && r13<r5) resp = 0.0f;
01068                                     else
01069                                       {
01070                                         if (r[6]) resp *= r14; else resp *= (minRel - r14);
01071                                         if (resp <= 0.0f && r14<r6) resp = 0.0f;
01072                                         else
01073                                           {
01074                                             if (r[7]) resp *= r15; else resp *= (minRel - r15);
01075                                             if (resp <= 0.0f && r15<r7) resp = 0.0f;
01076                                             else
01077                                               {
01078                                                 // normalize it by the number of features:
01079                                                 resp = pow(resp, 1.0/8.0);
01080                                               }
01081                                           }
01082                                       }
01083                                   }
01084                               }
01085                             }
01086                           }
01087                       }
01088                       // normalize it by the number of features:
01089                       // resp = pow(resp, 1.0/8.0);
01090                     }
01091                   }
01092                 }
01093               }
01094             }
01095           }
01096         }
01097       }
01098 
01099       // store the response
01100       *rp++ = T(resp);
01101     }
01102     // skip border and go to next row of pixels:
01103     ip0 += dx*2; ip45 += dx*2; ip90 += dx*2; ip135 += dx*2; rp += dx*2;
01104   }
01105 
01106   return result;
01107 }
01108 
01109 // ######################################################################
01110 namespace
01111 {
01112   // Trivial helper function for MSTFilterPartial()
01113   template <class DstItr, class SrcItr>
01114   inline void MSTFILT(DstItr dptr, SrcItr sptr,
01115                     const int w, const int jmax, const int imax)
01116   {
01117     for(int j = 0; j < jmax; ++j)
01118     {
01119       for (int i = 0; i < imax; ++i)
01120         dptr[i] *= sptr[i];
01121 
01122       sptr += w; dptr += w;
01123     }
01124   }
01125 }
01126 
01127 template <class T>
01128 Image<T> MSTFilterPartial(const Image<T>& i0,  const Image<T>& i45,
01129                                const Image<T>& i90, const Image<T>& i135,
01130                                const bool r[8],     const int dx = 6,
01131                                const int dy = 6,
01132                                const bool useEuclidDiag = false)
01133 {
01134 GVX_TRACE(__PRETTY_FUNCTION__);
01135   // the preamble is identical to MSTFilterFull:
01136 
01137   ASSERT(i0.isSameSize(i45) && i0.isSameSize(i90) && i0.isSameSize(i135));
01138   Image<T> result(i0.getDims(), ZEROS);
01139 
01140   const int w = i0.getWidth(), h = i0.getHeight();
01141 
01142   int dx_diag, dy_diag;
01143 
01144   // Compute the diagonal offsets if needed as a euclidian distance
01145   // from the center in dx,dy or should we just put it on a "grid"
01146   if(useEuclidDiag)
01147   {
01148     dx_diag = (int)round(fastSqrt((dx*dx)/2.0f));
01149     dy_diag = (int)round(fastSqrt((dy*dy)/2.0f));
01150   }
01151   else
01152   {
01153     dx_diag = dx;
01154     dy_diag = dy;
01155   }
01156 
01157  // non diagonal elements
01158   const int o0 =  dx;
01159   const int o2 = -dy*w;
01160   const int o4 = -dx;
01161   const int o6 =  dy*w;
01162 
01163   const int o8 =  dx*2;
01164   const int o10 = -dy*w*2;
01165   const int o12 = -dx*2;
01166   const int o14 =  dy*w*2;
01167 
01168   // diagonal elements
01169   const int o1 =  dx_diag - dy_diag*w;
01170   const int o3 = -dx_diag - dy_diag*w;
01171   const int o5 = -dx_diag + dy_diag*w;
01172   const int o7 =  dx_diag + dy_diag*w;
01173 
01174   const int o9 =  (dx_diag - dy_diag*w)*2;
01175   const int o11 = (-dx_diag - dy_diag*w)*2;
01176   const int o13 = (-dx_diag + dy_diag*w)*2;
01177   const int o15 =  (dx_diag + dy_diag*w)*2;
01178 
01179   const int offset = dx + dy*w;
01180 
01181   typename Image<T>::iterator const rpp = result.beginw() + offset;
01182 
01183   // compute the number of relevant features (for normalization):
01184   int nr = 0; for (int i = 0; i < 8; i++) if (r[i]) nr++;
01185 
01186   const int imax = w - dx*2;
01187   const int jmax = h - dy*2;
01188 
01189   // initialize the valid portion of the response array to 1.0's
01190   {
01191     typename Image<T>::iterator rp = rpp;
01192     for (int j = 0; j < jmax; ++j)
01193     {
01194       for (int i = 0; i < imax; ++i)
01195         rp[i] = T(1.0);
01196       rp += w;
01197     }
01198   }
01199 
01200   // loop over the bulk of the images, computing the responses of
01201   // the MST filter:
01202   {
01203     if (r[0]) MSTFILT(rpp, i0.begin()   + o0 + offset, w, jmax, imax);
01204     if (r[1]) MSTFILT(rpp, i45.begin()  + o1 + offset, w, jmax, imax);
01205     if (r[2]) MSTFILT(rpp, i90.begin()  + o2 + offset, w, jmax, imax);
01206     if (r[3]) MSTFILT(rpp, i135.begin() + o3 + offset, w, jmax, imax);
01207     if (r[4]) MSTFILT(rpp, i0.begin()   + o4 + offset, w, jmax, imax);
01208     if (r[5]) MSTFILT(rpp, i45.begin()  + o5 + offset, w, jmax, imax);
01209     if (r[6]) MSTFILT(rpp, i90.begin()  + o6 + offset, w, jmax, imax);
01210     if (r[7]) MSTFILT(rpp, i135.begin() + o7 + offset, w, jmax, imax);
01211 
01212     if (r[0]) MSTFILT(rpp, i0.begin()   + o8 + offset, w, jmax, imax);
01213     if (r[1]) MSTFILT(rpp, i45.begin()  + o9 + offset, w, jmax, imax);
01214     if (r[2]) MSTFILT(rpp, i90.begin()  + o10 + offset, w, jmax, imax);
01215     if (r[3]) MSTFILT(rpp, i135.begin() + o11 + offset, w, jmax, imax);
01216     if (r[4]) MSTFILT(rpp, i0.begin()   + o12 + offset, w, jmax, imax);
01217     if (r[5]) MSTFILT(rpp, i45.begin()  + o13 + offset, w, jmax, imax);
01218     if (r[6]) MSTFILT(rpp, i90.begin()  + o14 + offset, w, jmax, imax);
01219     if (r[7]) MSTFILT(rpp, i135.begin() + o15 + offset, w, jmax, imax);
01220 
01221   }
01222 
01223   // normalize the responses by the number of relevant features,
01224   // optimizing by using sqrt() or cbrt() where possible (this gives
01225   // an average speedup of ~3x across all MST filter types):
01226   {
01227     typename Image<T>::iterator rp = rpp;
01228     if (nr == 1)
01229     {
01230       // nothing to do here
01231     }
01232     else if (nr == 2)
01233     {
01234       for (int j = 0; j < jmax; ++j)
01235       {
01236         for (int i = 0; i < imax; ++i)
01237           rp[i] = T(fastSqrt(rp[i]));
01238         rp += w;
01239       }
01240     }
01241     else if (nr == 3)
01242     {
01243       for (int j = 0; j < jmax; ++j)
01244       {
01245         for (int i = 0; i < imax; ++i)
01246           rp[i] = T(cbrt(rp[i]));
01247         rp += w;
01248       }
01249     }
01250     else if (nr == 4)
01251     {
01252       for (int j = 0; j < jmax; ++j)
01253       {
01254         for (int i = 0; i < imax; ++i)
01255           rp[i] = T(fastSqrt(fastSqrt(rp[i])));
01256         rp += w;
01257       }
01258     }
01259     else
01260     {
01261       const double power = 1.0 / nr;
01262       for (int j = 0; j < jmax; ++j)
01263       {
01264         for (int i = 0; i < imax; ++i)
01265           rp[i] = T(pow(rp[i], power));
01266         rp += w;
01267       }
01268     }
01269   }
01270   return result;
01271 }
01272 
01273 
01274 // ######################################################################
01275 
01276 template <class T>
01277 Image<typename promote_trait<T, float>::TP> gradientmag(const Image<T>& input)
01278 {
01279 GVX_TRACE(__PRETTY_FUNCTION__);
01280   typedef typename promote_trait<T, float>::TP TF;
01281 
01282   Image<TF> result(input.getDims(), NO_INIT);
01283   typename Image<T>::const_iterator src = input.begin();
01284   typename Image<TF>::iterator dst = result.beginw();
01285   const int w = input.getWidth(), h = input.getHeight();
01286   TF zero = TF();
01287 
01288   // first row is all zeros:
01289   for (int i = 0; i < w; i ++) *dst ++ = zero;
01290   src += w;
01291 
01292   // loop over inner rows:
01293   for (int j = 1; j < h-1; j ++)
01294     {
01295       // leftmost pixel is zero:
01296       *dst ++ = zero; ++ src;
01297 
01298       // loop over inner columns:
01299       for (int i = 1; i < w-1; i ++)
01300         {
01301           TF valx = src[1] - src[-1];
01302           TF valy = src[w] - src[-w];
01303 
01304           *dst++ = sqrt(valx * valx + valy * valy);
01305           ++ src;
01306         }
01307 
01308       // rightmost pixel is zero:
01309       *dst ++ = zero; ++ src;
01310     }
01311 
01312   // last row is all zeros:
01313   for (int i = 0; i < w; i ++) *dst ++ = zero;
01314 
01315   return result;
01316 }
01317 
01318 // ######################################################################
01319 template <class T>
01320 Image<typename promote_trait<T, float>::TP> gradientori(const Image<T>& input)
01321 {
01322 GVX_TRACE(__PRETTY_FUNCTION__);
01323   typedef typename promote_trait<T, float>::TP TF;
01324 
01325   Image<TF> result(input.getDims(), NO_INIT);
01326   typename Image<T>::const_iterator src = input.begin();
01327   typename Image<TF>::iterator dst = result.beginw();
01328   const int w = input.getWidth(), h = input.getHeight();
01329   TF zero = TF();
01330 
01331   // first row is all zeros:
01332   for (int i = 0; i < w; i ++) *dst ++ = zero;
01333   src += w;
01334 
01335   // loop over inner rows:
01336   for (int j = 1; j < h-1; j ++)
01337     {
01338       // leftmost pixel is zero:
01339       *dst ++ = zero; ++ src;
01340 
01341       // loop over inner columns:
01342       for (int i = 1; i < w-1; i ++)
01343         {
01344           TF valx = src[1] - src[-1];
01345           TF valy = src[w] - src[-w];
01346 
01347           *dst++ = atan2(valy, valx);
01348           ++ src;
01349         }
01350 
01351       // rightmost pixel is zero:
01352       *dst ++ = zero; ++ src;
01353     }
01354 
01355   // last row is all zeros:
01356   for (int i = 0; i < w; i ++) *dst ++ = zero;
01357 
01358   return result;
01359 }
01360 
01361 // ######################################################################
01362 template <class T>
01363 void gradient(const Image<T>& input,
01364               Image<typename promote_trait<T, float>::TP>& mag,
01365               Image<typename promote_trait<T, float>::TP>& ori)
01366 {
01367 GVX_TRACE(__PRETTY_FUNCTION__);
01368   typedef typename promote_trait<T, float>::TP TF;
01369 
01370   mag.resize(input.getDims()); ori.resize(input.getDims());
01371   typename Image<T>::const_iterator src = input.begin();
01372   typename Image<TF>::iterator m = mag.beginw(), o = ori.beginw();
01373   const int w = input.getWidth(), h = input.getHeight();
01374   TF zero = TF();
01375 
01376   // first row is all zeros:
01377   for (int i = 0; i < w; i ++) { *m ++ = zero; *o ++ = zero; }
01378   src += w;
01379 
01380   // loop over inner rows:
01381   for (int j = 1; j < h-1; j ++)
01382     {
01383       // leftmost pixel is zero:
01384       *m ++ = zero; *o ++ = zero; ++ src;
01385 
01386       // loop over inner columns:
01387       for (int i = 1; i < w-1; i ++)
01388         {
01389           TF valx = src[1] - src[-1];
01390           TF valy = src[w] - src[-w];
01391 
01392           *m++ = sqrt(valx * valx + valy * valy);
01393           *o++ = atan2(valy, valx);
01394           ++ src;
01395         }
01396 
01397       // rightmost pixel is zero:
01398       *m ++ = zero; *o ++ = zero; ++ src;
01399     }
01400 
01401   // last row is all zeros:
01402   for (int i = 0; i < w; i ++) { *m ++ = zero; *o ++ = zero; }
01403 }
01404 
01405 // ######################################################################
01406 template <class T>
01407 void gradientSobel(const Image<T>& input,
01408               Image<typename promote_trait<T, float>::TP>& mag,
01409               Image<typename promote_trait<T, float>::TP>& ori,
01410                                   int kernelSize)
01411 {
01412 GVX_TRACE(__PRETTY_FUNCTION__);
01413   typedef typename promote_trait<T, float>::TP TF;
01414 
01415   ASSERT( (kernelSize == 3 ) | (kernelSize == 5));
01416   mag.resize(input.getDims(), true); ori.resize(input.getDims(), true);
01417   typename Image<T>::const_iterator src = input.begin();
01418   typename Image<TF>::iterator m = mag.beginw(), o = ori.beginw();
01419   const int w = input.getWidth(), h = input.getHeight();
01420   TF zero = TF();
01421 
01422   // first rows are all zeros:
01423   switch (kernelSize) {
01424     case 3:
01425       for (int i = 0; i < w; i ++) { *m ++ = zero; *o ++ = zero; }
01426       src += w;
01427       break;
01428     case 5:
01429       for (int i = 0; i < w*2; i ++) { *m ++ = zero; *o ++ = zero; }
01430       src += w*2;
01431       break;
01432   }
01433 
01434   switch (kernelSize){
01435     case 3:
01436       // loop over inner rows:
01437       for (int j = 1; j < h-1; j ++)
01438       {
01439         // leftmost pixel is zero:
01440         *m ++ = zero; *o ++ = zero; ++ src;
01441         // loop over inner columns:
01442         for (int i = 1; i < w-1; i ++)
01443         {
01444           TF valx = -1*src[-1*w + -1] + 0*src[-1*w + 0] + 1*src[-1*w + 1]
01445             + -2*src[ 0*w + -1] + 0*src[ 0*w + 0] + 2*src[ 0*w + 1]
01446             + -1*src[ 1*w + -1] + 0*src[ 1*w + 0] + 1*src[ 1*w + 1];
01447 
01448           TF valy =  1*src[-1*w + -1] +  2*src[-1*w + 0] +  1*src[-1*w + 1]
01449             +  0*src[ 0*w + -1] +  0*src[ 0*w + 0] +  0*src[ 0*w + 1]
01450             + -1*src[ 1*w + -1] + -2*src[ 1*w + 0] + -1*src[ 1*w + 1];
01451 
01452           *m++ = sqrt(valx * valx + valy * valy);
01453           *o++ = atan2(valy, valx);
01454           ++ src;
01455         }
01456         // rightmost pixel is zero:
01457         *m ++ = zero; *o ++ = zero; ++ src;
01458       }
01459       break;
01460 
01461     case 5:
01462       // loop over inner rows:
01463       for (int j = 2; j < h-2; j ++)
01464       {
01465         // leftmost pixel is zero:
01466         *m ++ = zero; *o ++ = zero; ++ src;
01467         *m ++ = zero; *o ++ = zero; ++ src;
01468         // loop over inner columns:
01469         for (int i = 2; i < w-2; i ++)
01470         {
01471           TF valx = -1*src[-2*w + -2] +  -2*src[-2*w + -1] + 0*src[-2*w + 0] +  2*src[-2*w + 1] + 1*src[-2*w + 2]
01472             + -4*src[-1*w + -2] +  -8*src[-1*w + -1] + 0*src[-1*w + 0] +  8*src[-1*w + 1] + 4*src[-1*w + 2]
01473             + -6*src[ 0*w + -2] + -12*src[ 0*w + -1] + 0*src[ 0*w + 0] + 12*src[ 0*w + 1] + 6*src[ 0*w + 2]
01474             + -4*src[ 1*w + -2] +  -8*src[ 1*w + -1] + 0*src[ 1*w + 0] +  8*src[ 1*w + 1] + 4*src[ 1*w + 2]
01475             + -1*src[ 2*w + -2] +  -2*src[ 2*w + -1] + 0*src[ 2*w + 0] +  2*src[ 2*w + 1] + 1*src[ 2*w + 2];
01476 
01477           TF valy =  1*src[-2*w + -2] +  4*src[-2*w + -1] +   6*src[-2*w + 0] +  4*src[-2*w + 1] +  1*src[-2*w + 2]
01478             +  2*src[-1*w + -2] +  8*src[-1*w + -1] +  12*src[-1*w + 0] +  8*src[-1*w + 1] +  2*src[-1*w + 2]
01479             +  0*src[ 0*w + -2] +  0*src[ 0*w + -1] +   0*src[ 0*w + 0] +  0*src[ 0*w + 1] +  0*src[ 0*w + 2]
01480             + -2*src[ 1*w + -2] + -8*src[ 1*w + -1] + -12*src[ 1*w + 0] + -8*src[ 1*w + 1] + -2*src[ 1*w + 2]
01481             + -1*src[ 2*w + -2] + -4*src[ 2*w + -1] +  -6*src[ 2*w + 0] + -4*src[ 2*w + 1] + -1*src[ 2*w + 2];
01482 
01483           *m++ = sqrt(valx * valx + valy * valy);
01484           *o++ = atan2(valy, valx);
01485           ++ src;
01486         }
01487         // rightmost pixel is zero:
01488         *m ++ = zero; *o ++ = zero; ++ src;
01489       }
01490       break;
01491   }
01492 
01493 
01494   // last rows are all zeros:
01495   switch (kernelSize){
01496     case 3:
01497       for (int i = 0; i < w; i ++) { *m ++ = zero; *o ++ = zero; }
01498       break;
01499     case 5:
01500       for (int i = 0; i < w*2; i ++) { *m ++ = zero; *o ++ = zero; }
01501       break;
01502   }
01503 }
01504 
01505 // ######################################################################
01506 Image<float> nonMaxSuppr(const Image<float>& mag, const Image<float>& ori)
01507 {
01508   //Non maximal suppersion
01509   Image<float> outImg = mag; //(mag.getDims(), ZEROS);
01510   for(int y=0; y<mag.getHeight(); y++)
01511     for(int x=0; x<mag.getWidth(); x++)
01512     {
01513       if (mag.getVal(x,y) > 0)
01514       {
01515         float t = ori.getVal(x,y);
01516         //if (t<0.57 && t > -0.57)
01517         //{
01518         //  if (mag.getVal(x,y) >= mag.getVal(x,y+1) &&
01519         //      mag.getVal(x,y) >  mag.getVal(x,y-1))
01520         //    outImg.setVal(x,y, mag.getVal(x,y));
01521         //} else if (t > 1.04 || t < -1.04)
01522         //{
01523         //  if (mag.getVal(x,y) >= mag.getVal(x+1,y) &&
01524         //      mag.getVal(x,y) >  mag.getVal(x-1,y))
01525         //    outImg.setVal(x,y, mag.getVal(x,y));
01526         //} else if (t>0.57)
01527         //{
01528         //  if (mag.getVal(x,y) >= mag.getVal(x-1,y+1) &&
01529         //      mag.getVal(x,y) >  mag.getVal(x+1,y-1))
01530         //    outImg.setVal(x,y, mag.getVal(x,y));
01531         //} else {
01532         //  if (mag.getVal(x,y) >= mag.getVal(x-1,y-1) &&
01533         //      mag.getVal(x,y) >  mag.getVal(x+1,y+1))
01534         //    outImg.setVal(x,y, mag.getVal(x,y));
01535         //}
01536 
01537         
01538         int dx = int(1.5*cos(t));
01539         int dy = int(1.5*sin(t));
01540 
01541         if (mag.coordsOk(x+dx, y-dy) &&
01542             mag.coordsOk(x-dx, y+dy) )
01543         {
01544           //Remove the edge if its not a local maxima
01545           if (mag.getVal(x,y) < mag.getVal(x+dx, y-dy) ||
01546               mag.getVal(x,y) <= mag.getVal(x-dx, y+dy) )
01547             outImg.setVal(x,y,0);
01548           
01549         }
01550 
01551       }
01552     }
01553 
01554   return outImg;
01555 }
01556 
01557 // ######################################################################
01558 template <class T>
01559 Image<T> shuffleImage(const Image<T> &img)
01560 {
01561   //result image
01562   Image<T> result(img.getDims(), NO_INIT);
01563 
01564   uint imgSize = img.getSize();
01565   for(uint i=0; i < imgSize; i++)
01566   {
01567     uint j = i + rand() / (RAND_MAX / (imgSize-i) + 1);
01568     result[j] = img[i];
01569     result[i] = img[j];
01570   }
01571 
01572   return result;
01573 }
01574 
01575 
01576 // Include the explicit instantiations
01577 #include "inst/Image/FilterOps.I"
01578 
01579 // ######################################################################
01580 /* So things look consistent in everyone's emacs... */
01581 /* Local Variables: */
01582 /* indent-tabs-mode: nil */
01583 /* End: */
Generated on Sun May 8 08:05:07 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3