test-FOE.C

Go to the documentation of this file.
00001 /*!@file Robots/Beobot2/Navigation/FOE_Navigation/test-FOE.C 
00002   find the focus of expansion */
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: $
00035 // $Id: $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 #include "Component/OptionManager.H"
00040 #include "Devices/FrameGrabberConfigurator.H"
00041 
00042 #include "Media/FrameSeries.H"
00043 
00044 #include "Image/ColorOps.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Image/Image.H"
00047 #include "Image/Layout.H"
00048 #include "Raster/Raster.H"
00049 
00050 #include "SIFT/Keypoint.H"
00051 #include "SIFT/VisualObject.H"
00052 #include "SIFT/VisualObjectMatch.H"
00053 
00054 #include "Transport/FrameInfo.H"
00055 #include "Util/Pause.H"
00056 #include "Util/Timer.H"
00057 #include "Util/Types.H"
00058 #include "Util/csignals.H"
00059 #include "Util/log.H"
00060 #include <math.h>
00061 #include <cstdio>
00062 #include "Robots/Beobot2/Navigation/FOE_Navigation/FoeDetector.H"
00063 
00064 
00065 #define DOT_NUM          200           // 200  1000
00066 
00067 #define WIDTH            320           // 320  640
00068 #define HEIGHT           240           // 240  480
00069 #define FOE_X            2*WIDTH/4     // W/4 
00070 #define FOE_Y            2*HEIGHT/4    // 2H/4 +4 
00071 
00072 #define DOT_VEL          2.0/80.0      // Shuo: .035
00073 
00074 
00075 // Shuo: in PsychToolbox: size refers to diameter, in our code radius
00076 // Shuo: Abs max: 21, ave DS is 9.767 across all dots in each frames
00077 #define DOT_ORG_DSIZE    .02    // .04
00078 #define DOT_DSIZE        .07    // .035
00079 #define MIN_DOT_SIZE     1   
00080 #define MAX_DOT_SIZE     5   
00081 #define ABS_MAX_DSIZE    50
00082 #define NFRAME           60
00083 
00084 #define HAVE_MOTION      1
00085 #define HAVE_TEMP_SGRAD  1
00086 #define HAVE_SPAT_SGRAD  1
00087 
00088 #define NUM_PYR_LEVEL    2 // 3 for 640x480
00089 #define NUM_DIRS         8
00090 #define NUM_SPEEDS       3
00091 
00092 // get the ground truth from a text file
00093 std::vector<Point2D<int> > getGT(std::string gtFilename);
00094 
00095 Image<byte>  calculateShift
00096 (Image<byte> lum, Image<byte> prevLum, nub::ref<OutputFrameSeries> ofs);
00097 
00098 // get the image for stimuli
00099 Image<byte> getFoeDots
00100 (uint step, bool haveMotion, bool  haveTempSGrad, bool haveSpatSGrad,
00101  float dx, float dy, float dotOrgDSize);
00102 
00103 Image<byte> getPlanarMotionStimuli
00104 (Image<byte> temp, uint step, float dx, float dy);
00105 
00106 Image<byte> getBarStimuli(uint step);
00107 Image<byte> getShapeStimuli(uint step);
00108 Image<byte> getApertureProblemStimuli(uint step);
00109 
00110 // this is stimuli like in Fukuchi,Tsuchiya,Koch VSS/JOV 2009/2010
00111 // FOE is FOE_X,FOE_Y
00112 Image<byte> getCleanFOE
00113 (uint step, uint totalStep, uint mag, float dx, float dy, Image<byte> image);
00114 
00115 Image<byte> getPlanarMotionImage
00116 (uint step, uint totalStep, float dx, float dy, Image<byte> image);
00117 
00118 Image<byte> shiftImage(SIFTaffine aff, Image<byte> ref, Image<byte> tst);
00119 
00120 Image<byte> getImage
00121 (std::string stimuli, std::vector<std::string> args, 
00122  nub::ref<FoeDetector> fd, uint step);
00123 
00124 // ######################################################################
00125 std::vector<Point2D<float> > dots;
00126 std::vector<float> dotSizes;
00127 
00128 std::vector<Point2D<float> > pdots;
00129 std::vector<float> pdotSizes;
00130 
00131 // ######################################################################
00132 int main(const int argc, const char **argv)
00133 {
00134   MYLOGVERB = LOG_INFO;  // suppress debug messages
00135 
00136   volatile int signum = 0;
00137   catchsignals(&signum);
00138 
00139   ModelManager manager("Test Motion Energy");
00140 
00141   nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager));
00142   manager.addSubComponent(ifs);
00143 
00144   nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager));
00145   manager.addSubComponent(ofs);
00146 
00147   nub::ref<FoeDetector> fd(new FoeDetector(manager));
00148   manager.addSubComponent(fd);
00149 
00150   if (manager.parseCommandLine((const int)argc, (const char**)argv,
00151                                "<stimuli> <options>", 0, 9) == false)
00152     return(1);
00153 
00154   fd->reset(NUM_PYR_LEVEL, NUM_DIRS, NUM_SPEEDS);
00155 
00156   std::string stimuli("Image");
00157   if(manager.numExtraArgs() > 0)
00158     stimuli = manager.getExtraArgAs<std::string>(0);
00159   LINFO("Stimuli: %s", stimuli.c_str());
00160 
00161   manager.start();
00162 
00163   Timer timer(1000000);
00164   timer.reset();  // reset the timer
00165   int frame = 0;
00166 
00167   PauseWaiter p;
00168 
00169   uint step; step = 0;
00170 
00171   // to get to the good part
00172   //for(uint i = 0; i < 50; i++) //was 25
00173   //  ifs->updateNext();
00174 
00175   // get ground truth file 
00176   std::string gtFilename
00177     ("/lab/tmpib/u/siagian/neuroscience/Data/FOE/driving_nat_Browning.txt");
00178   std::vector<Point2D<int> > gt = getGT(gtFilename);
00179   int ldpos = gtFilename.find_last_of('.');
00180   std::string prefix = gtFilename.substr(0, ldpos);
00181 
00182   // for finding ground truth
00183   rutz::shared_ptr<XWinManaged> win;
00184   
00185   float totalErr = 0.0;
00186 
00187   std::vector<std::string> args;
00188   for(uint i = 0; i < manager.numExtraArgs(); i++)
00189     args.push_back(manager.getExtraArgAs<std::string>(i)); 
00190 
00191   Image<byte> prevLum;
00192   Image<PixRGB<byte> > prevImage;
00193   Image<PixRGB<byte> > prevImage2;
00194   while (1)
00195     {
00196       if (signum != 0)
00197         {
00198           LINFO("quitting because %s was caught", signame(signum));
00199           break;
00200         }
00201 
00202       if (ofs->becameVoid())
00203         {
00204           LINFO("quitting because output stream was closed or became void");
00205           break;
00206         }
00207 
00208       if (p.checkPause())
00209         continue;
00210 
00211       const FrameState is = ifs->updateNext();
00212       if (is == FRAME_COMPLETE) break; // done receiving frames
00213 
00214       Image< PixRGB<byte> > input = ifs->readRGB();
00215       if(frame == 0) 
00216         {
00217           uint width  = input.getWidth();
00218           uint height = input.getHeight();
00219           win.reset(new XWinManaged(Dims(width, height), 0, 0, "GT"));
00220         }
00221 
00222       // empty image signifies end-of-stream
00223       if (!input.initialized()) break;
00224       Image<byte> lum = luminance(input);
00225       Point2D<float> pshift(0.0,0.0); 
00226       if(step != 0)
00227         {
00228           // calculate planar shift using SIFT 
00229           lum = calculateShift(lum,prevLum, ofs);
00230         }
00231       if( manager.numExtraArgs() > 0)
00232         lum = getImage(stimuli, args, fd, step);
00233 
00234       // for saving videos
00235       prevImage2 = prevImage;
00236       prevImage  = input;
00237 
00238       if (!lum.initialized()) break; step++;
00239 
00240       // compute the focus of expansion (FOE)
00241       Point2D<int> foe = fd->getFoe(lum, FOE_METHOD_TEMPLATE, false);
00242       //Point2D<int> foe = fd->getFoe(lum, FOE_METHOD_AVERAGE);
00243       LINFO("[%d]Foe: %d %d", frame, foe.i, foe.j);
00244 
00245       // illustration of the size of the receptive field
00246       if(!stimuli.compare("ShowRF"))
00247         {
00248           uint rfI = 44;
00249           uint rfJ = 152;
00250           lum.setVal(rfI, rfJ, 300.0F);      
00251           drawRect(lum, Rectangle::tlbrI(144,36,159,51), byte(255));
00252           drawRect(lum, Rectangle::tlbrI(148,40,155,47), byte(255));
00253           
00254           drawRect(lum, Rectangle::tlbrI(rfJ-8, rfI-8, rfJ+8, rfI+8), byte(255));
00255           drawRect(lum, Rectangle::tlbrI(rfJ-16,rfI-16,rfJ+16,rfI+16), byte(255));
00256         }
00257 
00258       ofs->writeGrayLayout(fd->getMTfeaturesDisplay(lum), "MT Features",
00259                            FrameInfo("motion energy output images", SRC_POS));
00260 
00261       // write the file
00262       if(frame >= 4)
00263         {
00264           float err = foe.distance(gt[frame-2]); 
00265           totalErr += err;
00266           LINFO("Foe: %d %d: GT: %d %d --> %f --> avg: %f", 
00267                 foe.i, foe.j, gt[frame-2].i, gt[frame-2].j, 
00268                 err, totalErr/(frame-3));
00269 
00270           Image<PixRGB<byte> > simg = prevImage2;
00271           drawCross(simg, foe        , PixRGB<byte>(0,255,0), 10, 2);
00272           drawCross(simg, gt[frame-2], PixRGB<byte>(255,0,0), 10, 2);
00273           win->drawImage(simg,0,0);
00274           //Raster::WriteRGB(simg, sformat("%s_STnPS_%06d.ppm", prefix.c_str(), frame-2));
00275         }
00276 
00277       //ofs->writeGrayLayout
00278       //  (lum, "test-FOE Main", FrameInfo("foe output", SRC_POS));
00279       const FrameState os = ofs->updateNext();
00280       //LINFO("frame[%d]: %8.3f %8.3f", frame, pshift.i, pshift.j); 
00281       Raster::waitForKey();
00282 
00283       if (os == FRAME_FINAL)
00284         break;
00285 
00286       prevLum  = lum;
00287       frame++;
00288     }
00289 
00290   LINFO("%d frames in %gs (%.2ffps)\n", 
00291         frame, timer.getSecs(), frame / timer.getSecs());
00292 
00293   // stop all our ModelComponents
00294   manager.stop();
00295 
00296   // all done!
00297   return 0;
00298 
00299 }
00300 
00301 // ######################################################################
00302 std::vector<Point2D<int> > getGT(std::string gtFilename)
00303 {
00304   std::vector<Point2D<int> > gt;
00305 
00306   FILE *fp;  char inLine[200]; //char comment[200];
00307 
00308   LINFO("ground truth file: %s",gtFilename.c_str());
00309   if((fp = fopen(gtFilename.c_str(),"rb")) == NULL)
00310     { LINFO("not found"); return gt; }
00311 
00312   // populate the trial information
00313   uint nFrames = 0;
00314   while(fgets(inLine, 200, fp) != NULL)
00315     {
00316       int x, y;
00317       sscanf(inLine, "%d %d", &x, &y);      
00318       LDEBUG("[%3d] x: %d y: %d", nFrames, x, y);
00319       gt.push_back(Point2D<int>(x,y));
00320 
00321       nFrames++;
00322     }
00323   return gt;
00324 }
00325 
00326 // ######################################################################
00327 Image<byte> getImage
00328   (std::string stimuli, std::vector<std::string> args, 
00329    nub::ref<FoeDetector> fd, uint step)
00330 {
00331   Image<byte> lum;
00332 
00333   // Different stimuli:
00334   if(!stimuli.compare("Image")) 
00335     {
00336       float di =  0.0; float dj = 0.0;
00337       //float di =  -3.6; float dj = -.6; // first frame ACB
00338       if(args.size() > 2)
00339         {
00340           di = atof(args[1].c_str()); 
00341           dj = atof(args[2].c_str()); 
00342           //fd->setObserverRotation(di, dj);
00343         }
00344       LDEBUG("di: %f, dj: %f", di, dj);
00345     }
00346   else if(!stimuli.compare("BarStimuli"))
00347     lum = getBarStimuli(step); 
00348   else if(!stimuli.compare("ApertureProblem"))
00349     lum = getApertureProblemStimuli(step);
00350   else if(!stimuli.compare("CleanFoe"))
00351     {
00352       uint total = 30;  // 15 for the Fukuchi, et. al. paper
00353       if(args.size() > 1)
00354         total = uint(atoi(args[1].c_str()));
00355       float dx = 0.0;
00356       float dy = 0.0;
00357       if(args.size() > 3)
00358         {
00359           dx = atof(args[2].c_str());  
00360           dy = atof(args[3].c_str()); 
00361         }
00362       lum = getCleanFOE(step, total, 2.0, dx, dy, lum);
00363       
00364       //           float di =  0.0; float dj = 0.0;
00365       //           if(manager.numExtraArgs() > 5)
00366       //             {
00367       //               di = manager.getExtraArgAs<float>(4); 
00368       //               dj = manager.getExtraArgAs<float>(5); 
00369       //               fd->setObserverRotation(di, dj);
00370       //             }
00371       // planar (Yaw-Pitch) motion correction
00372       uint dir =  0.0; float speed = 0.0;
00373       if(args.size() > 5)
00374         {
00375           dir   = uint(atoi(args[4].c_str())); 
00376           speed = atof(args[5].c_str()); 
00377           fd->setObserverRotation(dir, speed);
00378         }
00379     }
00380   else if(!stimuli.compare("FoeDots"))      
00381     {
00382       bool haveMotion    = HAVE_MOTION;
00383       bool haveTempSGrad = HAVE_TEMP_SGRAD;
00384       bool haveSpatSGrad = HAVE_SPAT_SGRAD;
00385       if(args.size() > 5)
00386         {
00387           haveMotion    = bool(atoi(args[1].c_str())); 
00388           haveTempSGrad = bool(atoi(args[2].c_str())); 
00389           haveSpatSGrad = bool(atoi(args[3].c_str())); 
00390         }
00391       
00392       float dx = 0.0; float dy = 0.0;
00393       //float dx = pshift.i; float dy = pshift.j;
00394       if(args.size() > 5)
00395         {
00396           dx = atof(args[4].c_str()); 
00397           dy = atof(args[5].c_str()); 
00398         }
00399       
00400       float dotOrgDSize = DOT_ORG_DSIZE; 
00401       if(args.size() > 6)
00402         {
00403           dotOrgDSize =  atof(args[6].c_str());
00404         }        
00405       
00406       // planar (Yaw-Pitch) motion correction
00407       uint dir =  0.0; float speed = 0.0;
00408       if(args.size() > 8)
00409         {
00410           dir   = uint(atoi(args[7].c_str()));
00411           speed = atof(args[8].c_str()); 
00412           fd->setObserverRotation(dir, speed);
00413         }
00414       
00415       LINFO("[%3d] haveMotion: %d haveTempSGrad: %d haveSpatSGrad: %d "
00416             "dx dy: %7.3f %7.3f dotOrgDSize: %f comp: %d %f",
00417             step, haveMotion, haveTempSGrad, haveSpatSGrad, 
00418             dx, dy, dotOrgDSize, dir, speed);
00419       lum = getFoeDots(step, haveMotion, haveTempSGrad, haveSpatSGrad, 
00420                        dx, dy, dotOrgDSize);
00421       
00422           //float px = 2.0; float py = 0.0;
00423 //           if(manager.numExtraArgs() > 2)
00424 //             {
00425 //               dx = manager.getExtraArgAs<float>(1); 
00426 //               dy = manager.getExtraArgAs<float>(2); 
00427 //             }
00428           //lum = getPlanarMotionStimuli(lum, step, px, py);
00429     }
00430   else if(!stimuli.compare("PlanarDots"))
00431     {
00432       Image<byte> temp(WIDTH, HEIGHT, ZEROS);
00433       
00434       float dx = 0.0; float dy = 0.0;
00435       if(args.size() > 2)
00436         {
00437           dx = atof(args[1].c_str()); 
00438           dy = atof(args[2].c_str()); 
00439         }
00440       lum = getPlanarMotionStimuli(temp, step, dx, dy);
00441     }
00442   else if(!stimuli.compare("PlanarImage")) 
00443     {
00444       uint total = 30;  // 15 for the Fukuchi, et. al. paper
00445       float dx =  0.0; float dy = 0.0;
00446       if(args.size() > 2)
00447         {
00448           dx = atof(args[1].c_str()); 
00449           dy = atof(args[2].c_str()); 
00450         }
00451       lum = getPlanarMotionImage(step, total, dx, dy, lum);
00452     }
00453   else LFATAL("Wrong option");
00454 
00455   return lum;
00456 }
00457 
00458 // ######################################################################
00459  Image<byte> calculateShift(Image<byte> lum, Image<byte> prevLum,
00460                             nub::ref<OutputFrameSeries> ofs)
00461 {
00462   VisualObjectMatchAlgo voma(VOMA_SIMPLE);
00463 //   if (strcmp(argv[1], "KDTree") == 0) voma = VOMA_KDTREE;
00464 //   else if (strcmp(argv[1], "KDBBF") == 0) voma = VOMA_KDTREEBBF;
00465 //   else if (strcmp(argv[1], "Simple") != 0)
00466 //     LFATAL("Unknown matching method %s", argv[0]);
00467 
00468   // create visual objects:
00469   rutz::shared_ptr<VisualObject> vo1(new VisualObject("lum", "", lum));
00470   rutz::shared_ptr<VisualObject> vo2(new VisualObject("plum", "", prevLum));
00471 
00472   // compute the matching keypoints:
00473   VisualObjectMatch match(vo1, vo2, voma);
00474   LDEBUG("Found %u matches", match.size());
00475 
00476   // let's prune the matches:
00477   uint np = match.prune();
00478   LDEBUG("Pruned %u outlier matches.", np);
00479 
00480   // show our final affine transform:
00481   SIFTaffine s = match.getSIFTaffine();
00482   LDEBUG("[tstX]   [ %- .3f %- .3f ] [refX]   [%- .3f]", s.m1, s.m2, s.tx);
00483   LDEBUG("[tstY] = [ %- .3f %- .3f ] [refY] + [%- .3f]", s.m3, s.m4, s.ty);
00484 
00485 
00486   LDEBUG("getKeypointAvgDist = %f", match.getKeypointAvgDist());
00487   LDEBUG("getAffineAvgDist = %f", match.getAffineAvgDist());
00488   LDEBUG("getScore = %f", match.getScore());
00489 
00490   if (match.checkSIFTaffine() == false)
00491     LINFO("### Affine is too weird -- BOGUS MATCH");
00492 
00493   // get an image showing the matches:
00494   Image< PixRGB<byte> > mimg = match.getMatchImage(1.0F);
00495   Image< PixRGB<byte> > fimg = match.getFusedImage(0.25F);
00496 
00497   // LINFO("lum");
00498   // ofs->writeRGB
00499   //   (toRGB(lum), "test-FOE Main", FrameInfo("foe output", SRC_POS));
00500   // Raster::waitForKey();
00501 
00502   // LINFO("prevLum");
00503   // ofs->writeRGB
00504   //   (toRGB(prevLum), "test-FOE Main", FrameInfo("foe output", SRC_POS));
00505   // Raster::waitForKey();
00506 
00507 
00508   LINFO("Shift: %f %f", s.tx, s.ty);
00509   // ofs->writeRGB
00510   //   (fimg, "test-FOE Main", FrameInfo("foe output", SRC_POS));
00511   // Raster::waitForKey();
00512 
00513   Image<byte> res = shiftImage(s, lum, prevLum);
00514 
00515   // LINFO("shifted result");
00516   // ofs->writeRGB
00517   //   (toRGB(res), "test-FOE Main", FrameInfo("foe output", SRC_POS));
00518   // Raster::waitForKey();
00519 
00520   //Point2D<float> shift(s.tx,s.ty);
00521   return res;
00522 }
00523 
00524 // ######################################################################
00525  Image<byte> shiftImage(SIFTaffine aff, Image<byte> refi, Image<byte> tsti)
00526 {
00527   // we loop over all pixel locations in the ref image, transform the
00528   // coordinates using the forward affine transform, get the pixel
00529   // value in the test image, and mix:
00530 
00531   uint w = refi.getWidth(), h = refi.getHeight();
00532   Image<byte> result(w, h, ZEROS);
00533   Image<byte>::const_iterator rptr = refi.begin();
00534   Image<byte>::iterator dptr = result.beginw();
00535 
00536   for (uint j = 0; j < h; j ++)
00537     for (uint i = 0; i < w; i ++)
00538       {
00539         float u, v;
00540         aff.transform(float(i), float(j), u, v);
00541         byte rval = *rptr++;
00542 
00543         if (tsti.coordsOk(u, v))
00544           {
00545             byte tval = tsti.getValInterp(u, v);
00546             //PixRGB<byte> mval = PixRGB<byte>(rval * mix + tval * (1.0F - mix));
00547             *dptr++ = tval;
00548           }
00549         else
00550           //*dptr++ = PixRGB<byte>(rval * mix);
00551           *dptr++ = byte(rval);
00552       }
00553 
00554   return result; 
00555  }
00556 
00557 
00558 // ######################################################################
00559 Image<byte> getApertureProblemStimuli(uint step)
00560 {
00561   Image<byte> temp(WIDTH, HEIGHT, ZEROS);
00562 
00563   // create dot initially
00564   if(step == 0)
00565     {
00566       dots.resize(1); 
00567       // top left
00568       dots[0] = Point2D<float> (WIDTH/2, HEIGHT/4);      
00569     }
00570 
00571   uint len = 15;
00572   // APERTURE PROBLEM
00573   //===============================================
00574   dots[0] = Point2D<float>(dots[0].i + 2.0, dots[0].j);
00575   drawLine
00576     (temp, 
00577      Point2D<int>(dots[0].i-len, dots[0].j-len),
00578      Point2D<int>(dots[0].i+len, dots[0].j+len), byte(255), 1);
00579   
00580   return temp;
00581 }
00582 
00583 // ######################################################################
00584 Image<byte> getShapeStimuli(uint step)
00585 {
00586   Image<byte> temp(WIDTH, HEIGHT, ZEROS);
00587   // moving left
00588 //   Rectangle r(Point2D<int>(100,100), Dims(20,20));
00589 //   //Rectangle r(Point2D<int>(0+step*10,0+step*10), Dims(20,20));
00590 //   if(step%2 ==0)
00591 //     drawFilledRect(temp,r,byte(255));
00592 //   //if(step%2 ==0)
00593 //   //drawDisk(temp,Point2D<int>(100+step*1,100+step*1),5,byte(255));    
00594   return temp;
00595 }
00596 
00597 // ######################################################################
00598 Image<byte> getBarStimuli(uint step)
00599 {
00600   Image<byte> temp(WIDTH, HEIGHT, ZEROS);
00601 
00602   // initially create dots
00603   if(step == 0)
00604     {
00605       dots.resize(4); dotSizes.resize(4);
00606 
00607       // top left
00608       dots[0] = Point2D<float> (WIDTH/2, HEIGHT/4);      
00609       dotSizes[0] = 1.0;  
00610       dots[1] = Point2D<float> (WIDTH/4, HEIGHT/2);      
00611       dotSizes[1] = 1.0; 
00612       dots[2] = Point2D<float> (WIDTH/8, HEIGHT/4);      
00613       dotSizes[2] = 1.0;      
00614       dots[3] = Point2D<float> (WIDTH/4, HEIGHT/8);      
00615       dotSizes[3] = 1.0;
00616 
00617       // bottom right
00618 //       dots[0] = Point2D<float> (7*WIDTH/8, 3*HEIGHT/4);      
00619 //       dotSizes[0] = 1.0;  
00620 //       dots[1] = Point2D<float> (3*WIDTH/4, 7*HEIGHT/8);      
00621 //       dotSizes[1] = 1.0; 
00622 //       dots[2] = Point2D<float> (WIDTH/2, 3*HEIGHT/4);      
00623 //       dotSizes[2] = 1.0;      
00624 //       dots[3] = Point2D<float> (3*WIDTH/4, HEIGHT/2);      
00625 //       dotSizes[3] = 1.0; 
00626 
00627     }
00628 
00629   // move the dots if needed
00630   if(HAVE_MOTION)
00631     {
00632       //for(uint i = 0; i < dotNum; i++)
00633         dots[0] = Point2D<float>(dots[0].i + 2.0, dots[0].j);
00634         dots[1] = Point2D<float>(dots[1].i,       dots[1].j + 1.0);
00635         dots[2] = Point2D<float>(dots[2].i - 1.0, dots[2].j);
00636         dots[3] = Point2D<float>(dots[3].i,       dots[3].j - 1.0);
00637 
00638         //LINFO("loc: %f %f: size: %f", dots[i].i, dots[i].j, dotSizes[i]);      
00639     }
00640   // finally draw the dots
00641   //for(uint i = 0; i < dotNum; i++)
00642     //drawDisk(temp,Point2D<int>(dots[i].i, dots[i].j),dotSizes[i],byte(255));
00643 
00644     //drawDisk(temp,Point2D<int>(dots[0].i, dots[0].j), 1.0,byte(255));
00645     //drawDisk(temp,Point2D<int>(dots[1].i, dots[1].j), 1.0,byte(255));
00646     //drawDisk(temp,Point2D<int>(dots[2].i, dots[2].j), 1.0,byte(255));
00647     //drawDisk(temp,Point2D<int>(dots[3].i, dots[3].j), 1.0,byte(255));
00648 
00649   drawLine
00650     (temp, 
00651      Point2D<int>(dots[0].i, dots[0].j-15),
00652      Point2D<int>(dots[0].i, dots[0].j+15), byte(255), 1);  
00653 
00654   // control the thickness of the line
00655 //     drawLine
00656 //       (temp, 
00657 //        Point2D<int>(dots[0].i, dots[0].j-15),
00658 //        Point2D<int>(dots[0].i, dots[0].j+15), byte(255), 1);
00659 //     drawLine
00660 //       (temp, 
00661 //        Point2D<int>(dots[0].i+1, dots[0].j-15),
00662 //        Point2D<int>(dots[0].i+1, dots[0].j+15), byte(255), 1);
00663 //     drawLine
00664 //       (temp, 
00665 //        Point2D<int>(dots[0].i-1, dots[0].j-15),
00666 //        Point2D<int>(dots[0].i-1, dots[0].j+15), byte(255), 1);
00667 //     drawLine
00668 //       (temp, 
00669 //        Point2D<int>(dots[0].i-2, dots[0].j-15),
00670 //        Point2D<int>(dots[0].i-2, dots[0].j+15), byte(255), 1);
00671 //     drawLine
00672 //       (temp, 
00673 //        Point2D<int>(dots[0].i-3, dots[0].j-15),
00674 //        Point2D<int>(dots[0].i-3, dots[0].j+15), byte(255), 1);
00675 //     drawLine
00676 //       (temp, 
00677 //        Point2D<int>(dots[0].i+2, dots[0].j-15),
00678 //        Point2D<int>(dots[0].i+2, dots[0].j+15), byte(255), 1);
00679 //     drawLine
00680 //       (temp, 
00681 //        Point2D<int>(dots[0].i-4, dots[0].j-15),
00682 //        Point2D<int>(dots[0].i-4, dots[0].j+15), byte(255), 1);
00683 //     drawLine
00684 //       (temp, 
00685 //        Point2D<int>(dots[0].i+3, dots[0].j-15),
00686 //        Point2D<int>(dots[0].i+3, dots[0].j+15), byte(255), 1);
00687 
00688     //===============================================
00689 //     drawLine
00690 //       (temp, 
00691 //        Point2D<int>(dots[1].i-15, dots[1].j),
00692 //        Point2D<int>(dots[1].i+15, dots[1].j), byte(255), 1);
00693 
00694 //     drawLine
00695 //       (temp, 
00696 //        Point2D<int>(dots[2].i, dots[2].j-15),
00697 //        Point2D<int>(dots[2].i, dots[2].j+15), byte(255), 1);
00698 
00699 //     drawLine
00700 //       (temp, 
00701 //        Point2D<int>(dots[3].i-15, dots[3].j),
00702 //        Point2D<int>(dots[3].i+15, dots[3].j), byte(255), 1);
00703 
00704 
00705              //drawDisk(temp,Point2D<int>(dots[i].i, dots[i].j),dotSizes[i],byte(255));
00706   //temp.setVal(dots[i].i, dots[i].j, byte(128));
00707 
00708   //drawDisk(temp,Point2D<int>(FOE_X,FOE_Y),5,byte(128));    
00709 
00710   return temp;
00711 }
00712 
00713 // ######################################################################
00714 Image<byte> getPlanarMotionStimuli
00715 (Image<byte> temp, uint step, float dx, float dy)
00716 {
00717   //if(step > NFRAME) return Image<byte>();
00718 
00719   uint dotNum = 200;//200;//DOT_NUM;
00720 
00721   float orgDotSize = 1.0;
00722 
00723   // create random dot initially
00724   if(step == 0)
00725     {
00726       pdots.resize(dotNum); pdotSizes.resize(dotNum);
00727       for(uint i = 0; i < dotNum; i++)
00728         {
00729           pdots[i] = Point2D<float>
00730             (WIDTH  * double(rand())/(RAND_MAX + 1.0),
00731              HEIGHT * double(rand())/(RAND_MAX + 1.0));
00732           pdotSizes[i] = orgDotSize; 
00733         }
00734     }
00735   
00736   // check for out-of-bounds dot needed to be shown
00737   for(uint i = 0; i < dotNum; i++)
00738     {
00739       // NOTE: can also kill dots randomly before going out of the image
00740       if(!temp.getBounds().contains(Point2D<int>(pdots[i].i, pdots[i].j))) 
00741         {
00742           float srx = 0.0;   float sry = 0.0;
00743           float rx  = WIDTH; float ry  = HEIGHT;
00744           if(dx < 0.0)     { srx = 7.0*WIDTH/8.0; rx  = WIDTH/8; }
00745           else if(dx > 0.0){ srx = 0.0;           rx  = WIDTH/8; }
00746           
00747           if(dy < 0.0)     { sry = 7.0*HEIGHT/8.0; ry  = HEIGHT/8; }
00748           else if(dy > 0.0){ sry = 0.0;            ry  = HEIGHT/8; }
00749 
00750           float sx = rx * double(rand())/(RAND_MAX + 1.0) + srx; 
00751           float sy = ry * double(rand())/(RAND_MAX + 1.0) + sry;
00752           
00753           pdots[i] = Point2D<float>(sx,sy);
00754           pdotSizes[i] = orgDotSize; 
00755           LDEBUG("new dots[%3d]: %7.3f %7.3f", i, sx, sy);
00756         }
00757       else
00758         {
00759           Point2D<int> pt(pdots[i].i, pdots[i].j);
00760           LDEBUG("[%3d] it's ok: (%7.3f %7.3f) -> %3d %3d", 
00761                  i, pdots[i].i, pdots[i].j, pt.i, pt.j);
00762         }
00763     }
00764 
00765   // planar motion
00766   if(dx != 0.0 || dy != 0.0)
00767     for(uint i = 0; i < dotNum; i++)
00768       {
00769         pdots[i] = Point2D<float>(pdots[i].i + dx, 
00770                                   pdots[i].j + dy);
00771       }
00772 
00773   // finally draw the dots
00774   for(uint i = 0; i < dotNum; i++)
00775     {
00776       LDEBUG("[%d] loc: %10.3f %10.3f: size: %7.3f", 
00777              i, pdots[i].i, pdots[i].j, pdotSizes[i]);
00778       drawDisk(temp,Point2D<int>(pdots[i].i, pdots[i].j),
00779                pdotSizes[i],byte(255));
00780       //temp.setVal(pdots[i].i, pdots[i].j, byte(128));
00781     }
00782   return temp;
00783 }
00784 
00785 // ######################################################################
00786 Image<byte> orgPlanarImage;
00787 Image<byte> getPlanarMotionImage
00788 (uint step, uint totalStep, float dx, float dy, Image<byte> image)
00789 {
00790   // just loop it 
00791   step = step % totalStep;
00792 
00793   // set original image on first step
00794   if(step == 0)
00795     { 
00796       orgPlanarImage = image;
00797     }
00798   image = orgPlanarImage;
00799   
00800   uint width  = image.getWidth();
00801   uint height = image.getHeight(); 
00802   float scale =  1.25;
00803   Image<byte> temp = rescale(image, scale*width, scale*height);
00804   float nwidth  = temp.getWidth();
00805   float nheight = temp.getHeight(); 
00806 
00807   float sleft = 0.0; if(dx < 0.0) sleft = nwidth  - 1 - width;
00808   float stop  = 0.0; if(dy < 0.0) stop  = nheight - 1 - height; 
00809   
00810   float left  = sleft + dx*step;
00811   float top   = stop  + dy*step; 
00812 
00813   //if(top  < 0.0) top  = 0.0;
00814   //if(left < 0.0) left = 0.0;
00815 
00816   Rectangle r = 
00817     Rectangle::tlbrI(top, left, top+height-1, left+width-1);
00818 
00819 //   LINFO("[%3d/%3d] FOE(%7.3f %7.3f) %f p(%7.3f %7.3f) [[%7.3f %7.3f]] " 
00820 //          "[%3d %3d %3d %3d] temp(%3d %3d) ((%3d %3d))", 
00821 //         step, totalStep, 
00822 //         foeX,foeY, scale, px, py, top, left,
00823 //         r.top(), r.left(), r.bottomI(), r.rightI(), 
00824 //         temp.getWidth(), temp.getHeight(),
00825 //         r.width(),r.height());
00826   Image<byte> result = crop(temp, r);
00827 
00828   return result;
00829 }
00830 
00831 // ######################################################################
00832 Image<byte> getFoeDots
00833 (uint step, bool haveMotion, bool  haveTempSGrad, bool haveSpatSGrad,
00834  float dx, float dy, float dotOrgDSize)
00835 {
00836   //if(step > NFRAME) return Image<byte>();
00837 
00838   Image<byte> temp(WIDTH, HEIGHT, ZEROS);
00839 
00840   float orgDotSize = 1.0;
00841 
00842   // create random dot initially
00843   if(step == 0)
00844     {
00845       dots.resize(DOT_NUM); dotSizes.resize(DOT_NUM);
00846       for(uint i = 0; i < DOT_NUM; i++)
00847         {
00848           dots[i] = Point2D<float>
00849             (WIDTH  * double(rand())/(RAND_MAX + 1.0),
00850              HEIGHT * double(rand())/(RAND_MAX + 1.0));
00851 
00852           // just do it in order to get identical average size
00853           //float range = MAX_DOT_SIZE - MIN_DOT_SIZE;
00854           //dotSizes[i] = i*range/(DOT_NUM-1.0)+ double(MIN_DOT_SIZE); 
00855           dotSizes[i] = orgDotSize; 
00856         }
00857     }
00858 
00859   // check for out-of-bounds dot needed to be shown
00860   for(uint i = 0; i < DOT_NUM; i++)
00861     {
00862       // NOTE: can also kill dots randomly before going out of the image
00863       // NOTE: how about adding new dots in the FOE quadrants
00864       if(!temp.getBounds().contains(Point2D<int>(dots[i].i, dots[i].j))) 
00865         {
00866           dots[i] = Point2D<float>
00867             (WIDTH  * double(rand())/(RAND_MAX + 1.0),
00868              HEIGHT * double(rand())/(RAND_MAX + 1.0) );
00869 
00870           // keep the sizes or 1.0?
00871           dotSizes[i] = orgDotSize; 
00872         }
00873     }
00874 
00875   // modify sizes according to rules
00876   for(uint i = 0; i < DOT_NUM; i++)
00877     {
00878       if(haveTempSGrad && haveSpatSGrad)
00879         {
00880           float dist = sqrt(pow((dots[i].i - FOE_X), 2.0) + 
00881                             pow((dots[i].j - FOE_Y), 2.0)  ); 
00882           if(haveMotion)
00883             {
00884               dotSizes[i] = dotOrgDSize * dist;
00885             }
00886           // growing, FOE coherent, but not moving 
00887           else
00888             {
00889               if(step == 0)
00890                 {
00891                   dotSizes[i] = dotOrgDSize * dist;
00892                 }
00893               else
00894                 {
00895                   // increase until ABS_MAX_DSIZE, then stop
00896                   if(dotSizes[i] < ABS_MAX_DSIZE)
00897                     {
00898                       dotSizes[i] = (1.0 + DOT_DSIZE) *
00899                         dotOrgDSize * dist;
00900                     }
00901                   // else dot size stays the same
00902                 }
00903             }
00904         }
00905       else if(haveTempSGrad && !haveSpatSGrad)
00906         {
00907           // all dot have same size just increase 
00908           float ds = MAX_DOT_SIZE - MIN_DOT_SIZE;
00909           dotSizes[i] = step*ds/(NFRAME - 1.0)+ double(MIN_DOT_SIZE); 
00910         }
00911       else if(!haveTempSGrad && haveSpatSGrad)
00912         {
00913           float dist = sqrt(pow((dots[i].i - FOE_X), 2.0) + 
00914                             pow((dots[i].j - FOE_Y), 2.0)  ); 
00915           dotSizes[i] = dotOrgDSize * dist;
00916         }
00917       // else just keep size 
00918     }
00919 
00920   // move the dots if needed
00921   if(haveMotion)
00922     for(uint i = 0; i < DOT_NUM; i++)
00923       {
00924         dots[i] = Point2D<float>
00925           (dots[i].i + DOT_VEL * (dots[i].i - FOE_X),
00926            dots[i].j + DOT_VEL * (dots[i].j - FOE_Y));
00927       }
00928 
00929   // add lateral motion
00930   if(dx != 0.0 || dy != 0.0)
00931     for(uint i = 0; i < DOT_NUM; i++)
00932       {
00933         dots[i] = Point2D<float>(dots[i].i + dx, dots[i].j + dy);
00934       }
00935 
00936   // finally draw the dots
00937   for(uint i = 0; i < DOT_NUM; i++)
00938     {
00939       //LINFO("loc: %10.3f %10.3f: size: %7.3f", 
00940       //      dots[i].i, dots[i].j, dotSizes[i]);
00941       drawDisk(temp,Point2D<int>(dots[i].i, dots[i].j),dotSizes[i],byte(255));
00942       //temp.setVal(dots[i].i, dots[i].j, byte(128));
00943     }
00944 
00945   // draw the FOE
00946   //drawDisk(temp,Point2D<int>(FOE_X,FOE_Y),2,byte(128));    
00947 
00948   return temp;
00949 }
00950 
00951 
00952 // ######################################################################
00953 // this is stimuli like in Fukuchi,Tsuchiya,Koch VSS/JOV 2009/2010
00954 // FOE is FOE_X,FOE_Y
00955 Image<byte> orgImage;
00956 Image<byte> getCleanFOE
00957 (uint step, uint totalStep, uint mag, float dx, float dy, Image<byte> image)
00958 {
00959   // just loop it 
00960   step = step % totalStep;
00961 
00962   // set original image on first step
00963   if(step == 0)
00964     { 
00965       orgImage = image;
00966       return image; 
00967     }
00968   image = orgImage;
00969   
00970   uint width  = image.getWidth();
00971   uint height = image.getHeight(); 
00972 
00973   float nsize = (step/(totalStep - 1.0));
00974   float scale =  1.0 / (1.0 - nsize*1.0/mag);
00975   Image<byte> temp = rescale(image, scale*width, scale*height);
00976   float nwidth  = temp.getWidth();
00977   float nheight = temp.getHeight(); 
00978 
00979   float px = float(FOE_X)/float(width);
00980   float py = float(FOE_Y)/float(height);
00981 
00982   float foeX  = px*nwidth; 
00983   float foeY  = py*nheight; 
00984 
00985   float left  = foeX - float(FOE_X) + dx*step;
00986   float top   = foeY - float(FOE_Y) + dy*step; 
00987 
00988   //if(top  < 0.0) top  = 0.0;
00989   //if(left < 0.0) left = 0.0;
00990 
00991   Rectangle r = 
00992     Rectangle::tlbrI(top, left, top+height-1, left+width-1);
00993 
00994   LINFO("[%3d/%3d] FOE(%7.3f %7.3f) %f p(%7.3f %7.3f) [[%7.3f %7.3f]] " 
00995          "[%3d %3d %3d %3d] temp(%3d %3d) ((%3d %3d))", 
00996         step, totalStep, 
00997         foeX,foeY, scale, px, py, top, left,
00998         r.top(), r.left(), r.bottomI(), r.rightI(), 
00999         temp.getWidth(), temp.getHeight(),
01000         r.width(),r.height());
01001   Image<byte> result = crop(temp, r);
01002 
01003   return result;
01004 }
01005 
01006 // ######################################################################
01007 /* So things look consistent in everyone's emacs... */
01008 /* Local Variables: */
01009 /* indent-tabs-mode: nil */
01010 /* End: */
Generated on Sun May 8 08:05:36 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3