GistEstimatorGen.C

Go to the documentation of this file.
00001 /*!@file Neuro/GistEstimatorGen.C extract estimated gist
00002          using available features of the image                          */
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: Zhicheng Li <zhicheng@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/GistEstimatorGen.C $
00035 // $Id: GistEstimatorGen.C 13065 2010-03-28 00:01:00Z itti $
00036 //
00037 
00038 // ######################################################################
00039 /*! Extract gist of image                                              */
00040 
00041 
00042 #include "Neuro/GistEstimatorGen.H"
00043 #include "Component/ModelManager.H"
00044 #include "Channels/ChannelMaps.H"
00045 #include "Channels/BlueYellowChannel.H"
00046 #include "Channels/ColorChannel.H"
00047 #include "Channels/GaborChannel.H"
00048 #include "Channels/IntensityChannel.H"
00049 #include "Channels/OrientationChannel.H"
00050 #include "Channels/RedGreenChannel.H"
00051 #include "Channels/Hue1Channel.H"
00052 #include "Channels/Hue2Channel.H"
00053 #include "Channels/HueChannel.H"
00054 #include "Channels/H2SVChannel.H"
00055 #include "Channels/CIELabChannel.H"
00056 #include "Channels/JunctionChannel.H"
00057 #include "Channels/EndPointChannel.H"
00058 #include "Channels/TJunctionChannel.H"
00059 #include "Channels/LJunctionChannel.H"
00060 #include "Channels/XJunctionChannel.H"
00061 #include "GUI/XWinManaged.H"
00062 #include "Image/CutPaste.H"
00063 #include "Image/DrawOps.H"
00064 #include "Image/FilterOps.H"
00065 #include "Image/MathOps.H"
00066 #include "Image/ShapeOps.H"
00067 #include "Neuro/gistParams.H"
00068 #include "Raster/Raster.H"
00069 #include "Simulation/SimEventQueue.H"
00070 #include "Neuro/NeuroSimEvents.H"
00071 #include "Simulation/SimEvents.H"
00072 #include "Channels/ChannelOpts.H"
00073 #include "Channels/SingleChannel.H"
00074 #include "Util/Timer.H"
00075 #include "Util/StringUtil.H"
00076 #include "Neuro/NeuroOpts.H"
00077 
00078 #define PYR_LEVEL 5 // if without center surround then use 5 levels pyramid
00079 
00080 
00081 // ######################################################################
00082 // get subsum of an image - more efficient implementation
00083 Image<float> getSubSumGen(Image<float> img)
00084 {
00085   Image<float> res(1, 21, ZEROS);
00086 
00087   int w = img.getWidth();  int h = img.getHeight();
00088   std::vector<float> tempRes(21);
00089   for (int i = 0; i < 21; i++) tempRes[i] = 0.0;
00090   std::vector<int> counts(16);
00091   for (int i = 0 ; i < 16; i++) counts[i] = 0;
00092 
00093   Image<float>::const_iterator itr = img.begin();
00094   for (int y = 0; y < h; ++y)
00095     {
00096       int suby = (4*y)/h;
00097       for (int x = 0; x < w; ++x)
00098         {
00099           int subx = (4*x)/w;
00100           int subpos = 4*suby + subx;
00101           tempRes[subpos+5] += *itr;
00102 
00103           ++(counts[subpos]);
00104           ++itr;
00105         }
00106 
00107     }
00108 
00109   int order[] = { 5,6,9,10, 7,8,11,12, 13,14,17,18, 15,16,19,20 };
00110   for (int i = 0 ; i < 16; ++i)
00111     if (counts[i] > 0)
00112         res[i+5] =  tempRes[order[i]] / (counts[order[i] - 5]+ 0.0);
00113 
00114    float tre1 = tempRes[5] + tempRes[6] + tempRes[9] + tempRes[10];
00115    int ct1 = counts[0] + counts[1] + counts[4] + counts[5];
00116 
00117    float tre2 = tempRes[7] + tempRes[8] + tempRes[11] + tempRes[12];
00118    int ct2 = counts[2] + counts[3] + counts[6] + counts[7];
00119 
00120    float tre3 = tempRes[13] + tempRes[14] + tempRes[17] + tempRes[18];
00121    int ct3 = counts[8] + counts[9] + counts[12] + counts[13];
00122 
00123    float tre4 = tempRes[15] + tempRes[16] + tempRes[19] + tempRes[20];
00124    int ct4 = counts[10] + counts[11] + counts[14] + counts[15];
00125 
00126   res[1] = tre1/ct1;
00127   res[2] = tre2/ct2;
00128   res[3] = tre3/ct3;
00129   res[4] = tre4/ct4;
00130 
00131   res[0] = (tre1 + tre2 + tre3 + tre4)/(ct1 + ct2 + ct3 + ct4);
00132 
00133   LDEBUG("lev1   : %14.4f", res[0]);
00134   LDEBUG("lev2   : %14.4f, %14.4f", res[1], res[2]);
00135   LDEBUG("       : %14.4f, %14.4f", res[3], res[4]);
00136   LDEBUG("lev3   : %14.4f, %14.4f, %14.4f, %14.4f",
00137          res[ 5], res[ 6], res[ 9], res[10]);
00138   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00139          res[ 7], res[ 8], res[11], res[12]);
00140   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00141          res[13], res[14], res[17], res[18]);
00142   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00143          res[15], res[16], res[19], res[20]);
00144 
00145   return res;
00146 }
00147 
00148 
00149 // ######################################################################
00150 GistEstimatorGen::GistEstimatorGen(OptionManager& mgr,
00151                                    const std::string& descrName,
00152                                    const std::string& tagName) :
00153   GistEstimatorAdapter(mgr, descrName, tagName),
00154   SIMCALLBACK_INIT(SimEventVisualCortexOutput),
00155   itsLevelSpec(&OPT_LevelSpec, this),
00156   itsUseCS(&OPT_GistCenterSurroundFlag,this)
00157 {
00158   itsGistSize = 0;
00159 }
00160 
00161 // ######################################################################
00162 GistEstimatorGen::~GistEstimatorGen()
00163 { }
00164 
00165 // ######################################################################
00166 void GistEstimatorGen::
00167 onSimEventVisualCortexOutput(SimEventQueue& q, rutz::shared_ptr<SimEventVisualCortexOutput>& e)
00168 {
00169   //Grab the channel maps from the visual cortex
00170   rutz::shared_ptr<SimReqVCXmaps> vcxm(new SimReqVCXmaps(this));
00171   q.request(vcxm); // VisualCortex is now filling-in the maps...
00172   rutz::shared_ptr<ChannelMaps> chm = vcxm->channelmaps();
00173 
00174   //Compute the full size gist feature vector
00175   getFeatureVector(chm);
00176 
00177   // post an event so that anyone interested in gist can grab it:
00178   rutz::shared_ptr<SimEventGistOutput>
00179     ew(new SimEventGistOutput(this, itsGistVector));
00180   q.post(ew);
00181 }
00182 
00183 // ######################################################################
00184 Image<double> GistEstimatorGen::getGist()
00185 {
00186   return itsGistVector;
00187 }
00188 
00189 // ######################################################################
00190 void GistEstimatorGen::start1()
00191 {
00192   getManager().setOptionValString(&OPT_SingleChannelComputeFullPyramidForGist,"true");
00193   GistEstimatorAdapter::start1();
00194 }
00195 
00196 // ######################################################################
00197 void GistEstimatorGen::getFeatureVector(rutz::shared_ptr<ChannelMaps> chanMaps)
00198 {
00199   //! first get the gist feature size and allocate the gist vector size
00200   int sz = 0, sz_cs=0, sz_nocs = 0;
00201   if(itsUseCS.getVal() == 1 || itsUseCS.getVal() == 2)
00202     sz_cs += chanMaps->numSubmaps();
00203 
00204   // sz_nocs is the number of how many raw pyramid types
00205   if(itsUseCS.getVal() == 0 || itsUseCS.getVal() == 2)
00206     for(uint i=0; i < chanMaps->numSubchans(); i++)
00207       {
00208         rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00209         if(currChan->numSubchans() == 0)
00210           sz_nocs++;
00211         else
00212           sz_nocs += currChan->numSubchans();
00213       }
00214   sz_nocs *= PYR_LEVEL;
00215 
00216   sz = sz_cs + sz_nocs;
00217   LINFO("there are in total %4d gist feature chans", sz);
00218   itsGistVector.resize(1,NUM_GIST_FEAT * sz, NO_INIT);
00219 
00220   int count = 0;
00221 
00222   //! get the center-surround feature values
00223   if(itsUseCS.getVal() == 1 || itsUseCS.getVal() == 2)
00224     for(int i = 0; i<sz_cs; i++)
00225       {
00226         inplacePaste(itsGistVector,getSubSumGen(chanMaps->getRawCSmap(i)),
00227                      Point2D<int>(0, count*NUM_GIST_FEAT));
00228         count++;
00229       }
00230 
00231   //! get the non center-surround feature values
00232   if(itsUseCS.getVal() == 0 || itsUseCS.getVal() == 2)
00233     for(uint i=0; i<chanMaps->numSubchans(); i++)
00234       {
00235         rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00236         if(currChan->numSubchans() == 0)
00237           {
00238             ASSERT(currChan->hasPyramid());
00239             for(uint j=0; j<PYR_LEVEL; j++)
00240               {
00241                 inplacePaste(itsGistVector,getSubSumGen
00242                              (currChan->getPyramid().getImage(j)),
00243                              Point2D<int>(0,count*NUM_GIST_FEAT));
00244                 count++;
00245               }
00246           }
00247         else
00248           {
00249             for(uint i=0; i<currChan->numSubchans(); i++)
00250               {
00251                 rutz::shared_ptr<ChannelMaps> currSubChan = currChan->subChanMaps(i);
00252                 ASSERT(currSubChan->hasPyramid());
00253                 for(uint j=0; j<PYR_LEVEL; j++)
00254                   {
00255                     inplacePaste(itsGistVector,getSubSumGen
00256                                  (currSubChan->getPyramid().getImage(j)),
00257                                  Point2D<int>(0,count*NUM_GIST_FEAT));
00258                     count++;
00259                   }
00260               }
00261           }
00262       }
00263   ASSERT(count == sz);
00264   itsGistSize = sz;
00265 }
00266 
00267 // ######################################################################
00268 // get gist histogram to visualize the data
00269 Image<float> GistEstimatorGen::getGistImage(int sqSize,
00270                                             float minO, float maxO,
00271                                             float minC, float maxC,
00272                                             float minI, float maxI)
00273 {
00274   // square size
00275   int s = sqSize;
00276   Image<float> img(NUM_GIST_COL * s, NUM_GIST_FEAT * s, ZEROS);
00277   float range;
00278 
00279   // setup range for orientation channel if necessary
00280   if(maxO == minO)
00281     {
00282       minO = itsGistVector.getVal(0);
00283       maxO = itsGistVector.getVal(0);
00284       for(int i = 0; i < 16; i++)
00285         for(int j = 0; j < NUM_GIST_FEAT; j++)
00286           {
00287             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00288             if(val < minO)
00289               minO = val;
00290             else if(val > maxO)
00291               maxO = val;
00292           }
00293       LDEBUG("Orientation Channel Min: %f, max: %f", minO, maxO);
00294     }
00295   range = maxO - minO;
00296 
00297   // orientation channel
00298   for(int a = 0; a < 4; a++)
00299     for(int b = 0; b < 4; b++)
00300       for(int j = 0; j < NUM_GIST_FEAT; j++)
00301         {
00302           int i  = b*4 + a;
00303           int ii = a*4 + b;
00304           float val = itsGistVector.getVal(ii*NUM_GIST_FEAT+j);
00305           //float val = log(itsGistVector.getVal(i*NUM_GIST_FEAT+j)+1);
00306           //val = val * val;
00307           drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minO)/range);
00308           //LINFO("val[%d]: %f",j,val);
00309         }
00310 
00311   // setup range for color channel if necessary
00312   if(maxC == minC)
00313     {
00314       minC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00315       maxC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00316       for(int i = 16; i < 28; i++)
00317         for(int j = 0; j < NUM_GIST_FEAT; j++)
00318           {
00319             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00320             if(val < minC)
00321               minC = val;
00322             else if(val > maxC)
00323               maxC = val;
00324           }
00325       LDEBUG("Color Channel Min: %f, max: %f", minC, maxC);
00326     }
00327   range = maxC - minC;
00328 
00329   // color channel
00330   for(int i = 16; i < 28; i++)
00331     for(int j = 0; j < NUM_GIST_FEAT; j++)
00332       {
00333         float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00334         //float val = log(itsGistVector.getVal(i*NUM_GIST_FEAT+j)+1);
00335         //val = val * val;
00336         drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minC)/range);
00337         //LINFO("val[%d]: %f",j,val);
00338       }
00339 
00340   // setup range for intensity channel if necessary
00341   if(maxI == minI)
00342     {
00343       minI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00344       maxI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00345       for(int i = 28; i < 34; i++)
00346         for(int j = 0; j < NUM_GIST_FEAT; j++)
00347           {
00348             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00349             if(val < minI)
00350               minI = val;
00351             else if(val > maxI)
00352               maxI = val;
00353           }
00354       LDEBUG("Intensity Channel Min: %f, max: %f", minI, maxI);
00355     }
00356   range = maxI - minI;
00357 
00358   // intensity channel
00359   for(int i = 28; i < NUM_GIST_COL; i++)
00360     for(int j = 0; j < NUM_GIST_FEAT; j++)
00361       {
00362         float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00363         //float val = log(itsGistVector.getVal(i*NUM_GIST_FEAT+j)+1);
00364         //val = val * val;
00365         drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minI)/range);
00366         //LINFO("val[%d]: %f",j,val);
00367       }
00368 
00369   // draw the delineation
00370   // spatially
00371   float max = 1.0f;
00372   drawLine(img, Point2D<int>(0,  1*s), Point2D<int>(NUM_GIST_COL*s,  1*s), max,   1);
00373   drawLine(img, Point2D<int>(0,  5*s), Point2D<int>(NUM_GIST_COL*s,  5*s), max,   1);
00374   drawLine(img, Point2D<int>(0,  9*s), Point2D<int>(NUM_GIST_COL*s,  9*s), max/2, 1);
00375   drawLine(img, Point2D<int>(0, 13*s), Point2D<int>(NUM_GIST_COL*s, 13*s), max/2, 1);
00376   drawLine(img, Point2D<int>(0, 17*s), Point2D<int>(NUM_GIST_COL*s, 17*s), max/2, 1);
00377 
00378   // channelwise
00379   drawLine(img, Point2D<int>( 4*s, 0), Point2D<int>( 4*s, NUM_GIST_FEAT*s), max, 1);
00380   drawLine(img, Point2D<int>( 8*s, 0), Point2D<int>( 8*s, NUM_GIST_FEAT*s), max, 1);
00381   drawLine(img, Point2D<int>(12*s, 0), Point2D<int>(12*s, NUM_GIST_FEAT*s), max, 1);
00382   drawLine(img, Point2D<int>(16*s, 0), Point2D<int>(16*s, NUM_GIST_FEAT*s), max, 1);
00383   drawLine(img, Point2D<int>(22*s, 0), Point2D<int>(22*s, NUM_GIST_FEAT*s), max, 1);
00384   drawLine(img, Point2D<int>(28*s, 0), Point2D<int>(28*s, NUM_GIST_FEAT*s), max, 1);
00385 
00386   return img;
00387 }
00388 
00389 // ######################################################################
00390 // get gist difference: Jeffrey Divergence
00391 Image<float> GistEstimatorGen::diffGist(Image<float> in)
00392 {
00393   LFATAL("fix");
00394   float total = 0.0;
00395   float a,b,c,d;
00396 
00397   for(int i = 0; i < NUM_GIST_COL; i++)
00398     {
00399       for(int j = 0; j < NUM_GIST_FEAT; j++)
00400         {
00401           a = itsGistVector.getVal(i*NUM_GIST_FEAT +j) /
00402             itsGistVector.getVal(i*NUM_GIST_FEAT);
00403           b = in.getVal(i*NUM_GIST_FEAT +j) / in.getVal(i*NUM_GIST_FEAT);
00404           c = itsGistVector.getVal(i*NUM_GIST_FEAT) +
00405             in.getVal(i*NUM_GIST_FEAT);
00406           d = (a - b) * c/2;
00407           LINFO("%6.3f - %6.3f = %f",a,b,fabs(d));
00408 
00409           if((j-5)%4 == 3) LINFO("-:-:-");
00410           total += sqrt((d*d));
00411         }
00412       LINFO("  ");
00413     }
00414   LINFO("Diff = %f -> %f\n",total,total/NUM_GIST_COL/NUM_GIST_FEAT);
00415   Raster::waitForKey();
00416 
00417   return Image<float>();
00418 }
00419 
00420 
00421 // ######################################################################
00422 // get the gist size at the begining to allocate the size for itsGistVector
00423 int GistEstimatorGen::getGistSize()
00424 {
00425   return itsGistSize;
00426 }
00427 
00428 
00429 
00430 // ######################################################################
00431 /* So things look consistent in everyone's emacs... */
00432 /* Local Variables: */
00433 /* indent-tabs-mode: nil */
00434 /* End: */
Generated on Sun May 8 08:41:03 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3