Landmark.C

Go to the documentation of this file.
00001 /*!@file Beobot/Landmark.C Landmark class for localization */
00002 
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: Christian Siagian <siagian@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Beobot/Landmark.C $
00035 // $Id: Landmark.C 14309 2010-12-11 02:23:48Z siagian $
00036 //
00037 // FIXXX ADD: motion recognition
00038 //      different VOMA
00039 
00040 #include "Beobot/Landmark.H"
00041 #include "Util/Timer.H"
00042 #include "Raster/Raster.H"
00043 #include "Image/CutPaste.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/MathOps.H"
00046 
00047 #include <iostream>
00048 #include <list>
00049 #include <fstream>
00050 
00051 #define FWAIT_NUM                    5U
00052 #define MIN_LINKS                    3U
00053 #define NUM_FRAME_LOOKBACK           10
00054 
00055 // ######################################################################
00056 Landmark::Landmark(const std::string& name):
00057   itsName(name),
00058   itsVoma (new VisualObjectMatchAlgo(VOMA_SIMPLE)),
00059   //VOMA_KDTREE or VOMA_KDTREEBBF
00060   itsVisualObjectDB(new VisualObjectDB()),
00061   itsOffsetCoords(),
00062   itsVisualObjectFNum(),
00063   itsTempVisualObjectDB(new VisualObjectDB()),
00064   itsTempOffsetCoords(),
00065   itsTempVisualObjectFNum(),
00066   itsKPtrackers(),
00067   itsCip()
00068 {
00069   // these numbers are default value (may be incorrect)
00070   // should check if there are objects in the DB first
00071   itsLatestVisualObjectFNum      = 0;
00072   itsLatestTempVisualObjectFNum  = 0;
00073 }
00074 
00075 // ######################################################################
00076 Landmark::Landmark(rutz::shared_ptr<VisualObject>& obj,
00077                    Point2D<int> objOffset, uint fNum,
00078                    const std::string& name):
00079   itsName(name),
00080   itsVoma (new VisualObjectMatchAlgo(VOMA_SIMPLE)),
00081   //VOMA_KDTREE or VOMA_KDTREEBBF
00082   itsVisualObjectDB(new VisualObjectDB()),
00083   itsOffsetCoords(),
00084   itsVisualObjectFNum(),
00085   itsTempVisualObjectDB(new VisualObjectDB()),
00086   itsTempOffsetCoords(),
00087   itsTempVisualObjectFNum(),
00088   itsKPtrackers(),
00089   itsCip()
00090 {
00091   itsLatestVisualObjectFNum      = fNum;
00092   itsLatestTempVisualObjectFNum  = 0;
00093   init(obj, objOffset, fNum);
00094 }
00095 
00096 // ######################################################################
00097 void Landmark::init(rutz::shared_ptr<VisualObject>& obj,
00098                     Point2D<int> objOffset, uint fNum)
00099 {
00100   // add the first object to the newly created databases
00101   // landmarks are found because it is salient
00102   // or labelled salient by the input program
00103   addObject(obj, objOffset, fNum);
00104 
00105   // register the keypoints locations
00106   for(uint i = 0; i < obj->numKeypoints(); i++)
00107     {
00108       rutz::shared_ptr<KeypointTracker>
00109         newKPtracker(new KeypointTracker(sformat("KPtrk%d_%d", fNum, i)));
00110       newKPtracker->add(obj->getKeypoint(i), objOffset, fNum);
00111       itsKPtrackers.push_back(newKPtracker);
00112     }
00113   LINFO("there are %"ZU" keypoints tracked", itsKPtrackers.size());
00114 }
00115 
00116 // ######################################################################
00117 bool Landmark::loadFrom(const std::string& fname)
00118 {
00119   // load the actual VisualObjectDatabase
00120   bool succeed = false;  
00121 
00122   // FILE *fp; 
00123   // if((fp = fopen(fname.c_str(),"rb")) == NULL)
00124   //   LFATAL("Landmark file %s not found", fname.c_str());  
00125   // LINFO("Loading Environment file %s",envFName.c_str());
00126 
00127   const char *fn = fname.c_str();
00128   LINFO("Loading Visual Object database: '%s'...", fn);
00129 
00130   std::ifstream inf(fn);
00131   if (inf.is_open() == false) 
00132     { LERROR("Cannot open '%s' -- USING EMPTY", fn); succeed = false; }
00133   else
00134     {
00135       // inf>>(*this);
00136       std::string name;
00137       std::getline(inf, name);
00138       
00139       itsVisualObjectDB->setName(name);
00140       
00141       uint size; inf>>size;      
00142       itsVisualObjectDB->clearObjects(size); 
00143       
00144       uint count = 0;
00145       while (count < size)
00146         {
00147           rutz::shared_ptr<VisualObject> newvo(new VisualObject());
00148 
00149           //is>>(*newvo);
00150           newvo->createVisualObject(inf, *newvo, false);
00151 
00152           std::string iname = newvo->getImageFname();
00153 
00154           // we add the actual path to the image file name       
00155           std::string::size_type spos =  fname.find_last_of('/');        
00156           std::string filePath("");
00157           if(spos != std::string::npos)  
00158             filePath = fname.substr(0,spos+1);   
00159           std::string fiName =  filePath + iname;          
00160           newvo->setImageFname(fiName);          
00161           newvo->loadImage();
00162 
00163           itsVisualObjectDB->setObject(count, newvo);
00164           count++;
00165           LDEBUG("[%d] %s ",  count, fiName.c_str());
00166         }
00167 
00168       inf.close();
00169       LINFO("Done. Loaded %u VisualObjects.", numObjects());
00170       succeed = true;
00171     }
00172   //Raster::waitForKey();
00173   
00174   
00175 
00176   
00177   //if(itsVisualObjectDB->loadFrom(fname,false))
00178   if(succeed)
00179     {
00180       // set the name
00181       itsName = itsVisualObjectDB->getName();
00182 
00183       // extract the other information from the name
00184       // I know. it's clever
00185       for(uint i = 0; i < itsVisualObjectDB->numObjects(); i++)
00186         {
00187           std::string tName = itsVisualObjectDB->getObject(i)->getName();
00188           int ioff, joff, fNum;
00189           std::string temp;
00190 
00191           // ObjName_Ioffset_Ioffset_fNum
00192           // we parse it in reverse
00193           LDEBUG("tName: %s", tName.c_str());
00194           int lupos = tName.find_last_of('_');
00195           temp = tName.substr(lupos+1, tName.length()-lupos-1);
00196           tName = tName.substr(0, lupos);
00197           fNum = atoi(temp.c_str());
00198 
00199           lupos = tName.find_last_of('_');
00200           temp = tName.substr(lupos+1, tName.length()-lupos-1);
00201           tName = tName.substr(0, lupos);
00202           joff = atoi(temp.c_str());
00203 
00204           lupos = tName.find_last_of('_');
00205           temp = tName.substr(lupos+1, tName.length()-lupos-1);
00206           tName = tName.substr(0, lupos);
00207           ioff = atoi(temp.c_str());
00208 
00209           tName = tName.substr(0, lupos);
00210 
00211           LDEBUG("[%3d] %30s: (%3d %3d) fnum: %5d",
00212                  i, tName.c_str(), ioff, joff, fNum);
00213 
00214           itsOffsetCoords.push_back(Point2D<int>(ioff, joff));
00215           itsVisualObjectFNum.push_back(fNum);
00216 
00217           itsVisualObjectDB->getObject(i)->setName(tName);
00218 
00219         }
00220       return true;
00221     }
00222   else return false;
00223 }
00224 
00225 // ######################################################################
00226 void Landmark::setSessionInfo()
00227 {
00228   itsSession.clear();
00229   itsSessionIndexRange.clear();
00230   ASSERT(itsVisualObjectDB->numObjects() > 0);
00231 
00232   std::string lname; uint sind = 0, eind = 0;
00233   for(uint i = 0; i < itsVisualObjectDB->numObjects(); i++)
00234     {
00235       // get the proper session stem
00236       // take out the suffix object numbers: _SAL_xxxxxxx_xx
00237       std::string sname = itsVisualObjectDB->getObject(i)->getName();
00238       sname = sname.substr(0, sname.find_last_of('_'));
00239       sname = sname.substr(0, sname.find_last_of('_'));
00240       sname = sname.substr(0, sname.find_last_of('_'));
00241 
00242       // if session name changed then add it to the list
00243       if(i != 0 && sname.compare(lname))
00244         {
00245           itsSessionIndexRange.push_back(std::pair<uint,uint>(sind,eind));
00246           itsSession.push_back(lname);
00247           sind = i;
00248         }
00249       lname = sname;
00250       eind = i;
00251     }
00252 
00253   // add the last session if needed
00254   itsSessionIndexRange.push_back(std::pair<uint,uint>(sind,eind));
00255   itsSession.push_back(lname);
00256 
00257   // print the sessions
00258   uint nSession = itsSession.size();
00259   for(uint i = 0; i < nSession; i++)
00260     LDEBUG("session[%3d] %30s: [%4d %4d]", i, itsSession[i].c_str(),
00261            itsSessionIndexRange[i].first, itsSessionIndexRange[i].second);
00262 
00263   // compute the average salient features of the VO in the landmark
00264   computeSalientFeatures();
00265 }
00266 
00267 // ######################################################################
00268 void Landmark::computeSalientFeatures()
00269 {
00270   uint nObject = numObjects();
00271   if (nObject == 0) return;
00272   uint nFeatures = itsVisualObjectDB->getObject(0)->numFeatures();
00273   itsSalientFeatures.resize(nFeatures);
00274 
00275   // get features of each object
00276   for(uint i = 0; i < nFeatures; i++)
00277     {
00278       Image<double> temp(1,nObject, NO_INIT);
00279       Image<double>::iterator aptr = temp.beginw(), stop = temp.endw();
00280 
00281       uint j = 0;
00282       while (aptr != stop)
00283         {
00284           *aptr++ = itsVisualObjectDB->getObject(j)->getFeature(i); j++;
00285         }
00286       double tMean  = mean(temp);
00287       double tStdev = stdev(temp);
00288       LDEBUG("[%5d] m: %f s: %f", i, tMean, tStdev);
00289 
00290       itsSalientFeatures[i] = std::pair<double,double>(tMean, tStdev);
00291     }
00292 }
00293 
00294 // ######################################################################
00295 float Landmark::matchSalientFeatures(rutz::shared_ptr<VisualObject> object)
00296 {
00297 //  uint nObject = numObjects();
00298 //  if (nObject == 0) return -1.0;
00299 
00300   std::vector<float> objFeat = object->getFeatures();
00301 
00302   // check with every objects
00303 //  float min = 1.0; float max = 0.0;
00304 //   for(uint j = 0; j < nObject; j++)
00305 //     {
00306 //       std::vector<double> feat2 = getObject(j)->getFeatures();
00307 
00308 //       // feature similarity  [ 0.0 ... 1.0 ]:
00309 //       float cval = 0.0;
00310 //       for(uint i = 0; i < objFeat.size(); i++)
00311 //         {
00312 //           float val = pow(objFeat[i] - feat2[i], 2.0); cval += val;
00313 //         }
00314 //       cval = sqrt(cval/objFeat.size());
00315 //       if(cval < min) min = cval;
00316 //       if(cval > max) max = cval;
00317 //       LDEBUG("cval[%d]: %f", j, cval);
00318 //     }
00319 
00320   // feature similarity  [ 0.0 ... 1.0 ]:
00321   float cval = 0.0;
00322 
00323   std::vector<float>::iterator aptr = objFeat.begin(), stop = objFeat.end();
00324   std::vector<std::pair<double,double> >::iterator
00325     bptr = itsSalientFeatures.begin();
00326   while (aptr != stop)
00327     {
00328       float val = pow(*aptr++ - (*bptr).first, 2.0F); bptr++;
00329       cval += val;
00330     }
00331 
00332 //   float cval2 = 0.0F;
00333 //   for(uint i = 0; i < objFeat.size(); i++)
00334 //     {
00335 //       float val = pow(objFeat[i] - itsSalientFeatures[i].first, 2.0F);
00336 //       cval2 += val;
00337 //     }
00338 
00339   cval = sqrt(cval/objFeat.size());
00340 //  LDEBUG("min: %f: max: %f cval: %f", min, max, cval);
00341 
00342   // range: [ 0.0 ... 1.0 ] the lower the better the match
00343   return cval;
00344 }
00345 
00346 // ######################################################################
00347 bool Landmark::saveTo(const std::string& fname)
00348 {
00349   // put the Landmark name as the DB name
00350   itsVisualObjectDB->setName(itsName);
00351 
00352   uint nObjects = itsVisualObjectDB->numObjects();
00353   std::vector<std::string> tNames(nObjects);
00354 
00355   // put all the individual object information on the VO name
00356   // ObjName iOffset jOffset fNum
00357   for(uint i = 0; i < nObjects; i ++)
00358     {
00359       int ioff, joff, fNum;
00360       ioff = itsOffsetCoords[i].i;
00361       joff = itsOffsetCoords[i].j;
00362       fNum = itsVisualObjectFNum[i];
00363 
00364       std::string orgName = itsVisualObjectDB->getObject(i)->getName();
00365       tNames[i] = orgName;
00366       LDEBUG("%s__%d_%d_%d", orgName.c_str(), ioff, joff, fNum);
00367       std::string
00368         appName(sformat("%s_%d_%d_%d",
00369                         orgName.c_str(), ioff, joff, fNum));
00370 
00371       itsVisualObjectDB->getObject(i)->setName(std::string(appName));
00372     }
00373 
00374   // save the VisualObject DB
00375   bool retVal = itsVisualObjectDB->saveTo(fname);
00376 
00377   // revert back to the original names
00378   for(uint i = 0; i < nObjects; i ++)
00379     {
00380       itsVisualObjectDB->getObject(i)->setName(tNames[i]);
00381     }
00382   return retVal;
00383 }
00384 
00385 // ######################################################################
00386 Landmark::~Landmark()
00387 { }
00388 
00389 // ######################################################################
00390 // build the landmark by adding the new Visual Object
00391 rutz::shared_ptr<VisualObjectMatch>
00392 Landmark::build(rutz::shared_ptr<VisualObject> obj,
00393                 Point2D<int> objOffset, uint fNum)
00394 {
00395   // if this is the first item
00396   if(numObjects() == 0)
00397     {
00398       init(obj, objOffset, fNum);
00399       return rutz::shared_ptr<VisualObjectMatch>();
00400     }
00401   else
00402     return input(obj, objOffset, fNum);
00403 }
00404 
00405 // ######################################################################
00406 // build the landmark by adding visual object with no salient point
00407 // (image of whole frame, for example)
00408 rutz::shared_ptr<VisualObjectMatch>
00409 Landmark::build(rutz::shared_ptr<VisualObject> obj, uint fNum)
00410 {
00411   return build(obj, Point2D<int>( 0,  0), fNum);
00412 }
00413 
00414 // ######################################################################
00415 // just like build except it does not add the object
00416 // only return where it would have been placed (in DB or Temp DB)
00417 // or if it is rejected altogether
00418 rutz::shared_ptr<VisualObjectMatch>
00419 Landmark::buildCheck(rutz::shared_ptr<VisualObject> obj,
00420                      Point2D<int> objOffset, uint fNum,
00421                      bool &inDB, bool &inTDB, int &tIndex)
00422 {
00423   // if this is the first item
00424   if(numObjects() == 0)
00425     {
00426       // init situation
00427       inDB = false; inTDB = false;
00428       return rutz::shared_ptr<VisualObjectMatch>();
00429     }
00430   else
00431     return inputCheck(obj, objOffset, fNum, inDB, inTDB, tIndex);
00432 }
00433 
00434 // ######################################################################
00435 // corresponding non salient object input
00436 rutz::shared_ptr<VisualObjectMatch>
00437 Landmark::buildCheck(rutz::shared_ptr<VisualObject> obj, uint fNum,
00438                 bool &inDB, bool &inTDB, int &tIndex)
00439 {
00440   return buildCheck(obj, Point2D<int>( 0,  0), fNum,
00441                     inDB, inTDB, tIndex);
00442 }
00443 
00444 // ######################################################################
00445 // build the landmark using salient object
00446 // based on information passed by build check
00447 rutz::shared_ptr<VisualObjectMatch>
00448 Landmark::build(rutz::shared_ptr<VisualObject> obj,
00449                 Point2D<int> objOffset, uint fNum,
00450                 bool inDB, bool inTDB, int tIndex,
00451                 rutz::shared_ptr<VisualObjectMatch> cmatch)
00452 {
00453   // if this is the first item
00454   if(numObjects() == 0)
00455     {
00456       init(obj, objOffset, fNum);
00457       return rutz::shared_ptr<VisualObjectMatch>();
00458     }
00459   else
00460     return input(obj, objOffset, fNum, inDB, inTDB, tIndex, cmatch);
00461 }
00462 
00463 // ######################################################################
00464 // build the landmark using non-salient object
00465 // based on information passed by build check
00466 rutz::shared_ptr<VisualObjectMatch>
00467 Landmark::build(rutz::shared_ptr<VisualObject> obj, uint fNum,
00468                 bool inDB, bool inTDB, int tIndex,
00469                 rutz::shared_ptr<VisualObjectMatch> cmatch)
00470 {
00471   return build(obj, Point2D<int>(0,0), fNum, inDB, inTDB, tIndex, cmatch);
00472 }
00473 
00474 // ######################################################################
00475 // track the landmark using the new Visual Object
00476 rutz::shared_ptr<VisualObjectMatch>
00477 Landmark::input(rutz::shared_ptr<VisualObject> obj,
00478                 Point2D<int> objOffset, uint fNum)
00479 {
00480   Image<PixRGB<byte> > objImg = obj->getImage();
00481   int objW = objImg.getDims().w();
00482   int objH = objImg.getDims().h();
00483 
00484   Rectangle objRect(objOffset, objImg.getDims());
00485   LINFO("%s (sal:[%d %d]) info: at [%d, %d, %d, %d]: %d by %d",
00486         obj->getName().c_str(), obj->getSalPoint().i, obj->getSalPoint().j,
00487         objOffset.i, objOffset.j,
00488         objOffset.i+objW-1, objOffset.j + objH-1, objW, objH);
00489 
00490   // find match with the last NUM_FRAME_LOOKBACK
00491   //  objects in the DB
00492   rutz::shared_ptr<VisualObjectMatch> cmatch;
00493   int mInd = findDBmatch(obj, cmatch, NUM_FRAME_LOOKBACK);
00494   LINFO("found DB match: %d", mInd);
00495 
00496   // if match not found and DB is empty
00497   if(mInd == -1)
00498     {
00499       int mtInd = findTempDBmatch(obj, cmatch, NUM_FRAME_LOOKBACK);
00500       LINFO("found TDB match: %d",mtInd);
00501 
00502       // if we find a match with a temp object
00503       if(mtInd != -1)
00504         {
00505           // move the temp object to DB
00506           moveTempVisualObjectToDB(mtInd);
00507           LINFO("now have %d objects",
00508                 itsVisualObjectDB->numObjects());
00509         }
00510       else
00511         {
00512           // also could not find a match in the temp holding
00513           LINFO("not adding %s (%d) to landmark %s",
00514                 obj->getName().c_str(), fNum, itsName.c_str());
00515           return cmatch;
00516         }
00517     }
00518 
00519   // special framing for checking with whole scene
00520   if(obj->getSalPoint().i == -1 && obj->getSalPoint().j == -1)
00521     cmatch = cropInputImage(obj, objOffset, mInd, cmatch);
00522 
00523   // add object to the temp db:
00524   LINFO("put to temp holding first");
00525   tAddObject(obj, objOffset, fNum);
00526 
00527   // use the matches from the actual inserted object
00528   //trackKeypoints(cmatch, mInd);
00529 
00530   return cmatch;
00531 }
00532 
00533 // ######################################################################
00534 // track check the landmark using the new Visual Object
00535 rutz::shared_ptr<VisualObjectMatch>
00536 Landmark::inputCheck(rutz::shared_ptr<VisualObject> obj,
00537                      Point2D<int> objOffset, uint fNum,
00538                      bool &inDB, bool &inTDB, int &tIndex)
00539 {
00540   Image<PixRGB<byte> > objImg = obj->getImage();
00541   int objW = objImg.getDims().w();
00542   int objH = objImg.getDims().h();
00543 
00544   Rectangle objRect(objOffset, objImg.getDims());
00545   LINFO("%s (sal:[%d %d]) info: at [%d, %d, %d, %d]: %d by %d",
00546         obj->getName().c_str(), obj->getSalPoint().i, obj->getSalPoint().j,
00547         objOffset.i, objOffset.j,
00548         objOffset.i+objW-1, objOffset.j + objH-1, objW, objH);
00549 
00550   // find match with the last NUM_FRAME_LOOKBACK
00551   // objects in the DB
00552   rutz::shared_ptr<VisualObjectMatch> cmatch;
00553   int mInd = findDBmatch(obj, cmatch, NUM_FRAME_LOOKBACK);
00554   LINFO("find DB match: %d", mInd);
00555 
00556   // if match not found and DB is empty
00557   if(mInd == -1)
00558     {
00559       inDB = false;
00560       int mtInd = findTempDBmatch(obj, cmatch, NUM_FRAME_LOOKBACK);
00561       LINFO("found match at temp: %d",mtInd);
00562 
00563       // if we find a match with a temp objects
00564       if(mtInd != -1) { inTDB = true; tIndex = mtInd; }
00565       else
00566         {
00567           // also could not find a match in the temp holding
00568           inTDB = false; tIndex = -1;
00569           LINFO("cannot add %s (%d) to landmark %s",
00570                 obj->getName().c_str(), fNum, itsName.c_str());
00571           return cmatch;
00572         }
00573     }
00574   // it matches with DB, so TDB is irrelevant (default to false)
00575   else { inDB = true; inTDB = false; tIndex = mInd; }
00576 
00577   return cmatch;
00578 }
00579 
00580 // ######################################################################
00581 // track the landmark using the new Visual Object
00582 // with the information passed by buildcheck
00583 rutz::shared_ptr<VisualObjectMatch>
00584 Landmark::input(rutz::shared_ptr<VisualObject> obj,
00585                 Point2D<int> objOffset, uint fNum,
00586                 bool inDB, bool inTDB, int tIndex,
00587                 rutz::shared_ptr<VisualObjectMatch> cmatch)
00588 {
00589   Image<PixRGB<byte> > objImg = obj->getImage();
00590   int objW = objImg.getDims().w();
00591   int objH = objImg.getDims().h();
00592 
00593   Rectangle objRect(objOffset, objImg.getDims());
00594   LINFO("%s (sal:[%d %d]) at [%d, %d, %d, %d]: %d by %d: {%d %d %d}",
00595         obj->getName().c_str(), obj->getSalPoint().i, obj->getSalPoint().j,
00596         objOffset.i, objOffset.j,
00597         objOffset.i+objW-1, objOffset.j + objH-1, objW, objH,
00598         inDB, inTDB,tIndex);
00599 
00600   // if not match just return without inserting
00601   if(!inDB && !inTDB)
00602     {
00603       // no matching was done, return null pointer
00604       return rutz::shared_ptr<VisualObjectMatch>();
00605     }
00606 
00607   // if match was found at TDB
00608   if(!inDB && inTDB)
00609     {
00610       // move the temp object to DB
00611       moveTempVisualObjectToDB(tIndex);
00612       LINFO("now have %d objects", itsVisualObjectDB->numObjects());
00613     }
00614 
00615   // special framing for checking with whole scene
00616   if(obj->getSalPoint().i == -1 && obj->getSalPoint().j == -1)
00617     cmatch = cropInputImage(obj, objOffset, tIndex, cmatch);
00618 
00619   // add object to the temp db:
00620   LINFO("put to temp holding first");
00621   tAddObject(obj, objOffset, fNum);
00622 
00623   // no matching was done, return null pointer
00624   return rutz::shared_ptr<VisualObjectMatch>();
00625 }
00626 
00627 // ######################################################################
00628 rutz::shared_ptr<VisualObjectMatch> Landmark::cropInputImage
00629 ( rutz::shared_ptr<VisualObject> &obj, Point2D<int> &objOffset,
00630   int mInd, rutz::shared_ptr<VisualObjectMatch> cmatch)
00631 {
00632   const Image<PixRGB<byte> > objImg = obj->getImage();
00633 
00634   // get the bounding box for tracked subregion
00635   Rectangle tempR = cmatch->getOverlapRect();
00636   LINFO("getOverlapRect [ %d, %d, %d, %d ]",
00637         tempR.top(), tempR.left(), tempR.bottomI(), tempR.rightI());
00638   tempR = tempR.getOverlap(objImg.getBounds());
00639 
00640   // if we are tracking,
00641   // make sure the image does not increase uncontrollably
00642   Dims prevDims =
00643     itsVisualObjectDB->getObject(mInd)->getImage().getDims();
00644   if((tempR.width()  > 1.05 * prevDims.w()) ||
00645      (tempR.height() > 1.05 * prevDims.h())   )
00646     {
00647       LINFO("%d by %d  vs %d by %d resize window manually",
00648             tempR.width(),tempR.height(), prevDims.w(), prevDims.h());
00649 
00650       Point2D<int> nPt(int(-cmatch->getSIFTaffine().tx),
00651                   int(-cmatch->getSIFTaffine().ty) );
00652 
00653       tempR = Rectangle(nPt, prevDims).getOverlap(objImg.getBounds());
00654       LINFO(" at [%d, %d, %d, %d]: %d by %d",
00655             nPt.i , nPt.j,
00656             nPt.i + prevDims.w() - 1,  nPt.j + prevDims.h() - 1,
00657             prevDims.w(),  prevDims.h());
00658     }
00659 
00660   // crop image and create new Visual Object
00661   Image< PixRGB<byte> > cImg = crop(objImg, tempR);
00662   objOffset.i += tempR.left();
00663   objOffset.j += tempR.top();
00664   LINFO("Overlap object: (%d,%d)", objOffset.i, objOffset.j);
00665 
00666   std::string wName = obj->getName() + std::string("-SAL");
00667   std::string wfName = wName + std::string(".png");
00668   obj.reset(new VisualObject(wName, wfName, cImg));
00669 
00670   // return match between DB and the object
00671   bool isSIFTfit;
00672   rutz::shared_ptr<VisualObjectMatch>
00673     cmatch2 = match(itsVisualObjectDB->getObject(mInd), obj, isSIFTfit);
00674   return cmatch2;
00675 }
00676 
00677 // ######################################################################
00678 void Landmark::transferEvidence
00679 ( rutz::shared_ptr<Landmark> landmark2,
00680   bool indb2, bool intdb2, int tIndex2,
00681   rutz::shared_ptr<VisualObjectMatch> cmatch)
00682 {
00683   rutz::shared_ptr<VisualObject> object2;
00684   Point2D<int> objOffset2;
00685   uint fnum2;
00686 
00687   LINFO("{%d, %d, %d}", indb2, intdb2, tIndex2);
00688 
00689   // insert straight to the Visual Object DB
00690   if(indb2)
00691     {
00692       object2    = landmark2->getObject(tIndex2);
00693       objOffset2 = landmark2->getOffsetCoords(tIndex2);
00694       fnum2      = landmark2->getVisualObjectFNum(tIndex2);
00695 
00696       addObject(object2, objOffset2, fnum2);
00697     }
00698   else if(intdb2)
00699     {
00700       object2    = landmark2->getTempObject(tIndex2);
00701       objOffset2 = landmark2->getTempOffsetCoords(tIndex2);
00702       fnum2      = landmark2->getTempVisualObjectFNum(tIndex2);
00703 
00704       addObject(object2, objOffset2, fnum2);
00705     }
00706 
00707   // cleanly delete the visual evidence from the other list
00708   if(indb2 || intdb2)
00709     landmark2->cleanDelete(indb2, intdb2, tIndex2);
00710 }
00711 
00712 // ######################################################################
00713 void Landmark::cleanDelete(bool indb, bool intdb, int tIndex)
00714 {
00715   if(indb)
00716     {
00717       LINFO("in db");
00718       if(numTempObjects() == 0 ||
00719          itsLatestTempVisualObjectFNum < itsVisualObjectFNum[tIndex])
00720         {
00721           LINFO("  none to move in temp");
00722           eraseObject(tIndex);
00723           eraseOffsetCoords(tIndex);
00724           eraseVisualObjectFNum(tIndex);
00725         }
00726       else
00727         {
00728           LINFO("  something to move in temp");
00729           // move the next frame on temp to the soon to be
00730           // un-occupied spot in the DB
00731           uint fnum = itsVisualObjectFNum[tIndex];
00732           uint ltfnum = itsLatestTempVisualObjectFNum;
00733 
00734           int rindex = -1;
00735           for(uint fn = fnum+1; fn <= ltfnum; fn++)
00736             {
00737               for(int i = int(itsTempVisualObjectFNum.size()-1); i >= 0; i--)
00738                 {
00739                   uint cn = itsTempVisualObjectFNum[i];
00740                   if(cn == fn)
00741                     {
00742                       rindex = i;
00743                       LINFO("rind: %d i: %d cn: %d fn: %d", rindex, i, cn, fn);
00744                       i = 0; fn = ltfnum+1;
00745                    }
00746                 }
00747             }
00748 
00749           if(rindex != -1)
00750             {
00751               LINFO("before: fnum: %d",itsVisualObjectFNum[tIndex]);
00752               itsVisualObjectDB->setObject
00753                 (tIndex, itsTempVisualObjectDB->getObject(rindex));
00754               itsOffsetCoords[tIndex]     = itsTempOffsetCoords[rindex];
00755               itsVisualObjectFNum[tIndex] = itsTempVisualObjectFNum[rindex];
00756               LINFO("after : fnum: %d",itsVisualObjectFNum[tIndex]);
00757 
00758               LINFO("before: T: %d", numTempObjects());
00759               eraseTempObject(rindex);
00760               eraseTempOffsetCoords(rindex);
00761               eraseTempVisualObjectFNum(rindex);
00762               LINFO("after : T: %d", numTempObjects());
00763             }
00764 
00765           // update latest number for temp
00766           itsLatestTempVisualObjectFNum = 0;
00767           for(uint i = 0; i < itsTempVisualObjectFNum.size(); i++)
00768             {
00769               if(itsLatestTempVisualObjectFNum <  itsTempVisualObjectFNum[i])
00770                 itsLatestTempVisualObjectFNum = itsTempVisualObjectFNum[i];
00771             }
00772         }
00773 
00774       // update latest number for vodb
00775       itsLatestVisualObjectFNum = 0;
00776       for(uint i = 0; i < itsVisualObjectFNum.size(); i++)
00777         {
00778           if(itsLatestVisualObjectFNum < itsVisualObjectFNum[i])
00779             itsLatestVisualObjectFNum = itsVisualObjectFNum[i];
00780         }
00781     }
00782   else if(intdb)
00783     {
00784       LINFO("intdb");
00785 
00786       eraseTempObject(tIndex);
00787       eraseTempOffsetCoords(tIndex);
00788       eraseTempVisualObjectFNum(tIndex);
00789 
00790       // update latest number for temp
00791       itsLatestTempVisualObjectFNum = 0;
00792       for(uint i = 0; i < itsTempVisualObjectFNum.size(); i++)
00793         {
00794           if(itsLatestTempVisualObjectFNum <  itsTempVisualObjectFNum[i])
00795             itsLatestTempVisualObjectFNum = itsTempVisualObjectFNum[i];
00796         }
00797     }
00798 }
00799 
00800 // ######################################################################
00801 // get the position of the landmark
00802 Point2D<int> Landmark::getPosition()
00803 {
00804   uint last = numObjects() - 1;
00805   //uint fNum =  itsVisualObjectFNum[last];
00806 
00807   // get the active trackers
00808   std::vector<rutz::shared_ptr<Keypoint> > activeKP = getActiveKeypoints();
00809   LINFO("have %"ZU" active keypoints", activeKP.size());
00810 
00811   // get fittest tracker
00812   rutz::shared_ptr<KeypointTracker> fittestKPtr = getFittestKPtr();
00813   std::vector<rutz::shared_ptr<Keypoint> >
00814     fKP = fittestKPtr->getKeypoints();
00815 
00816   // get its last absolute loc
00817   Point2D<int> res = fittestKPtr->getAbsLoc();
00818   LINFO("%s: (%d,%d)", fittestKPtr->getName().c_str(), res. i, res.j);
00819 
00820   // draw the changes
00821   if(itsMatchWin.is_valid())
00822     {
00823       // draw the points
00824       int w = itsMatchWin->getDims().w()/2;
00825       int h = itsMatchWin->getDims().h()/2;
00826       Image< PixRGB<byte> > tImg(w,h,ZEROS);
00827       Image< PixRGB<byte> > oImg =
00828         itsVisualObjectDB->getObject(last)->getImage();
00829       for(uint i = 0; i < fKP.size(); i++)
00830         {
00831           const float x = fKP[i]->getX();
00832           const float y = fKP[i]->getY();
00833           Point2D<int> loc(int(x + 0.5F), int(y + 0.5F));
00834           drawDisk(oImg, loc, 2, PixRGB<byte>(255,0,0));
00835           LINFO("Loc: (%d,%d)",loc.i,loc.j);
00836         }
00837       inplacePaste(tImg, oImg,   Point2D<int>(0, 0));
00838       itsMatchWin->drawImage(tImg,w,h);
00839     }
00840 
00841   return res;
00842 }
00843 
00844 // ######################################################################
00845 // get the current velocity of the landmark
00846 // ===> USE VELOCITY LATER
00847 Point2D<int> Landmark::getVelocity()
00848 {
00849   // stationary keypoint by default
00850   if(numObjects() == 1)
00851     return Point2D<int>(0,0);
00852 
00853   // extrapolate speed from the last 5 points
00854 
00855   return Point2D<int>(0,0);
00856 }
00857 
00858 // ######################################################################
00859 // get the keypoints in the current frames that are likely to be
00860 // as determined using the trackers
00861 std::vector<rutz::shared_ptr<Keypoint> > Landmark::getActiveKeypoints()
00862 {
00863   // the number of frames the landmark has been activated
00864   uint last = numObjects() - 1;
00865   uint fNum =  itsVisualObjectFNum[last];
00866   uint sfNum = itsVisualObjectFNum[0];
00867   uint dfnum = fNum - sfNum;
00868   dfnum+=0;
00869   LINFO("fNum: %d, sfNum: %d, dfnum: %d",fNum, sfNum, dfnum);
00870 
00871   std::vector<rutz::shared_ptr<Keypoint> > res;
00872   //uint count = 0;
00873 
00874   // go through all the trackers
00875   for(uint i = 0; i < itsKPtrackers.size(); i++)
00876     {
00877       // if it is active and has length at least 3
00878       if((itsKPtrackers[i]->hasKeypointInFrame(fNum)) &&
00879          (itsKPtrackers[i]->numKeypoints() > dfnum    ||
00880           itsKPtrackers[i]->numKeypoints() >= MIN_LINKS))
00881         {
00882           res.push_back(itsKPtrackers[i]->getKeypointInFrame(fNum));
00883           //LINFO("from tracker%d: %d, %d", i,
00884           //      itsKPtrackers[i]->hasKeypointInFrame(fNum),
00885           //      itsKPtrackers[i]->numKeypoints() );
00886           //count++;
00887         }
00888       //if(count > 4) break;
00889     }
00890 
00891   // check it out
00892   if(itsMatchWin.is_valid())
00893     {
00894       // draw the points
00895       int w = itsMatchWin->getDims().w()/2;
00896       int h = itsMatchWin->getDims().h()/2;
00897       Image< PixRGB<byte> > tImg(w,h,ZEROS);
00898       Image< PixRGB<byte> >
00899         oImg = itsVisualObjectDB->getObject(last)->getImage();
00900       for(uint i = 0; i < res.size(); i++)
00901         {
00902           const float x = res[i]->getX();
00903           const float y = res[i]->getY();
00904           Point2D<int> loc(int(x + 0.5F), int(y + 0.5F));
00905           drawDisk(oImg, loc, 2, PixRGB<byte>(255,0,0));
00906           //LINFO("Loc: (%d,%d)",loc.i,loc.j);
00907         }
00908       inplacePaste(tImg, oImg,   Point2D<int>(0, 0));
00909       itsMatchWin->drawImage(tImg,w,h);
00910     }
00911 
00912   return res;
00913 }
00914 
00915 // ######################################################################
00916 //get the longest active tracker
00917 rutz::shared_ptr<KeypointTracker> Landmark::getFittestKPtr()
00918 {
00919   // the current frame number
00920   uint last = numObjects() - 1;
00921   uint fNum =  itsVisualObjectFNum[last];
00922 
00923   rutz::shared_ptr<KeypointTracker> res;
00924   uint maxLength = 0U;
00925 
00926   // go through all the tracker
00927   for(uint i = 0; i < itsKPtrackers.size(); i++)
00928     {
00929       if((itsKPtrackers[i]->hasKeypointInFrame(fNum)) &&
00930          (itsKPtrackers[i]->numKeypoints() > maxLength))
00931         {
00932           res = itsKPtrackers[i];
00933           maxLength =  itsKPtrackers[i]->numKeypoints();
00934         }
00935     }
00936 
00937   LINFO("%s: %d", res->getName().c_str(), res->numKeypoints());
00938   return res;
00939 }
00940 
00941 // ######################################################################
00942 // Prune the Visual Object keypoints of frame index temporally
00943 void Landmark::temporalPrune(uint index)
00944 {
00945   rutz::shared_ptr<VisualObject> pObj =
00946     itsVisualObjectDB->getObject(index);
00947   //std::vector< rutz::shared_ptr<Keypoint> > fkeypoints =
00948   //  pObj->getKeypoints();
00949   LDEBUG("pObj[%d] BEFORE numFeatures: %d", index, pObj->numKeypoints());
00950 
00951   // create a temporary list of keypoints indexes to keep
00952   std::vector< rutz::shared_ptr<Keypoint> > prunedfKp;
00953 
00954   // go through the trackers
00955   for(uint i = 0; i < itsKPtrackers.size(); i++)
00956     {
00957       // for the ones that has the index
00958       if(itsKPtrackers[i]->hasKeypointInFrame(index))
00959       {
00960         // store it
00961         rutz::shared_ptr<Keypoint> kp =
00962           itsKPtrackers[i]->getKeypointInFrame(index);
00963         prunedfKp.push_back(kp);
00964       }
00965     }
00966 
00967   // delete the keypoints that are noted as kept
00968   rutz::shared_ptr<VisualObject> prunedfObj
00969     (new VisualObject(pObj->getName(),
00970                       pObj->getImageFname(), pObj->getImage(),
00971                       pObj->getSalPoint(),
00972                       pObj->getFeatures(), prunedfKp));
00973   LDEBUG("PRUNED numFeatures: %d",prunedfObj->numKeypoints());
00974   itsVisualObjectDB->setObject(index, prunedfObj);
00975   LDEBUG("fAFTER numFeatures: %d", pObj->numKeypoints());
00976 
00977   // isSorted = false; DO WE NEED TO DO THIS???
00978 }
00979 
00980 // // ######################################################################
00981 // // Prune the Visual Object keypoints of the last
00982 // void Landmark::temporalPrune(rutz::shared_ptr<VisualObjectMatch> match)
00983 // {
00984 //   // prune the just added object
00985 //   uint last = itsVisualObjectDB->numObjects() - 1;
00986 //   rutz::shared_ptr<VisualObject> obj =
00987 //    itsVisualObjectDB->getObject(last);
00988 //   std::vector< rutz::shared_ptr<Keypoint> > keypoints =
00989 //     obj->getKeypoints();
00990 
00991 //   // create a temporary list of keypoints indexes to keep
00992 //   std::vector< rutz::shared_ptr<Keypoint> > prunedKp;
00993 
00994 //   LDEBUG("match->size: %d, kp->size: %d ",
00995 //          match->size(), keypoints.size());
00996 //   // go through all the keypoint matches
00997 //   for(uint i = 0; i < match->size(); i++)
00998 //     {
00999 //       // go through the previous frame keypoints
01000 //       for(uint j = 0; j < keypoints.size(); j++)
01001 //         {
01002 //           // if the keypoint in the match are found
01003 //           if((*match)[i].refkp == keypoints[j])
01004 //           {
01005 //             // add to the temporary list
01006 //             prunedKp.push_back(keypoints[j]);
01007 //           }
01008 //         }
01009 //     }
01010 // //       // note: the behavior of vector::erase()
01011 //          // guarantees this code works...
01012 
01013 //   // delete the keypoints that are noted as kept
01014 //   LDEBUG("BEFORE numFeatures: %d",
01015 //          itsVisualObjectDB->getObject(last)->numKeypoints());
01016 //   rutz::shared_ptr<VisualObject> prunedObj
01017 //     (new VisualObject(obj->getName(),
01018 //                       obj->getImageFname(), obj->getImage(),
01019 //                       obj->getFeatures(), prunedKp));
01020 //   LDEBUG("PRUNED OBJ numFeatures: %d",prunedObj->numKeypoints());
01021 //   itsVisualObjectDB->setObject(last, prunedObj);
01022 //   LINFO("AFTER numFeatures: %d",
01023 //         itsVisualObjectDB->getObject(last)->numKeypoints());
01024 // }
01025 
01026 // ######################################################################
01027 // track the keypoints of the just added object
01028 void Landmark::trackKeypoints(rutz::shared_ptr<VisualObjectMatch> match,
01029                               int mInd)
01030 {
01031   uint last = itsVisualObjectDB->numObjects() - 1;
01032   uint fNum =  itsVisualObjectFNum[last];
01033   rutz::shared_ptr<VisualObject> voTst = itsVisualObjectDB->getObject(last);
01034   rutz::shared_ptr<VisualObject> voRef = itsVisualObjectDB->getObject(mInd);
01035 
01036   LINFO("we are comparing frames %d and %d",mInd, last);
01037   LINFO("ref->size %d, tst->size: %d match->size: %d, kp->size: %"ZU" ",
01038         voRef->numKeypoints(), voTst->numKeypoints(),
01039         match->size(), itsKPtrackers.size());
01040 
01041   // initialize all tst keypoints as not yet added
01042   std::vector<bool> voTstkpIsAdded;
01043   for(uint i = 0; i < voTst->numKeypoints(); i++)
01044     voTstkpIsAdded.push_back(false);
01045 
01046 //   // go through all the matches
01047 //   for(uint i = 0; i < match->size(); i++)
01048 //     {
01049 //       printf ("[%4d]",i);
01050 //       // the ref keypoint
01051 //       for(uint k = 0; k < voRef->numKeypoints(); k++)
01052 //         if((*match)[i].refkp == voRef->getKeypoint(k)) printf("%4d ->", k);
01053 
01054 //       // the tst keypoint
01055 //       for(uint k = 0; k < voTst->numKeypoints(); k++)
01056 //         if((*match)[i].tstkp == voTst->getKeypoint(k)) printf("%4d\n", k);
01057 //    }
01058 //   Raster::waitForKey();
01059 
01060   // go through all the matches
01061   for(uint i = 0; i < match->size(); i++)
01062     {
01063       //LINFO("[%3d]",i);
01064 
01065       // get the tracker with the ref keypoint
01066       for(uint j = 0; j < itsKPtrackers.size(); j++)
01067         {
01068            // if the keypoint is in one of the matches
01069           if(itsKPtrackers[j]->hasKeypointInFrame(mInd) &&
01070              (*match)[i].refkp == itsKPtrackers[j]->getKeypointInFrame(mInd))
01071              {
01072                // add it to the tracker
01073                itsKPtrackers[j]->add((*match)[i].tstkp,
01074                                      itsOffsetCoords[last],
01075                                      itsVisualObjectFNum[last]);
01076 
01077                // note that the tst keypoint has been added
01078                for(uint k = 0; k < voTst->numKeypoints(); k++)
01079                  {
01080                    if((*match)[i].tstkp == voTst->getKeypoint(k))
01081                      {
01082                        voTstkpIsAdded[k] = true;
01083                        //LINFO("added to %3d -> %d", k, j);
01084                      }
01085                  }
01086              }
01087         }
01088     }
01089 
01090   // create new tracker for the rest of the tst keypoints
01091   uint nAdded = 0U;
01092   for(uint i = 0; i < voTst->numKeypoints(); i++)
01093     {
01094       if(!voTstkpIsAdded[i])
01095         {
01096           rutz::shared_ptr<KeypointTracker>
01097             newKPtracker(new KeypointTracker
01098                          (sformat("KPtrk%d_%d", fNum, nAdded)));
01099           newKPtracker->add(voTst->getKeypoint(i),
01100                             itsOffsetCoords[last],
01101                             itsVisualObjectFNum[last]);
01102           itsKPtrackers.push_back(newKPtracker);
01103           nAdded++;
01104           //LINFO("Adding tracker: %d for %d", itsKPtrackers.size(), i);
01105         }
01106     }
01107 
01108   // prune inactive and dormant trackers from 5 frames ago
01109   // and that frame was in the list
01110   uint ndel = 0U;
01111   if(fNum >= FWAIT_NUM)
01112     {
01113       uint pfNum = fNum - FWAIT_NUM;
01114 
01115       // prune the keypoints
01116       std::vector<rutz::shared_ptr<KeypointTracker> >::iterator
01117         itr = itsKPtrackers.begin();
01118       while (itr < itsKPtrackers.end())
01119         {
01120           // that are inactive since pfNum and has less than MIN_LINKS chain
01121           if((*itr)->isInactiveSince((pfNum+1)) &&
01122              (*itr)->numKeypoints() < MIN_LINKS)
01123             {
01124               itr = itsKPtrackers.erase(itr); ++ ndel;
01125             }
01126           else ++ itr;
01127           // note: the behavior of vector::erase() guarantees this code works..
01128         }
01129       LINFO("we pruned %d inactive tracker from frame %d", ndel, pfNum);
01130 
01131       // pruning the keypoints off the VO
01132       LINFO(":{}: %d",pfNum);
01133       int pfNumInd = getFNumIndex(pfNum);
01134 
01135       if(pfNumInd != -1)
01136         {
01137           LINFO("BEFORE(%d) -> %d numFeatures: %d", pfNum, pfNumInd,
01138                 itsVisualObjectDB->getObject(pfNumInd)->numKeypoints());
01139           temporalPrune(pfNumInd);
01140           LINFO("AFTER (%d) -> %d numFeatures: %d", pfNum, pfNumInd,
01141                 itsVisualObjectDB->getObject(pfNumInd)->numKeypoints());
01142           //Raster::waitForKey();
01143         }
01144       else
01145         {
01146           LINFO("skipping %d -> %d", pfNum, pfNumInd);
01147           Raster::waitForKey();
01148         }
01149     }
01150   else
01151     LINFO("we pruned 0 inactive trackers");
01152 
01153   LINFO("we added %d  tracker for frame %d", nAdded, fNum);
01154   LINFO("there are %"ZU" keypoints being tracked", itsKPtrackers.size());
01155 //  for(uint j = 0; j < itsKPtrackers.size(); j++)
01156 //     {
01157 //       printf("[%3d]",j); itsKPtrackers[j]->print();
01158 //     }
01159 }
01160 
01161 // ######################################################################
01162 int Landmark::getFNumIndex(uint fNum)
01163 {
01164   uint cInd = itsVisualObjectDB->numObjects() - 1;
01165   uint cfNum =  itsVisualObjectFNum[cInd];
01166   //LINFO("cInd: %d, (cfNum: %d, fNum: %d)",cInd,cfNum,fNum);
01167 
01168   // look for the index only when fNum is still bigger than current
01169   while (fNum <= cfNum && cInd >= 0)
01170     {
01171       //LINFO(" cInd: %d, (cfNum: %d, fNum: %d)",cInd,cfNum,fNum);
01172       if(fNum == cfNum) return cInd;
01173       if(cInd == 0) return -1;
01174       cInd --;
01175       cfNum =  itsVisualObjectFNum[cInd];
01176     }
01177 
01178     return -1;
01179 }
01180 
01181 // ######################################################################
01182 Rectangle Landmark::getObjectRect(uint index)
01183 {
01184   rutz::shared_ptr<VisualObject>
01185     vo = itsVisualObjectDB->getObject(index);
01186   Dims voDims = vo->getImage().getDims();
01187   return Rectangle(itsOffsetCoords[index], voDims);
01188 }
01189 
01190 // ######################################################################
01191 rutz::shared_ptr<VisualObjectMatch>
01192 Landmark::match(rutz::shared_ptr<VisualObject> a,
01193                 rutz::shared_ptr<VisualObject> b, bool &isFit,
01194                 float maxPixDist, float minfsim,
01195                 float minscore, uint minmatch,
01196                 float maxRotate, float maxScale, float maxShear,
01197                 bool showMatch)
01198 {
01199   // compute the matching keypoints:
01200   Timer tim(1000000); tim.reset();
01201   rutz::shared_ptr<VisualObjectMatch>
01202     matchRes(new VisualObjectMatch(a, b, *itsVoma));
01203   uint64 t = tim.get();
01204 
01205   // let's prune the matches:
01206   uint orgSize = matchRes->size();
01207   tim.reset();
01208   uint np = matchRes->prune();
01209   uint t2 = tim.get();
01210 
01211   LDEBUG("Found %u matches for (%s & %s) in %.3fms: pruned %u in %.3fms",
01212          orgSize, a->getName().c_str(),
01213          b->getName().c_str(), float(t) * 0.001F,
01214          np, float(t2) * 0.001F);
01215 
01216   // matching scores
01217   float kpAvgDist    = matchRes->getKeypointAvgDist();
01218   float afAvgDist    = matchRes->getAffineAvgDist();
01219   float score        = matchRes->getScore();
01220   bool  isSIFTaffine = matchRes->
01221     checkSIFTaffine(maxRotate, maxScale, maxShear);
01222   LDEBUG("maxPixDist: %f minfsim: %f minscore: %f minmatch: %d "
01223          "maxRotate: %f maxScale: %f maxShear: %f",
01224          maxPixDist, minfsim, minscore, minmatch,
01225          maxRotate, maxScale, maxShear);
01226   LDEBUG("kpAvgDist = %.4f|affAvgDist = %.4f|score: %.4f|aff? %d",
01227          kpAvgDist, afAvgDist, score, isSIFTaffine);
01228 
01229   if (!isSIFTaffine) LDEBUG("### bad Affine -- BOGUS MATCH");
01230   else if(matchRes->size() >= minscore)
01231     {
01232       // show our final affine transform:
01233       SIFTaffine s = matchRes->getSIFTaffine();
01234       LDEBUG("[tstX]   [ %- .3f %- .3f ] [refX]   [%- .3f]", s.m1, s.m2, s.tx);
01235       LDEBUG("[tstY] = [ %- .3f %- .3f ] [refY] + [%- .3f]", s.m3, s.m4, s.ty);
01236     }
01237 
01238   // check SIFT match
01239   bool isSIFTfit = (isSIFTaffine && (score >= minscore) &&
01240                     (matchRes->size() >= minmatch));
01241   LDEBUG("isSIFTfit: %d: (%d && (%f >= %f) && (%d >= %d)) ", isSIFTfit,
01242          isSIFTaffine, score, minscore, matchRes->size(), minmatch);
01243 
01244   // check sal match
01245   // we skip this step if the salient point is not provided
01246   bool isSalfit = false;
01247   bool salAvailable =
01248     (a->getSalPoint().isValid() && a->getSalPoint().isValid());
01249   if(isSIFTfit && salAvailable)
01250     {
01251       float sdiff = matchRes->getSalDiff();
01252       float sdist = matchRes->getSalDist();
01253 
01254       // has to pass distance proximity test (maxPixDist pixels),
01255       // and minfsim feature similarity
01256       if(sdist <= maxPixDist && sdiff >= minfsim) isSalfit = true;
01257       LDEBUG("isSalFit: %d: (%f <= %f && %f >= %f", isSalfit,
01258              sdist, maxPixDist, sdiff, minfsim);
01259     }
01260   else isSalfit = true;
01261 
01262   isFit = isSIFTfit && isSalfit;
01263   LDEBUG("isFit? %d", isFit);
01264 
01265   // if there are images to be displayed
01266   if(showMatch && itsMatchWin.is_valid() &&
01267      a->getImage().initialized() && b->getImage().initialized())
01268     {
01269       int w = itsMatchWin->getDims().w()/2;
01270       int h = itsMatchWin->getDims().h()/2;
01271 
01272       // get an image showing the matches and the fused image
01273       Image< PixRGB<byte> > mImg = matchRes->getMatchImage(1.0F);
01274       Image< PixRGB<byte> > fImg = matchRes->getFusedImage(0.25F);
01275       Image< PixRGB<byte> > tImg(2*w,2*h,ZEROS);
01276 
01277       inplacePaste(tImg, mImg,   Point2D<int>(0, 0));
01278       inplacePaste(tImg, fImg,   Point2D<int>(w, 0));
01279 
01280       itsMatchWin->drawImage(tImg,0,0);
01281     }
01282   return matchRes;
01283 }
01284 
01285 // ######################################################################
01286 void Landmark::addObject(rutz::shared_ptr<VisualObject> obj,
01287                          Point2D<int> objOffset, uint fNum)
01288 {
01289   // add the object to the db:
01290   if (itsVisualObjectDB->addObject(obj))
01291     {
01292       // note the frame number and coordinates
01293       itsVisualObjectFNum.push_back(fNum);
01294       itsOffsetCoords.push_back(objOffset);
01295       if(itsLatestVisualObjectFNum < fNum)
01296         itsLatestVisualObjectFNum = fNum;
01297 
01298       if(obj->getSalPoint().i != -1)
01299         LINFO("Added SAL VisualObject '%s' as part of %s evidence.",
01300               obj->getName().c_str(), itsName.c_str());
01301       else
01302         LINFO("Added NON_SAL VisualObject '%s' as part of %s evidence.",
01303               obj->getName().c_str(), itsName.c_str());
01304     }
01305   else
01306     LERROR("FAILED adding VisualObject '%s' to database -- IGNORING",
01307            obj->getName().c_str());
01308 }
01309 
01310 // ######################################################################
01311 void Landmark::tAddObject(rutz::shared_ptr<VisualObject> obj,
01312                           Point2D<int> objOffset, uint fNum)
01313 {
01314   // add to the tempVODB instead
01315   if (itsTempVisualObjectDB->addObject(obj))
01316     {
01317       // note the frame number and coordinates
01318       itsTempVisualObjectFNum.push_back(fNum);
01319       itsTempOffsetCoords.push_back(objOffset);
01320       if(itsLatestTempVisualObjectFNum < fNum)
01321         itsLatestTempVisualObjectFNum = fNum;
01322 
01323       if(obj->getSalPoint().i != -1)
01324         LINFO("Added SAL VisualObject '%s' as part of %s "
01325               "temporary holding",
01326               obj->getName().c_str(), itsName.c_str());
01327       else
01328         LINFO("Added NON_SAL VisualObject '%s' as part of %s "
01329               "temporary holding",
01330               obj->getName().c_str(), itsName.c_str());
01331     }
01332   else
01333     LERROR("FAILED adding VisualObject '%s' to temp holding",
01334            obj->getName().c_str());
01335 }
01336 
01337 // ######################################################################
01338 int Landmark::match
01339 ( rutz::shared_ptr<VisualObject> obj,
01340   rutz::shared_ptr<VisualObjectMatch> &cmatch, int start, int end,
01341   float maxPixDist, float minfsim, float minscore, uint minmatch,
01342   float maxRotate, float maxScale, float maxShear)
01343 {
01344   if(start == -1) start = 0; ASSERT(start >= 0);
01345   if(end == -1) end = numObjects() - 1; ASSERT(end < int(numObjects()));
01346   ASSERT(start <= end);
01347 
01348   // return -1 if match not found
01349   int index = findDBmatch(obj, cmatch, end-start+1, true, start,
01350                           maxPixDist, minfsim, minscore, minmatch,
01351                           maxRotate, maxScale, maxShear);
01352   return index;
01353 }
01354 
01355 // ######################################################################
01356 int Landmark::findDBmatch
01357 (rutz::shared_ptr<VisualObject> obj,
01358  rutz::shared_ptr<VisualObjectMatch> &cmatch, uint nFrames,
01359  bool isForward, int start,
01360  float maxPixDist, float minfsim, float minscore, uint minmatch,
01361  float maxRotate, float maxScale, float maxShear)
01362 {
01363   // if db is empty return -1 right away
01364   if(itsVisualObjectDB->numObjects() == 0)
01365     { LINFO("%s DB is empty", itsName.c_str()); return -1; }
01366 
01367   // setup the range for vo checking
01368   int sInd, eInd, inc; // note: end index not included
01369   ASSERT((start >= 0 && start < int(numObjects())) || start == -1);
01370   if(start == -1 &&isForward) sInd = 0;
01371   else if(start == -1 && !isForward) sInd = numObjects() - 1;
01372   else sInd = start;
01373 
01374   if(isForward)
01375     { eInd = start+nFrames; inc = 1; }
01376   else
01377     { eInd = sInd - nFrames; if(eInd < -1) eInd = -1; inc = -1; }
01378   LDEBUG("Range %s DB: [%d, %d} by %d", itsName.c_str(), sInd, eInd, inc);
01379   int i = sInd;  int matchInd = -1;
01380   while(i != eInd)
01381     {
01382       LDEBUG("check %s DB(%d): %s",itsName.c_str(), i,
01383              itsVisualObjectDB->getObject(i)->getName().c_str());
01384 
01385       // check SIFT and Saliency match
01386       bool isFit; cmatch = match(obj, itsVisualObjectDB->getObject(i), isFit,
01387                                  maxPixDist, minfsim, minscore, minmatch,
01388                                  maxRotate, maxScale, maxShear);
01389 
01390       // if we didn't have a match, flip the order (assymetric matching)
01391       if(!isFit)
01392         {
01393           cmatch = match(itsVisualObjectDB->getObject(i), obj, isFit,
01394                          maxPixDist, minfsim, minscore, minmatch,
01395                          maxRotate, maxScale, maxShear);
01396         }
01397 
01398       // found first good match: break (maybe can do better)
01399       if(isFit) { matchInd = i; return matchInd; }
01400       i += inc;
01401     }
01402   return matchInd;
01403 }
01404 
01405 // ######################################################################
01406 int Landmark::findTempDBmatch(rutz::shared_ptr<VisualObject> obj,
01407                               rutz::shared_ptr<VisualObjectMatch> &cmatch,
01408                               uint nFrames,
01409                               float maxPixDist, float minfsim,
01410                               float minscore, uint minmatch)
01411 {
01412   // if temp db is empty return -1 right away
01413   if(itsTempVisualObjectDB->numObjects() == 0)
01414     { LINFO("TDB of %s is empty", itsName.c_str()); return -1; }
01415 
01416   // find match with the last nFrames objects in the tempDB
01417   int mtInd = -1;  int mintIndex;
01418   if(itsTempVisualObjectDB->numObjects() < nFrames)
01419     mintIndex = 0;
01420   else
01421     mintIndex = itsTempVisualObjectDB->numObjects() - nFrames;
01422   LINFO("Range %s tempDB:  [%d, %d]", itsName.c_str(), mintIndex,
01423         itsTempVisualObjectDB->numObjects() - 1);
01424 
01425   for(int i = itsTempVisualObjectDB->numObjects() - 1; i >= mintIndex; i--)
01426     {
01427       LDEBUG("check %s tempDB(%d): %s",itsName.c_str(), i,
01428              itsTempVisualObjectDB->getObject(i)->getName().c_str());
01429 
01430       // check SIFT and Saliency match
01431       bool isFit;
01432       cmatch = match(obj, itsTempVisualObjectDB->getObject(i), isFit,
01433                      maxPixDist, minfsim, minscore, minmatch);
01434 
01435       // if we didn't have a match, flip the order (asymmetric matching)
01436       if(!isFit)
01437         {
01438           cmatch = match(itsTempVisualObjectDB->getObject(i), obj, isFit,
01439                          maxPixDist, minfsim, minscore, minmatch);
01440         }
01441 
01442       // found first good match: break (maybe a bad policy)
01443       if(isFit){ mtInd = i; return mtInd; }
01444     }
01445   return mtInd;
01446 }
01447 
01448 // ######################################################################
01449 void Landmark::moveLatestTempVisualObjectToDB()
01450 {
01451   int index = itsTempVisualObjectFNum.size() - 1;
01452   if(index == -1)
01453     {
01454       LINFO("nothing to move in temp of %s", itsName.c_str());
01455       return;
01456     }
01457 
01458   LINFO("moving T(%d): %s", index,
01459         itsTempVisualObjectDB->getObject(index)->getName().c_str());
01460   moveTempVisualObjectToDB(index);
01461 }
01462 
01463 // ######################################################################
01464 void Landmark::moveTempVisualObjectToDB(int index)
01465 {
01466   ASSERT(index >= 0 && index < int(numTempObjects()));
01467 
01468   // push back the temp objects to the DB
01469   addObject(itsTempVisualObjectDB->getObject(index),
01470             itsTempOffsetCoords[index],
01471             itsTempVisualObjectFNum[index]);
01472 
01473   // update the latest number for DB
01474   if(itsLatestVisualObjectFNum < itsTempVisualObjectFNum[index])
01475     itsLatestVisualObjectFNum =  itsTempVisualObjectFNum[index];
01476 
01477   // erase the info off the temp list
01478   itsTempVisualObjectDB->eraseObject(index);
01479   itsTempOffsetCoords.erase(itsTempOffsetCoords.begin() + index);
01480   itsTempVisualObjectFNum.erase(itsTempVisualObjectFNum.begin() + index);
01481 
01482   // update latest number for temp
01483   itsLatestTempVisualObjectFNum = 0;
01484   for(uint i = 0; i < itsTempVisualObjectFNum.size(); i++)
01485     {
01486       if(itsLatestTempVisualObjectFNum <  itsTempVisualObjectFNum[i])
01487         itsLatestTempVisualObjectFNum = itsTempVisualObjectFNum[i];
01488     }
01489 }
01490 
01491 // ######################################################################
01492 uint Landmark::numMatch(rutz::shared_ptr<Landmark> lmk,
01493                         float maxPixDist, float minfsim,
01494                         float minscore, uint minmatch)
01495 {
01496   uint count = 0;
01497 
01498   // go through all the objects in the input Landmark
01499   for(uint i = 0; i < lmk->numObjects(); i++)
01500   {
01501     LDEBUG("checking lmk->object(%d)", i);
01502     rutz::shared_ptr<VisualObject> obj = lmk->getObject(i);
01503 
01504     // check with the objects in the DBlist
01505     for(uint j = 0; j < numObjects(); j++)
01506       {
01507         LDEBUG("     with object(%d)", j);
01508 
01509         // check SIFT and Saliency match
01510         bool isFit;
01511         rutz::shared_ptr<VisualObjectMatch> cmatch =
01512           match(obj, itsVisualObjectDB->getObject(j), isFit,
01513                 maxPixDist, minfsim, minscore, minmatch);
01514         //if(itsMatchWin.is_valid())
01515         //  itsMatchWin->setTitle(sformat("M: obj(%d)-db(%d)",i,j).c_str());
01516 
01517         // if necesarry reverse the order
01518         if(!isFit)
01519         {
01520           cmatch = match(itsVisualObjectDB->getObject(j), obj, isFit,
01521                          maxPixDist, minfsim, minscore, minmatch);
01522           //if(itsMatchWin.is_valid())
01523           //  itsMatchWin->setTitle(sformat("M: db(%d)&in(%d)",i,j).c_str());
01524         }
01525 
01526         // if we pass both sal and sift tests
01527         if(isFit)
01528           {
01529             count++;
01530             LDEBUG("Match: %s(%d) & %s(%d), count: %d",
01531                    lmk->getName().c_str(),i, itsName.c_str(), j, count);
01532 
01533             // end the inner loop
01534             j = numObjects();
01535           }
01536       }
01537   }
01538 
01539   return count;
01540 }
01541 
01542 // ######################################################################
01543 void Landmark::combine(rutz::shared_ptr<Landmark> lmk1,
01544                        rutz::shared_ptr<Landmark> lmk2)
01545 {
01546   // add all objects in lmk1
01547   for(uint i = 0; i <lmk1-> numObjects(); i++)
01548     {
01549       addObject(lmk1->getObject(i),
01550                 lmk1->getOffsetCoords(i),
01551                 lmk1->getVisualObjectFNum(i));
01552     }
01553 
01554   // add all objects in lmk2
01555   for(uint i = 0; i <lmk2-> numObjects(); i++)
01556     {
01557       addObject(lmk2->getObject(i),
01558                 lmk2->getOffsetCoords(i),
01559                 lmk2->getVisualObjectFNum(i));
01560     }
01561 }
01562 
01563 // ######################################################################
01564 void Landmark::append(rutz::shared_ptr<Landmark> lmk)
01565 {
01566   // add all objects in the input lmk
01567   for(uint i = 0; i <lmk->numObjects(); i++)
01568     {
01569       addObject(lmk->getObject(i),
01570                 lmk->getOffsetCoords(i),
01571                 lmk->getVisualObjectFNum(i));
01572     }
01573 }
01574 
01575 // ######################################################################
01576 struct SortObj
01577 {
01578   SortObj() { };
01579 
01580   SortObj(const rutz::shared_ptr<VisualObject> _obj,
01581           const Point2D<int> _objOffset,
01582           const uint _fNum,
01583           const uint _sNum) :
01584     obj(_obj),
01585     objOffset(_objOffset),
01586     fNum(_fNum),
01587     sNum(_sNum)
01588   {  }
01589 
01590   rutz::shared_ptr<VisualObject> obj;
01591   Point2D<int> objOffset;
01592   uint fNum;
01593   uint sNum;
01594 
01595   bool operator < (const SortObj& rhs)
01596   {
01597     if(sNum != rhs.sNum) return sNum < rhs.sNum;
01598     else return fNum < rhs.fNum;
01599   }
01600 
01601 };
01602 
01603 void Landmark::sort(std::vector<std::string> sessionNames)
01604 {
01605   std::list<SortObj> tList;
01606   for(uint i = 0; i < numObjects(); i++)
01607     {
01608       // save the objects, offset coordinates, and frame number
01609       // to a temporary place
01610       rutz::shared_ptr<VisualObject> obj =
01611         itsVisualObjectDB->getObject(i);
01612 
01613       // get the object name
01614       std::string sname = obj->getName();
01615       LDEBUG("session name: %s", sname.c_str());
01616       sname = sname.substr(0, sname.find_last_of('_'));
01617       sname = sname.substr(0, sname.find_last_of('_'));
01618       sname = sname.substr(0, sname.find_last_of('_'));
01619 
01620       uint j = 0;
01621       // check it against the names on the list
01622       while((j < sessionNames.size()) && (sname != sessionNames[j])) j++;
01623       if(j == sessionNames.size())
01624         LFATAL("Session not in list: %s (%s)",
01625                sname.c_str(), obj->getName().c_str());
01626 
01627       Point2D<int> objOffset = itsOffsetCoords[i];
01628       uint fNum = itsVisualObjectFNum[i];
01629 
01630       LDEBUG("B[%s] [%3d,%3d] [%3d] sNum: %d", obj->getName().c_str(),
01631              objOffset.i, objOffset.j, fNum, j);
01632 
01633       tList.push_back(SortObj(obj,objOffset,fNum,j));
01634     }
01635 
01636   tList.sort();
01637 
01638   rutz::shared_ptr<VisualObjectDB> vodb(new VisualObjectDB());
01639   std::list<SortObj>::iterator itr = tList.begin();
01640   uint ii = 0;
01641   while (itr != tList.end())
01642     {
01643       vodb->addObject((*itr).obj);
01644       itsOffsetCoords[ii] =  (*itr).objOffset;
01645       itsVisualObjectFNum[ii] = (*itr).fNum;
01646       itr++; ii++;
01647     }
01648 
01649   itsVisualObjectDB = vodb;
01650 
01651 //   for(uint i = 0; i < numObjects(); i++)
01652 //     {
01653 //       rutz::shared_ptr<VisualObject> obj =
01654 //         itsVisualObjectDB->getObject(i);
01655 //       Point2D<int> objOffset = itsOffsetCoords[i];
01656 //       uint fNum = itsVisualObjectFNum[i];
01657 
01658 //       LINFO("B[%s] [%3d,%3d] [%3d]", obj->getName().c_str(),
01659 //             objOffset.i, objOffset.j, fNum);
01660 //     }
01661 }
01662 
01663 // ######################################################################
01664 /* So things look consistent in everyone's emacs... */
01665 /* Local Variables: */
01666 /* indent-tabs-mode: nil */
01667 /* End: */
Generated on Sun May 8 08:40:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3