MiddleTemporal.C

00001 /*!@file Robots2/Beobot2/Navigation/FOE_Navigation/MiddleTemporal.C */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu>
00033 // $HeadURL: svn://ilab.usc.edu/trunk/saliency/src/Robots/Beobot2/Navigation/FOE_Navigation/MiddleTemporal.C
00034 // $ $Id: $
00035 //
00036 //////////////////////////////////////////////////////////////////////////
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 
00041 #include "Robots/Beobot2/Navigation/FOE_Navigation/MiddleTemporal.H"
00042 
00043 #include  <cstdio>
00044 #include "Image/ColorOps.H"
00045 #include "Image/CutPaste.H"
00046 #include "Image/DrawOps.H"
00047 #include "Image/FilterOps.H"
00048 #include "Image/MathOps.H"
00049 #include "Image/Pixels.H"
00050 #include "Image/ShapeOps.H"
00051 #include "Image/SimpleFont.H"
00052 
00053 #include "Util/Timer.H"
00054 
00055 // ######################################################################
00056 // ######################################################################
00057 
00058 // ######################################################################
00059 MiddleTemporal::MiddleTemporal()
00060 {
00061   itsWin.reset();
00062 }
00063 
00064 // ######################################################################
00065 MiddleTemporal::~MiddleTemporal()
00066 { }
00067 
00068 // ######################################################################
00069 std::vector<Image<float> > MiddleTemporal::getMTfeatures()
00070 {
00071   return itsMTfeatures;
00072 }
00073 
00074 // ######################################################################
00075 std::vector<Image<float> > MiddleTemporal::getMToptimalShift()
00076 {
00077   return itsMToptimalShift;
00078 }
00079 
00080 // ######################################################################
00081 void MiddleTemporal::computeMTfeatures
00082 (std::vector<std::vector<ImageSet<float> > > rawSpatioTemporalEnergy)
00083 {
00084   if(rawSpatioTemporalEnergy[0][0].size() == 0) return;
00085   itsRawSpatioTemporalEnergy = rawSpatioTemporalEnergy;
00086   reset();
00087 
00088  // find optimal speed for each direction
00089   //Timer tim(1000000);
00090   for (uint i = 0; i < itsNumDirs; i++)
00091     {
00092       //tim.reset();
00093       computeMaxSpeed(i);
00094       //uint64 t1 = tim.get();
00095       //LINFO("[%3d] max speed: %f", i, t1/1000.0);
00096     }
00097 
00098   //displayItsSpatioTemporalEnergy();
00099   //printItsSpatioTemporalEnergy(140, 158, 45, 85, true, 100.0);
00100 
00101   // compute max in 4x4 top level regions
00102   computeSteMaxVals();
00103 
00104   // DEBUG
00105 //   LINFO("Max Vals 0");
00106 //   print(itsSteMaxVals[0], 170/4, 188/4, 45/4, 75/4, true);
00107 //   LINFO("MaxVals 1");
00108 //   print(itsSteMaxVals[1], 170/4, 188/4, 45/4, 75/4, true);
00109   
00110   // normalize with the max values regardless of direction
00111   normalizeOnMaxVal();
00112 
00113   // DEBUG
00114 //   LINFO("After Normalize on Max");
00115 //   printItsSpatioTemporalEnergy(170, 188, 45, 75, true);  
00116  
00117   // opponencies: NOTE: from opposite direction of motion
00118   // this will subdue locations that do not have maximum values
00119   computeDirSteMaxVals();
00120 
00121   // DEBUG
00122 //   LINFO("0 Max Vals 0");
00123 //   print(itsDirSteMaxVals[0][0], 170/4, 188/4, 45/4, 75/4, true);
00124 //   LINFO("0 MaxVals 1");
00125 //   print(itsDirSteMaxVals[0][1], 170/4, 188/4, 45/4, 75/4, true);
00126   
00127 //   LINFO("4 Max Vals 0");
00128 //   print(itsDirSteMaxVals[4][0], 170/4, 188/4, 45/4, 75/4, true);
00129 //   LINFO("4 MaxVals 1");
00130 //    print(itsDirSteMaxVals[4][1], 170/4, 188/4, 45/4, 75/4, true);
00131 
00132   computeOpponencies();
00133 
00134   // DEBUG
00135 //   LINFO("after opponencies");
00136 //   printItsSpatioTemporalEnergy(170, 188, 45, 75, true);
00137 //   //print(motion, 165/div, 175/div, 45/div, 75/div, true);
00138 //   //print(motion, 175/div, 185/div, 45/div, 75/div, true);
00139 //   //print(motion, 185/div, 195/div, 45/div, 75/div, true);
00140 
00141 
00142   // normalize the MT features with the percentage of dominance
00143   weighMTfeaturesForDominance();
00144 
00145   // find max values for each direction among all the scales
00146   findMaxMotionVals();
00147 
00148   // DEBUG
00149   //printItsSpatioTemporalEnergy(170, 188, 45, 75, true, 100.0);
00150 
00151   // DEBUG
00152   // for ACB: 5,15,30,50
00153   //printItsMTfeatures(35, 50, 5, 25, true);
00154   //printItsMToptimalShift(35, 50, 5, 25, true);
00155   //displayItsMTfeatures();
00156   //displayItsMToptimalShift();
00157 }
00158 
00159 // ######################################################################
00160 void MiddleTemporal::reset()
00161 {
00162   itsNumDirs       = itsRawSpatioTemporalEnergy.size();
00163   itsNumSpeeds     = itsRawSpatioTemporalEnergy[0].size();
00164   itsNumPyrLevels  = itsRawSpatioTemporalEnergy[0][0].size();
00165 
00166   //itsSpatioTemporalPyrs.clear();
00167   //itsSpatioTemporalPyrs.resize(itsNumDirs);
00168   //for(uint i = 0; i < itsNumDirs; i++)
00169   //  itsSpatioTemporalPyrs[i].resize(itsNumSpeeds);
00170 
00171   //itsRawSpatioTemporalEnergy.clear();
00172   //itsRawSpatioTemporalEnergy.resize(itsNumDirs);
00173   //for(uint i = 0; i < itsNumDirs; i++)
00174   //  itsRawSpatioTemporalEnergy[i].resize(itsNumSpeeds);
00175 
00176   itsSpatioTemporalEnergy.resize(itsNumDirs);
00177   itsSpatioTemporalEnergyOptimalShift.resize(itsNumDirs);
00178   for(uint i = 0; i < itsNumDirs; i++)
00179     itsSpatioTemporalEnergyOptimalShift[i].reset(itsNumPyrLevels);
00180 
00181   itsMTfeatures.resize(itsNumDirs);
00182   itsMToptimalShift.resize(itsNumDirs);
00183 }
00184 
00185 
00186 // ######################################################################
00187 void MiddleTemporal::computeMaxSpeed(uint index)
00188 {
00189   int depth = itsRawSpatioTemporalEnergy[index][0].size();
00190   if(depth == 0) return;
00191   ImageSet<float> result(depth);
00192 
00193   // compute the motion detection at each location
00194   for (int scale = 0; scale < depth; scale++)
00195     result[scale] = computeMaxSpeed(index, scale);
00196 
00197   itsSpatioTemporalEnergy[index] = result;
00198 }
00199 
00200 // ######################################################################
00201 Image<float> MiddleTemporal::computeMaxSpeed(uint index, int scale)
00202 {
00203   // find max among all the spatial and temporal shifts
00204   // --> basically max among all the shifting values
00205 
00206   uint width  = itsRawSpatioTemporalEnergy[index][0][scale].getWidth();
00207   uint height = itsRawSpatioTemporalEnergy[index][0][scale].getHeight();
00208   Image<float> result(width, height, ZEROS);
00209 
00210   itsSpatioTemporalEnergyOptimalShift[index][scale] = 
00211     Image<float>(width, height, ZEROS);
00212 
00213   Image<float>::iterator resultT = result.beginw();
00214 
00215   Image<float>::iterator 
00216     shiftT = itsSpatioTemporalEnergyOptimalShift[index][scale].beginw(); 
00217 
00218   Image<float>::iterator resT[itsNumSpeeds];
00219   for (unsigned int i = 0; i < itsNumSpeeds; i++)
00220     resT[i] = itsRawSpatioTemporalEnergy[index][i][scale].beginw();
00221   
00222   for(uint i = 0; i < width; i++)
00223     {
00224       for(uint j = 0; j < height; j++)
00225         {
00226           float max = 0.0; float optShift = 0.0;          
00227           for(uint r = 0; r < itsNumSpeeds; r++)
00228             {
00229               float val = *resT[r]++; 
00230               if(max < val) 
00231                 {
00232                   max = val;
00233                   optShift = pow(2.0,r); //FIXXX add case for 1/2, 1/3, 1/4
00234                 }
00235             }
00236           *resultT++ = max;
00237           *shiftT++  = optShift;
00238         }
00239     }
00240 
00241   return result;
00242 }
00243 
00244 // ######################################################################
00245 void MiddleTemporal::computeSteMaxVals()
00246 {
00247   itsSteMaxVals.reset(itsNumPyrLevels);
00248   //itsDirSteMaxVals.resize(itsNumDirs);
00249   //for(uint i = 0; i < itsNumDirs; i++)
00250   //  itsDirSteMaxVals[i].reset(itsNumPyrLevels);
00251 
00252   uint width  = itsSpatioTemporalEnergy[0][0].getWidth();
00253   uint height = itsSpatioTemporalEnergy[0][0].getHeight();  
00254 
00255   // got through each level
00256   for(uint l = 0; l < itsNumPyrLevels; l++)
00257     {
00258       uint pxSize  = uint(pow(2.0, l));
00259       uint lwidth  = width/pxSize;
00260       uint lheight = height/pxSize;
00261 
00262       // create a local max map
00263       // NOTE: is global max biologically plausible?
00264       uint steps = 1; 
00265       if(pxSize < MAX_NEIGHBORHOOD) 
00266         steps = MAX_NEIGHBORHOOD/pxSize;
00267 
00268       // fill in max values for each level
00269       itsSteMaxVals[l] = Image<float>(lwidth/steps, lheight/steps, NO_INIT);
00270       //for(uint dir = 0; dir < itsNumDirs; dir++)
00271       //  itsDirSteMaxVals[dir][l] = 
00272       //    Image<float>(lwidth/steps, lheight/steps, NO_INIT);
00273 
00274       //LINFO("[%3d] lw/h: %d %d -> %d step: %d", 
00275       //      l, lwidth, lheight, pxSize, steps);
00276       
00277       for(uint i = 0; i < lwidth; i+= steps)
00278         {
00279           for(uint j = 0; j < lheight; j+= steps)
00280             {
00281               // we find max for all directions
00282               float max = 0.0;
00283               for(uint d = 0; d < itsNumDirs; d++)
00284                 {
00285                   //float dirMax = 0.0;
00286                   for(uint di = 0; di < steps; di++)
00287                     {
00288                       for(uint dj = 0; dj < steps; dj++)
00289                         {
00290                           float val = 
00291                             itsSpatioTemporalEnergy[d][l].getVal(i+di,j+dj);
00292                           if(val > max) max = val;
00293                           //if(val > dirMax) dirMax = val;
00294 
00295 
00296 //                       // DEBUG:
00297 //                       if(i >= 148 && i <= 151 &&
00298 //                          j >=  60 && j <=  63   ) 
00299 //                         {
00300 //                           LINFO("[%d](%3d %3d) d(%3d %3d) -> %3d %3d: %f %f",
00301 //                                 d,i,j, di,dj, i+di,j+dj, val, max); 
00302 //                         }
00303 
00304 
00305 
00306 
00307                         }
00308                     }
00309                   //itsDirSteMaxVals[d][l].setVal(i/steps, j/steps, dirMax);
00310                 }
00311               itsSteMaxVals[l].setVal(i/steps, j/steps, max);
00312             }
00313         }      
00314     }
00315 }
00316 
00317 // ######################################################################
00318 void MiddleTemporal::computeDirSteMaxVals()
00319 {
00320   //itsSteMaxVals.reset(itsNumPyrLevels);
00321   itsDirSteMaxVals.resize(itsNumDirs);
00322   for(uint i = 0; i < itsNumDirs; i++)
00323     itsDirSteMaxVals[i].reset(itsNumPyrLevels);
00324 
00325   uint width  = itsSpatioTemporalEnergy[0][0].getWidth();
00326   uint height = itsSpatioTemporalEnergy[0][0].getHeight();  
00327 
00328   // got through each level
00329   for(uint l = 0; l < itsNumPyrLevels; l++)
00330     {
00331       uint pxSize  = uint(pow(2.0, l));
00332       uint lwidth  = width/pxSize;
00333       uint lheight = height/pxSize;
00334 
00335       // create a local max map
00336       // NOTE: is global max biologically plausible?
00337       uint steps = 1; 
00338       if(pxSize < MAX_NEIGHBORHOOD) 
00339         steps = MAX_NEIGHBORHOOD/pxSize;
00340 
00341       // fill in max values for each level
00342       //itsSteMaxVals[l] = Image<float>(lwidth/steps, lheight/steps, NO_INIT);
00343       for(uint dir = 0; dir < itsNumDirs; dir++)
00344         itsDirSteMaxVals[dir][l] = 
00345           Image<float>(lwidth/steps, lheight/steps, NO_INIT);
00346 
00347       //LINFO("[%3d] lw/h: %d %d -> %d step: %d", 
00348       //      l, lwidth, lheight, pxSize, steps);
00349       
00350       for(uint i = 0; i < lwidth; i+= steps)
00351         {
00352           for(uint j = 0; j < lheight; j+= steps)
00353             {
00354               // we find max for all directions
00355               //float max = 0.0;
00356               for(uint d = 0; d < itsNumDirs; d++)
00357                 {
00358                   float dirMax = 0.0;
00359                   for(uint di = 0; di < steps; di++)
00360                     {
00361                       for(uint dj = 0; dj < steps; dj++)
00362                         {
00363                           float val = 
00364                             itsSpatioTemporalEnergy[d][l].getVal(i+di,j+dj);
00365                           //if(val > max) max = val;
00366                           if(val > dirMax) dirMax = val;
00367 
00368 
00369 //                       // DEBUG:
00370 //                       if(i >= 148 && i <= 151 &&
00371 //                          j >=  60 && j <=  63   ) 
00372 //                         {
00373 //                           LINFO("[%d](%3d %3d) d(%3d %3d) -> %3d %3d: %f %f",
00374 //                                 d,i,j, di,dj, i+di,j+dj, val, max); 
00375 //                         }
00376 
00377 
00378 
00379 
00380                         }
00381                     }
00382                   itsDirSteMaxVals[d][l].setVal(i/steps, j/steps, dirMax);
00383                 }
00384               //itsSteMaxVals[l].setVal(i/steps, j/steps, max);
00385             }
00386         }      
00387     }
00388 }
00389 
00390 // ######################################################################
00391 // normalize on the max value regardless of direction
00392 void MiddleTemporal::normalizeOnMaxVal()
00393 {
00394   uint width  = itsSpatioTemporalEnergy[0][0].getWidth();
00395   uint height = itsSpatioTemporalEnergy[0][0].getHeight();  
00396 
00397   // got through each level
00398   for(uint l = 0; l < itsNumPyrLevels; l++)
00399     {
00400       uint pxSize  = uint(pow(2.0, l));
00401       uint lwidth  = width/pxSize;
00402       uint lheight = height/pxSize;
00403 
00404       uint steps = 1; 
00405       if(pxSize < MAX_NEIGHBORHOOD) steps = MAX_NEIGHBORHOOD/pxSize;
00406       for(uint i = 0; i < lwidth; i+= steps)
00407         {
00408           for(uint j = 0; j < lheight; j+= steps)
00409             {
00410               uint mi = i/steps;
00411               uint mj = j/steps;
00412               
00413               uint lm =  0;              if(mi > 2)              lm = mi - 3; 
00414               uint rm = lwidth/steps-1;  if(mi < lwidth/steps-4) rm = mi + 3;
00415               uint tm =  0;              if(mj > 2)              tm = mj - 3; 
00416               uint bm = lheight/steps-1; if(mj < lheight/steps-4)bm = mj + 3;
00417 
00418               // FIXXX: need to interpolate for levels 3 and higher
00419 
00420 //               // DEBUG:
00421 //               if(i >=  148 && i <= 151 &&
00422 //                  j >=  60 && j <=  63   ) 
00423 //                 {
00424 //                   LINFO("(%3d %3d %3d %3d) -> %3d %3d",
00425 //                         lm,rm,tm,bm, mi,mj); 
00426 //                 }
00427 
00428 
00429               // get max vals among a neighborhood
00430               float max = 0.0;
00431               for(uint bi = lm; bi <= rm; bi++)
00432                 {
00433                   for(uint bj = tm; bj <= bm; bj++)
00434                     {
00435                       float val = itsSteMaxVals[l].getVal(bi, bj);
00436                       if(max < val) max = val;
00437 
00438 
00439 //                       // DEBUG:
00440 //                       if(i >= 148 && i <= 151 &&
00441 //                          j >=  60 && j <=  63   ) 
00442 //                         {
00443 //                           LINFO("(%3d %3d) val %10.3f -> max %10.3f",
00444 //                                 bi, bj, val, max); 
00445 //                         }
00446 
00447 
00448 
00449 
00450                     }
00451                 }
00452 
00453               // normalize each point
00454               for(uint d = 0; d < itsNumDirs; d++)
00455                 {
00456                   for(uint di = 0; di < steps; di++)
00457                     {
00458                       for(uint dj = 0; dj < steps; dj++)
00459                         {
00460                           float val = itsSpatioTemporalEnergy[d][l].getVal(i+di,j+dj);
00461 
00462                           if(max == 0.0) 
00463                             itsSpatioTemporalEnergy[d][l].setVal(i+di,j+dj, 0.0);
00464                           else
00465                             itsSpatioTemporalEnergy[d][l].setVal(i+di,j+dj, val/max);
00466 
00467 
00468 
00469 //                           if(val > 30000.0)
00470 //                                LINFO("[%d](%3d %3d) d(%3d %3d) -> %3d %3d: %f/%f = %f",
00471 //                                      d,i,j, di,dj, i+di,j+dj, val, max, val/max); 
00472                           
00473 //                           // DEBUG:
00474 //                           if(i+di >= 148 && i+di <= 151 &&
00475 //                              j+dj >=  60 && j+dj <=  63   ) 
00476 //                             {
00477 //                               LINFO("[%d](%3d %3d) d(%3d %3d) -> %3d %3d: %f/%f = %f",
00478 //                                     d,i,j, di,dj, i+di,j+dj, val, max, val/max); 
00479 //                             }
00480 
00481 
00482 
00483 
00484                         }
00485                     }
00486                 }
00487             }
00488         }
00489     }
00490 }
00491 
00492 // ######################################################################
00493 void MiddleTemporal::computeOpponencies()
00494 {
00495   // get lateral inhibition values on each location
00496   std::vector <ImageSet<float> > osInhibitMap(itsNumDirs);
00497   std::vector <ImageSet<float> >  nInhibitMap(itsNumDirs);
00498   for (uint i = 0; i < itsNumDirs; i++)
00499     {
00500       osInhibitMap[i].reset(itsSpatioTemporalEnergy[i].size());
00501       //nInhibitMap[i].reset(itsSpatioTemporalEnergy[i].size());
00502       for(uint j = 0; j < itsSpatioTemporalEnergy[i].size(); j++)
00503         {
00504           osInhibitMap[i][j] = getOnSpotInhibitSpatioTemporalEnergy(i,j);   
00505           //nInhibitMap[i][j]  = getNeighborInhibitSpatioTemporalEnergy(i,j);
00506         }
00507     }
00508 
00509   // perform lateral inhibition on each location
00510   for (uint i = 0; i < itsNumDirs; i++)
00511     {
00512       for(uint j = 0; j < itsSpatioTemporalEnergy[i].size(); j++)
00513         {         
00514           itsSpatioTemporalEnergy[i][j] -= osInhibitMap[i][j]; 
00515 
00516 //           for (uint k = 0; k < itsNumDirs; k++)
00517 //             {
00518 //               // NOTE FIX maybe add weights 
00519 //               //          according to how disagreeing the direction is
00520 //               if(k != i)
00521 //                 itsSpatioTemporalEnergy[i][j] -= nInhibitMap[i][j]; 
00522 //             }
00523 
00524           // we are going to clamp the result to 0.0;
00525           float mn,mx; getMinMax(itsSpatioTemporalEnergy[i][j],mn,mx);
00526           inplaceClamp(itsSpatioTemporalEnergy[i][j], 0.0f, mx);
00527         }
00528     }
00529 
00530   // NOTE: ---> how about end-stop neurons for end of bars
00531 
00532   // at this point everything should have been normalized to 0 to 1.0 max
00533 }
00534 
00535 // ######################################################################
00536 void MiddleTemporal::weighMTfeaturesForDominance()
00537 {
00538 
00539 }
00540 
00541 // ######################################################################
00542 Image<float> MiddleTemporal::getOnSpotInhibitSpatioTemporalEnergy
00543 (uint dir, uint scale)
00544 {
00545   uint oppDir = (dir + itsNumDirs/2)%itsNumDirs;
00546 
00547   uint width  = itsSpatioTemporalEnergy[dir][scale].getWidth();
00548   uint height = itsSpatioTemporalEnergy[dir][scale].getHeight();  
00549   uint pxSize = uint(pow(2.0, scale));
00550   uint steps   = 1; 
00551   if(pxSize < MAX_NEIGHBORHOOD) steps = MAX_NEIGHBORHOOD/pxSize;
00552   uint nwidth  = width/steps;
00553   uint nheight = height/steps;
00554 
00555 
00556   Image<float> result(width,height,NO_INIT); 
00557   Image<float>::iterator resultT = result.beginw();
00558   
00559   /*Image<float>::iterator stT[itsNumDirs];
00560   for (unsigned int i=0; i < itsNumDirs; i++)
00561     stT[i] = itsSpatioTemporalEnergy[i][scale].beginw();*/
00562 
00563   // NOTE: (other dir average then subtract) have more artifacts
00564   //       but keep all other possible evidences 
00565   //       may help in aperture problem 
00566   //       DO NOT just get the max (although it is cleaner)
00567   for(uint j = 0; j < height; j++)
00568     {
00569       for(uint i = 0; i < width; i++)
00570         {
00571           float sum = 0.0; 
00572           float opp = 0.0;
00573           for (uint k = 0; k < itsNumDirs; k++)
00574             {
00575               // NOTE: use this line if don't want center surround
00576               //float tval = *stT[k]++;
00577 
00578               // NOTE: to find 4x4 neighborhood max values of opponencies
00579               //       better than just a single location 
00580               // get the max vals around this location
00581               uint mi = i/steps;
00582               uint mj = j/steps;
00583               
00584               uint lm = 0;         if(mi > 0)        lm = mi - 1; 
00585               uint rm = nwidth-1;  if(mi < nwidth-2) rm = mi + 1;
00586               uint tm = 0;         if(mj > 0)        tm = mj - 1; 
00587               uint bm = nheight-1; if(mj < nheight-2)bm = mj + 1;
00588 
00589 //               // DEBUG:
00590 //              if(i == 180 && j == 60)
00591 //               if(i >=  148 && i <= 151 && j >=  60 && j <=  63   ) 
00592 //                 {
00593 //                   LINFO("[%3d %3d] (%3d %3d %3d %3d) -> %3d %3d", i,j, lm,rm,tm,bm, mi,mj); 
00594 //                 }
00595 
00596               float nmax = 0.0;
00597               for(uint bi = lm; bi <= rm; bi++)
00598                 {
00599                   for(uint bj = tm; bj <= bm; bj++)
00600                     {
00601                       float nval = itsDirSteMaxVals[k][scale].getVal(bi, bj);
00602                       if(nmax < nval) nmax = nval;
00603  
00604                       //if(i == 180 && j == 60)
00605                         //               if(i >=  148 && i <= 151 && j >=  60 && j <=  63   ) 
00606                         //{
00607                         //  LINFO("[%3d %3d] -> %10.3f %10.3f", bi,bj, nval, nmax); 
00608                         //}
00609 
00610 
00611 
00612                    }
00613                 }
00614 
00615               float tval = nmax;
00616 
00617 
00618               // accumulate opponencies only for other directions
00619               if(k != dir) sum += tval;
00620               //if(k != dir && k != oppDir) sum += tval;
00621              
00622               // also find
00623               if(k == oppDir) opp = tval;
00624               //if(max < tval) max =  tval;
00625 
00626             }
00627           sum /= (itsNumDirs-2.0);
00628 
00629           
00630           // NOTE: experiment with both average and just the opposite direction
00631           //       -->on stationary stimuli (or stimuli that's too slow/fast) 
00632           //          opposite direction gives equal firings.  
00633           *resultT++ = opp; //(sum+opp);         
00634         }
00635     }
00636 
00637   return result;
00638 }
00639 
00640 // ######################################################################
00641 Image<float> MiddleTemporal::getNeighborInhibitSpatioTemporalEnergy
00642 (uint dir, uint scale)
00643 {  
00644   uint width  = itsSpatioTemporalEnergy[dir][scale].getWidth();
00645   uint height = itsSpatioTemporalEnergy[dir][scale].getHeight();  
00646   Image<float> result(width,height,ZEROS); 
00647 
00648   float cosAng = cos((2.0*M_PI * dir)/itsNumDirs); 
00649   float sinAng = sin((2.0*M_PI * dir)/itsNumDirs); 
00650   
00651   Image<float>::iterator stT[itsNumDirs];
00652   for (unsigned int i=0; i < itsNumDirs; i++)
00653     stT[i] = itsSpatioTemporalEnergy[i][scale].beginw();
00654 
00655   // NOTE: FIX maybe add .5 to make sure the diagonal is taken care
00656   //LINFO("c,s(%10.3f, %10.3f) [%3d %3d]", cosAng, sinAng, width, height);
00657 
00658   // NOTE: inhibit neighbor motion if they're not in agreement with yours
00659 
00660   std::vector<float> fweights(4);
00661   fweights[0] = .15;
00662   fweights[1] = .07;
00663   fweights[2] = .02;
00664   fweights[3] = .01;
00665 
00666   std::vector<float> bweights(3);
00667   bweights[0] = .10;
00668   bweights[1] = .05;
00669   bweights[2] = .02;
00670 
00671   for(uint j = 0; j < height; j++)
00672     {
00673       for(uint i = 0; i < width; i++)
00674         {
00675           float val = *stT[dir]++;          
00676           //float val  = itsSpatioTemporalEnergy[dir][scale].getVal(i,j);
00677           for(uint k = 0; k < fweights.size(); k++)
00678             {
00679               int ii = (i + (k+1.0)*cosAng);
00680               int jj = (j + (k+1.0)*sinAng);
00681  
00682               if(ii > 0 && ii < int(width) &&
00683                  jj > 0 && jj < int(height)   )
00684                 {
00685                   float rval = result.getVal(ii,jj);                  
00686                   result.setVal(ii,jj, rval + (fweights[k] * val));
00687                 }
00688            }
00689         }
00690 
00691       // add the backward inhibitory as well if needed
00692     }
00693   return result;
00694 }
00695 
00696 // ######################################################################
00697 void MiddleTemporal::findMaxMotionVals()
00698 {
00699   // SCALE INTEGRATION
00700   // normalizing to 1.0 is working if we expand the local max normalizer
00701   // we only use 2 levels now to go from 1 pix - 8pix displacement
00702   // all that it needed really
00703 
00704   uint width  = itsSpatioTemporalEnergy[0][0].getWidth();
00705   uint height = itsSpatioTemporalEnergy[0][0].getHeight();
00706 
00707   uint mWidth  = width/MAX_NEIGHBORHOOD;
00708   uint mHeight = height/MAX_NEIGHBORHOOD;
00709   //LINFO("MTfeatures size: %d x %d", mWidth, mHeight);
00710 
00711   // got through each point in each direction
00712   for(uint d = 0; d < itsNumDirs; d++)
00713     {
00714       Image<float> tMTfeatures (mWidth, mHeight, NO_INIT);
00715       Image<float>::iterator tmtT = tMTfeatures.beginw();
00716 
00717       Image<float> tMToptimalShift (mWidth, mHeight, NO_INIT);
00718       Image<float>::iterator tmtosT = tMToptimalShift.beginw();
00719 
00720       for(uint j = 0; j < mHeight; j++)
00721         {
00722           for(uint i = 0; i < mWidth; i++)
00723             {
00724               // find max among all scales
00725               float max = 0.0; float optShift = 0.0;
00726               for(uint l = 0; l < itsNumPyrLevels; l++)
00727                 {
00728                   uint pxSize  = uint(pow(2.0, l));
00729                   uint lwidth  = width/pxSize;
00730                   uint lheight = height/pxSize;
00731 
00732                   uint steps = 1; 
00733                   if(pxSize < MAX_NEIGHBORHOOD) 
00734                     steps = MAX_NEIGHBORHOOD/pxSize;
00735 
00736                   // translated coordinate
00737                   uint ti = i * steps;
00738                   uint tj = j * steps;
00739 
00740                   // take care of boundary conditions                  
00741                   uint lstep = ti; if(ti         >= steps) lstep = ti - steps;
00742                   uint rstep = ti; if(ti+steps <   lwidth) rstep = ti + steps;
00743                   uint tstep = tj; if(tj         >= steps) tstep = tj - steps;
00744                   uint bstep = tj; if(tj+steps <  lheight) bstep = tj + steps;
00745 
00746                   // this needs interpolation
00747                   if(pxSize > MAX_NEIGHBORHOOD)
00748                     {
00749                       // NOTE: ADD LATER
00750                       uint div = pxSize/MAX_NEIGHBORHOOD; 
00751                       //LINFO("interp: (%3d %3d) t[%3d %3d] {%3d %3d}: %3d %3d", 
00752                       //      i,j, ti, tj, d, l, i/div, j/div);
00753                       float val =
00754                         itsSpatioTemporalEnergy[d][l].getVal(i/div,j/div);
00755                       float shift =
00756                         itsSpatioTemporalEnergyOptimalShift[d][l].getVal(i/div,j/div);
00757                       if(max < val)
00758                         {
00759                           max = val;
00760                           optShift = shift;
00761                         }
00762                     }
00763                   else
00764                     {
00765                       for(uint di = lstep; di < rstep; di++)
00766                         {
00767                           for(uint dj = tstep; dj < bstep; dj++)
00768                             {
00769                               //LINFO("(%3d %3d) t[%3d %3d] {%3d %3d}[%3d %3d %3d %3d] d: %3d %3d", 
00770                               //      i,j, ti, tj, d, l, lstep, rstep, tstep, bstep, di, dj);
00771                               float val = 
00772                                 itsSpatioTemporalEnergy[d][l].getVal(di, dj);
00773                               float shift = 
00774                                 itsSpatioTemporalEnergyOptimalShift[d][l].getVal(di, dj) * pxSize;
00775                               if(max < val) 
00776                                 {
00777                                   max = val;
00778                                   optShift = shift;
00779                                 }
00780                             }
00781                         }
00782                     }
00783                 }              
00784 
00785               //tMTfeatures.setVal(i,j, max);
00786               //LINFO("%f %f %f",tMTfeatures.getVal(i,j), max, *tmtT); tmtT++;
00787               *tmtT++ = max; 
00788               *tmtosT++ = optShift;
00789             }
00790         }
00791       itsMTfeatures[d]     = tMTfeatures;
00792       itsMToptimalShift[d] = tMToptimalShift;
00793     }
00794 }
00795 
00796 // ######################################################################
00797 void MiddleTemporal::printItsSpatioTemporalEnergy
00798 (uint si, uint ei, uint sj, uint ej, bool stop, float div)
00799 {
00800   if(itsSpatioTemporalEnergy[0].size() == 0) return;
00801     
00802   //for(uint k = 0; k < 1; k++)
00803   for(uint k = 0; k < itsNumPyrLevels; k++)
00804     {
00805       uint step = uint(pow(2.0,k));
00806       for(uint i = 0; i < itsNumDirs; i++)
00807         {
00808           LINFO("itsSpatioTemporalEnergy features: dir: %d lev: %d", i, k);
00809           
00810           for(uint y = sj/step; y < ej/step; y++)
00811             {
00812               for(uint x = si/step; x < ei/step; x++)
00813                 printf("%8.3f ", itsSpatioTemporalEnergy[i][k].getVal(x,y)/div);
00814               printf("\n");
00815             }
00816           LINFO("\n");
00817           
00818           //i+= 3; // < just to see dir: 0 and 4 or motion left and right
00819           
00820           if(stop) Raster::waitForKey();
00821         }
00822     }
00823 }
00824 
00825 // ######################################################################
00826 void MiddleTemporal::displayItsSpatioTemporalEnergy()
00827 {
00828   if(itsSpatioTemporalEnergy[0].size() == 0) return;
00829   uint w = itsSpatioTemporalEnergy[0][0].getWidth();
00830   uint h = itsSpatioTemporalEnergy[0][0].getHeight();
00831   Image<float> disp(w*4, h*2,NO_INIT);
00832 
00833   if(itsWin.is_invalid())
00834     itsWin.reset(new XWinManaged(Dims(w*4,h*2), w+10, 0, "FOE Detector"));
00835   else itsWin->setDims(Dims(w*4,h*2));
00836   
00837   for(uint i = 0; i < itsNumPyrLevels; i++)
00838   //for(uint i = 0; i < 1; i++)
00839     {
00840       LINFO("level: %d", i);
00841 
00842       uint scale = uint(pow(2.0, i)); 
00843       inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[0][i], scale), 
00844                    Point2D<int>(0,   0));
00845       inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[1][i], scale), 
00846                    Point2D<int>(w,   0));
00847       inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[2][i], scale), 
00848                    Point2D<int>(2*w, 0));
00849       inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[3][i], scale), 
00850                    Point2D<int>(3*w, 0));
00851 
00852       if(itsNumDirs > 4)
00853         {
00854           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[4][i], scale), 
00855                        Point2D<int>(0,   h));
00856           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[5][i], scale), 
00857                        Point2D<int>(w,   h));
00858           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[6][i], scale), 
00859                        Point2D<int>(2*w, h));
00860           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[7][i], scale), 
00861                        Point2D<int>(3*w, h));
00862         }
00863 
00864       if(itsNumDirs > 8)
00865         {
00866           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[8][i],  scale), 
00867                        Point2D<int>(0,     h));
00868           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[9][i],  scale), 
00869                        Point2D<int>(w/2,   h));
00870           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[10][i], scale), 
00871                        Point2D<int>(w,     h));
00872           inplacePaste(disp, zoomXY(itsSpatioTemporalEnergy[11][i], scale), 
00873                        Point2D<int>(3*w/2, h));
00874         } 
00875       itsWin->drawImage(disp,0,0);
00876       Raster::waitForKey();
00877     }
00878 }
00879 
00880 // ######################################################################
00881 void MiddleTemporal::printItsMTfeatures
00882 (uint si, uint ei, uint sj, uint ej, bool stop)
00883 {
00884   if(itsSpatioTemporalEnergy[0].size() == 0) return;
00885 
00886   
00887   LINFO("MT features ");
00888   for(uint i = 0; i < itsNumDirs; i++)
00889     {
00890       for(uint y = sj; y < ej; y++)
00891         {
00892           for(uint x = si; x < ei; x++)
00893             printf("%7.3f ", itsMTfeatures[i].getVal(x,y));
00894           printf("\n");
00895         }
00896       LINFO("MT features: %d", i);
00897       if(stop)Raster::waitForKey();
00898     }
00899 }
00900 
00901 // ######################################################################
00902 void MiddleTemporal::printItsMToptimalShift
00903 (uint si, uint ei, uint sj, uint ej, bool stop)
00904 {
00905   if(itsSpatioTemporalEnergy[0].size() == 0) return;
00906 
00907   
00908   LINFO("MT features Optimal Shift");
00909   for(uint i = 0; i < itsNumDirs; i++)
00910     {
00911       for(uint y = sj; y < ej; y++)
00912         {
00913           for(uint x = si; x < ei; x++)
00914             printf("%7.3f ", itsMToptimalShift[i].getVal(x,y));
00915           printf("\n");
00916         }
00917       LINFO("MT features: %d", i);
00918       if(stop)Raster::waitForKey();
00919     }
00920 }
00921 
00922 // ######################################################################
00923 void MiddleTemporal::displayItsMToptimalShift()
00924 {
00925   if(itsSpatioTemporalEnergy[0].size() == 0) return; 
00926   uint w = itsSpatioTemporalEnergy[0][0].getWidth();
00927   uint h = itsSpatioTemporalEnergy[0][0].getHeight();
00928   
00929   uint wDisp = w*2; uint hDisp = h/2;
00930   if(itsNumDirs == 8)      { wDisp = w*2; hDisp = h;     }
00931   else if(itsNumDirs == 8) { wDisp = w*2; hDisp = 3*h/2; }
00932 
00933   Image<float> disp(wDisp,hDisp,NO_INIT);
00934   if(itsWin.is_invalid())
00935     itsWin.reset(new XWinManaged(Dims(wDisp,hDisp), w+10, 0, "FOE Detector"));
00936   else itsWin->setDims(Dims(wDisp, hDisp));
00937 
00938   LINFO("display MT optimal shift");
00939 
00940   inplacePaste(disp, zoomXY(itsMToptimalShift[0], MAX_NEIGHBORHOOD/2), 
00941                Point2D<int>(0,     0));
00942   inplacePaste(disp, zoomXY(itsMToptimalShift[1], MAX_NEIGHBORHOOD/2), 
00943                Point2D<int>(w/2,   0));
00944   inplacePaste(disp, zoomXY(itsMToptimalShift[2], MAX_NEIGHBORHOOD/2), 
00945                Point2D<int>(w,     0));
00946   inplacePaste(disp, zoomXY(itsMToptimalShift[3], MAX_NEIGHBORHOOD/2), 
00947                Point2D<int>(3*w/2, 0));
00948 
00949   if(itsNumDirs > 4)
00950     {
00951       inplacePaste(disp, zoomXY(itsMToptimalShift[4], MAX_NEIGHBORHOOD/2), 
00952                    Point2D<int>(0,    h/2));
00953       inplacePaste(disp, zoomXY(itsMToptimalShift[5], MAX_NEIGHBORHOOD/2), 
00954                    Point2D<int>(w/2,  h/2));
00955       inplacePaste(disp, zoomXY(itsMToptimalShift[6], MAX_NEIGHBORHOOD/2), 
00956                    Point2D<int>(w,    h/2));
00957       inplacePaste(disp, zoomXY(itsMToptimalShift[7], MAX_NEIGHBORHOOD/2), 
00958                    Point2D<int>(3*w/2,h/2));
00959     }
00960   
00961   if(itsNumDirs > 8)
00962     {
00963       inplacePaste(disp, zoomXY(itsMToptimalShift[8],  MAX_NEIGHBORHOOD/2), 
00964                    Point2D<int>(0,     h));
00965       inplacePaste(disp, zoomXY(itsMToptimalShift[9],  MAX_NEIGHBORHOOD/2), 
00966                    Point2D<int>(w/2,   h));
00967       inplacePaste(disp, zoomXY(itsMToptimalShift[10], MAX_NEIGHBORHOOD/2), 
00968                    Point2D<int>(w,     h));
00969       inplacePaste(disp, zoomXY(itsMToptimalShift[11], MAX_NEIGHBORHOOD/2), 
00970                    Point2D<int>(3*w/2, h));
00971     } 
00972 
00973   float mn,mx; getMinMax(disp,mn,mx);      
00974   drawLine(disp, Point2D<int>(0    , h/2), Point2D<int>(w*2  , h/2), mx, 1);
00975   drawLine(disp, Point2D<int>(0    , h  ), Point2D<int>(w*2  , h  ), mx, 1);
00976   drawLine(disp, Point2D<int>(w/2  , 0  ), Point2D<int>(w/2  , h  ), mx, 1);
00977   drawLine(disp, Point2D<int>(w    , 0  ), Point2D<int>(w    , h  ), mx, 1);
00978   drawLine(disp, Point2D<int>(3*w/2, 0  ), Point2D<int>(3*w/2, h  ), mx, 1);
00979   itsWin->drawImage(disp,0,0);
00980   Raster::waitForKey();  
00981 }
00982 
00983 // ######################################################################
00984 void MiddleTemporal::displayItsMTfeatures()
00985 {
00986   if(itsSpatioTemporalEnergy[0].size() == 0) return; 
00987   uint w = itsSpatioTemporalEnergy[0][0].getWidth();
00988   uint h = itsSpatioTemporalEnergy[0][0].getHeight();
00989   
00990   uint wDisp = w*2; uint hDisp = h/2;
00991   if(itsNumDirs == 8)      { wDisp = w*2; hDisp = h;     }
00992   else if(itsNumDirs == 8) { wDisp = w*2; hDisp = 3*h/2; }
00993 
00994   Image<float> disp(wDisp,hDisp,NO_INIT);
00995   if(itsWin.is_invalid())
00996     itsWin.reset(new XWinManaged(Dims(wDisp,hDisp), w+10, 0, "FOE Detector"));
00997   else itsWin->setDims(Dims(wDisp, hDisp));
00998 
00999   LINFO("display MT features");
01000 
01001   inplacePaste(disp, zoomXY(itsMTfeatures[0], MAX_NEIGHBORHOOD/2), 
01002                Point2D<int>(0,     0));
01003   inplacePaste(disp, zoomXY(itsMTfeatures[1], MAX_NEIGHBORHOOD/2), 
01004                Point2D<int>(w/2,   0));
01005   inplacePaste(disp, zoomXY(itsMTfeatures[2], MAX_NEIGHBORHOOD/2), 
01006                Point2D<int>(w,     0));
01007   inplacePaste(disp, zoomXY(itsMTfeatures[3], MAX_NEIGHBORHOOD/2), 
01008                Point2D<int>(3*w/2, 0));
01009 
01010   if(itsNumDirs > 4)
01011     {
01012       inplacePaste(disp, zoomXY(itsMTfeatures[4], MAX_NEIGHBORHOOD/2), 
01013                    Point2D<int>(0,    h/2));
01014       inplacePaste(disp, zoomXY(itsMTfeatures[5], MAX_NEIGHBORHOOD/2), 
01015                    Point2D<int>(w/2,  h/2));
01016       inplacePaste(disp, zoomXY(itsMTfeatures[6], MAX_NEIGHBORHOOD/2), 
01017                    Point2D<int>(w,    h/2));
01018       inplacePaste(disp, zoomXY(itsMTfeatures[7], MAX_NEIGHBORHOOD/2), 
01019                    Point2D<int>(3*w/2,h/2));
01020     }
01021   
01022   if(itsNumDirs > 8)
01023     {
01024       inplacePaste(disp, zoomXY(itsMTfeatures[8],  MAX_NEIGHBORHOOD/2), 
01025                    Point2D<int>(0,     h));
01026       inplacePaste(disp, zoomXY(itsMTfeatures[9],  MAX_NEIGHBORHOOD/2), 
01027                    Point2D<int>(w/2,   h));
01028       inplacePaste(disp, zoomXY(itsMTfeatures[10], MAX_NEIGHBORHOOD/2), 
01029                    Point2D<int>(w,     h));
01030       inplacePaste(disp, zoomXY(itsMTfeatures[11], MAX_NEIGHBORHOOD/2), 
01031                    Point2D<int>(3*w/2, h));
01032     } 
01033 
01034   float mn,mx; getMinMax(disp,mn,mx);      
01035   drawLine(disp, Point2D<int>(0    , h/2), Point2D<int>(w*2  , h/2), mx, 1);
01036   drawLine(disp, Point2D<int>(0    , h  ), Point2D<int>(w*2  , h  ), mx, 1);
01037   drawLine(disp, Point2D<int>(w/2  , 0  ), Point2D<int>(w/2  , h  ), mx, 1);
01038   drawLine(disp, Point2D<int>(w    , 0  ), Point2D<int>(w    , h  ), mx, 1);
01039   drawLine(disp, Point2D<int>(3*w/2, 0  ), Point2D<int>(3*w/2, h  ), mx, 1);
01040   itsWin->drawImage(disp,0,0);
01041   Raster::waitForKey();  
01042 }
01043 
01044 // ######################################################################
01045 Layout<byte> MiddleTemporal::getMTfeaturesDisplay(Image<byte> image)
01046 {
01047   if(itsRawSpatioTemporalEnergy.size() == 0 || 
01048      itsRawSpatioTemporalEnergy[0][0].size() == 0)
01049     return Layout<byte>(image);
01050 
01051   uint width  = image.getWidth();
01052   uint height = image.getHeight();   
01053 
01054   uint scale = 1;
01055   Image<float> lum    = image;
01056   Image<float> motion(width* scale, height * scale, ZEROS);
01057 
01058   uint mtWidth  = itsMTfeatures[0].getWidth();
01059   uint mtHeight = itsMTfeatures[0].getHeight();
01060 
01061   Image<float>::iterator mtT[itsNumDirs];
01062   for (unsigned int i=0; i < itsNumDirs; i++)
01063     mtT[i] = itsMTfeatures[i].beginw();
01064 
01065   Image<float>::iterator mtosT[itsNumDirs];
01066   for (unsigned int i=0; i < itsNumDirs; i++)
01067     mtosT[i] = itsMToptimalShift[i].beginw();
01068 
01069   float boom = 0;
01070   // go through each MT locations
01071   for(uint dir = 0; dir < itsNumDirs; dir++)
01072     {
01073       float angle = (dir*2.0*M_PI)/itsNumDirs; 
01074       if(dir%2 == 1) 
01075         { 
01076           //LINFO("[%d> ang: %f", dir, angle);
01077           angle = (dir*2.0*M_PI)/itsNumDirs + M_PI/2.0;
01078           //LINFO("<%d] ang: %f", dir, angle);
01079         }
01080       // draw an arrow for each location
01081       for(uint j = 0; j < mtHeight; j++)
01082         {
01083           for(uint i = 0; i < mtWidth; i++)
01084             {
01085               float val   = *mtT[dir]++;
01086               float shift = *mtosT[dir]++;
01087               if(val > .20)// && dir == 3 && boom != 10 && shift == 8.0)//(dir != 0 && dir != 4))
01088                 {
01089                   boom++;
01090                   //LINFO("val %f, ang: %f (%d %d)", val, angle, i,j);
01091                   drawLine(motion, 
01092                            Point2D<int>(i*MAX_NEIGHBORHOOD*scale,
01093                                         j*MAX_NEIGHBORHOOD*scale), 
01094                            //angle, val*MAX_NEIGHBORHOOD*scale, 1.0F);
01095                            angle, shift*4*scale, val);
01096   
01097                   //drawDisk(motion, 
01098                   //          Point2D<int>(i*MAX_NEIGHBORHOOD*scale,
01099                   //                       j*MAX_NEIGHBORHOOD*scale), 2, val);
01100                }
01101             }
01102         }
01103     }
01104 
01105   Image<float> res = motion;
01106   inplaceNormalize(res,    0.0F, 255.0F);
01107   inplaceNormalize(lum,    0.0F,  64.0F);
01108   inplaceNormalize(motion, 0.0F, 255.0F);
01109 
01110   // draw the location of the FOE
01111   //drawCross(res, itsFoe, 1.0f, 10, 1);
01112   
01113   Image<byte> vimg = res;
01114   //writeText(vimg, Point2D<int>(1,1), "img", byte(0), byte(255),
01115   //          SimpleFont::fixedMaxWidth(8));
01116   
01117   Image<byte> himg = res;
01118   //writeText(himg, Point2D<int>(1,1), "motion", byte(0), byte(255),
01119   //          SimpleFont::fixedMaxWidth(8));
01120   
01121 //   Layout<byte> disp = 
01122 //     vcat(hcat(lum, Image<byte>(quad)), hcat(himg, vimg));
01123 
01124   Layout<byte> disp(res+lum);
01125 
01126   return disp;
01127 }
01128 
01129 // ######################################################################
01130 /* So things look consistent in everyone's emacs... */
01131 /* Local Variables: */
01132 /* indent-tabs-mode: nil */
01133 /* End: */
Generated on Sun May 8 08:41:18 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3