Ganglion.C

Go to the documentation of this file.
00001 /*!@file SceneUnderstanding/Ganglion.C  */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
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: Lior Elazary <elazary@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/plugins/SceneUnderstanding/Ganglion.C $
00035 // $Id: Ganglion.C 13551 2010-06-10 21:56:32Z itti $
00036 //
00037 
00038 #ifndef GANGLION_C_DEFINED
00039 #define GANGLION_C_DEFINED
00040 
00041 #include "plugins/SceneUnderstanding/Ganglion.H"
00042 
00043 #include "Image/DrawOps.H"
00044 #include "Image/MathOps.H"
00045 #include "Image/Layout.H"
00046 #include "Simulation/SimEventQueue.H"
00047 #include "Simulation/SimEvents.H"
00048 #include "Media/MediaSimEvents.H"
00049 #include "Channels/InputFrame.H"
00050 #include "Image/Kernels.H"
00051 #include "Image/FilterOps.H"
00052 #include "Image/Convolutions.H"
00053 #include "GUI/DebugWin.H"
00054 #include <math.h>
00055 #include <fcntl.h>
00056 #include <limits>
00057 #include <string>
00058 
00059 const ModelOptionCateg MOC_GANGLION = {
00060   MOC_SORTPRI_3,   "Ganglion-Related Options" };
00061 
00062 // Used by: SimulationViewerEyeMvt
00063 const ModelOptionDef OPT_GanglionShowDebug =
00064   { MODOPT_ARG(bool), "GanglionShowDebug", &MOC_GANGLION, OPTEXP_CORE,
00065     "Show debug img",
00066     "ganglion-debug", '\0', "<true|false>", "false" };
00067 //#include "Neuro/NeuroSimEvents.H"
00068 
00069 
00070 // ######################################################################
00071 Ganglion::Ganglion(OptionManager& mgr, const std::string& descrName,
00072     const std::string& tagName) :
00073   SimModule(mgr, descrName, tagName),
00074   SIMCALLBACK_INIT(SimEventInputFrame),
00075   SIMCALLBACK_INIT(SimEventSaveOutput),
00076   itsShowDebug(&OPT_GanglionShowDebug, this)
00077 
00078 {
00079   init(Dims(320,240));
00080 }
00081 
00082 // ######################################################################
00083 Ganglion::~Ganglion()
00084 {
00085 
00086 }
00087 
00088 // ######################################################################
00089 void Ganglion::init(Dims numCells)
00090 {
00091   Image<float> img(numCells, ZEROS);
00092   itsGanglionCellsMu.push_back(img);
00093   itsGanglionCellsInput.push_back(img);
00094   itsGanglionCellsOutput.push_back(img);
00095   itsGanglionCellsOutput.push_back(img);
00096 
00097   img.clear(1.0);
00098   itsGanglionCellsSig.push_back(img);
00099   itsGanglionCellsPrior.push_back(img);
00100 
00101 
00102   //itsProbe.i = 100;
00103   //itsProbe.j = 220;
00104   itsProbe.i = -1;
00105   itsProbe.j = -1;
00106 
00107   //NOTE: Should the ganglion cells be initalizied randomly from the
00108   //using the learned sigma?
00109 
00110 }
00111 
00112 // ######################################################################
00113 void Ganglion::onSimEventInputFrame(SimEventQueue& q,
00114                                   rutz::shared_ptr<SimEventInputFrame>& e)
00115 {
00116   // here is the inputs image:
00117   const Image<PixRGB<byte> > inimg = e->frame().asRgb();
00118   itsCurrentImg = inimg;
00119 
00120   //set the ganglion input
00121   Image<float> rg, by;
00122   getRGBY(inimg, rg, by, 25.0F);
00123   ////Image<byte> input = by + rg + luminance(inimg);
00124   ////TODO should return 3 seperate channels, for better discrimnation
00125   Image<float> in = rg; // + rg + luminance(inimg);
00126   inplaceNormalize(in, 0.0F, 255.0F);
00127   //Image<byte> input = in;
00128   Image<byte> input = luminance(inimg);
00129 
00130  // cvEqualizeHist(img2ipl(input),img2ipl(input));
00131   itsGanglionCellsInput[LUM] = input;
00132 
00133   //itsGanglionCellsInput[RG] = rg;
00134   //itsGanglionCellsInput[BY] = by;
00135 
00136   evolve();
00137 
00138   //Output the cells
00139   q.post(rutz::make_shared(new SimEventGanglionOutput(this, itsGanglionCellsOutput)));
00140 
00141   // Create a new Retina Image from the inputImage, and post it to the queue
00142   //q.post(rutz::make_shared(
00143   //      new SimEventRetinaImage(
00144   //        this,
00145   //        InputFrame(InputFrame::fromRgb(&inimg, q.now())),
00146   //        Rectangle(Point2D<int>(0,0), inimg.getDims()),
00147   //        Point2D<int>(0,0)
00148   //        )
00149   //      )
00150   //    );
00151 
00152 }
00153 
00154 // ######################################################################
00155 void Ganglion::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e)
00156 {
00157   if (itsShowDebug.getVal())
00158     {
00159       // get the OFS to save to, assuming sinfo is of type
00160       // SimModuleSaveInfo (will throw a fatal exception otherwise):
00161       nub::ref<FrameOstream> ofs =
00162         dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs;
00163       Layout<PixRGB<byte> > disp = getDebugImage();
00164       ofs->writeRgbLayout(disp, "Ganglion", FrameInfo("Ganglion", SRC_POS));
00165 
00166   //    if (SeC<SimEventVisualCortexOutput> e = q.check<SimEventVisualCortexOutput>(this, SEQ_ANY))
00167   //      ofs->writeGray(e->vco(), "SMap", FrameInfo("SMap", SRC_POS));
00168 
00169     }
00170 }
00171 
00172 
00173 void Ganglion::setBias(const ImageSet<float>& prior)
00174 {
00175 
00176   Point2D<int> maxPos; float maxVal;
00177   findMax(prior[0], maxPos, maxVal);
00178   LINFO("maxVal %f", maxVal);
00179 
00180 
00181   float filter_period = 100;
00182   float elongation = 2.0;
00183   float angle = 90;
00184   int size = -1;
00185   const double major_stddev = filter_period / 30.0;
00186   const double minor_stddev = major_stddev * elongation;
00187 
00188   Image<float> gabor = gaborFilter3(major_stddev, minor_stddev,
00189       filter_period, 90, 180 - angle + 90.0 , size);
00190 
00191    gabor -= mean(gabor);
00192 
00193   // normalize to unit sum-of-squares:
00194   gabor /= sum(squared(gabor));
00195 
00196   gabor *= 20;
00197   gabor += 1.0;
00198 
00199   const int w = itsGanglionCellsMu[0].getWidth(), h = itsGanglionCellsMu[0].getHeight();
00200   const int Nx = gabor.getWidth(), Ny = gabor.getHeight();
00201   Image<float> result = itsGanglionCellsMu[0]; //(w, h, ZEROS);
00202   //Image<float> result(w,h,ZEROS);
00203 
00204   Image<float>::const_iterator sptr = itsGanglionCellsMu[0].begin();
00205   Image<float>::iterator dptr = result.beginw();
00206 
00207   const int kkk = Nx * Ny - 1;
00208   const int Nx2 = (Nx - 1) / 2;
00209   const int Ny2 = (Ny - 1) / 2;
00210 
00211   const float* filter = gabor.getArrayPtr();
00212   // very inefficient implementation; one has to be crazy to use non
00213   // separable filters anyway...
00214   for (int j = 0; j < h; ++j) // LOOP rows of src
00215     {
00216       const int j_offset = j-Ny2;
00217 
00218       for (int i = 0; i < w; ++i) // LOOP columns of src
00219         {
00220           if (prior[0].getVal(i,j) > 1)
00221           {
00222             ////float sum = 0;
00223             const int i_offset = i-Nx2;
00224             const int kj_bgn = std::max(- j_offset, 0);
00225             const int kj_end = std::min(h - j_offset, Ny);
00226 
00227 
00228             //float filter_period = 100;
00229             //float elongation = 2.0;
00230             //float angle = 90; //(prior[1].getVal(i,j)+M_PI/2)*180/M_PI;
00231             //int size = -1;
00232             //const double major_stddev = filter_period / 30.0;
00233             //const double minor_stddev = major_stddev * elongation;
00234 
00235             //Image<float> gabor2 = gaborFilter3(major_stddev, minor_stddev,
00236             //    filter_period, 90, 180 - angle + 90.0 , size);
00237 
00238             //gabor2 -= mean(gabor2);
00239 
00240             //// normalize to unit sum-of-squares:
00241             //gabor2 /= sum(squared(gabor2));
00242 
00243             //gabor2 *= 20;
00244             //gabor2 += 1.0;
00245 
00246 
00247             for (int kj = kj_bgn; kj < kj_end; ++kj) // LOOP rows of filter
00248             {
00249               const int kjj = kj + j_offset; // row of src
00250               const int src_offset = w * kjj + i_offset;
00251               const int filt_offset = kkk - Nx*kj;
00252 
00253               const int ki_bgn = std::max(-i_offset, 0);
00254               const int ki_end = std::min(w-i_offset, Nx);
00255 
00256               for (int ki = ki_bgn; ki < ki_end; ++ki) // LOOP cols of filt
00257               {
00258                   dptr[ki + src_offset] += sptr[ki + src_offset] * filter[filt_offset - ki];
00259                 //dptr[ki + src_offset] = sptr[ki + src_offset] * 3.0;
00260               }
00261             }
00262             //SHOWIMG(result);
00263           }
00264 
00265         }
00266     }
00267     LINFO("Result");
00268     SHOWIMG(result);
00269     itsGanglionCellsMu[0] = result;
00270   //Create a filtered output
00271 
00272 
00273 
00274   //float scale = 2;
00275   //Image<float> dog = dogFilter<float>(1.75F + 0.5F*scale, ori, (int)(1 + 1*scale));
00276 
00277   //// normalize to zero mean:
00278   //dog -= mean(dog);
00279 
00280   //// normalize to unit sum-of-squares:
00281   //dog /= sum(squared(dog));
00282 
00283 
00284 
00285   //SHOWIMG(itsGanglionCellsPrior[0]);
00286   ////if (maxVal > 1.0)
00287   //{
00288   //  tmp.clear(1.0F);
00289   //  maxPos.i = 67 ; maxPos.j = 95;
00290 
00291   //  //Rectangle rectPos(Point2D<int>(maxPos.i, maxPos.j), Dims(50,3));
00292   //  //Rectangle rectNeg(Point2D<int>(maxPos.i, maxPos.j-3), Dims(50,3));
00293   //  //drawFilledRectOR(tmp, rect, 255.0F, 1, prior[0].getVal(maxPos));
00294   //  //drawFilledRect(tmp, rectPos, 1.01F);
00295   //  //drawFilledRect(tmp, rectNeg, 0.95F);
00296   //  //drawCircle(tmp, maxPos, 10, 255.0F);
00297   //  //inplaceNormalize(tmp, 0.0F, 255.0F);
00298 
00299 
00300   //  itsGanglionCellsPrior[0] = tmp;
00301 
00302   //  //SHOWIMG(tmp);
00303   //  //SHOWIMG(itsGanglionCellsMu[0]);
00304   //  itsGanglionCellsMu[0] *= tmp;
00305   //  //SHOWIMG(itsGanglionCellsMu[0]);
00306 
00307   //}
00308  // else {
00309  //   itsGanglionCellsPrior[0].clear(0.0F);
00310  // }
00311 
00312 
00313 
00314 
00315   //SHOWIMG(tmp);
00316 
00317 
00318 }
00319 
00320 // ######################################################################
00321 void Ganglion::setInput(const Image<PixRGB<byte> > &img)
00322 {
00323 
00324   //Retina processing
00325 
00326   //histogram equlization
00327 
00328 
00329   //set the ganglion input
00330   //Image<float> rg, by;
00331   //getRGBY(img, rg, by, 25.0F);
00332   Image<byte> input = luminance(img);
00333   if (itsProbe.isValid())
00334   {
00335     printf("%i %i %i %i %i\n", input.getVal(itsProbe),
00336         input.getVal(itsProbe.i-1, itsProbe.j-1),
00337         input.getVal(itsProbe.i+1, itsProbe.j-1),
00338         input.getVal(itsProbe.i+1, itsProbe.j+1),
00339         input.getVal(itsProbe.i-1, itsProbe.j+1));
00340   }
00341 
00342  // cvEqualizeHist(img2ipl(input),img2ipl(input));
00343   itsGanglionCellsInput[LUM] = input;
00344 
00345   //itsGanglionCellsInput[RG] = rg;
00346   //itsGanglionCellsInput[BY] = by;
00347 
00348 
00349   evolve();
00350 }
00351 
00352 // ######################################################################
00353 void Ganglion::evolve()
00354 {
00355   float R = 3.5; //Sensor noise variance
00356   float Q=0.5;  //Prcess noise variance
00357 
00358   //getchar();
00359   for(int i=0; i<1; i++)
00360   {
00361 
00362     //Update the gagnlion cells
00363     Image<float>::const_iterator inPtr = itsGanglionCellsInput[i].begin();
00364     Image<float>::const_iterator inStop = itsGanglionCellsInput[i].end();
00365 
00366     Image<float>::iterator gangMuPtr = itsGanglionCellsMu[i].beginw();
00367     Image<float>::iterator gangPriorPtr = itsGanglionCellsPrior[i].beginw();
00368     Image<float>::iterator gangSigPtr = itsGanglionCellsSig[i].beginw();
00369     Image<float>::iterator outMuPtr = itsGanglionCellsOutput[0].beginw();
00370     Image<float>::iterator outSigPtr = itsGanglionCellsOutput[1].beginw();
00371 
00372     //Kalman filtering  for each ganglion cell
00373     while(inPtr != inStop)
00374     {
00375       //Predict
00376       float mu_hat = *gangMuPtr; // + *gangPriorPtr;
00377       float sig_hat = *gangSigPtr + Q;
00378 
00379       //update
00380       float K = (sig_hat)/(sig_hat + R);
00381       *gangMuPtr = mu_hat + K * (*inPtr - mu_hat);
00382       *gangSigPtr = (1-K)*sig_hat;
00383 
00384       //Calculate surprise KL(P(M|D),P(M))
00385       //P(M|D) = N(*gangMuPtr, * gangSigPtr);
00386       //P(M) = N(mu_hat, sig_hat);
00387 
00388       float surprise = (((*gangMuPtr-mu_hat)*(*gangMuPtr-mu_hat)) + (*gangSigPtr * *gangSigPtr) + (sig_hat*sig_hat));
00389       surprise = surprise / (2*sig_hat*sig_hat);
00390       surprise += log(sig_hat / *gangSigPtr);
00391 
00392       //if (surprise > 0.1)
00393       //  *outPtr = *inPtr;
00394       //else
00395       //*outPtr = surprise;
00396       *outMuPtr = *inPtr; //*gangMuPtr; TODO change back
00397       *outSigPtr = *gangSigPtr;
00398 
00399       ++inPtr;
00400       ++gangMuPtr;
00401       ++gangPriorPtr;
00402       ++gangSigPtr;
00403       ++outMuPtr;
00404       ++outSigPtr;
00405     }
00406   }
00407 
00408 }
00409 
00410 Layout<PixRGB<byte> > Ganglion::getDebugImage()
00411 {
00412   Layout<PixRGB<byte> > outDisp;
00413   //Display the results
00414   Image<float> gangIn = itsGanglionCellsInput[0];
00415   Image<float> gangPercMu = itsGanglionCellsMu[0];
00416 
00417   //SHOWIMG(itsGanglionCellsSig[0]);
00418 
00419 
00420   //Display result
00421   inplaceNormalize(gangIn, 0.0F, 255.0F);
00422 
00423 
00424   if (itsProbe.isValid())
00425     drawCircle(gangIn, itsProbe, 6, 255.0F);
00426   inplaceNormalize(gangPercMu, 0.0F, 255.0F);
00427   //inplaceNormalize(gangPercSig, 0.0F, 255.0F);
00428   //inplaceNormalize(gangOut, 0.0F, 255.0F);
00429 
00430   Layout<PixRGB<byte> > disp;
00431   disp = hcat(itsCurrentImg, toRGB(Image<byte>(gangPercMu)));
00432   //disp = hcat(disp, toRGB(Image<byte>(gangPercSig)));
00433   //disp = hcat(disp, toRGB(Image<byte>(gangOut)));
00434   outDisp = vcat(outDisp, disp);
00435 
00436   return outDisp;
00437 
00438 }
00439 
00440 // ######################################################################
00441 /* So things look consistent in everyone's emacs... */
00442 /* Local Variables: */
00443 /* indent-tabs-mode: nil */
00444 /* End: */
00445 
00446 #endif
00447 
Generated on Sun May 8 08:05:31 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3