PopulationHeadingMap.C

Go to the documentation of this file.
00001 /*!@file  Robots/Beobot2/Navigation/FOE_Navigation/PopulationHeadingMap.C
00002   Lappe&Rauschecker 1993's Population Heading Map algorithm */
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: Christian Siagian <siagian@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/Beobot2/Navigation/FOE_Navigation/PopulationHeadingMap.C
00035 // $Id: $
00036 //
00037 #ifndef ROBOTS_BEOBOT2_NAVIGATION_FOENAVIGATION_POPULATIONHEADINGMAP_C_DEFINED
00038 #define ROBOTS_BEOBOT2_NAVIGATION_FOENAVIGATION_POPULATIONHEADINGMAP_C_DEFINED
00039 
00040 #define PHM_NUM_DIRECTIONS                  4
00041 #define PHM_FOE_STEP                       16
00042 #define PHM_NUM_MSTD_POPULATION_NEURONS    20
00043 #define PHM_NUM_MSTD_INPUT_NEURONS         30
00044 
00045 #define PHM_MU                             .20F  
00046 
00047 #include "Robots/Beobot2/Navigation/FOE_Navigation/PopulationHeadingMap.H"
00048 
00049 #include "Image/CutPaste.H"
00050 #include "Image/DrawOps.H"
00051 #include "Image/MatrixOps.H"
00052 #include "Image/LinearAlgebra.H"
00053 #include "Image/ShapeOps.H"
00054 
00055 #include "Util/Timer.H"
00056 
00057 #include <stdio.h>
00058 
00059 // ######################################################################
00060 PopulationHeadingMap::PopulationHeadingMap(float focalLength):
00061   itsFocalLength(focalLength)
00062 {
00063 
00064 }
00065 
00066 // ######################################################################
00067 void PopulationHeadingMap::setFocalLength(float focalLength)
00068 {
00069   itsFocalLength = focalLength;
00070 }
00071 
00072 // ######################################################################
00073 PopulationHeadingMap::~PopulationHeadingMap()
00074 { }
00075 
00076 // ######################################################################
00077 // it would be nice if this function runs fast
00078 // so that we can reinitialize 
00079 void PopulationHeadingMap::initialize(Dims dims)
00080 {
00081 
00082   // find the orthogonal complement of C(Tj)
00083   //   find A: bases of C(Tj)
00084   //   find the nullspace of A: this is the orthogonal complement
00085   
00086   
00087 
00088   
00089   // also the matched pair neuron
00090   // J_(i,j,k,l)' = - J_(i,j,k,l)
00091 
00092 }
00093 
00094 // ######################################################################
00095 //! return FOE from image of movement between the two input images
00096 void PopulationHeadingMap::getFOE(Image<byte> stim1, Image<byte> stim2)
00097 {
00098   itsCurrentImage = stim1;
00099   getFOE(stim2);
00100 }
00101 
00102 // ######################################################################
00103 //! return  FOE from image of movement 
00104 //! between this image and the previous one
00105 void PopulationHeadingMap::getFOE(Image<byte> stim)
00106 {
00107   // NOTE: Particle filtering to run multiple hypotheses
00108 
00109   // don't do anything if this is the first frame
00110   if(!itsCurrentImage.initialized())
00111     {
00112       itsCurrentImage  = stim;
00113       itsPreviousImage = stim;
00114       LINFO("NOT ENOUGH INPUT YET");
00115       return;
00116     }
00117 
00118   LINFO("Focal Length: %f", itsFocalLength);
00119 
00120   itsPreviousImage = itsCurrentImage;
00121   itsCurrentImage  = stim;
00122 
00123   // compute the optic flow for the input MT neurons
00124   // : spatiotemporal, Lucas&Kanade, etc.
00125   itsOpticalFlow =
00126     getCleanOpticFlow(Image<byte>(itsPreviousImage.getDims(),ZEROS));
00127   //getLucasKanadeOpticFlow(itsPreviousImage, itsCurrentImage);  
00128   itsOpticalFlowImage = 
00129     drawOpticFlow(itsPreviousImage, itsOpticalFlow);
00130 
00131   //getCleanOpticFlow3(Image<byte>(itsPreviousImage.getDims(),ZEROS));
00132 
00133   if(itsWin.is_invalid())
00134     itsWin.reset(new XWinManaged(itsCurrentImage.getDims(), 
00135                                  0, 0, "Pop Heading Map"));
00136   itsWin->setDims(itsCurrentImage.getDims());
00137   itsWin->drawImage(itsOpticalFlowImage,0,0);
00138   
00139   LINFO("got the optic flow");
00140   Raster::waitForKey();
00141 
00142 
00143   //itsMTfeatures = itsOpticalFlow->getMTfeatures();
00144 
00145   // compute output for each MSTd neuron
00146   computePopulationHeading(); 
00147 
00148   // find the most likely heading
00149 
00150 }
00151 // ######################################################################
00152 void PopulationHeadingMap::computePopulationHeading()
00153 {
00154   itsHeadingDirectionMap = 
00155     Image<float>(itsCurrentImage.getWidth() /PHM_FOE_STEP, 
00156                  itsCurrentImage.getHeight()/PHM_FOE_STEP, ZEROS);
00157 
00158   uint border = 2;
00159   uint hdw = itsHeadingDirectionMap.getWidth();
00160   uint hdh = itsHeadingDirectionMap.getHeight();
00161 
00162   // the number of inputs that each MSTd cells received
00163   uint m = PHM_NUM_MSTD_INPUT_NEURONS; // can change it to 20 from 30
00164 
00165   // the number of neurons that each direction draw from
00166   uint n = PHM_NUM_MSTD_POPULATION_NEURONS;
00167 
00168   // compute likelihood for each direction Tj
00169   for(uint jx = border; jx < hdw - border; jx++)
00170     {
00171       for(uint jy = border; jy < hdh - border; jy++)
00172         {
00173           float U = 0.0;
00174 
00175           //Timer tim(1000000); tim.reset();
00176 
00177           // pick m random flows
00178           std::vector<uint> lind = pickRandomLocations(m);
00179           std::vector<Point2D<float> > points = getLocations(lind);
00180           std::vector<Point2D<float> > flows  = getFlowVectors(lind); 
00181 
00182           //uint64 t1 = tim.get();
00183 
00184           // compute C(T)
00185           Image<float> C = computeC(points, jx, jy);
00186 
00187           //uint64 t2 = tim.get();
00188 
00189           // compute orthogonal complement: c_perp 
00190           // using the above random points 
00191           Image<float> c_perp = computeOrthogonalComplement(C);
00192           
00193           //LINFO("time: %f", t1/1000.0);
00194           //LINFO("time: %f", (t2 -t1)/1000.0);
00195           //LINFO("time: %f", tim.get()/1000.0);
00196           //Raster::waitForKey();
00197           // for each MT node in the Tj direction population
00198           for(uint l = 0; l < n; l++)
00199             {
00200               // number of null space dimension
00201               uint nndims = c_perp.getWidth();
00202 
00203               // pick a random vector c_perp_l from c_perp
00204               uint rvindex = uint(nndims * float(rand())/(RAND_MAX + 1.0F));
00205               Image<double> c_perp_l = 
00206                 crop(c_perp, Point2D<int>(rvindex, 0), Dims(1,2*m));
00207 
00208               Image<double>::iterator cpli = c_perp_l.beginw();
00209 
00210               // for each input MT neuron to the node
00211               double total = 0.0;
00212               for(uint i = 0; i < m; i++)
00213                 {
00214                   // calculate the neuron i firing rate
00215                   double dx = flows[i].i;
00216                   double dy = flows[i].j;                  
00217 
00218                   total += dx*(*cpli++); //c_perp_l.getVal(0, i*2); //(*cpli++); 
00219                   total += dy*(*cpli++); //c_perp_l.getVal(0, i*2+1); //(*cpli++); 
00220                   
00221                   // for each direction in the location
00222                   //for(uint k = 0; k < PHM_NUM_DIRECTIONS; k++)
00223                   //  {
00224                       //float J_ijkl =  itsWeights[jx][jy][k].getVal(pt);
00225                       //float s_ik   = itsMTfeatures[k].getVal(pt);
00226 
00227                       //total +=  * s_ik;
00228                   //  }                  
00229                 } 
00230 
00231               // firing rate using sigmoid function
00232               // do the opposite as well to get an optimal result 
00233               // near zero
00234               double ul = sigmoid(PHM_MU - total) + sigmoid(PHM_MU + total) -1.0;
00235               //double ul = -fabs(total);
00236 
00237               //LINFO("U[%d] Total: %f -> %f", l, total, ul);
00238               U += ul;//-pow(ul,2.0);
00239             }
00240           LINFO("j[%3d %3d]: U: %f",jx,jy, U/n);
00241           
00242           //if(jx != 2 & jy != ) U = 0.0;
00243 
00244           itsHeadingDirectionMap.setVal(jx,jy, U/n);
00245         }
00246     }
00247 
00248   if(itsWin.is_invalid())
00249     itsWin.reset(new XWinManaged(itsCurrentImage.getDims(), 0, 0, "Pop Heading Map"));
00250   itsWin->setDims(itsCurrentImage.getDims());
00251   itsWin->drawImage(zoomXY(itsHeadingDirectionMap, PHM_FOE_STEP),0,0);
00252   LINFO("map");
00253   Raster::waitForKey();
00254 
00255 }
00256 
00257 // ######################################################################
00258 double PopulationHeadingMap::sigmoid(double x) 
00259 {
00260   return 1.0F/(1.0F + pow(M_E,-x));
00261 } 
00262 
00263 // ######################################################################
00264 std::vector<uint> PopulationHeadingMap::pickRandomLocations(uint m)
00265 {  
00266   std::vector<uint> locIndexes(m);
00267 
00268   std::vector<Point2D<float> > flowLocations = 
00269     itsOpticalFlow->getFlowLocations();
00270   uint numFlows = flowLocations.size();
00271 
00272   // make sure there is no duplicate locations
00273   std::vector<bool> picked(numFlows);
00274   for(uint i = 0; i < numFlows; i++) picked[i] = false;
00275 
00276   // get n random locations
00277   for(uint i = 0; i < m; i++)
00278     {      
00279       uint rindex = 
00280         uint(numFlows * float(rand())/(RAND_MAX + 1.0F));
00281 
00282       while(picked[rindex])
00283           rindex = uint(numFlows * float(rand())/(RAND_MAX + 1.0F));
00284 
00285       locIndexes[i] = rindex;
00286       picked[rindex] = true;
00287     }
00288 
00289   return locIndexes;
00290 }
00291 
00292 // ######################################################################
00293 std::vector<Point2D<float> > 
00294 PopulationHeadingMap::getLocations(std::vector<uint> lind)
00295 {  
00296   uint m = lind.size();
00297   std::vector<Point2D<float> > locs(m);
00298 
00299   std::vector<Point2D<float> > flowLocations = 
00300     itsOpticalFlow->getFlowLocations();
00301 
00302   //Image<PixRGB<byte> > img = itsOpticalFlowImage;
00303 
00304   // get n random locations
00305   for(uint i = 0; i < m; i++)
00306     {      
00307       locs[i] = flowLocations[lind[i]];
00308 
00309       //drawDisk(img, Point2D<int>(locs[i].i, locs[i].j), 2, PixRGB<byte>(255,255,0));
00310     }
00311 
00312   // if(itsWin.is_invalid())
00313   //   itsWin.reset(new XWinManaged(img.getDims(), 0, 0, "Pop Heading Map"));
00314   // itsWin->setDims(img.getDims());
00315   // itsWin->drawImage(img,0,0);
00316   // LINFO("random points");
00317   // Raster::waitForKey();
00318 
00319 
00320   return locs;
00321 }
00322 
00323 // ######################################################################
00324 std::vector<Point2D<float> > 
00325 PopulationHeadingMap::getFlowVectors(std::vector<uint> lind)
00326 {  
00327   uint m = lind.size();
00328   std::vector<Point2D<float> > flows(m);
00329 
00330   std::vector<rutz::shared_ptr<FlowVector> > fv = 
00331     itsOpticalFlow->getFlowVectors();
00332 
00333   // get n random locations
00334   for(uint i = 0; i < m; i++)
00335     {      
00336       flows[i] = 
00337         Point2D<float>
00338         (fv[lind[i]]->p2.i -  fv[lind[i]]->p1.i,
00339          fv[lind[i]]->p2.j -  fv[lind[i]]->p1.j);
00340     }
00341 
00342   return flows;
00343 }
00344 
00345 // ######################################################################
00346 Image<double> 
00347 PopulationHeadingMap::computeC
00348 (std::vector<Point2D<float> > points, uint jx, uint jy)
00349 {
00350   // NOTE_FIXXX: compute the focal length from the two initial images
00351   float f = itsFocalLength;
00352   //LINFO("Focal Length: %f", f);
00353 
00354   int w = itsCurrentImage.getWidth();
00355   int h = itsCurrentImage.getHeight();
00356 
00357   // create C(T)
00358   uint m = points.size();
00359   Image<double> C(m+3, 2*m, ZEROS);
00360 
00361   double Tx = double(jx)*PHM_FOE_STEP - double(w/2);
00362   double Ty = double(jy)*PHM_FOE_STEP - double(h/2);
00363   double Tz = f;
00364 
00365   double wh = w/2;
00366   double hh = h/2;
00367 
00368   // fill matrix for every point 
00369   for(uint i = 0; i < m; i++)
00370     {
00371       // make the center 
00372       double x =  points[i].i - wh;
00373       double y =  points[i].j - hh; 
00374 
00375       //LINFO("[%f %f]:{%f, %f, %f}", x,y, Tx,Ty,Tz);
00376 
00377       // compute A(x_i,y_i)T
00378       C.setVal(i, i*2,   -f*Tx + x*Tz);
00379       C.setVal(i, i*2+1, -f*Ty + y*Tz);
00380 
00381       // compute B(x_i,y_i)
00382       C.setVal(m,   i*2,   x*y/f      );
00383       C.setVal(m+1, i*2,   -f-(x*x/f) );
00384       C.setVal(m+2, i*2,   y          );
00385       C.setVal(m,   i*2+1, f + (y*y/f));
00386       C.setVal(m+1, i*2+1, -x*y/f     );
00387       C.setVal(m+2, i*2+1, -x         );
00388     }
00389   
00390   // for(int j = 0; j < C.getHeight(); j++)
00391   //   {
00392   //     for(int i = 0; i < C.getWidth(); i++)
00393   //       {
00394   //         printf("%9.3f ", C.getVal(i,j));
00395   //       }
00396   //     printf("\n");
00397   //   }
00398   // Raster::waitForKey();
00399 
00400   return C;
00401 }
00402 
00403 // ######################################################################
00404 Image<double> 
00405 PopulationHeadingMap::computeOrthogonalComplement(Image<double> C)
00406 {
00407   // perform SVD on C; C = [U][S]([V]T)
00408   Image<double> U;
00409   Image<double> S;
00410   Image<double> V;
00411   svd(C, U, S, V, SVD_LAPACK, SVD_FULL);
00412   
00413   // LINFO("C[%3d %3d] =  U[%3d %3d] S[%3d %3d] V[%3d %3d]",
00414   //       C.getHeight(), C.getWidth(),
00415   //       U.getHeight(), U.getWidth(),
00416   //       S.getHeight(), S.getWidth(),
00417   //       V.getHeight(), V.getWidth() );
00418   
00419   uint m = C.getHeight();
00420   uint n = C.getWidth();
00421   uint nindex = n;
00422   for(uint i = 0; i < n; i++) 
00423     {
00424       double val = S.getVal(i,i);
00425       //LINFO("[%3d]: %f", i, val);
00426 
00427       // figure out how many dimension the nullspace is
00428       if(val < 0.00000001) nindex = i;
00429     }
00430 
00431   uint nspacedims = m - nindex;
00432 
00433   //LINFO("nindex: %d nspacedims: %d", nindex, nspacedims);
00434 
00435   Image<double> Cperp = 
00436     crop(U, Point2D<int>(nindex,0),Dims(nspacedims,m));
00437 
00438   
00439   //Image<double> res = matrixMult(transpose(C),Cperp);  
00440   //print(res,std::string("res"));
00441   //Raster::waitForKey();
00442 
00443 
00444   return Cperp;
00445 }
00446 
00447 // ######################################################################
00448 void PopulationHeadingMap::print(Image<double> img, const std::string& name)
00449 {
00450   LINFO("%s:  %d by %d", name.c_str(), img.getWidth(),  img.getHeight());
00451   for(int j = 0; j < img.getHeight(); j++)
00452     {
00453       for(int i = 0; i < img.getWidth(); i++)
00454         {
00455           printf("%13.5f ", img.getVal(i,j));
00456         }
00457       printf("\n");
00458     }
00459 }
00460 // ######################################################################
00461 /* So things look consistent in everyone's emacs... */
00462 /* Local Variables: */
00463 /* indent-tabs-mode: nil */
00464 /* End: */
00465 
00466 #endif // ROBOTS_BEOBOT2_NAVIGATION_FOENAVIGATION_POPULATIONHEADINGMAP_C_DEFINED
Generated on Sun May 8 08:05:36 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3