RawGistEstimatorStd.C

Go to the documentation of this file.
00001 /*!@file Component/RawGistEstimatorStd.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: Sophie Marat <sophie.marat.ilab@gmail.com>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Neuro/RawGistEstimatorStd.C $
00035 // $Id: RawGistEstimatorStd.C $
00036 //
00037 
00038 // ######################################################################
00039 /*! Extract gist of image                                               */
00040 
00041 #include "Neuro/GistEstimatorStd.H"
00042 #include "Component/ModelManager.H"
00043 #include "Channels/ChannelMaps.H"
00044 //#include "Channels/BlueYellowChannel.H"
00045 //#include "Channels/ColorChannel.H"
00046 //#include "Channels/GaborChannel.H"
00047 //#include "Channels/IntensityChannel.H"
00048 //#include "Channels/OrientationChannel.H"
00049 //#include "Channels/RedGreenChannel.H"
00050 #include "GUI/XWinManaged.H"
00051 #include "Image/CutPaste.H"
00052 #include "Image/DrawOps.H"
00053 #include "Image/FilterOps.H"
00054 #include "Image/MathOps.H"
00055 #include "Image/ShapeOps.H"
00056 #include "Neuro/gistParams.H"
00057 #include "Raster/Raster.H"
00058 
00059 #include "Simulation/SimEventQueue.H"
00060 #include "Neuro/NeuroSimEvents.H"
00061 #include "Simulation/SimEvents.H"
00062 #include "Channels/ChannelOpts.H"
00063 #include "Channels/SingleChannel.H"
00064 
00065 #include "Util/Timer.H"
00066 #include "Util/StringUtil.H"
00067 
00068 // ######################################################################
00069 // get subsum of an image - more efficient implementation
00070 Image<double> getSubSum(Image<float> img)
00071 {
00072   Image<float> res(1, 21, ZEROS);
00073 
00074   int w = img.getWidth();  int h = img.getHeight();
00075   std::vector<float> tempRes(21);
00076 
00077   for (int i = 0; i < 21; i++) tempRes[i] = 0.0;
00078   std::vector<int> counts(16);
00079   for (int i = 0 ; i < 16; i++) counts[i] = 0;
00080 
00081   Image<float>::const_iterator itr = img.begin();
00082   for (int y = 0; y < h; ++y)
00083     {
00084       int suby = (4*y)/h;
00085       for (int x = 0; x < w; ++x)
00086         {
00087           int subx = (4*x)/w;
00088           int subpos = 4*suby + subx;
00089           tempRes[subpos+5] += *itr;
00090 
00091           ++(counts[subpos]);
00092           ++itr;
00093         }
00094     }
00095 
00096   int order[] = { 5,6,9,10, 7,8,11,12, 13,14,17,18, 15,16,19,20 };
00097   for (int i = 0 ; i < 16; ++i)
00098     if (counts[i] > 0)
00099         res[i+5] =  tempRes[order[i]] / (counts[order[i] - 5]+ 0.0);
00100 
00101    float tre1 = tempRes[5] + tempRes[6] + tempRes[9] + tempRes[10];
00102    int ct1 = counts[0] + counts[1] + counts[4] + counts[5];
00103 
00104    float tre2 = tempRes[7] + tempRes[8] + tempRes[11] + tempRes[12];
00105    int ct2 = counts[2] + counts[3] + counts[6] + counts[7];
00106 
00107    float tre3 = tempRes[13] + tempRes[14] + tempRes[17] + tempRes[18];
00108    int ct3 = counts[8] + counts[9] + counts[12] + counts[13];
00109 
00110    float tre4 = tempRes[15] + tempRes[16] + tempRes[19] + tempRes[20];
00111    int ct4 = counts[10] + counts[11] + counts[14] + counts[15];
00112 
00113   res[1] = tre1/ct1;
00114   res[2] = tre2/ct2;
00115   res[3] = tre3/ct3;
00116   res[4] = tre4/ct4;
00117 
00118   res[0] = (tre1 + tre2 + tre3 + tre4)/(ct1 + ct2 + ct3 + ct4);
00119 
00120   LDEBUG("lev1   : %14.4f", res[0]);
00121   LDEBUG("lev2   : %14.4f, %14.4f", res[1], res[2]);
00122   LDEBUG("       : %14.4f, %14.4f", res[3], res[4]);
00123   LDEBUG("lev3   : %14.4f, %14.4f, %14.4f, %14.4f",
00124          res[ 5], res[ 6], res[ 9], res[10]);
00125   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00126          res[ 7], res[ 8], res[11], res[12]);
00127   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00128          res[13], res[14], res[17], res[18]);
00129   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f",
00130          res[15], res[16], res[19], res[20]);
00131 
00132   return res;
00133 }
00134 
00135 // ######################################################################
00136 // get subsum of an image - less efficient but can change to stdev easily
00137 /*Image<double> getSubSum2(Image<float> img)
00138 {
00139   Image<double> res(1, 21, ZEROS);
00140 
00141   int w = img.getWidth();  int h = img.getHeight();
00142 
00143   int useMean = 1;
00144   // first level
00145   res[0] = mean(img); //sum(img);
00146 
00147   // second level
00148   // 1 2
00149   // 3 4
00150   Image<float> img1 = crop(img, Rectangle::tlbrI(0  , 0  , h/2-1,  w/2-1));
00151   Image<float> img2 = crop(img, Rectangle::tlbrI(0  , w/2, h/2-1,  w-1  ));
00152   Image<float> img3 = crop(img, Rectangle::tlbrI(h/2, 0  , h-1  ,  w/2-1));
00153   Image<float> img4 = crop(img, Rectangle::tlbrI(h/2, w/2, h-1  ,  w-1  ));
00154 
00155   if(useMean)
00156     {
00157       res[1] = mean(img1); //sum(img1);
00158       res[2] = mean(img2); //sum(img2);
00159       res[3] = mean(img3); //sum(img3);
00160       res[4] = mean(img4); //sum(img4);
00161     }
00162   else
00163     {
00164       res[1] = stdev(img1);//mean(img1); //sum(img1);
00165       res[2] = stdev(img2);//mean(img2); //sum(img2);
00166       res[3] = stdev(img3);//mean(img3); //sum(img3);
00167       res[4] = stdev(img4);//mean(img4); //sum(img4);
00168     }
00169 
00170   // third level
00171   // 1 2
00172   // 3 4
00173   int wX = img1.getWidth();  int hX = img1.getHeight();
00174   Image<float> imgX_1 = crop(img1, Rectangle::tlbrI(0   , 0   , hX/2-1,  wX/2-1));
00175   Image<float> imgX_2 = crop(img1, Rectangle::tlbrI(0   , wX/2, hX/2-1,  wX-1  ));
00176   Image<float> imgX_3 = crop(img1, Rectangle::tlbrI(hX/2, 0   , hX-1  ,  wX/2-1));
00177   Image<float> imgX_4 = crop(img1, Rectangle::tlbrI(hX/2, wX/2, hX-1  ,  wX-1  ));
00178   if(useMean)
00179     {
00180       res[5] = mean(imgX_1); //sum(imgX_1);
00181       res[6] = mean(imgX_2); //sum(imgX_2);
00182       res[7] = mean(imgX_3); //sum(imgX_3);
00183       res[8] = mean(imgX_4); //sum(imgX_4);
00184     }
00185   else
00186     {
00187       res[5] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1);
00188       res[6] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2);
00189       res[7] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3);
00190       res[8] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4);
00191     }
00192 
00193   wX = img2.getWidth();  hX = img2.getHeight();
00194   imgX_1 = crop(img2, Rectangle::tlbrI(0     , 0     , hX/2-1,  wX/2-1));
00195   imgX_2 = crop(img2, Rectangle::tlbrI(0     , wX/2  , hX/2-1,  wX-1  ));
00196   imgX_3 = crop(img2, Rectangle::tlbrI(hX/2  , 0     , hX-1  ,  wX/2-1));
00197   imgX_4 = crop(img2, Rectangle::tlbrI(hX/2  , wX/2  , hX-1  ,  wX-1  ));
00198   if(useMean)
00199     {
00200       res[ 9] = mean(imgX_1); //sum(imgX_1);
00201       res[10] = mean(imgX_2); //sum(imgX_2);
00202       res[11] = mean(imgX_3); //sum(imgX_3);
00203       res[12] = mean(imgX_4); //sum(imgX_4);
00204     }
00205   else
00206     {
00207       res[ 9] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1);
00208       res[10] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2);
00209       res[11] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3);
00210       res[12] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4);
00211     }
00212 
00213   wX = img3.getWidth();  hX = img3.getHeight();
00214   imgX_1 = crop(img3, Rectangle::tlbrI(0     , 0     , hX/2-1,  wX/2-1));
00215   imgX_2 = crop(img3, Rectangle::tlbrI(0     , wX/2  , hX/2-1,  wX-1  ));
00216   imgX_3 = crop(img3, Rectangle::tlbrI(hX/2  , 0     , hX-1  ,  wX/2-1));
00217   imgX_4 = crop(img3, Rectangle::tlbrI(hX/2  , wX/2  , hX-1  ,  wX-1  ));
00218   if(useMean)
00219     {
00220       res[13] = mean(imgX_1); //sum(imgX_1);
00221       res[14] = mean(imgX_2); //sum(imgX_2);
00222       res[15] = mean(imgX_3); //sum(imgX_3);
00223       res[16] = mean(imgX_4); //sum(imgX_4);
00224     }
00225   else
00226     {
00227       res[13] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1);
00228       res[14] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2);
00229       res[15] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3);
00230       res[16] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4);
00231     }
00232 
00233   wX = img4.getWidth();  hX = img4.getHeight();
00234   imgX_1 = crop(img4, Rectangle::tlbrI(0     , 0     , hX/2-1,  wX/2-1));
00235   imgX_2 = crop(img4, Rectangle::tlbrI(0     , wX/2  , hX/2-1,  wX-1  ));
00236   imgX_3 = crop(img4, Rectangle::tlbrI(hX/2  , 0     , hX-1  ,  wX/2-1));
00237   imgX_4 = crop(img4, Rectangle::tlbrI(hX/2  , wX/2  , hX-1  ,  wX-1  ));
00238   if(useMean)
00239     {
00240       res[17] = mean(imgX_1); //sum(imgX_1);
00241       res[18] = mean(imgX_2); //sum(imgX_2);
00242       res[19] = mean(imgX_3); //sum(imgX_3);
00243       res[20] = mean(imgX_4); //sum(imgX_4);
00244     }
00245   else
00246     {
00247       res[17] = stdev(imgX_1);//mean(imgX_1); //sum(imgX_1);
00248       res[18] = stdev(imgX_2);//mean(imgX_2); //sum(imgX_2);
00249       res[19] = stdev(imgX_3);//mean(imgX_3); //sum(imgX_3);
00250       res[20] = stdev(imgX_4);//mean(imgX_4); //sum(imgX_4);
00251     }
00252 
00253   LDEBUG("lev1   : %14.4f", res[0]);
00254   LDEBUG("lev2   : %14.4f, %14.4f", res[1], res[2]);
00255   LDEBUG("       : %14.4f, %14.4f", res[3], res[4]);
00256   LDEBUG("lev3   : %14.4f, %14.4f, %14.4f, %14.4f", res[ 5], res[ 6], res[ 9], res[10]);
00257   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f", res[ 7], res[ 8], res[11], res[12]);
00258   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f", res[13], res[14], res[17], res[18]);
00259   LDEBUG("       : %14.4f, %14.4f, %14.4f, %14.4f", res[15], res[16], res[19], res[20]);
00260 
00261   return res;
00262 }
00263 */
00264 
00265 // ######################################################################
00266 // get the mean of the image insige the polygon
00267 double getMeanPoly(Image<float> img, std::vector<Point2D<int> > polygon)
00268 {
00269   double res;
00270   double sum = 0;
00271   int countP = 0;
00272   //res = mean(img); 
00273   Point2D<int> P;
00274   for (int i = 0; i < img.getWidth(); i++)
00275     {
00276       for (int j = 0; j < img.getHeight(); j++)
00277         {
00278           P = Point2D<int> (i,j);
00279           if (pnpoly(polygon,P))
00280             {
00281               sum = sum + img.getVal(P);
00282               countP ++;
00283             }
00284         }
00285     }
00286 
00287   res = sum/countP; 
00288   return res;
00289 }
00290 
00291 
00292 
00293 // ######################################################################
00294 RawGistEstimatorStd::RawGistEstimatorStd(OptionManager& mgr,
00295                                    const std::string& descrName,
00296                                    const std::string& tagName) :
00297   ModelComponent(mgr, descrName, tagName)
00298 {
00299   itsGistVector.resize(1,NUM_GIST_FEAT * NUM_GIST_CHAN, NO_INIT);
00300 }
00301 
00302 // ######################################################################
00303 RawGistEstimatorStd::~RawGistEstimatorStd()
00304 { }
00305 
00306 // ######################################################################
00307 Image<float> RawGistEstimatorStd::compute(rutz::shared_ptr<ChannelMaps> chmp)
00308 {
00309   computeFeatureVector(chmp);
00310   return itsGistVector;
00311 }
00312 
00313 // ######################################################################
00314 std::vector<float> RawGistEstimatorStd::computeOnPolygon(rutz::shared_ptr<ChannelMaps> chanMaps, std::vector<Point2D<float> > polygonFS)
00315 {
00316   //create a gist vector
00317   std::vector<float> gistPolyVector;
00318     
00319   //rescale the polygon to be at the same level than the subMaps
00320   std::vector<Point2D<int> > polygon(polygonFS.size());
00321   Point2D<int> Ppoly;
00322   for(uint k=0; k<polygonFS.size(); k++)
00323     {
00324       Ppoly.i = (int) floor(polygonFS[k].i/16);
00325       Ppoly.j = (int) floor(polygonFS[k].j/16);
00326       polygon[k] = Ppoly;
00327     }
00328   //test wheter the polygon contain at least one pixel
00329   double areaPoly = area(polygon);
00330   if (areaPoly<=0)
00331     {
00332       LINFO("The given polygon is too small for the gist computation!");
00333       //find a bounding box with at leat one pixel
00334       int minx, miny, maxx, maxy;
00335       minx = miny =100000000;
00336       maxx = maxy =-100000000;
00337       for (uint k=0; k<polygonFS.size(); k++)
00338         {
00339           if(minx > (int) polygonFS[k].i) minx = (int) polygonFS[k].i;       
00340           if(miny > (int) polygonFS[k].j) miny = (int) polygonFS[k].j;
00341           if(maxx < (int) polygonFS[k].i) maxx = (int) polygonFS[k].i;
00342           if(maxy < (int) polygonFS[k].j) maxy = (int) polygonFS[k].j;
00343         }
00344       int minxR, minyR, maxxR, maxyR;
00345       minxR = floor(minx/16.0);
00346       minyR = floor(miny/16.0);
00347       maxxR = ceil(maxx/16.0);
00348       maxyR = ceil(maxy/16.0);
00349      
00350       polygon.clear();
00351       polygon.resize(4);
00352       polygon[0] = Point2D<int> (minxR, minyR);
00353       polygon[1] = Point2D<int> (maxxR, minyR);
00354       polygon[2] = Point2D<int> (maxxR, maxyR);
00355       polygon[3] = Point2D<int> (minxR, maxyR);
00356     }
00357 
00358   rutz::shared_ptr<ChannelMaps> orientationMaps;
00359   rutz::shared_ptr<ChannelMaps> colorMaps;
00360   rutz::shared_ptr<ChannelMaps> intensityMaps;
00361   
00362   for(uint i=0; i < chanMaps->numSubchans(); i++)
00363     {
00364       //Grab the current channel
00365       rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00366       
00367       //Determine the name of the channel
00368       std::vector<std::string> chanNameVec;
00369       split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec));
00370       std::string chanName = chanNameVec[1];
00371       
00372       //Assign the channel maps based on their name
00373       if(chanName == "orientation")
00374         orientationMaps = currChan;
00375       else if(chanName == "color")
00376         colorMaps = currChan;
00377       else if(chanName == "intensity")
00378         intensityMaps = currChan;
00379     }
00380   
00381   LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans());
00382   LDEBUG("Color Subchans: %d", colorMaps->numSubchans());
00383   LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans());
00384   
00385   //For now, we are expecting the default number of features in the channel maps, as per Siagian_Itti07pami.
00386   //TODO:This should be generalized later when things are more stable
00387   ASSERT(orientationMaps->numSubchans() == 4);
00388   ASSERT(colorMaps->numSubchans() == 2);
00389   ASSERT(intensityMaps->numSubchans() == 0);
00390 
00391   //Grab the individual orientation channels
00392   rutz::shared_ptr<ChannelMaps> orientation_0   = orientationMaps->subChanMaps(0);
00393   rutz::shared_ptr<ChannelMaps> orientation_45  = orientationMaps->subChanMaps(1);
00394   rutz::shared_ptr<ChannelMaps> orientation_90  = orientationMaps->subChanMaps(2);
00395   rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3);
00396 
00397   //Grab the different color channels
00398   rutz::shared_ptr<ChannelMaps> rg;
00399   rutz::shared_ptr<ChannelMaps> by;
00400   for(uint i=0; i<colorMaps->numSubchans(); i++)
00401     {
00402       std::vector<std::string> chanNameVec;
00403       split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec));
00404       std::string chanName = chanNameVec[2];
00405       
00406       if(chanName == "rg")
00407         rg = colorMaps->subChanMaps(i);
00408       else if(chanName == "by")
00409         by = colorMaps->subChanMaps(i);
00410     }
00411   
00412   ASSERT(rg.is_valid());
00413   ASSERT(by.is_valid());
00414 
00415   //For the Gist computed on the Polygon, no more subsum (=sum on grid) are done, the polygon is comnsidered as one cell, the mean is tacken on the whole polygon
00416   
00417   // orientation channel 0 degree
00418   int count = 0;
00419   for(int i = 0; i < NUM_GIST_LEV; i++)
00420     {
00421       float meanPoly = getMeanPoly(orientation_0->getSubmap(i), polygon);   
00422       gistPolyVector.push_back(meanPoly);
00423       count += 1;
00424     }
00425   // orientation channel 45 degree
00426   for(int i = 0; i < NUM_GIST_LEV; i++)
00427     {
00428       float meanPoly = getMeanPoly(orientation_45->getSubmap(i), polygon);  
00429       gistPolyVector.push_back(meanPoly);
00430       count += 1;;
00431     }
00432   // orientation channel 90 degree
00433   for(int i = 0; i < NUM_GIST_LEV; i++)
00434     {
00435       float meanPoly = getMeanPoly(orientation_90->getSubmap(i), polygon);   
00436       gistPolyVector.push_back(meanPoly);
00437       count += 1;
00438     }
00439   // orientation channel 135 degree
00440   for(int i = 0; i < NUM_GIST_LEV; i++)
00441     {
00442       float meanPoly = getMeanPoly(orientation_135->getSubmap(i), polygon); 
00443       gistPolyVector.push_back(meanPoly);
00444       count += 1;
00445     }
00446   
00447   //For the Red/Green and Blue/Yellow Channels,
00448   //Christian's model uses levels:  (2,5), (2,6), (3,6), (3,7), (4,7), (4,8)
00449   //However, this method will use:  (2,5), (3,6), (4,7), (2,6), (3,7), (4,8)
00450   //Same channels, just a different order... does this matter?
00451   
00452   // red / green opponency
00453   for(uint i=0; i<rg->numSubmaps(); i++)
00454     {
00455       float meanPoly = getMeanPoly(rg->getSubmap(i), polygon);   
00456       gistPolyVector.push_back(meanPoly);
00457       count += 1;    
00458     }
00459   // blue / yellow opponency
00460   for(uint i=0; i<by->numSubmaps(); i++)
00461     {
00462       float meanPoly = getMeanPoly(by->getSubmap(i), polygon);  
00463       gistPolyVector.push_back(meanPoly);
00464       count += 1;   
00465     }
00466   //intensity
00467   for(uint i=0; i<intensityMaps->numSubmaps(); i++)
00468     {
00469       float meanPoly = getMeanPoly(intensityMaps->getSubmap(i), polygon);  
00470       gistPolyVector.push_back(meanPoly);
00471       count += 1;
00472     }
00473   
00474   return gistPolyVector;
00475 }
00476 
00477 // ######################################################################
00478 void RawGistEstimatorStd::computeFeatureVector(rutz::shared_ptr<ChannelMaps> chanMaps)
00479 {
00480   rutz::shared_ptr<ChannelMaps> orientationMaps;
00481   rutz::shared_ptr<ChannelMaps> colorMaps;
00482   rutz::shared_ptr<ChannelMaps> intensityMaps;
00483   
00484   for(uint i=0; i < chanMaps->numSubchans(); i++)
00485     {
00486       //Grab the current channel
00487       rutz::shared_ptr<ChannelMaps> currChan = chanMaps->subChanMaps(i);
00488       
00489       //Determine the name of the channel
00490       std::vector<std::string> chanNameVec;
00491       split(currChan->getMap().name(), ":", std::back_inserter(chanNameVec));
00492       std::string chanName = chanNameVec[1];
00493       
00494       //Assign the channel maps based on their name
00495       if(chanName == "orientation")
00496         orientationMaps = currChan;
00497       else if(chanName == "color")
00498         colorMaps = currChan;
00499       else if(chanName == "intensity")
00500         intensityMaps = currChan;
00501     }
00502   
00503   LDEBUG("Orientation Subchans: %d", orientationMaps->numSubchans());
00504   LDEBUG("Color Subchans: %d", colorMaps->numSubchans());
00505   LDEBUG("Intensity Subchans: %d", intensityMaps->numSubchans());
00506 
00507   LINFO("Orientation Subchans: %d", orientationMaps->numSubchans());
00508   LINFO("Color Subchans: %d", colorMaps->numSubchans());
00509   LINFO("Intensity Subchans: %d", intensityMaps->numSubchans());
00510   
00511   //For now, we are expecting the default number of features in the channel maps, as per Siagian_Itti07pami.
00512   //TODO:This should be generalized later when things are more stable
00513   ASSERT(orientationMaps->numSubchans() == 4);
00514   ASSERT(colorMaps->numSubchans() == 2);
00515   ASSERT(intensityMaps->numSubchans() == 0);
00516   
00517   //Grab the individual orientation channels
00518   rutz::shared_ptr<ChannelMaps> orientation_0   = orientationMaps->subChanMaps(0);
00519   rutz::shared_ptr<ChannelMaps> orientation_45  = orientationMaps->subChanMaps(1);
00520   rutz::shared_ptr<ChannelMaps> orientation_90  = orientationMaps->subChanMaps(2);
00521   rutz::shared_ptr<ChannelMaps> orientation_135 = orientationMaps->subChanMaps(3);
00522   
00523   //Grab the different color channels
00524   rutz::shared_ptr<ChannelMaps> rg;
00525   rutz::shared_ptr<ChannelMaps> by;
00526   for(uint i=0; i<colorMaps->numSubchans(); i++)
00527     {
00528       std::vector<std::string> chanNameVec;
00529       split(colorMaps->subChanMaps(i)->getMap().name(), ":", std::back_inserter(chanNameVec));
00530       std::string chanName = chanNameVec[2];
00531       
00532       if(chanName == "rg")
00533         rg = colorMaps->subChanMaps(i);
00534       else if(chanName == "by")
00535         by = colorMaps->subChanMaps(i);
00536     }
00537   
00538   ASSERT(rg.is_valid());
00539   ASSERT(by.is_valid());
00540   
00541   //Start calculating the individual subsums on the channels, and pasting them into the gist vector
00542   // orientation channel 0 degree
00543   int count = 0;
00544   for(int i = 0; i < NUM_GIST_LEV; i++)
00545     {
00546       Image<float> subSum = getSubSum(orientation_0->getSubmap(i));
00547       inplacePaste(itsGistVector, subSum,
00548                    Point2D<int>(0, count));
00549       count += subSum.getHeight();
00550     }
00551   
00552   // orientation channel 45 degree
00553   for(int i = 0; i < NUM_GIST_LEV; i++)
00554     {
00555       Image<float> subSum = getSubSum(orientation_45->getSubmap(i));
00556       inplacePaste(itsGistVector,  subSum,
00557                    Point2D<int>(0, count));
00558       count += subSum.getHeight();
00559     }
00560   
00561   // orientation channel 90 degree
00562   for(int i = 0; i < NUM_GIST_LEV; i++)
00563     {
00564       Image<float> subSum = getSubSum(orientation_90->getSubmap(i));
00565       inplacePaste(itsGistVector, subSum,
00566                    Point2D<int>(0, count));
00567       count += subSum.getHeight();
00568     }
00569   
00570   // orientation channel 135 degree
00571   for(int i = 0; i < NUM_GIST_LEV; i++)
00572     {
00573       Image<float> subSum = getSubSum(orientation_135->getSubmap(i));
00574       inplacePaste(itsGistVector, subSum,
00575                    Point2D<int>(0, count));
00576       count += subSum.getHeight();
00577     }
00578   
00579   //For the Red/Green and Blue/Yellow Channels,
00580   //Christian's model uses levels:  (2,5), (2,6), (3,6), (3,7), (4,7), (4,8)
00581   //However, this method will use:  (2,5), (3,6), (4,7), (2,6), (3,7), (4,8)
00582   //Same channels, just a different order... does this matter?
00583   
00584   // red / green opponency
00585   for(uint i=0; i<rg->numSubmaps(); i++)
00586     {
00587       Image<float> subSum = getSubSum(rg->getSubmap(i));
00588       inplacePaste(itsGistVector, subSum,
00589                    Point2D<int>(0, count));
00590       count += subSum.getHeight();
00591     }
00592   
00593   // blue / yellow opponency
00594   for(uint i=0; i<by->numSubmaps(); i++)
00595     {
00596       Image<float> subSum = getSubSum(by->getSubmap(i));
00597       inplacePaste(itsGistVector, subSum,
00598                    Point2D<int>(0, count));
00599       count += subSum.getHeight();
00600     }
00601   
00602   
00603   //intensity
00604   for(uint i=0; i<intensityMaps->numSubmaps(); i++)
00605     {
00606       Image<float> subSum = getSubSum(intensityMaps->getSubmap(i));
00607       inplacePaste(itsGistVector, subSum,
00608                    Point2D<int>(0, count));
00609       count += subSum.getHeight();
00610     }
00611 }
00612 
00613 // ######################################################################
00614 // get gist histogram to visualize the data
00615 Image<float> RawGistEstimatorStd::getGistImage(int sqSize,
00616     float minO, float maxO,
00617     float minC, float maxC,
00618     float minI, float maxI)
00619 {
00620   // square size
00621   int s = sqSize;
00622   Image<float> img(NUM_GIST_COL * s, NUM_GIST_FEAT * s, ZEROS);
00623   float range;
00624   
00625   // setup range for orientation channel if necessary
00626   if(maxO == minO)
00627     {
00628       minO = itsGistVector.getVal(0);
00629       maxO = itsGistVector.getVal(0);
00630       for(int i = 0; i < 16; i++)
00631         for(int j = 0; j < NUM_GIST_FEAT; j++)
00632           {
00633             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00634             if(val < minO)
00635               minO = val;
00636             else if(val > maxO)
00637               maxO = val;
00638           }
00639       LDEBUG("Orientation Channel Min: %f, max: %f", minO, maxO);
00640     }
00641   range = maxO - minO;
00642   
00643   // orientation channel
00644   for(int a = 0; a < 4; a++)
00645     for(int b = 0; b < 4; b++)
00646       for(int j = 0; j < NUM_GIST_FEAT; j++)
00647         {
00648           int i  = b*4 + a;
00649           int ii = a*4 + b;
00650           float val = itsGistVector.getVal(ii*NUM_GIST_FEAT+j);
00651           drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minO)/range);
00652         }
00653   
00654   // setup range for color channel if necessary
00655   if(maxC == minC)
00656     {
00657       minC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00658       maxC = itsGistVector.getVal(16*NUM_GIST_FEAT);
00659       for(int i = 16; i < 28; i++)
00660         for(int j = 0; j < NUM_GIST_FEAT; j++)
00661           {
00662             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00663             if(val < minC)
00664               minC = val;
00665             else if(val > maxC)
00666               maxC = val;
00667           }
00668       LDEBUG("Color Channel Min: %f, max: %f", minC, maxC);
00669     }
00670   range = maxC - minC;
00671   
00672   // color channel
00673   for(int i = 16; i < 28; i++)
00674     for(int j = 0; j < NUM_GIST_FEAT; j++)
00675       {
00676         float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00677         drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minC)/range);
00678       }
00679   
00680   // setup range for intensity channel if necessary
00681   if(maxI == minI)
00682     {
00683       minI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00684       maxI = itsGistVector.getVal(28*NUM_GIST_FEAT);
00685       for(int i = 28; i < 34; i++)
00686         for(int j = 0; j < NUM_GIST_FEAT; j++)
00687           {
00688             float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00689             if(val < minI)
00690               minI = val;
00691             else if(val > maxI)
00692               maxI = val;
00693           }
00694       LDEBUG("Intensity Channel Min: %f, max: %f", minI, maxI);
00695     }
00696   range = maxI - minI;
00697   
00698   // intensity channel
00699   for(int i = 28; i < NUM_GIST_COL; i++)
00700     for(int j = 0; j < NUM_GIST_FEAT; j++)
00701       {
00702         float val = itsGistVector.getVal(i*NUM_GIST_FEAT+j);
00703         drawPatch(img, Point2D<int>(i*s+s/2,j*s+s/2),s/2,(val-minI)/range);
00704       }
00705   
00706   // draw the delineation
00707   // spatially
00708   float max = 1.0f;
00709   drawLine(img, Point2D<int>(0,  1*s), Point2D<int>(NUM_GIST_COL*s,  1*s), max,   1);
00710   drawLine(img, Point2D<int>(0,  5*s), Point2D<int>(NUM_GIST_COL*s,  5*s), max,   1);
00711   drawLine(img, Point2D<int>(0,  9*s), Point2D<int>(NUM_GIST_COL*s,  9*s), max/2, 1);
00712   drawLine(img, Point2D<int>(0, 13*s), Point2D<int>(NUM_GIST_COL*s, 13*s), max/2, 1);
00713   drawLine(img, Point2D<int>(0, 17*s), Point2D<int>(NUM_GIST_COL*s, 17*s), max/2, 1);
00714   
00715   // channelwise
00716   drawLine(img, Point2D<int>( 4*s, 0), Point2D<int>( 4*s, NUM_GIST_FEAT*s), max, 1);
00717   drawLine(img, Point2D<int>( 8*s, 0), Point2D<int>( 8*s, NUM_GIST_FEAT*s), max, 1);
00718   drawLine(img, Point2D<int>(12*s, 0), Point2D<int>(12*s, NUM_GIST_FEAT*s), max, 1);
00719   drawLine(img, Point2D<int>(16*s, 0), Point2D<int>(16*s, NUM_GIST_FEAT*s), max, 1);
00720   drawLine(img, Point2D<int>(22*s, 0), Point2D<int>(22*s, NUM_GIST_FEAT*s), max, 1);
00721   drawLine(img, Point2D<int>(28*s, 0), Point2D<int>(28*s, NUM_GIST_FEAT*s), max, 1);
00722 
00723   return img;
00724 }
00725 
00726 // ######################################################################
00727 // get gist difference: Jeffrey Divergence
00728 Image<double> RawGistEstimatorStd::diffGist(Image<double> in)
00729 {
00730   LFATAL("fix");
00731   double total = 0.0;
00732   double a,b,c,d;
00733   
00734   for(int i = 0; i < NUM_GIST_COL; i++)
00735     {
00736       for(int j = 0; j < NUM_GIST_FEAT; j++)
00737         {
00738           a = itsGistVector.getVal(i*NUM_GIST_FEAT +j) /
00739             itsGistVector.getVal(i*NUM_GIST_FEAT);
00740           b = in.getVal(i*NUM_GIST_FEAT +j) / in.getVal(i*NUM_GIST_FEAT);
00741           c = itsGistVector.getVal(i*NUM_GIST_FEAT) +
00742             in.getVal(i*NUM_GIST_FEAT);
00743           d = (a - b) * c/2;
00744           LINFO("%6.3f - %6.3f = %f",a,b,fabs(d));
00745           
00746           if((j-5)%4 == 3) LINFO("-:-:-");
00747           total += sqrt((d*d));
00748         }
00749       LINFO("  ");
00750     }
00751   LINFO("Diff = %f -> %f\n",total,total/NUM_GIST_COL/NUM_GIST_FEAT);
00752   Raster::waitForKey();
00753   
00754   return Image<double>();
00755 }
00756 
00757 // ######################################################################
00758 /* So things look consistent in everyone's emacs... */
00759 /* Local Variables: */
00760 /* indent-tabs-mode: nil */
00761 /* End: */
Generated on Sun May 8 08:40:23 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3