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