LandmarkDB.C

Go to the documentation of this file.
00001 /*!@file Beobot/LandmarkDB.C manages groups of landmarks, which includes
00002   spatial,geographical, temporal and episodic information               */
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/LandmarkDB.C $
00035 // $Id: LandmarkDB.C 12962 2010-03-06 02:13:53Z irock $
00036 //
00037 
00038 #include "Beobot/LandmarkDB.H"
00039 #include "Image/DrawOps.H"      // for drawing
00040 #include "Image/CutPaste.H"     // for inplacePaste()
00041 #include "Util/Timer.H"
00042 
00043 #include <cstdio>
00044 
00045 // ######################################################################
00046 LandmarkDB::LandmarkDB(uint nSegment):
00047   itsScenes(),
00048   itsLandmarks(),
00049   itsActiveLmkList(),
00050   itsSkipList(),
00051   itsSessionNames(),
00052   itsSessionLandmarks()
00053 {
00054   if(nSegment > 0) resize(nSegment);
00055 }
00056 
00057 // ######################################################################
00058 LandmarkDB::~LandmarkDB()
00059 { }
00060 
00061 // ######################################################################
00062 void LandmarkDB::build
00063 ( std::vector<rutz::shared_ptr<VisualObject> > &inputVO,
00064   std::vector<Point2D<int> > &objOffset, uint fNum, uint currSegNum,
00065   rutz::shared_ptr<VisualObject> scene)
00066 {
00067   ASSERT(currSegNum < itsLandmarks.size());
00068   LINFO("BEFORE lmks[%d].sz: %"ZU, currSegNum,
00069         itsLandmarks[currSegNum].size());
00070 
00071   // set the full scene size
00072   itsScenes.push_back(scene);
00073   int imgW   = scene->getImage().getWidth();
00074   int imgH   = scene->getImage().getHeight();
00075   float imgD = sqrt(imgW*imgW + imgH*imgH);
00076   Dims sDims = scene->getImage().getDims();
00077 
00078   // make sure only to consider object with > 5 keypoints
00079   uint onobj = inputVO.size();
00080   kpFilter(inputVO, objOffset);
00081 
00082   // for each objects get the matching scores
00083   // consider both the quality of match and object distance
00084   uint nobj = inputVO.size(); if(nobj == 0) return;
00085   uint nlmk = itsLandmarks[currSegNum].size();
00086   LINFO("get scores: num objects: %d, num landmarks: %d", nobj, nlmk);
00087   std::vector<std::vector<rutz::shared_ptr<VisualObjectMatch> > >
00088     resMatch(nobj);
00089   std::vector<std::vector<bool> > inDB(nobj);
00090   std::vector<std::vector<bool> > inTDB(nobj);
00091   std::vector<std::vector<int> > tIndex(nobj);
00092   std::vector<std::vector<float> > scores(nobj);
00093   std::vector<std::vector<float> > siftscores(nobj);
00094   std::vector<std::vector<float> > sdiffscores(nobj);
00095   for(uint i = 0; i < nobj; i++)
00096     {
00097       // check the salient region against existing landmarks
00098       for(uint j = 0; j < nlmk; j++)
00099         {
00100           if(itsActiveLmkList[currSegNum][j])
00101             {
00102               bool indb; bool intdb; int tindex;
00103               rutz::shared_ptr<VisualObjectMatch> cmatch =
00104                 itsLandmarks[currSegNum][j]
00105                 ->buildCheck(inputVO[i], objOffset[i], fNum,
00106                              indb, intdb, tindex);
00107 
00108               LINFO("[%d] Match obj[%d] with lmk[%d][%d]: {%d %d %d}",
00109                     fNum, i, currSegNum, j, indb, intdb, tindex);
00110 
00111               inDB[i].push_back(indb);
00112               inTDB[i].push_back(intdb);
00113               tIndex[i].push_back(tindex);
00114               resMatch[i].push_back(cmatch);
00115 
00116               // get the sift score
00117               float siftscore = 0.0f;
00118               if(indb || intdb) siftscore = cmatch->getScore();
00119 
00120               // get offset distance
00121               float dscore = 0.0;
00122               if(indb || intdb)
00123                 dscore = getOffsetDistScore
00124                   (itsLandmarks[currSegNum][j], indb, intdb, tindex,
00125                    inputVO[i], objOffset[i], sDims, cmatch);
00126 
00127               // get overlap score
00128               float oscore = 0.0;
00129               if(indb || intdb) oscore = getOverlapScore(cmatch);
00130 
00131               // get the salient-based score
00132               float sdist = 0.0f; float salscore = 0.0f;
00133               float sdiff = cmatch->getSalDiff();
00134               if(indb || intdb)
00135                 {
00136                   sdist = cmatch->getSalDist();
00137                   sdist = 1.0 - sdist/imgD;
00138                   salscore = sdist * sdiff;
00139                 }
00140 
00141               float score = salscore;
00142               scores[i].push_back(score);
00143               siftscores[i].push_back(siftscore);
00144               sdiffscores[i].push_back(sdiff);
00145               LINFO("match obj[%d] & lmks[%d][%d] sift[%f %f %f] sal[%f %f]",
00146                     i, currSegNum, j, siftscore, dscore, oscore,
00147                     sdist, sdiff);
00148               // FIX: && (fNum%20 == 0)
00149               //if((indb || intdb)) Raster::waitForKey();
00150             }
00151           else
00152             {
00153               //LINFO("landmark[%d][%d] is inactive", currSegNum,j);
00154               inDB[i].push_back(false);
00155               inTDB[i].push_back(false);
00156               tIndex[i].push_back(-1);
00157               resMatch[i].push_back(rutz::shared_ptr<VisualObjectMatch>());
00158               scores[i].push_back(0.0f);
00159               siftscores[i].push_back(0.0f);
00160               sdiffscores[i].push_back(0.0f);
00161             }
00162           //Raster::waitForKey();
00163         }
00164     }
00165 
00166   // second pass:
00167   // check all the objects that is still not a candidate for any landmarks
00168   // usually because the SIFT module reject it.
00169   // we will now try to indirectly estimate the correct landmark
00170   for(uint i = 0; i < nobj; i++)
00171     {
00172       bool matched = false;
00173       // check if this object is matched
00174       for(uint j = 0; j < nlmk; j++) if(scores[i][j] > 0.0) matched = true;
00175 
00176       // check the salient region against existing landmarks
00177       if(!matched)
00178         {
00179           LINFO("object %d not matched", i);
00180 
00181           for(uint j = 0; j < nlmk; j++)
00182             {
00183               if(itsActiveLmkList[currSegNum][j])
00184                 {
00185                   // get the latest frame of that landmark
00186                   bool indb; bool intdb; int tindex = -1;
00187                   rutz::shared_ptr<VisualObject> lobj
00188                     = itsLandmarks[currSegNum][j]->getLatestObject
00189                     (indb, intdb, tindex);
00190 
00191                   LINFO("got latest object of lmk[][%d]", j);
00192 
00193                   const std::vector<float>& feat1 = lobj->getFeatures();
00194                   const std::vector<float>& feat2 = inputVO[i]->getFeatures();
00195 
00196                   // feature similarity  [ 0.0 ... 1.0 ]:
00197                   float cval = 0.0;
00198                   for(uint k = 0; k < feat1.size(); k++)
00199                     {
00200                       float val = pow(feat1[k] - feat2[k], 2.0); cval += val;
00201                     }
00202                   cval = sqrt(cval/feat1.size());
00203                   float sscore =  1.0F - cval;
00204 
00205                   if(sscore > .80)
00206                     {
00207                       LINFO("obj[%d] lmk[%d] good match (%f) check SIFT",
00208                             i, j, sscore);
00209 
00210                       uint lfNum =
00211                         itsLandmarks[currSegNum][j]->getLatestFNum();
00212 
00213                       // match the two scenes
00214                       LINFO("matching scenes: %d and %d", lfNum, fNum);
00215                       rutz::shared_ptr<VisualObject> a = itsScenes[lfNum];
00216                       rutz::shared_ptr<VisualObject> b = itsScenes[fNum];
00217 
00218                       // check SIFT match
00219                       float kpAvgDist, afAvgDist, score;
00220                       bool isSIFTaffine; SIFTaffine siftAffine;
00221                       VisualObjectMatchAlgo voma(VOMA_SIMPLE);
00222 
00223                       // compute the matching keypoints:
00224                       Timer tim(1000000); tim.reset();
00225                       rutz::shared_ptr<VisualObjectMatch>
00226                         matchRes(new VisualObjectMatch(a, b, voma));
00227                       uint64 t = tim.get();
00228 
00229                       // let's prune the matches:
00230                       uint orgSize = matchRes->size();
00231                       tim.reset();
00232                       uint np = matchRes->prune();
00233                       uint t2 = tim.get();
00234 
00235                       LINFO("Found %u matches (%s & %s) in %.3fms:"
00236                             " pruned %u in %.3fms",
00237                             orgSize, a->getName().c_str(),
00238                             b->getName().c_str(), float(t) * 0.001F,
00239                             np, float(t2) * 0.001F);
00240 
00241                       // matching score
00242                       kpAvgDist    = matchRes->getKeypointAvgDist();
00243                       afAvgDist    = matchRes->getAffineAvgDist();
00244                       score        = matchRes->getScore();
00245                       isSIFTaffine = matchRes->checkSIFTaffine
00246                         (M_PI/4,5.0F,0.25F);
00247                       siftAffine   = matchRes->getSIFTaffine();
00248                       LINFO("kpAvgDist = %.4f|affAvgDist = %.4f|"
00249                             " score: %.4f|aff? %d",
00250                             kpAvgDist, afAvgDist, score, isSIFTaffine);
00251 
00252                       if (!isSIFTaffine)
00253                         LINFO("### Affine is too weird -- BOGUS MATCH");
00254                       else
00255                         {
00256                           // show our final affine transform:
00257                           LINFO("[testX]  [ %- .3f %- .3f ] [refX]   [%- .3f]",
00258                                 siftAffine.m1, siftAffine.m2, siftAffine.tx);
00259                           LINFO("[testY]= [ %- .3f %- .3f ] [refY] + [%- .3f]",
00260                                 siftAffine.m3, siftAffine.m4, siftAffine.ty);
00261                         }
00262 
00263                       bool isSIFTfit = (isSIFTaffine && (score > 2.5) &&
00264                                         (matchRes->size() > 3));
00265                       LINFO("OD isSIFTfit %d", isSIFTfit);
00266 
00267 //                       // get an image showing the matches and the fused image
00268 //                       int wo = itsWin->getDims().w()/2;
00269 //                       int ho = itsWin->getDims().h()/2;
00270 //                       Image< PixRGB<byte> > mImg = matchRes->getMatchImage(1.0F);
00271 //                       Image< PixRGB<byte> > fImg = matchRes->getFusedImage(0.25F);
00272 //                       Image< PixRGB<byte> > tImg(2*wo,2*ho,ZEROS);
00273 //                       inplacePaste(tImg, mImg,   Point2D<int>(0,  0));
00274 //                       inplacePaste(tImg, fImg,   Point2D<int>(wo, 0));
00275 //                       itsWin->drawImage(tImg,0,0);
00276 //                       Raster::waitForKey();
00277 
00278                       if(isSIFTfit)
00279                         {
00280                           // get the location
00281                           Point2D<int> loffset = itsLandmarks[currSegNum][j]
00282                             ->getLatestOffsetCoords();
00283                           Point2D<int> salpt1 = lobj->getSalPoint() + loffset;
00284                           Point2D<int> salpt2 = inputVO[i]->getSalPoint() +
00285                             objOffset[i];
00286                           LINFO("loffset: %d %d", loffset.i, loffset.j);
00287 
00288                           // forward affine transform [A * ref -> tst ]
00289                           float u, v; siftAffine.transform
00290                                         (salpt1.i, salpt1.j, u, v);
00291                           float dist = salpt2.distance
00292                             (Point2D<int>(int(u+0.5F), int(v+0.5F)));
00293                           LINFO("pos1: (%d,%d) -> (%f,%f) & "
00294                                 "pos2: (%d,%d): dist: %f",
00295                                 salpt1.i, salpt1.j, u, v,
00296                                 salpt2.i, salpt2.j, dist);
00297 
00298                           float sdist  = 1.0 - dist/imgD;
00299 
00300                           if(dist < 10.0F)
00301                             {
00302                               inDB[i][j] = indb;
00303                               inTDB[i][j] = intdb;
00304                               tIndex[i][j] = tindex;
00305                               scores[i][j] = (sdist * sscore);
00306                               siftscores[i][j] = (score);
00307                               sdiffscores[i][j] = (sscore);
00308                             }
00309                         }
00310                     }
00311                   else{ LINFO("score too low: %f",sscore); }
00312                 }
00313             }
00314         }
00315     }
00316 
00317   // check if there are more than 1 objects being properly matched
00318 
00319   // FIX: if there are landmarks that can match with more than 1 objects.
00320   // we can only keep the best one
00321   // that other one hopefully would be closer to another landmark
00322   // else it will be a new landmark by itself
00323 
00324 //   printScores(inputVO, currSegNum, siftscores);
00325 //   printScores(inputVO, currSegNum, sdiffscores);
00326 //   printScores(inputVO, currSegNum, scores);
00327 
00328   LINFO("skipping: ");
00329   for(int i = 0; i < int(onobj - nobj); i++)
00330     LINFO("%d %s", i, itsSkipList[itsSkipList.size()-1-i]->getName().c_str());
00331   //Raster::waitForKey();
00332 
00333   // while there is an insertable object
00334   std::vector<bool> inserted(nobj);
00335   std::vector<bool> lmatched(nlmk);
00336   for(uint i = 0; i < nobj; i++) inserted[i] = false;
00337   for(uint j = 0; j < nlmk; j++) lmatched[j] = false;
00338 
00339   // for each object
00340   std::vector<float> ratio(nobj);
00341   for(uint i = 0; i < nobj; i++) ratio[i] = 0.0;
00342   bool done = false; if(nlmk == 0) done = true;
00343   while(!done)
00344     {
00345       // calculate the best/2nd best match ratio
00346       float mratio; int mind; std::vector<int> mlist;
00347       findBestMatch(scores, ratio, inserted, lmatched, mratio, mind, mlist);
00348 
00349       // if no more matches, we are done
00350       if(mind == -1) done = true;
00351       else
00352         {
00353           int ilbest = mlist[0];
00354           // for multiple matches
00355           if(mlist.size() > 1)
00356             {
00357               LINFO("transfer");
00358               //Raster::waitForKey();
00359               // we want to create momentum to 1 landmark
00360 
00361               // FIX: if the best ratio is not much better than the others
00362 
00363               // find the best landmark
00364               // and insert all matching salient regions to it
00365               int ilmax = -1; int maxlsize = -1;
00366               for(uint j = 0; j < mlist.size(); j++)
00367                 {
00368                   // check the landmark sizes
00369                   int clsize =
00370                     itsLandmarks[currSegNum][mlist[j]]->numObjects() +
00371                     itsLandmarks[currSegNum][mlist[j]]->numTempObjects();
00372 
00373                   LINFO("lsize[%d]: %d", mlist[j], clsize);
00374 
00375                   if(clsize > maxlsize){ ilmax = mlist[j]; maxlsize = clsize; }
00376                 }
00377               ilbest = ilmax;
00378               LINFO("ilbest: %d", ilbest);
00379 
00380               // if they differ by more than 2
00381               // else push the object to the latest one
00382 
00383               // insert one by one to the new landmark
00384               for(uint j = 0; j < mlist.size(); j++)
00385                 {
00386                   // the matching frames from the other landmark
00387                   // is inserted first
00388                   if(mlist[j] != ilbest)
00389                     {
00390                       // check if this frame is already in the evidence
00391                       LINFO("transf lmk[][%d] to lmk[][%d]", mlist[j], ilbest);
00392                       // transfer visual objects properly
00393                       itsLandmarks[currSegNum][ilbest]->transferEvidence
00394                         (itsLandmarks[currSegNum][mlist[j]],
00395                          inDB[mind][mlist[j]], inTDB[mind][mlist[j]],
00396                          tIndex[mind][mlist[j]], resMatch[mind][mlist[j]]);
00397                     }
00398                 }
00399             }
00400 
00401           // insert inputVO to the best match ratio
00402           LINFO("Inserting obj %d to landmark[%d][%d]",
00403                 mind, currSegNum, ilbest);
00404           itsLandmarks[currSegNum][ilbest]
00405             ->build(inputVO[mind], objOffset[mind], fNum,
00406                     inDB[mind][ilbest], inTDB[mind][ilbest],
00407                     tIndex[mind][ilbest], resMatch[mind][ilbest]);
00408 
00409           // note object is already inserted (landmark matched)
00410           inserted[mind] = true;
00411           lmatched[mlist[0]] = true;
00412         }
00413     }
00414 
00415   // for the rest of the objects create new landmarks
00416   for(uint i = 0; i < nobj; i++)
00417     {
00418       if(!inserted[i])
00419         {
00420           LINFO("create landmark %"ZU, itsLandmarks[currSegNum].size());
00421           std::string
00422             lmName(sformat("landmark%07"ZU, itsLandmarks[currSegNum].size()));
00423           rutz::shared_ptr<Landmark> newlm
00424             (new Landmark(inputVO[i], objOffset[i], fNum, lmName));
00425           newlm->setMatchWin(itsWin);
00426           itsLandmarks[currSegNum].push_back(newlm);
00427           itsActiveLmkList[currSegNum].push_back(true);
00428         }
00429     }
00430 
00431   // check if there is a landmark with 0 size
00432   for(uint j = 0; j < nlmk; j++)
00433     {
00434       // check both landmark sizes
00435       int clsize =
00436         itsLandmarks[currSegNum][j]->numObjects() +
00437         itsLandmarks[currSegNum][j]->numTempObjects();
00438       // make it inactive
00439       if(clsize == 0) itsActiveLmkList[currSegNum][j] = false;
00440     }
00441 
00442   LINFO("AFTER lmks[%d].sz: %"ZU, currSegNum, itsLandmarks[currSegNum].size());
00443 
00444   // make landmarks that are not receiving frames the last NFDIFF inactive
00445   classifyInactiveLandmarks(fNum, NFDIFF);
00446 }
00447 
00448 // ######################################################################
00449 void LandmarkDB::kpFilter
00450 ( std::vector<rutz::shared_ptr<VisualObject> > &inputVO,
00451   std::vector<Point2D<int> > &objOffset)
00452 {
00453   LINFO("  BEFORE kpFilter: %"ZU, inputVO.size());
00454 
00455   // while we still have a vo to check
00456   std::vector<rutz::shared_ptr<VisualObject> >::iterator
00457     voitr = inputVO.begin();
00458   std::vector<Point2D<int> >::iterator obitr = objOffset.begin();
00459 
00460   uint i = 0;
00461   while (voitr < inputVO.end())
00462     {
00463       // skip if we have less than 5 keypoints
00464       if((*voitr)->numKeypoints() <= 5)
00465         {
00466           LINFO("skip: %s (%d kp)", (*voitr)->getName().c_str(),
00467                 (*voitr)->numKeypoints());
00468           itsSkipList.push_back((*voitr));
00469 
00470 //           int w = itsWin->getDims().w();
00471 //           int h = itsWin->getDims().h();
00472 //           Image<PixRGB<byte> > tIma(w,h,ZEROS);
00473 //           inplacePaste
00474 //             (tIma,(*voitr)->getKeypointImage(1.0F,0.0F), Point2D<int>(0, 0));
00475 //           itsWin->drawImage(tIma,0,0);
00476 //           LINFO("Image %d:  %s has %d kp", i,
00477 //                 (*voitr)->getName().c_str(),
00478 //                 (*voitr)->numKeypoints());
00479 //           //Raster::waitForKey();
00480 
00481           voitr = inputVO.erase(voitr);
00482           obitr = objOffset.erase(obitr);
00483         }
00484       else{ voitr++; obitr++; }
00485       i++;
00486     }
00487   LINFO("  AFTER kpFilter: %"ZU, inputVO.size());
00488 }
00489 
00490 // ######################################################################
00491 float LandmarkDB::getOffsetDistScore
00492 ( rutz::shared_ptr<Landmark> landmark, int indb, int intdb, int tindex,
00493   rutz::shared_ptr<VisualObject> vo, Point2D<int> offset, Dims sDims,
00494   rutz::shared_ptr<VisualObjectMatch> cmatch)
00495 {
00496   float dscore = 0.0;
00497 
00498   Point2D<int> objOffset2;
00499   if(indb)
00500     objOffset2 = landmark->getOffsetCoords(tindex);
00501   else
00502     objOffset2 = landmark->getTempOffsetCoords(tindex);
00503   bool isODmatch = (vo == cmatch->getVoRef());
00504   Point2D<int> diff;
00505   if(isODmatch)
00506     {
00507       diff = cmatch->getSpatialDist(offset, objOffset2);
00508       //itsWin->drawImage(cmatch->getMatchImage(sDims, offset, objOffset2),0,0);
00509     }
00510   else
00511     {
00512       diff = cmatch->getSpatialDist(objOffset2, offset);
00513       //itsWin->drawImage(cmatch->getMatchImage(sDims, objOffset2, offset),0,0);
00514     }
00515   float dist = diff.distance(Point2D<int>(0,0));
00516 
00517   // dist: 0 to 25.0 -> range 1.0 to .98
00518   if(dist <= 25.0)
00519     dscore = 1.0 - (dist/25.0) * .02;
00520   // dist 25.0 to 200.0 -> range .98 to .01
00521   else if(dist > 25.0 && dist <= 200.0)
00522     dscore = .98 - ((dist - 25.0)/175.0)* .97;
00523   // dist > 200.0 -> range .01
00524   else
00525     dscore = .01;
00526   LINFO("dist: (%d,%d): %f", diff.i, diff.j, dist);
00527 
00528   return dscore;
00529 }
00530 
00531 // ######################################################################
00532 float LandmarkDB::getOverlapScore
00533 (rutz::shared_ptr<VisualObjectMatch> cmatch)
00534 {
00535   float oscore = 0.0;
00536 
00537   int area1 = cmatch->getVoRef()->getImage().getSize();
00538   int area2 = cmatch->getVoTest()->getImage().getSize();
00539   Rectangle rovl = cmatch->getOverlapRect();
00540 
00541   if(!rovl.isValid()) return oscore;
00542 
00543   float ovl = float(rovl.width() * rovl.height());
00544   oscore = (ovl/area1 + ovl/area2)/2.0;
00545   LINFO("area1: %d, area2: %d, ovl: %f, oscore: %f",
00546         area1, area2, ovl, oscore);
00547   return oscore;
00548 }
00549 
00550 // ######################################################################
00551 void LandmarkDB::printScores
00552 ( std::vector<rutz::shared_ptr<VisualObject> > inputVO,
00553   int currSegNum, std::vector<std::vector<float> > inscores)
00554 {
00555   int printlimit = 25;
00556   uint nobj = inputVO.size();
00557   uint nlmk = itsActiveLmkList[currSegNum].size();
00558   LINFO("nobj: %d nlmk: %d", nobj, nlmk);
00559 
00560   // print sal scores
00561   printf("          ");
00562   int lcount = 0;
00563   for(uint j = 0; j < nlmk; j++)
00564     {
00565       if(itsActiveLmkList[currSegNum][j] && lcount < printlimit)
00566        {
00567          printf("%6d",j);
00568          lcount++;
00569        }
00570     }
00571   printf("\n");
00572   for(uint i = 0; i < nobj; i++)
00573     {
00574       int len = inputVO[i]->getName().length();
00575       printf("%10s", inputVO[i]->getName().substr(len-10).c_str());
00576       lcount = 0;
00577       for(uint j = 0; j < nlmk; j++)
00578         {
00579           if(itsActiveLmkList[currSegNum][j] && lcount < printlimit)
00580             {
00581               printf("%6.2f", inscores[i][j]);
00582               lcount++;
00583             }
00584         }
00585       printf("\n");
00586     }
00587   printf("\n");
00588 }
00589 
00590 // ######################################################################
00591 void LandmarkDB::findBestMatch
00592 (std::vector<std::vector<float> > scores, std::vector<float> &ratio,
00593  std::vector<bool> &inserted, std::vector<bool> &lmatched,
00594  float &mratio, int &mind, std::vector<int> &mlist)
00595 {
00596   // calculate ratio for each object
00597   for(uint i = 0; i < scores.size(); i++)
00598     {
00599       ratio[i] = 0.0;
00600       // make sure at least 1 landmark is still available to insert to
00601       bool hasMatch = false;
00602       for(uint j = 0; j < scores[i].size(); j++)
00603         if(scores[i][j] > 0.0 && !lmatched[j]) hasMatch = true;
00604 
00605       // check if it inserted (or inactive)
00606       if(!inserted[i] && hasMatch)
00607         {
00608           // go through each landmark
00609           float max = 0.0f; float max2 = 0.0f;
00610           for(uint j = 0; j < scores[i].size(); j++)
00611             {
00612               if(scores[i][j] > max)
00613                 { max2 = max; max = scores[i][j]; }
00614               else if(scores[i][j] > max2)
00615                 { max2 = scores[i][j]; }
00616             }
00617           if(max2 < .25) ratio[i] = max/.25;
00618           else           ratio[i] = max/max2;
00619         }
00620       LINFO("ratio[%d]: %f", i, ratio[i]);
00621     }
00622 
00623   // go through each ratio
00624   mratio = 0.0; mind = -1;
00625   for(uint i = 0; i < ratio.size(); i++)
00626     {
00627       if(!inserted[i])
00628         {
00629           if(ratio[i] > mratio)
00630             { mratio = ratio[i]; mind = i; }
00631         }
00632     }
00633   if(mind == -1) { LINFO("no more matches"); return; }
00634 
00635   // get the matching indexes
00636   for(uint j = 0; j < scores[mind].size(); j++)
00637     {
00638       // check if it inserted (or inactive)
00639       if(!lmatched[j] && scores[mind][j] > 0.0)
00640         mlist.push_back(j);
00641     }
00642   LINFO("max ratio: %f obj[%d]: %"ZU" matches", mratio, mind, mlist.size());
00643 }
00644 
00645 // ######################################################################
00646 void LandmarkDB::classifyInactiveLandmarks(uint fNum, uint nfDiff, bool print)
00647 {
00648   //bool stop = false;
00649   for(uint i = 0; i < itsLandmarks.size(); i++)
00650     for(uint j = 0; j < itsLandmarks[i].size(); j++)
00651       {
00652         if(itsActiveLmkList[i][j] &&
00653            ((itsLandmarks[i][j]->getLatestFNum() + nfDiff) < fNum))
00654           {
00655             // move the latest object on the temp VO to the DB
00656             itsLandmarks[i][j]->moveLatestTempVisualObjectToDB();
00657             itsActiveLmkList[i][j] = false;
00658             //stop = true;
00659             if(print) LINFO("made landmark [%d][%d] inactive", i, j);
00660           }
00661 
00662         if(itsActiveLmkList[i][j] && print)
00663           LINFO("landmark[%3d %3d]   active: %5d,%5d: %3d + %3d = %3d", i, j,
00664                 itsLandmarks[i][j]->getVisualObjectFNum(0),
00665                 itsLandmarks[i][j]->getLatestFNum(),
00666                 itsLandmarks[i][j]->numObjects(),
00667                 itsLandmarks[i][j]->numTempObjects(),
00668                 itsLandmarks[i][j]->numObjects() +
00669                 itsLandmarks[i][j]->numTempObjects());
00670         else if(itsLandmarks[i][j]->numObjects() > 0 && print)
00671           LINFO("landmark[%3d %3d] inactive: %5d,%5d: %3d + %3d = %3d", i, j,
00672                 itsLandmarks[i][j]->getVisualObjectFNum(0),
00673                 itsLandmarks[i][j]->getLatestFNum(),
00674                 itsLandmarks[i][j]->numObjects(),
00675                 itsLandmarks[i][j]->numTempObjects(),
00676                 itsLandmarks[i][j]->numObjects() +
00677                 itsLandmarks[i][j]->numTempObjects());
00678         else if(print)
00679           LINFO("landmark[%3d %3d] inactive:    -1,   -1: %3d + %3d = %3d", i, j,
00680                 itsLandmarks[i][j]->numObjects(),
00681                 itsLandmarks[i][j]->numTempObjects(),
00682                 itsLandmarks[i][j]->numObjects() +
00683                 itsLandmarks[i][j]->numTempObjects());
00684       }
00685   //if(stop) Raster::waitForKey();
00686 }
00687 
00688 // ######################################################################
00689 void LandmarkDB::finishBuild(uint rframe)
00690 {
00691   // make all landmarks inactive and then prune them
00692   classifyInactiveLandmarks(rframe, 0, true);
00693   pruneLandmarks();
00694 
00695   // show the Visual Objects skipped
00696   //printSkiplist();
00697 }
00698 
00699 // ######################################################################
00700 void LandmarkDB::pruneLandmarks()
00701 {
00702   // go through all segments
00703   for(uint i = 0; i < itsLandmarks.size(); i++)
00704     {
00705       std::vector< rutz::shared_ptr<Landmark> >::iterator itr =
00706         itsLandmarks[i].begin();
00707       uint ct = 0; uint orgCt = 0;
00708       // go through all the landmarks in the segment
00709       while (itr < itsLandmarks[i].end())
00710         {
00711           uint numObjects  = (*itr)->numObjects();
00712           uint numTempObjects = (*itr)->numTempObjects();
00713           uint numTotal = numObjects + numTempObjects;
00714 
00715           int range = 0; int start = -1; int end = -1;
00716           if(numObjects > 0)
00717             {
00718               start = (*itr)->getVisualObjectFNum(0);
00719               end   = (*itr)->getLatestFNum();
00720               range = end - start;
00721             }
00722 
00723           // criterion:
00724           // allow very persistent salient, slightly ephemeral object:
00725           // range <= 20 frames but numTotal >= 8
00726           // allow less persistently salient, but consistently detected:
00727           // range > 20 & numTotal >= 5
00728           if (((range <= 20) && (numTotal >= 8)) ||
00729               ((range >  20) && (numTotal >= 5))    )
00730             {
00731               // change the name to keep order
00732               std::string lmName(sformat("landmark%07u", ct));
00733               LINFO("include: %s [%d %d: %d] (%d + %d = %d): %s",
00734                     (*itr)->getName().c_str(), start, end, range,
00735                     numObjects, numTempObjects, numTotal, lmName.c_str());
00736               (*itr)->setName(lmName);
00737               ++ itr;
00738               ct++;
00739             }
00740           else
00741             {
00742               LINFO("Landmark[%d][%d] is too small: [%d %d: %d] %d + %d = %d",
00743                     i, orgCt, start, end, range,
00744                     numObjects, numTempObjects, numTotal);
00745               // remove from the list
00746               itr = itsLandmarks[i].erase(itr);
00747             }
00748           orgCt++;
00749         }
00750     }
00751 }
00752 
00753 // ######################################################################
00754 void LandmarkDB::display()
00755 {
00756   // can only display if there is a window display
00757   if(itsWin.is_invalid()) { LINFO("no window display"); return; }
00758 
00759   Dims d = itsWin->getDims();
00760   int w = d.w(), h = d.h();
00761   int nSegment = itsLandmarks.size();
00762 
00763   // check each segment
00764   for(int  i = 0; i < nSegment; i ++)
00765     {
00766       // how many landmarks recovered for this segment
00767       int size = itsLandmarks[i].size();
00768       printf("segment [%4d] has: %d landmarks\n",i,size);
00769       for(int j = 0; j < size; j++)
00770         {
00771           // how many objects for each landmark
00772           int nObjects  = itsLandmarks[i][j]->numObjects();
00773           int nTObjects = itsLandmarks[i][j]->numTempObjects();
00774           printf("   lm[%4d][%4d] has %d vo + %d temp =  %d\n", i, j,
00775                 nObjects,  nTObjects, nObjects + nTObjects);
00776 
00777           // display each
00778           for(int k = 0; k < nObjects; k++)
00779             {
00780               printf("image %4d: %s   ", k, itsLandmarks[i][j]
00781                     ->getObject(k)->getName().c_str());
00782               Image<PixRGB<byte> > tIma(w,h,ZEROS);
00783 
00784               Point2D<int> salpt =
00785                 itsLandmarks[i][j]->getObject(k)->getSalPoint();
00786               Point2D<int> offset =
00787                 itsLandmarks[i][j]->getOffsetCoords(k);
00788 
00789               inplacePaste
00790                 (tIma, itsLandmarks[i][j]->getObject(k)
00791                  ->getKeypointImage(1.0F,0.0F), offset);
00792               drawDisk(tIma, salpt+offset, 3, PixRGB<byte>(255,255,0));
00793 
00794               itsWin->drawImage(tIma,0,0);
00795               Raster::waitForKey();
00796             }
00797         }
00798     }
00799 }
00800 
00801 // ######################################################################
00802 void LandmarkDB::printSkiplist()
00803 {
00804   Dims d = itsWin->getDims();
00805   int w = d.w(), h = d.h();
00806 
00807   // show the skiplist
00808   LINFO("skipping %"ZU" images", itsSkipList.size());
00809   for(uint  i = 0; i < itsSkipList.size(); i ++)
00810     {
00811       Image<PixRGB<byte> > tIma(w,h,ZEROS);
00812       inplacePaste
00813         (tIma,itsSkipList[i]->getKeypointImage(1.0F,0.0F), Point2D<int>(0, 0));
00814       itsWin->drawImage(tIma,0,0);
00815       LINFO("Image %d:  %s has %d kp", i,
00816             itsSkipList[i]->getName().c_str(), itsSkipList[i]->numKeypoints());
00817       Raster::waitForKey();
00818     }
00819 }
00820 
00821 // ######################################################################
00822 void LandmarkDB::setSession(std::string sessionFName, bool sort)
00823 {
00824   // open the session file
00825   FILE *fp;  char inLine[100];
00826   if((fp = fopen(sessionFName.c_str(),"rb")) == NULL)
00827     LFATAL("session file: %s not found", sessionFName.c_str());
00828   LINFO("session file name: %s",sessionFName.c_str());
00829 
00830   // open the file
00831   itsSessionNames.clear();
00832   itsSessionLength.clear();
00833 
00834   // go through each session
00835   while(fgets(inLine, 1000, fp) != NULL)
00836   {
00837     // get the files in this category and ground truth
00838     char sName[100]; int cStart, cNum; int gTruth;
00839     sscanf(inLine, "%s %d %d %d", sName, &cStart, &cNum,  &gTruth);
00840     LDEBUG("%20s: %d: %d - %d: %d", sName, gTruth, cNum, cStart, cNum - cStart);
00841     itsSessionNames.push_back(std::string(sName));
00842     itsSessionLength.push_back(cNum - cStart);
00843   }
00844   fclose(fp);
00845 
00846   // if needed to resort the salient regions
00847   if(sort) sortLandmarks();
00848 
00849   // reset the session related information
00850   setSessionInfo();
00851 }
00852 
00853 // ######################################################################
00854 void LandmarkDB::sortLandmarks()
00855 {
00856   for(uint i = 0; i < itsLandmarks.size(); i++)
00857     for(uint j = 0; j < itsLandmarks[i].size(); j++)
00858       itsLandmarks[i][j]->sort(itsSessionNames);
00859 }
00860 
00861 // #####################################################################
00862 void LandmarkDB::setSessionInfo()
00863 {
00864   // set the session information for individual landmarks
00865   for(uint i = 0; i < itsLandmarks.size(); i++)
00866     for(uint j = 0; j < itsLandmarks[i].size(); j++)
00867       itsLandmarks[i][j]->setSessionInfo();
00868 
00869   // set a landmarks database for each session
00870   setSessionLandmarks();
00871 
00872   // set the location range for each landmark
00873   setLocationRange();
00874 }
00875 
00876 // ######################################################################
00877 void LandmarkDB::setSessionLandmarks()
00878 {
00879   LINFO("set");
00880   uint nses = itsSessionNames.size();
00881   if(nses == 0) return;
00882 
00883   uint nseg = itsLandmarks.size();
00884   itsSessionLandmarks.resize(nses);
00885   for(uint i = 0; i < nses; i++)
00886     {
00887       std::string session = itsSessionNames[i];
00888       LDEBUG("[%d] session: %s", i, session.c_str());
00889 
00890       // go through all the segments
00891       itsSessionLandmarks[i].resize(nseg);
00892       for(uint j = 0; j < nseg; j++)
00893         {
00894           uint nlmk = itsLandmarks[j].size();
00895           LDEBUG("itsLmk[%d]: %d", j, nlmk);
00896           for(uint k = 0; k < nlmk; k++)
00897             {
00898               LDEBUG("check: itsLmk[%d][%d] ", j, k);
00899               if(itsLandmarks[j][k]->haveSessionVO(session))
00900                 {
00901                   itsSessionLandmarks[i][j].push_back
00902                     (itsLandmarks[j][k]);
00903                   LDEBUG("match");
00904                 }
00905             }
00906         }
00907 
00908 //       // print the resulting database
00909 //       for(uint j = 0; j < nseg; j++)
00910 //         {
00911 //           uint nlmk = itsSessionLandmarks[i][j].size();
00912 //           for(uint k = 0; k < nlmk; k++)
00913 //             LINFO("lmk[%d][%d][%d]: %s", i, j, k,
00914 //                   itsSessionLandmarks[i][j][k]->getName().c_str());
00915 //         }
00916     }
00917 }
00918 
00919 // #####################################################################
00920 void LandmarkDB::setLocationRange()
00921 {
00922   LINFO("set");
00923 
00924   // store each landmark first & last occurance location
00925   uint nseg = itsLandmarks.size();
00926   itsLandmarkLocationRange.resize(nseg);
00927   for(uint i = 0; i < nseg; i++)
00928     {
00929       // go through all the landmarks
00930       uint nlmk = itsLandmarks[i].size();
00931       itsLandmarkLocationRange[i].resize(nlmk);
00932       for(uint j = 0; j < nlmk; j++)
00933         {
00934           uint nsession = itsLandmarks[i][j]->getNumSession();
00935 
00936           float mfltrav = 1.0;
00937           float mlltrav = 0.0;
00938           for(uint k = 0; k < nsession; k++)
00939             {
00940               // get the session index range
00941               std::pair<uint,uint> r =
00942                 itsLandmarks[i][j]->getSessionIndexRange(k);
00943 
00944               float fltrav = getLenTrav(i, j, r.first);
00945               float lltrav = getLenTrav(i, j, r.second);
00946 
00947               if(mfltrav > fltrav) mfltrav = fltrav;
00948               if(mlltrav < lltrav) mlltrav = lltrav;
00949 
00950               LDEBUG("[%d][%d]f-l: %f %f, m_f-l: %f %f",
00951                      i, j, fltrav, lltrav, mfltrav, mlltrav);
00952             }
00953 
00954           LDEBUG("m_f-l: %f %f", mfltrav, mlltrav);
00955 
00956           itsLandmarkLocationRange[i][j] =
00957             std::pair<float,float>(mfltrav, mlltrav);
00958         }
00959     }
00960 }
00961 
00962 // #####################################################################
00963 float LandmarkDB::getLenTrav(uint snum, uint lnum, uint index)
00964 {
00965   // get the object name
00966   std::string sname =
00967     itsLandmarks[snum][lnum]->getObject(index)->getName();
00968   LDEBUG("session name: %s", sname.c_str());
00969   sname = sname.substr(0, sname.find_last_of('_'));
00970   sname = sname.substr(0, sname.find_last_of('_'));
00971   sname = sname.substr(0, sname.find_last_of('_'));
00972 
00973   uint i = 0;
00974   // check it against the names on the list
00975   while((i < itsSessionNames.size()) &&
00976         (sname != itsSessionNames[i])  ) i++;
00977 
00978   // if found get the length traveled
00979   if(i < itsSessionNames.size())
00980     {
00981       float slen = float(itsSessionLength[i]);
00982       float fNum = float(itsLandmarks[snum][lnum]->
00983                          getVisualObjectFNum(index));
00984       LDEBUG("session name: %s: %f/%f = %f",
00985             itsSessionNames[i].c_str(), fNum, slen, fNum/slen);
00986       return fNum/slen;
00987     }
00988   else LFATAL("Session not in list: %s (%s)", sname.c_str(),
00989               itsLandmarks[snum][lnum]->getObject(index)->getName().c_str());
00990   return -1.0F;
00991 }
00992 
00993 // ######################################################################
00994 /* So things look consistent in everyone's emacs... */
00995 /* Local Variables: */
00996 /* indent-tabs-mode: nil */
00997 /* End: */
Generated on Sun May 8 08:04:29 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3