test-raomodel.C

Go to the documentation of this file.
00001 /*!@file AppNeuro/test-raomodel.C test model by Rao et al., Vis Res 2002 */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Philip Williams <plw@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppNeuro/test-raomodel.C $
00035 // $Id: test-raomodel.C 10982 2009-03-05 05:11:22Z itti $
00036 //
00037 
00038 #include "Channels/ChannelBase.H"
00039 #include "Channels/Jet.H"
00040 #include "Channels/JetFiller.H"
00041 #include "Component/ModelManager.H"
00042 #include "Image/DrawOps.H"
00043 #include "Image/MathOps.H"
00044 #include "Image/Pixels.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Media/MediaSimEvents.H"
00047 #include "Channels/ChannelOpts.H"
00048 #include "Channels/RawVisualCortex.H"
00049 #include "Simulation/SimEventQueueConfigurator.H"
00050 #include "Simulation/SimEventQueue.H"
00051 #include "Raster/Raster.H"
00052 #include "Util/log.H"
00053 
00054 #include <fstream>
00055 #include <string>
00056 
00057 #define SMIN 1
00058 #define SMAX 3
00059 
00060 namespace
00061 {
00062   // ######################################################################
00063   Image<float> getRaoJetMap(RawVisualCortex& vc,
00064                             const Jet<float>& targ,
00065                             const int smin, const int smax)
00066   {
00067     const int w = vc.getInputDims().w() >> smin;
00068     const int h = vc.getInputDims().h() >> smin;
00069     Image<float> result(w, h, NO_INIT);
00070     Jet<float> currJet(targ.getSpec());
00071 
00072     // now loop over the entire image and compute a weighted Jet
00073     // distance between that central Jet and the Jets extracted from all
00074     // the other locations in the image:
00075     for (int x = 0; x < w; x++)
00076       for (int y = 0; y < h; y++)
00077         {
00078           JetFiller f(Point2D<int>(x << smin, y << smin), currJet, false);
00079           vc.accept(f);
00080           result.setVal(x, y, float(raodistance(targ, currJet, smin, smax)));
00081         }
00082     return result;
00083   }
00084 }
00085 
00086 int main(const int argc, const char** argv)
00087 {
00088   // Instantiate a ModelManager:
00089   ModelManager manager("Test Rao Model");
00090 
00091   // create brain:
00092   nub::soft_ref<SimEventQueueConfigurator>
00093     seqc(new SimEventQueueConfigurator(manager));
00094   manager.addSubComponent(seqc);
00095 
00096   nub::soft_ref<RawVisualCortex> vcx(new RawVisualCortex(manager));
00097   manager.addSubComponent(vcx);
00098   manager.setOptionValString(&OPT_RawVisualCortexChans, "ICO");
00099 
00100   // Parse command-line:
00101   if (manager.parseCommandLine(argc, argv,
00102                                "jet <image.ppm> <x> <y> <jet.txt>   -OR-   "
00103                                "jet2 <image.ppm> <target.pgm> <jet.txt> -OR-  "
00104                                "snr <image.ppm> <target.pgm> <jet.txt> <lambda> <map.pgm>  -OR-  "
00105                                "search <image.ppm> <jet.txt> <lambda>",
00106                                4, 6) == false)
00107     return(1);
00108 
00109   // make sure all feature values are in [0..255]:
00110   manager.setModelParamVal("GaborChannelIntensity", 100.0, MC_RECURSE);
00111   nub::soft_ref<SimEventQueue> seq = seqc->getQ();
00112 
00113   bool do_jet = false, do_jet2 = false, do_snr = false, do_search = false;
00114   std::string action = manager.getExtraArg(0);
00115   if (action.compare("jet") == 0)
00116     {
00117       if (manager.numExtraArgs() != 5)
00118         LFATAL("USAGE: %s jet <image.ppm> <x> <y> <jet.txt>", argv[0]);
00119       do_jet = true;
00120     }
00121   else if (action.compare("jet2") == 0)
00122     {
00123       if (manager.numExtraArgs() != 4)
00124         LFATAL("USAGE: %s jet2 <image.ppm> <target.pgm> <jet.txt>", argv[0]);
00125       do_jet2 = true;
00126     }
00127   else if (action.compare("snr") == 0)
00128     {
00129       if (manager.numExtraArgs() != 6)
00130         LFATAL("USAGE: %s snr <image.ppm> <target.pgm> <jet.txt> <lambda> <map.pgm>", argv[0]);
00131       do_snr = true;
00132     }
00133   else if (action.compare("search") == 0)
00134     {
00135       if (manager.numExtraArgs() != 4)
00136         LFATAL("USAGE: %s search <image.ppm> <jet.txt> <lambda>", argv[0]);
00137       do_search = true;
00138     }
00139   else
00140     LFATAL("Incorrect usage -- try to run without args to see usage.");
00141 
00142   // Read input image from disk:
00143   Image< PixRGB<byte> > col_image =
00144     Raster::ReadRGB(manager.getExtraArg(1));
00145 
00146   // get model started:
00147   manager.start();
00148 
00149   // process the input image:
00150   vcx->input(InputFrame::fromRgb(&col_image));
00151   vcx->getOutput();
00152 
00153   rutz::shared_ptr<JetSpec> js(new JetSpec);
00154 
00155 
00156   js->addIndexRange(COLBAND, RAW, 0, 5);
00157   js->addIndexRange(COLBAND, RAW, SMIN, SMAX);
00158   js->addIndexRange(INTENS, RAW, 0, 3);
00159   js->addIndexRange(INTENS, RAW, SMIN, SMAX);
00160   /*
00161   js->addIndexRange(RG, RAW, SMIN, SMAX);
00162   js->addIndexRange(BY, RAW, SMIN, SMAX);
00163   js->addIndexRange(INTENS, RAW, SMIN, SMAX);
00164   */
00165 
00166 
00167   const uint nori = vcx->subChan("orientation")->getModelParamVal<uint>("NumOrientations");
00168   js->addIndexRange(ORI, RAW, 0, nori - 1);
00169   js->addIndexRange(ORI, RAW, SMIN, SMAX);
00170   js->print();
00171 
00172   // ===================================================================
00173   // do we want to just read out a jet using the (x,y) coordinate?
00174   if (do_jet)
00175     {
00176       int x = manager.getExtraArgAs<int>(2);
00177       int y = manager.getExtraArgAs<int>(3);
00178       Point2D<int> p(x, y);
00179 
00180       // initialize a Jet according to our JetSpec:
00181       Jet<float> j(js);
00182       JetFiller f(p, j, false);
00183       vcx->accept(f);
00184 
00185       // save it to disk:
00186       std::ofstream s(manager.getExtraArg(4).c_str());
00187       if (s.is_open() == false)
00188         LFATAL("Cannot write %s", manager.getExtraArg(4).c_str());
00189       s<<j<<std::endl;
00190       s.close();
00191       LINFO("Saved Jet(%d, %d) to %s -- DONE.", x, y,
00192             manager.getExtraArg(4).c_str());
00193     }
00194 
00195   // =========================================================================
00196   // do we want to just read out a jet using the target mask?
00197   if (do_jet2)
00198     {
00199       // Read target image from disk:
00200       Image<byte> target =
00201         Raster::ReadGray(manager.getExtraArg(2));
00202 
00203       // find the target coordinates
00204       int w = target.getWidth(), h = target.getHeight();
00205       int t = h+1, b = -1, l = w+1, r = -1;
00206       for (int i = 0; i < w; i++)
00207         for (int j = 0; j < h; j++)
00208           if (target.getVal(i,j) > 200){
00209             if (j < t) t = j;
00210             if (i < l) l = i;
00211             if (i > r) r = i;
00212             if (j > b) b = j;
00213           }
00214       int x = (r + l) / 2;
00215       int y = (t + b)/ 2;
00216       Point2D<int> p(x, y);
00217 
00218       // initialize a Jet according to our JetSpec:
00219       Jet<float> j(js);
00220       JetFiller f(p, j, false);
00221       vcx->accept(f);
00222 
00223       // save it to disk:
00224       std::ofstream s(manager.getExtraArg(3).c_str());
00225       if (s.is_open() == false)
00226         LFATAL("Cannot write %s", manager.getExtraArg(3).c_str());
00227       s<<j<<std::endl;
00228       s.close();
00229       LINFO("Saved Jet(%d, %d) to %s -- DONE.", x, y,
00230             manager.getExtraArg(3).c_str());
00231     }
00232 
00233   // =======================================================================
00234   // do we want to get a jetmap?
00235   if (do_snr)
00236     {
00237       // Read target image from disk:
00238       Image<byte> targetMask =
00239         Raster::ReadGray(manager.getExtraArg(2));
00240 
00241       std::ifstream s(manager.getExtraArg(3).c_str());
00242       if (s.is_open() == false)
00243         LFATAL("Cannot read %s", manager.getExtraArg(3).c_str());
00244       Jet<float> j(js);
00245       s>>j; s.close();
00246 
00247       float lambda = manager.getExtraArgAs<float>(4);
00248 
00249       // get the coarsest map:
00250       Image<float> jmap = getRaoJetMap(*vcx, j, SMAX, SMAX);
00251       float mi, ma; getMinMax(jmap, mi, ma);
00252       LINFO("jmap range [%f .. %f]", mi, ma);
00253 
00254       // apply softmax: Note that here we also divide the squared
00255       // distance values by 65535 such as to bring them back to a
00256       // [0..1] range which I guess was assumed by Rao et al:
00257       Image<float> fmap = exp(jmap * (-1.0f / (lambda*65535.0f)));
00258       float denom = sum(fmap); fmap *= 1.0f / denom;
00259 
00260       // compute SNR = max(sT) / max(sD)
00261       Image<float> targetMap(fmap.getDims(), ZEROS);
00262       float sT = 0.0f, sD = 0.0f;
00263       float BG_FIRING_RATE = 0.1f;
00264       if (targetMask.initialized()){
00265         // first scale the target mask to match the size of fmap
00266         if (targetMask.getWidth() > fmap.getWidth())
00267           targetMap = downSize(targetMask, fmap.getDims());
00268         else if (targetMask.getWidth() < fmap.getWidth())
00269           targetMap = rescale(targetMask, fmap.getDims());
00270         else
00271           targetMap = targetMask;
00272         // find sT as max salience within the target object
00273         // find sD as max salience outside the target object
00274         Image<float>::const_iterator aptr = targetMap.begin(),
00275           astop = targetMap.end();
00276         Image<float>::const_iterator sptr = fmap.begin(),
00277           sstop = fmap.end();
00278         while (aptr != astop && sptr != sstop)
00279           {
00280             if (*aptr > 0.0f){
00281               if (sT < *sptr)
00282                 sT = *sptr;
00283             }
00284             else {
00285               if (sD < *sptr)
00286                 sD = *sptr;
00287             }
00288             aptr++; sptr++;
00289           }
00290       }
00291       // find SNR
00292       float SNR = log((sT + BG_FIRING_RATE) / (sD + BG_FIRING_RATE));
00293       LINFO ("sT = %f, sD = %f", sT, sD);
00294       LINFO ("-------------- SNR = %f dB", SNR);
00295 
00296       // output the SNR in a file
00297       FILE * fout = fopen("snr", "w");
00298       fprintf(fout, " SNR = %f dB", SNR);
00299       fclose(fout);
00300 
00301       // save the map:
00302       Raster::WriteFloat(fmap, FLOAT_NORM_0_255, manager.getExtraArg(5), RASFMT_PNM);
00303 
00304       LINFO("Saved Fmap to %s -- DONE.", manager.getExtraArg(5).c_str());
00305     }
00306 
00307   // ======================================================================
00308   // do we want to search?
00309   if (do_search)
00310     {
00311       std::ifstream s(manager.getExtraArg(2).c_str());
00312       if (s.is_open() == false)
00313         LFATAL("Cannot read %s", manager.getExtraArg(2).c_str());
00314       Jet<float> j(js);
00315       s>>j; s.close();
00316 
00317       // start with the coarsest scale only and progressively include
00318       // more scales:
00319       float lambda = atof(manager.getExtraArg(3).c_str());
00320       for (int k = SMAX; k >= SMIN; k --)
00321         {
00322           LINFO("Using scales [%d .. %d], lambda = %f", k, SMAX, lambda);
00323 
00324           // get the map:
00325           Image<float> jmap = getRaoJetMap(*vcx, j, k, SMAX);
00326           float mi, ma; getMinMax(jmap, mi, ma);
00327           LINFO("jmap range [%f .. %f]", mi, ma);
00328 
00329           // apply softmax: Note that here we also divide the squared
00330           // distance values by 65535 such as to bring them back to a
00331           // [0..1] range which I guess was assumed by Rao et al:
00332           Image<float> fmap = exp(jmap * (-1.0f / (lambda*65535.0f)));
00333           float denom = sum(fmap); fmap *= 1.0f / denom;
00334 
00335           // find the saccade target:
00336           float xhat = 0.0f, yhat = 0.0f;
00337           int w = fmap.getWidth(), h = fmap.getHeight();
00338           for (int jj = 0; jj < h; jj ++)
00339             for (int ii = 0; ii < w; ii ++)
00340               {
00341                 float val = fmap.getVal(ii, jj);
00342                 xhat += ii * val;
00343                 yhat += jj * val;
00344               }
00345           getMinMax(fmap, mi, ma);
00346           LINFO("fmap range [%f .. %f]", mi, ma);
00347           Point2D<int> win(int(xhat + 0.499f) << k, int(yhat + 0.499f) << k);
00348           LINFO("Saccade to (%d, %d)", win.i, win.j);
00349 
00350           // display fmap and winner:
00351           Raster::VisuFloat(fmap, FLOAT_NORM_0_255, "fmap.pgm");
00352           Image< PixRGB<byte> > traj(col_image);
00353           drawPatch(traj, win, 5, PixRGB<byte>(255, 255, 0));
00354           int foar = std::max(traj.getWidth(), traj.getHeight()) / 12;
00355           drawCircle(traj, win, foar, PixRGB<byte>(255, 255, 0), 3);
00356           Raster::VisuRGB(traj, "traj.ppm");
00357 
00358 
00359           // get ready for next saccade:
00360           lambda *= 0.5f;
00361         }
00362     }
00363 
00364   // all done!
00365   manager.stop();
00366   return 0;
00367 }
00368 
00369 // ######################################################################
00370 /* So things look consistent in everyone's emacs... */
00371 /* Local Variables: */
00372 /* indent-tabs-mode: nil */
00373 /* End: */
Generated on Sun May 8 08:04:11 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3