Gist_Navigation.C

00001 /*!@file Robots2/Beobot2/Navigation/Gist_Navigation/Gist_Navigation.C Ice Module to log data    */
00002 // //////////////////////////////////////////////////////////////////// //
00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00004 // University of Southern California (USC) and the iLab at USC.         //
00005 // See http://iLab.usc.edu for information about this project.          //
00006 // //////////////////////////////////////////////////////////////////// //
00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00009 // in Visual Environments, and Applications'' by Christof Koch and      //
00010 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00011 // pending; application number 09/912,225 filed July 23, 2001; see      //
00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00013 // //////////////////////////////////////////////////////////////////// //
00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00015 //                                                                      //
00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00017 // redistribute it and/or modify it under the terms of the GNU General  //
00018 // Public License as published by the Free Software Foundation; either  //
00019 // version 2 of the License, or (at your option) any later version.     //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00024 // PURPOSE.  See the GNU General Public License for more details.       //
00025 //                                                                      //
00026 // You should have received a copy of the GNU General Public License    //
00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00029 // Boston, MA 02111-1307 USA.                                           //
00030 // //////////////////////////////////////////////////////////////////// //
00031 //
00032 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu>
00033 // $HeadURL: svn://ilab.usc.edu/trunk/saliency/src/Robots/Beobot2/Gist_Navigation.C
00034 // $ $Id: Gist_Navigation.C 12962 2010-03-06 02:13:53Z irock $
00035 //
00036 //////////////////////////////////////////////////////////////////////////
00037 
00038 #include "Robots/Beobot2/Navigation/Gist_Navigation/Gist_Navigation.H"
00039 #include "Ice/BeobotEvents.ice.H"
00040 
00041 #include "Raster/Raster.H"
00042 #include "Util/sformat.H"
00043 #include "Image/Image.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/ColorOps.H"  // for luminance()
00046 #include "Image/MathOps.H"  // for stdev()
00047 #include "Image/MatrixOps.H"  // for matrixMult()
00048 #include "Image/CutPaste.H"  // for inplacePaste()
00049 
00050 
00051 #include "SIFT/Keypoint.H"
00052 #include "SIFT/VisualObject.H"
00053 #include "SIFT/VisualObjectMatch.H"
00054 #include "Transport/FrameInfo.H"
00055 
00056 #include "Ice/IceImageUtils.H"
00057 
00058 #include "Gist/trainUtils.H"
00059 
00060 #define  GIST_DATA_FOLDER   "../data/train/gistFeat/"
00061 #define  TRAIN_DATA_FOLDER  "../data/train/"
00062 #define  LEARN_RATE         0.025
00063 #define  NUM_DIRECTIONS     13
00064 
00065 // ######################################################################
00066 Gist_Navigation::Gist_Navigation(OptionManager& mgr,
00067                const std::string& descrName, const std::string& tagName) :
00068   RobotBrainComponent(mgr, descrName, tagName),
00069   itsFftComputer(new GistEstimatorFFT(mgr)),
00070   itsOfs(new OutputFrameSeries(mgr)),
00071   itsFfn(new FeedForwardNetwork()),
00072   itsTimer(1000000),
00073   itsCurrImgID(-1),
00074   itsPrevProcImgID(-1)
00075 {
00076   //addSubComponent(itsFftComputer);
00077   addSubComponent(itsOfs);
00078 
00079   // initialize the feed forward network
00080   initFFN();
00081 
00082   // setup the PCA eigenvector
00083   itsPcaIcaVector =
00084     setupPcaIcaMatrix("../data/train/E_FastICA.evec", 640, 40);
00085 }
00086 
00087 // ######################################################################
00088 void Gist_Navigation::initFFN()
00089 {
00090   // instantiate a 3-layer feed-forward network
00091   // initialize with the provided parameters
00092   //FFNtrainInfo pcInfo(manager.getExtraArg(0).c_str());
00093   //ffn_place->init3L(pcInfo.h1Name, pcInfo.h2Name, pcInfo.oName,
00094   //                  pcInfo.redFeatSize, pcInfo.h1size, pcInfo.h2size,
00095   //                  pcInfo.nOutput, 0.0, 0.0);
00096 
00097   itsFfn->init3L
00098     (sformat("%sh1.nnwt",TRAIN_DATA_FOLDER),
00099      sformat("%sh2.nnwt",TRAIN_DATA_FOLDER),
00100      sformat("%so.nnwt", TRAIN_DATA_FOLDER),
00101      40, 100, 50, NUM_DIRECTIONS, LEARN_RATE, 0.0);
00102 }
00103 
00104 // ######################################################################
00105 Gist_Navigation::~Gist_Navigation()
00106 { }
00107 
00108 // ######################################################################
00109 void Gist_Navigation::start1()
00110 {
00111 }
00112 
00113 // ######################################################################
00114 void Gist_Navigation::registerTopics()
00115 {
00116   // subscribe to all sensor data
00117   this->registerSubscription("CameraMessageTopic");
00118   this->registerSubscription("MotorMessageTopic");
00119   this->registerPublisher("MotorRequestTopic");
00120 }
00121 
00122 // ######################################################################
00123 void Gist_Navigation::evolve()
00124 {
00125   // check if the current image is updated
00126   its_Curr_Img_mutex.lock();
00127   bool newImageFlag = (itsPrevProcImgID < itsCurrImgID);
00128   its_Curr_Img_mutex.unlock();
00129 
00130   // if so, process
00131   if(newImageFlag)
00132     {
00133       itsTimer.reset();
00134 
00135       its_Curr_Img_mutex.lock();
00136       itsProcImg = itsCurrImg;
00137       itsPrevProcImgID = itsCurrImgID;
00138       its_Curr_Img_mutex.unlock();
00139 
00140       //process
00141 
00142       //     std::string saveFName(sformat("ImageLog/image_%015d.ppm",currRequestID));
00143       //     LINFO("saving: %s",saveFName.c_str());
00144       //     Raster::WriteRGB(ima, saveFName);
00145       //     std::string line =
00146       //       sformat("[%15.3f] CAM filename: %s", time/1000.0, saveFName.c_str());
00147       //     line += std::string("\n");
00148 
00149       // normalize image
00150       itsNormalizedProcImg = normalize(Image<float>(luminance(itsProcImg)));
00151 
00152       // compute FFT
00153       itsFftComputer->computeGistFeatureVector(itsNormalizedProcImg);
00154       itsFftFeatures = itsFftComputer->getGist();
00155 
00156       // reduce the dimension
00157       Image<double> in = matrixMult(itsPcaIcaVector, itsFftFeatures);
00158 
00159 //       LINFO("A[%d %d]", itsPcaIcaVector.getHeight(), itsPcaIcaVector.getWidth());
00160 //       LINFO("B[%d %d]", itsFftFeatures.getHeight(),  itsFftFeatures.getWidth());
00161 
00162 //       for(int i = 0; i < itsPcaIcaVector.getHeight(); i++)
00163 //         for(int j = 0; j < itsPcaIcaVector.getWidth(); j++)
00164 //           LINFO("PCA[%3d %3d]: %f", i, j, itsPcaIcaVector.getVal(j,i));
00165 
00166 //       for(int i = 0; i < itsFftFeatures.getHeight(); i++)
00167 //         for(int j = 0; j < itsFftFeatures.getWidth(); j++)
00168 //           LINFO("FFT[%3d %3d]: %f", i, j, itsFftFeatures.getVal(j,i));
00169 
00170 //       LINFO("C[%d %d]", in.getHeight(), in.getWidth());
00171 
00172 //       for(int i = 0; i < in.getHeight(); i++)
00173 //         LINFO("dir[%3d]: %f", i, in.getVal(0,i));
00174 
00175 //       Raster::waitForKey();
00176 
00177       // run the NN
00178       itsFfn->run3L(in);
00179 
00180       // Calculate the direction from NN probabilistically
00181       // ORIGINAL ACKERMAN CODE
00182       //double target = (double)rand()/(double)RAND_MAX;
00183       //double sum = 0.0; double tprob = 0.0;
00184       //uint dir;
00185       //for(dir = 0; dir < NUM_DIRECTIONS; dir++)
00186       //  sum += itsFfn->getOutput().getVal(0,dir);
00187       //for(dir = 0; dir < NUM_DIRECTIONS; dir++)
00188       //  {
00189       //    tprob += (itsFfn->getOutput().getVal(0,dir)/sum);
00190       //    if (tprob > target) break;
00191       //  }
00192       //LINFO("target: %f, sum: %f ", target, sum);
00193       //for(uint i = 0; i < NUM_DIRECTIONS; i++)
00194       //  {
00195       //    if(i == dir)
00196       //      LINFO("NN_Dir [%3d]: %.5f -> %f ***** GO HERE *****", i,
00197       //            itsFfn->getOutput().getVal(i),
00198       //            itsFfn->getOutput().getVal(i)/sum);
00199       //    else
00200       //      LINFO("NN_Dir [%3d]: %.5f -> %f", i,
00201       //            itsFfn->getOutput().getVal(i),
00202       //            itsFfn->getOutput().getVal(i)/sum);
00203       //  }
00204 
00205 
00206       itsNNrotCommand.resize(1, NUM_DIRECTIONS, ZEROS);
00207       itsRCrotCommand.resize(1, NUM_DIRECTIONS, ZEROS);
00208                         double sum = 0.0;
00209       // Calculate the direction from NN probabilistically
00210       uint dir = 0; double max = 0.0;
00211       for(uint i = 0; i < NUM_DIRECTIONS; i++)
00212         {
00213           itsNNrotCommand.setVal
00214             (0, i,
00215              .90 * itsFfn->getOutput().getVal(0,i) +
00216              .10 * (double)rand()/(double)RAND_MAX   );
00217           if(itsNNrotCommand.getVal(0, i) > max)
00218             { dir = i; max = itsNNrotCommand.getVal(0, i); }
00219                                         sum += itsNNrotCommand.getVal(0,i);
00220         }
00221                         //Normalize
00222       for(uint i = 0; i < NUM_DIRECTIONS; i++)
00223                         {
00224                                 itsNNrotCommand.setVal(0,i,itsNNrotCommand.getVal(0,i)/sum);
00225                         }
00226 //      for(uint i = 0; i < NUM_DIRECTIONS; i++)
00227 //        {
00228 //          if(i == dir)
00229 //            LINFO("NN_Dir [%3d]: %.5f -> %.5f ***** GO HERE *****", i,
00230 //                  itsFfn->getOutput().getVal(0,i),
00231 //                  itsNNrotCommand.getVal(i));
00232 //          else
00233 //            LINFO("NN_Dir [%3d]: %.5f -> %.5f", i,
00234 //                  itsFfn->getOutput().getVal(0,i),
00235 //                  itsNNrotCommand.getVal(i));
00236 //        }
00237 
00238       // get command from Remote Control (if available)
00239       int half_ND = NUM_DIRECTIONS/2;
00240       double rot   = double(half_ND - int(dir))/double(half_ND);
00241       double trans = 1.0;
00242 
00243       LINFO("[R:%f  T:%f]", rot, trans);
00244 
00245       // check if RC is biasing
00246       int rcMode;
00247       double rcTrans, rcRot;
00248       its_Curr_Mtr_mutex.lock();
00249       rcMode  = itsRemoteMode;
00250       rcRot   = itsRcRotSpeed;
00251       rcTrans = itsRcTransSpeed;
00252       its_Curr_Mtr_mutex.unlock();
00253       LINFO("RC[M:%d R:%f  T:%f]", rcMode, rcRot, rcTrans);
00254 
00255        for(uint i = 0; i < NUM_DIRECTIONS; i++)
00256          {
00257                                          itsRCrotCommand.setVal(0,i,0);
00258          }
00259       // learn (if rc is biasing)
00260       itsTrainMode = (rcMode == 3 && (rcRot > .1 || rcRot < -.1));
00261       if(itsTrainMode) // FIXXX: SETUP ENUMERATION OF RC_MODE
00262         {
00263           LINFO("\nTRAINING\n");
00264 
00265           uint bDir = uint((half_ND)*(1.0 - rcRot));
00266           if(bDir >=0 &&  bDir < NUM_DIRECTIONS)
00267             {
00268               itsRCrotCommand.setVal(0, bDir, 1.0);
00269 
00270               // give some weight to nearby orientations.
00271               if (bDir > 0)
00272                 itsRCrotCommand.setVal(0, bDir-1, 0.5);
00273               if (bDir > 1)
00274                 itsRCrotCommand.setVal(0, bDir-2, 0.25);
00275               if (bDir < NUM_DIRECTIONS - 1)
00276                 itsRCrotCommand.setVal(0, bDir+1, 0.5);
00277               if (bDir < NUM_DIRECTIONS - 2)
00278                 itsRCrotCommand.setVal(0, bDir+2, 0.25);
00279             }
00280           else LFATAL("CORRUPTED rcRot: %f", rcRot);
00281 
00282 //                                        for(uint i = 0; i < NUM_DIRECTIONS; i++)
00283 //                                        {
00284 //                                                LINFO("RC_Dir [%3d]: %.5f", i, itsRCrotCommand.getVal(i));
00285 //                                        }
00286 
00287 
00288           itsFfn->backprop3L(itsRCrotCommand);
00289 
00290           // save new weights
00291           itsFfn->write3L
00292             (sformat("%sh1.nnwt",TRAIN_DATA_FOLDER),
00293              sformat("%sh2.nnwt",TRAIN_DATA_FOLDER),
00294              sformat("%so.nnwt", TRAIN_DATA_FOLDER));
00295 
00296           // set the RC rotation as rotation command
00297           rot   = rcRot;
00298         }
00299 
00300       // TODO: RC motor cap related issues
00301       //       FIX BeoPilot RC command input
00302 
00303       // setup navigation command and send it to BeoPilot
00304       LINFO("Final[T:%f  R:%f]", trans, rot);
00305       updateMotor(trans, rot);
00306 
00307       //drawState();
00308       //itsOfs->writeRGB(itsDispImg, "Gist_nav", FrameInfo("Gist_nav",SRC_POS));
00309     }
00310 }
00311 
00312 // ######################################################################
00313 // normalize image by subtracting it with mean and dividing by stdev
00314 Image<float> Gist_Navigation::normalize(Image<float> img)
00315 {
00316   // ORIGINAL ACKERMAN & ITTI 2005 normalize code
00317 //     /************** 2: Do Image Preproc ****************/
00318 //     // extract Value (brightness/luminance/intensity/whatever) from HSV
00319 //     total = 0.0;
00320 //     iptr  = bwimage;
00321 //     while (data != ima.end())
00322 //     {
00323 //       double max = 0.0;
00324 //       if (data->red()   > max) max = data->red();
00325 //       if (data->green() > max) max = data->green();
00326 //       if (data->blue()  > max) max = data->blue();
00327 //       *iptr = max;
00328 //       data++;
00329 //       total += *iptr++;
00330 //     }
00331 
00332 //     //normalize
00333 //     mean = total / ((double)IMAGESIZE);
00334 //     std = 0.0;
00335 //     for(i = 0; i < IMAGESIZE; i++)
00336 //       std += pow(bwimage[i]-mean,2);
00337 //     std /= IMAGESIZE-1;
00338 //     std = sqrt(std);
00339 //     for(i = 0; i < IMAGESIZE; i++)
00340 //     {
00341 //       bwimage[i] -= mean;
00342 //       bwimage[i] /= std;
00343 //     }
00344 
00345   // our approach
00346   Image<float> tImg = img;
00347   double tMean  = float(mean(img));
00348   double tStdev = float(stdev(img));
00349   tImg -= tMean;
00350   tImg /= tStdev;
00351 
00352   return tImg;
00353 }
00354 
00355 // ######################################################################
00356 void Gist_Navigation::drawState()
00357 {
00358   uint w = itsProcImg.getWidth();
00359   uint h = itsProcImg.getHeight();
00360 
00361   itsDispImg.resize(w*2, 2*h, NO_INIT);
00362 
00363   // original image
00364   inplacePaste(itsDispImg, itsProcImg, Point2D<int>(0, 0));
00365 
00366   // normalized image
00367   Image<float> dispNorm = itsNormalizedProcImg;
00368   inplaceNormalize(dispNorm, 0.0f, 255.0f);
00369   Image<PixRGB<byte> > dn = Image<PixRGB<byte> >(toRGB(dispNorm));
00370   inplacePaste(itsDispImg, dn, Point2D<int>(w, 0));
00371 
00372   // Fourier Transform Image
00373   Image<float> fftImg = itsFftComputer->getFftImage();
00374   inplaceNormalize(fftImg, 0.0f, 255.0f);
00375   Image<PixRGB<byte> > fft = Image<PixRGB<byte> >(toRGB(fftImg));
00376   inplacePaste(itsDispImg, fft, Point2D<int>(0, h));
00377 
00378         std::vector<SimpleMeter> NNrotCommandMeters(13,SimpleMeter(20,60,0,100));
00379         std::vector<SimpleMeter> RCrotCommandMeters(13,SimpleMeter(20,60,0,100));
00380 
00381         char buffer[128];
00382         for(uint i = 0; i < NUM_DIRECTIONS; i++)
00383         {
00384 
00385                 sprintf(buffer, "%3d",int(itsNNrotCommand.getVal(i)*100));
00386 
00387                 Point2D<int> pastePoint = Point2D<int>(
00388                                         10+NNrotCommandMeters[i].getWidth()*i*1.05+w,
00389                                         2*h -15
00390                                         );
00391 
00392                 writeText(itsDispImg, pastePoint, buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),SimpleFont::FIXED(6));
00393 
00394                 pastePoint = Point2D<int>(
00395                                 10+NNrotCommandMeters[i].getWidth()*i*1.05+w,
00396                                 2*h - NNrotCommandMeters[i].getHeight() - 30
00397                                 );
00398                 inplacePaste(itsDispImg, NNrotCommandMeters[i].render(itsNNrotCommand.getVal(i)*100), pastePoint );
00399 
00400                 sprintf(buffer, "%3d",int(itsRCrotCommand.getVal(i)*100));
00401 
00402                 pastePoint = Point2D<int>(
00403                                         10+NNrotCommandMeters[i].getWidth()*i*1.05+w,
00404                                         2*h - RCrotCommandMeters[i].getHeight() - 45
00405                                         );
00406 
00407                 writeText(itsDispImg, pastePoint, buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),SimpleFont::FIXED(6));
00408 
00409                 pastePoint = Point2D<int>(
00410                                 10+RCrotCommandMeters[i].getWidth()*i*1.05+w,
00411                                 2*h - 2*RCrotCommandMeters[i].getHeight() - 60
00412                                 );
00413                 inplacePaste(itsDispImg, NNrotCommandMeters[i].render(itsRCrotCommand.getVal(i)*100), pastePoint );
00414         }
00415 
00416 }
00417 
00418 // ######################################################################
00419 void Gist_Navigation::updateMessage
00420 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&)
00421 {
00422   // camera message
00423   if(eMsg->ice_isA("::BeobotEvents::CameraMessage"))
00424   {
00425     // store the image
00426     BeobotEvents::CameraMessagePtr cameraMsg =
00427       BeobotEvents::CameraMessagePtr::dynamicCast(eMsg);
00428 
00429     int currRequestID = cameraMsg->RequestID;
00430     Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> >(cameraMsg->image);
00431 
00432     LDEBUG("Got a CameraMessage with Request ID = %d", currRequestID);
00433 
00434     its_Curr_Img_mutex.lock();
00435     itsCurrImg = img;
00436     itsCurrImgID = cameraMsg->RequestID;
00437     its_Curr_Img_mutex.unlock();
00438   }
00439   // motor message
00440   else if(eMsg->ice_isA("::BeobotEvents::MotorMessage"))
00441   {
00442     BeobotEvents::MotorMessagePtr mtrMsg =
00443       BeobotEvents::MotorMessagePtr::dynamicCast(eMsg);
00444     LDEBUG("Got a MotorMessage with Request ID = %d: RC Trans %f ,Rc Rot %f",
00445           mtrMsg->RequestID, itsRcTransSpeed, itsRcRotSpeed);
00446     its_Curr_Mtr_mutex.lock();
00447     itsRemoteMode = mtrMsg->rcMode;
00448     itsRcTransSpeed = mtrMsg->rcTransVel;
00449     itsRcRotSpeed = mtrMsg->rcRotVel;
00450     its_Curr_Mtr_mutex.unlock();
00451   }
00452 }
00453 
00454 // ######################################################################
00455 void Gist_Navigation::updateMotor(double tran, double rot)
00456 {
00457     BeobotEvents::MotorRequestPtr msg = new BeobotEvents::MotorRequest;
00458     msg->transVel = tran;
00459     msg->rotVel   = rot;
00460     this->publish("MotorRequestTopic", msg);
00461 //    LINFO("[%d] Publish motor request", itsPrevProcImgID);
00462 }
00463 
00464 // ######################################################################
00465 /* So things look consistent in everyone's emacs... */
00466 /* Local Variables: */
00467 /* indent-tabs-mode: nil */
00468 /* End: */
Generated on Sun May 8 08:41:18 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3