SurpriseMapFFT.C

Go to the documentation of this file.
00001 /*!@file Surprise/SurpriseMapFFT.C a surprise map */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Surprise/SurpriseMapFFT.C $
00035 // $Id: SurpriseMapFFT.C 9412 2008-03-10 23:10:15Z farhan $
00036 //
00037 
00038 #ifdef HAVE_FFTW3_H
00039 
00040 #include "Surprise/SurpriseMapFFT.H"
00041 
00042 #include "Image/All.H"       // for gaussianBlob()
00043 #include "Image/Kernels.H"
00044 #include "Image/Conversions.H"
00045 #include "Image/MathOps.H"
00046 #include "Util/Assert.H"
00047 #include "Raster/Raster.H"
00048 #include "Image/Pixels.H"
00049 
00050 #ifdef HAVE_FFTW3_H
00051 #include <fftw3.h>
00052 #endif
00053 
00054 // ######################################################################
00055 template <class T>
00056 SurpriseMapFFT<T>::SurpriseMapFFT() :
00057   itsModels(), itsQlen(0), itsInitialModel(),
00058   itsNeighSigma(0.0f), itsLocSigma(0.0f), itsNweights(), itsNWmin(0.0f),
00059   itsNeighUpdFac(0.7), itsProbe(-1, -1), itsSLfac(1.0), itsSSfac(0.1),
00060   itsSFSfac(1.0),itsSFPfac(1.0), itsDescrName("blank"),itsTagName("blank"),
00061   itsCounter(0)
00062 {}
00063 
00064 // ######################################################################
00065 template <class T>
00066 void SurpriseMapFFT<T>::init(const uint qlen, const double updatefac,
00067                           const double neighupdatefac,
00068                           const double sampleval, const double samplevar,
00069                           const float neighsigma, const float locsigma,
00070                           const Point2D<int>& probe, const double slfac,
00071                           const double ssfac, const double sfsfac,
00072                           const double sfpfac,
00073                           const std::string& descrName,
00074                           const std::string& tagName)
00075 {
00076   itsQlen = qlen;
00077   itsModels.clear();
00078   for(uint j = 0; j < itsFFTPModels.size(); j ++)
00079   {
00080     itsFFTSModels[j].clear();
00081     itsFFTPModels[j].clear();
00082   }
00083   itsInitialModel.init(updatefac, sampleval, samplevar);
00084   itsNeighSigma = neighsigma; itsLocSigma = locsigma;
00085   itsNweights.freeMem();
00086   itsNeighUpdFac = neighupdatefac;
00087   itsProbe = probe;
00088   itsVariance = samplevar;
00089   itsUpdatefac = updatefac;
00090   itsSLfac = slfac; itsSSfac = ssfac; itsSFSfac = sfsfac; itsSFPfac = sfpfac;
00091   itsDescrName = descrName;
00092   itsTagName = tagName;
00093   const int N = FFT_TIME_SLICE;
00094   LINFO("NEW FFT IN");
00095   in  = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * N));
00096   LINFO("NEW FFT OUT");
00097   out = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * N));
00098   //p   = fftw_plan_dft_1d(FFT_TIME_SLICE, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
00099   LINFO("NEW FFT PLAN");
00100   p   = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_PATIENT);
00101   LINFO("DONE");
00102   itsCounter = 0;
00103 }
00104 
00105 // ######################################################################
00106 template <class T>
00107 SurpriseMapFFT<T>::~SurpriseMapFFT()
00108 {}
00109 
00110 // ######################################################################
00111 template <class T>
00112 void SurpriseMapFFT<T>::reset()
00113 {
00114 
00115   for(uint j = 0; j < itsFFTSModels.size(); j ++)
00116   {
00117     itsFFTSModels[j].reset();
00118     itsFFTPModels[j].reset();
00119   }
00120 
00121   LINFO("DESTROY FFT PLAN");
00122   fftw_destroy_plan(p);
00123   fftw_free(in);
00124   fftw_free(out);
00125   LINFO("DONE");
00126 }
00127 
00128 // ######################################################################
00129 template <class T>
00130 Image<double> SurpriseMapFFT<T>::surprise(const SurpriseImage<T>& sample,
00131                                           const Image<double>& inputI,
00132                                           const Image<double>& var)
00133 {
00134   // set up a stack STL deque of to contain all images over time
00135   // for use in fft
00136   itsVarianceImage = var;
00137   if(fftStack.size() != FFT_TIME_SLICE)
00138   {
00139     fftStackCount = 0;
00140     fftStackReady = false;
00141     // reduce the number of FFT models by octave sized bins
00142     fftBins       = (unsigned char)(floor(log(FFT_TIME_SLICE/2)/log(2)));
00143     unsigned char tempsize = 1;
00144     // create octive sized bins and store thier size;
00145     for(unsigned char i = 0; i < fftBins; i++)
00146     {
00147       fftBinSize.push_back(tempsize);
00148       tempsize = tempsize * 2;
00149     }
00150     Image<double> temp;
00151     fftStack.resize(FFT_TIME_SLICE,temp);
00152   }
00153   // copy the sample onto the deque
00154   fftStack.pop_front();
00155   fftStack.push_back(inputI);
00156 
00157 
00158   // is it the first time we are called? if so, we need to setup our
00159   // size and reset our neighborhood cache:
00160   if (itsModels.empty())
00161   {
00162     // resize and reset our queue of models:
00163     SurpriseImage<T> models(sample.getDims()); // NOTE: uninitialized models
00164     models.clear(itsInitialModel);
00165     models.reset();
00166     itsFFTSModels.clear();
00167     itsFFTPModels.clear();
00168     itsModels.clear();
00169     for (uint i = 0; i < fftBins; i ++)
00170     {
00171       itsFFTSModels.push_back(models);
00172       itsFFTPModels.push_back(models);
00173       itsModels.clear();
00174     }
00175 
00176     // compute our Difference-of-Gaussians mask of weights:
00177     const int w = sample.getWidth(), h = sample.getHeight();
00178     const float sigma = itsNeighSigma * float(std::max(w, h));
00179     Dims d(w * 2 + 1, h * 2 + 1); Point2D<int> p(w, h);
00180     itsNweights = gaussianBlob<float>(d, p, sigma, sigma);
00181     itsNweights -= gaussianBlob<float>(d, p, itsLocSigma,
00182                                        itsLocSigma) *
00183       (itsLocSigma*itsLocSigma / (sigma * sigma) * 1.5f);
00184 
00185     inplaceRectify(itsNweights);  // eliminate negative values
00186 
00187     float mi, ma; getMinMax(itsNweights, mi, ma);
00188       itsNWmin = 0.01f * ma;
00189   }
00190   else if (itsModels[0].isSameSize(sample) == false)
00191     LFATAL("Inconsistent input size!");
00192   else if (itsFFTSModels[0].isSameSize(sample) == false)
00193     LFATAL("Inconsistent FFT signal mag input size!");
00194   else if (itsFFTPModels[0].isSameSize(sample) == false)
00195     LFATAL("Inconsistent FFT phase input size!");
00196   // each model feeds into the next one. The first (fastest) model
00197   // receives the sample from the image as input, and is updated. The
00198   // updated model then serves as input to the next slower model, and
00199   // so on. Total surprise is the product from all models:
00200   SurpriseImage<T> input(sample);
00201   Image<double> s;
00202 
00203   Image<float> locstot(input.getDims(), ZEROS);
00204   std::vector<Image<double> > sfs;
00205   std::vector<Image<double> > sfp;
00206 
00207   if(fftStackReady == true)
00208   {
00209     //float mi, ma;
00210     Image<double> temp;
00211     setFFTModels(input, itsNweights, itsNWmin, sfs, sfp);
00212     /*
00213     for(uint j = 0; j < itsFFTSModels.size(); j++)
00214     {
00215       //LINFO("FFT %d",j);
00216       //temp = itsFFTSModels[i][j].surprise(input);
00217       //LINFO("NEW S ****************************** %d %d",i-1,j);
00218       itsFFTSModels[j].neighborhoods(itsFFTSModels[j], itsNweights, itsNWmin);
00219       if (itsNeighUpdFac != 0.0) // use different update fac for neighs?
00220         itsFFTSModels[j].resetUpdFac(itsNeighUpdFac);
00221       // higher updfac -> stronger popout
00222       temp = itsFFTSModels[j].surprise(itsFFTSModels[j]);
00223       sfs.push_back(temp);
00224     }
00225     */
00226     /*
00227     //itsFFTSModels[1].neighborhoods(itsFFTSModels[1], itsNweights, itsNWmin);
00228     if (itsNeighUpdFac != 0.0) // use different update fac for neighs?
00229       itsFFTSModels[1].resetUpdFac(itsNeighUpdFac);
00230     // higher updfac -> stronger popout
00231     temp = itsFFTSModels[1].surprise(itsFFTSModels[0]);
00232     sfs.push_back(temp);
00233     */
00234     // the total surprise is roughly the pointwise product between
00235     // spatial and temporal surprises, for the current model, with a
00236     // small pedestal of spatial surprise to account for tonic
00237     // responses to static stimuli:
00238 
00239     Image<double> stot(sfs[0].getDims(), ZEROS);
00240     float mi, ma;
00241     Image<float> locstot(sfs[0].getDims(), ZEROS);
00242     float mi1, ma1;
00243     Image<float> lsf(sfs[0].getDims(), ZEROS);
00244     if (itsSFSfac)
00245     {
00246       if (itsSFSfac != 1.0)
00247       {
00248         for(uint j = 0; j < sfs.size() - 2; j++)
00249         {
00250           //LINFO("AA %f %d",itsSFSfac,sfs.size());
00251           stot += (sfs[j] * itsSFSfac)/sfs.size();
00252           locstot = stot;
00253           lsf = sfs[j];
00254           getMinMax(locstot, mi, ma);
00255           getMinMax(lsf, mi1, ma1);
00256           Image<byte> foo = sfs[j];
00257           //Raster::WriteGray(foo,sformat("Sout.%d.%d.pgm",i,j));
00258           //LINFO("FS1 min %f max %f",mi,ma);
00259           //LINFO("FS1  min %f max %f",mi1,ma1);
00260         }
00261       }
00262       else
00263       {
00264         for(uint j = 0; j < sfs.size() - 2; j++)
00265         {
00266           //LINFO("BB %f %d",itsSFSfac,sfs.size());
00267           stot += sfs[j]/sfs.size();
00268           locstot = stot;
00269           lsf = sfs[j];
00270           getMinMax(locstot, mi, ma);
00271           getMinMax(lsf, mi1, ma1);
00272           Image<byte> foo = sfs[j];
00273           //Raster::WriteGray(foo,sformat("Sout.%d.%d.pgm",i,j));
00274           //LINFO("FS2 min %f max %f",mi,ma);
00275           //LINFO("FS2  min %f max %f",mi1,ma1);
00276         }
00277       }
00278     }
00279 
00280     // total surprise combines multiplicatively across models with
00281     // different time scales:
00282     s = stot;
00283     locstot = s;
00284     getMinMax(locstot, mi, ma);
00285     //LINFO("S1 min %f max %f",mi,ma);
00286 
00287 
00288     // the results here should always be positive but sometimes turn
00289     // negative due to rounding errors in the surprise computation.
00290     // Let's clamp just to be sure, otherwise we'll end up with some
00291     // NaNs at later stages:
00292     inplaceRectify(s);
00293 
00294     // calm down total surprise:
00295     //s = toPower(s, 1.0 / (3.0*double(itsFFTSModels.size())));
00296     //s = s*255.0F;
00297     locstot = s;
00298     getMinMax(locstot, mi, ma);
00299     //LINFO("S2 min %f max %f",mi,ma);
00300   }
00301   else
00302   {
00303     s = locstot;
00304   }
00305   itsCounter++;
00306 
00307   //LINFO("S3 min %f max %f",mi,ma);
00308 
00309   // Do we have a full set of frames for fft?
00310   if(fftStackCount < FFT_TIME_SLICE)
00311     fftStackCount++;
00312   else
00313     fftStackReady = true;
00314 
00315 
00316   // return total surprise:
00317   return s;
00318 }
00319 
00320 // ######################################################################
00321 template <class T>
00322 const SurpriseImage<T>& SurpriseMapFFT<T>::getSurpriseImage(const
00323                                                          uint index) const
00324 {
00325   ASSERT(index < itsModels.size());
00326   return itsModels[index];
00327 }
00328 
00329 // ######################################################################
00330 template <class T>
00331 const SurpriseImage<T>& SurpriseMapFFT<T>::getSurpriseImageSFFT(
00332                                         const uint i) const
00333 {
00334   ASSERT(i < itsFFTSModels.size());
00335   return itsFFTSModels[i];
00336 }
00337 
00338 // ######################################################################
00339 template <class T>
00340 const SurpriseImage<T>& SurpriseMapFFT<T>::getSurpriseImagePFFT(
00341                                         const uint i) const
00342 {
00343   ASSERT(i < itsFFTPModels.size());
00344   return itsFFTPModels[i];
00345 }
00346 // ######################################################################
00347 template <class T>
00348 void SurpriseMapFFT<T>::setFFTModels(const SurpriseImage<T>& models,
00349                                      const Image<float>& weights,
00350                                      const float wmin,
00351                                      std::vector<Image<double> >& sfs,
00352                                      std::vector<Image<double> >& sfp)
00353 {
00354 #ifndef HAVE_FFTW3_H
00355   LFATAL("this program requires fftw3, "
00356          "but <fftw3.h> was not found during the configure process");
00357 #else
00358   // initialize FFT things
00359   const int    N               = FFT_TIME_SLICE;
00360   const double veryBigNumber   = pow(10,10);
00361   const double verySmallNumber = 0.0000000000001F;
00362 
00363   //in  = (fftw_complex*)(fftw_malloc(sizeof(fftw_complex) * N));
00364   //out = (fftw_complex*)(fftw_malloc(sizeof(fftw_complex) * N));
00365 
00366   //fftw_print_plan(p);
00367   //std::cerr << "\n";
00368   // initialize holder images to put FFT results into
00369   Image<double> SSpaces,  PSpaces;
00370   SSpaces.resize(itsFFTSModels[0].getWidth(),
00371                  itsFFTSModels[0].getHeight());
00372   PSpaces.resize(itsFFTSModels[0].getWidth(),
00373                  itsFFTSModels[0].getHeight());
00374 
00375   Image<double>::iterator iSSpace = SSpaces.beginw();
00376   Image<double>::iterator iPSpace = PSpaces.beginw();
00377   const unsigned int tpixels = itsFFTSModels[0].getWidth() *
00378                                itsFFTSModels[0].getHeight();
00379   for(unsigned int i = 0; i < tpixels ; i++ , ++iSSpace, ++iPSpace)
00380   {
00381     *iSSpace = 0; *iPSpace = 0;
00382   }
00383 
00384   Image<float> temps;
00385 
00386   /*
00387   float mis, mas;
00388   std::deque<Image<double> >::iterator ifftStack = fftStack.begin;
00389 
00390   for(int k = 0; k < N; k++, ++ifftStack)
00391   {
00392     temps = ifftStack;
00393     getMinMax(temps, mis, mas);
00394     //LINFO("DEQUE %d min %f max %f",k,mis,mas);
00395   }
00396   */
00397   // stack holder images into a vector
00398   std::vector<Image<double> > VSSpaces(itsFFTSModels.size(),SSpaces);
00399   std::vector<Image<double> > VPSpaces(itsFFTSModels.size(),PSpaces);
00400 
00401   for(int i = 0; i < itsFFTSModels[0].getWidth(); i++)
00402   {
00403     for(int j = 0; j < itsFFTSModels[0].getHeight(); j++)
00404     {
00405       for(unsigned int k = 0; k < (unsigned)N; k++)
00406       {
00407         in[k][1] = fftStack[k].getVal(i,j);
00408         in[k][0] = fftStack[k].getVal(i,j);
00409         //std::cerr << "INPUT: " << k << " " << in[k][1] << "\n";
00410       }
00411       //LINFO("DOING PLAN");
00412       fftw_execute(p);
00413       unsigned char binSize    = 1;
00414       unsigned char binCount   = 1;
00415       unsigned char bin        = 0;
00416       float         val        = 0.0F;
00417       int           k          = 0;
00418       //LINFO("Process FFT");
00419       while(bin != (unsigned char)itsFFTSModels.size())
00420       {
00421         // fftw returns a very large number if there is no response on
00422         // some given frequency what so ever. For instance, a constant
00423         // function yields a dirac delta and the rest are all large
00424         // numbers
00425         //LINFO("%f %f",(float)out[k][0],(float)out[k][1]);
00426 
00427         if((fabs(out[k][1]) < veryBigNumber) &&
00428            (fabs(out[k][0]) < veryBigNumber))
00429         {
00430           if(out[k][0] != 0)
00431             val = VPSpaces[bin].getVal(i,j) + fabs(atan(out[k][1]/out[k][0]));
00432           else
00433             val = 0.0F;
00434         }
00435         else
00436         {
00437           // compute phase from FFT
00438           val = verySmallNumber;
00439         }
00440         VPSpaces[bin].setVal(i,j,val);
00441 
00442         if(fabs(out[k][1]) < veryBigNumber)
00443           out[k][1] = out[k][1];
00444         else
00445           out[k][1] = verySmallNumber;
00446 
00447         if(fabs(out[k][0]) < veryBigNumber)
00448           out[k][0] = out[k][0];
00449         else
00450           out[k][0] = verySmallNumber;
00451 
00452         // compute sprectral mag. from FFT
00453         val = VSSpaces[bin].getVal(i,j)
00454           + sqrt(pow(out[k][0],2) + pow(out[k][1],2));
00455         //std::cerr << val << " S " << out[k][0] << " " << out[k][1] << "\n";
00456         VSSpaces[bin].setVal(i,j,val);
00457         // reduce size and noise by bin-ing by octave
00458         if(binCount == binSize)
00459         {
00460           // we normalize specta by 1/(N * sqrt(2)) to give a spectra
00461           // in the same range of values as a normal pixel
00462           val = (VSSpaces[bin].getVal(i,j)/binSize) * 1/(N * sqrt(2));
00463           VSSpaces[bin].setVal(i,j,val);
00464           val = (VPSpaces[bin].getVal(i,j)/binSize) * (255.0F/(3.14159F/2.0F));
00465           VPSpaces[bin].setVal(i,j,val);
00466           binSize  = binSize * 2;
00467           binCount = 1;
00468           bin++;
00469         }
00470         else
00471         {
00472           binCount++;
00473         }
00474         k++;
00475       }
00476     }
00477   }
00478 
00479 
00480   // get our stack of fft images into a start model then
00481   // surprise the current on-going model with it.
00482   Image<double> temp;
00483   Image<float>  holder;
00484   float mi, ma;
00485   for(int bin = 0; bin < (unsigned char)itsFFTSModels.size(); bin++)
00486   {
00487     //LINFO("%d",bin);
00488     Image<double> invar(VSSpaces[bin].getDims(), NO_INIT);
00489     //invar.clear(itsVariance);
00490     //std::cerr << itsUpdatefac << " " << itsVariance << "\n";
00491     holder = VSSpaces[bin];
00492     getMinMax(holder, mi, ma);
00493     //LINFO("BIN S %d min %f max %f",bin,mi,ma);
00494     holder = VPSpaces[bin];
00495     getMinMax(holder, mi, ma);
00496     //LINFO("BIN P %d min %f max %f",bin,mi,ma);
00497 
00498     Image<float> outImageO = VSSpaces[bin];
00499     Image<PixRGB<float> > outImageF;
00500     outImageO = rescale(outImageO,200,(int)round(200.0F*
00501                         ((float)outImageO.getHeight()/
00502                          (float)outImageO.getWidth())));
00503     outImageF = normalizeWithScale(outImageO,0,255.0F,255.0F,1,3);
00504     Image<PixRGB<byte> > outImage = outImageF;
00505     Raster::WriteRGB(outImage,sformat("out.fft.spec.frame%d.%s.%d.%dx%d.png",
00506                                           itsCounter,
00507                                           itsTagName.c_str(),
00508                                           bin,
00509                                           VSSpaces[bin].getWidth(),
00510                                           VSSpaces[bin].getHeight()
00511                                           ));
00512 
00513 
00514     Image<float> outImageO2 = VPSpaces[bin];
00515     Image<PixRGB<float> > outImageF2;
00516     outImageO2 = rescale(outImageO2,200,(int)round(200.0F*
00517                        ((float)outImageO2.getHeight()/
00518                        (float)outImageO2.getWidth())));
00519     outImageF2 = normalizeWithScale(outImageO2,0,255.0F,255.0F,1,3);
00520     outImage  = outImageF2;
00521     Raster::WriteRGB(outImage,sformat("out.fft.phas.frame%d.%s.%d.%dx%d.png",
00522                                           itsCounter,
00523                                           itsTagName.c_str(),
00524                                           bin,
00525                                           VPSpaces[bin].getWidth(),
00526                                           VPSpaces[bin].getHeight()
00527                                           ));
00528 
00529 
00530     SurpriseImage<T> SSSpaces(itsNeighUpdFac,
00531                               VSSpaces[bin],itsVarianceImage);
00532     SurpriseImage<T> SPSpaces(itsNeighUpdFac,
00533                               VPSpaces[bin],itsVarianceImage);
00534     //LINFO("A");
00535     //LINFO("FFT S ****************************** bin %d",bin);
00536     //SSSpaces.neighborhoods(SSSpaces, itsNweights, itsNWmin);
00537     //if (itsNeighUpdFac != 0.0) // use different update fac for neighs?
00538     //  SSSpaces.resetUpdFac(itsNeighUpdFac); // higher updfac -> stronger popout
00539     //Image<double> temp2(SSSpaces);
00540     temp = itsFFTSModels[bin].surprise(SSSpaces);
00541     //SSSpaces.neighborhoods(temp, itsNweights, itsNWmin);
00542     //temp = SSSpaces;
00543     sfs.push_back(temp);
00544     //LINFO("B");
00545     //LINFO("FFT P ****************************** bin %d",bin);
00546     temp = itsFFTPModels[bin].surprise(SPSpaces);
00547     sfp.push_back(temp);
00548   }
00549   //LINFO("DONE");
00550 #endif
00551 }
00552 
00553 
00554 
00555 
00556 
00557 
00558 // ######################################################################
00559 // explicit instantiations:
00560 template class SurpriseMapFFT<SurpriseModelSG>;
00561 template class SurpriseMapFFT<SurpriseModelSP>;
00562 template class SurpriseMapFFT<SurpriseModelOD>;
00563 
00564 #endif // HAVE_FFTW3_H
00565 
00566 // ######################################################################
00567 /* So things look consistent in everyone's emacs... */
00568 /* Local Variables: */
00569 /* indent-tabs-mode: nil */
00570 /* End: */
Generated on Sun May 8 08:06:53 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3