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: */