00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Robots/Beobot2/Navigation/GistSal_Navigation/CornerNavigation.H"
00039 #include "Ice/BeobotEvents.ice.H"
00040
00041 #include "Raster/Raster.H"
00042 #include "Util/sformat.H"
00043 #include "Image/Image.H"
00044 #include "Image/DrawOps.H"
00045 #include "Image/ColorOps.H"
00046 #include "Image/ShapeOps.H"
00047 #include "Image/MathOps.H"
00048 #include "Image/MatrixOps.H"
00049 #include "Image/CutPaste.H"
00050
00051 #include "Util/Timer.H"
00052
00053 #include "SIFT/Keypoint.H"
00054 #include "SIFT/VisualObject.H"
00055 #include "SIFT/VisualObjectMatch.H"
00056 #include "Transport/FrameInfo.H"
00057
00058 #include "Ice/IceImageUtils.H"
00059
00060 #include "Component/ModelParam.H"
00061 #include "Component/ModelOptionDef.H"
00062
00063 #define FOLDER "../data/corner"
00064 #define DBNAME "HNB"
00065 #define IMAGE_PREFIX "image_0000000000"
00066 #define IMAX 1.0
00067 #define IMIN 0.0
00068
00069 #define C_PROCEDURE_INACTIVE 0
00070 #define C_PROCEDURE_ACTIVE 1
00071 #define C_PROCEDURE_CONCLUDING 2
00072
00073 const ModelOptionCateg MOC_CornerNavigation =
00074 { MOC_SORTPRI_3, "QT Navigation Related Options" };
00075 const ModelOptionDef OPT_RealCamera =
00076 { MODOPT_ARG(bool), "RealCamera", &MOC_CornerNavigation, OPTEXP_CORE,
00077 "Do we want use real camera from BeoCamera? Default will load from image files.",
00078 "camera", '\0', "true | false", "false" };
00079
00080
00081 CornerNavigation::CornerNavigation(OptionManager& mgr,
00082 const std::string& descrName,
00083 const std::string& tagName) :
00084 RobotBrainComponent(mgr, descrName, tagName),
00085 itsFftComputer(new GistEstimatorFFT(mgr)),
00086 itsOfs(new OutputFrameSeries(mgr)),
00087 itsMapImg(320,240,ZEROS),
00088 itsReplayDBnum(0),
00089 itsFfn(new FeedForwardNetwork()),
00090 itsTimer(1000000),
00091 itsCurrImgID(-1),
00092 itsPrevProcImgID(-1),
00093 itsTeachImgID(0),
00094 itsReplayImgID(0),
00095 itsTransSpeed(0.0),
00096 itsRotSpeed(0.0),
00097 itsDirVector(0.0),
00098 itsDir(0),
00099 itsMilestoneErr(999.99),
00100 itsFalseErrRate(0.0),
00101 itsDirCount(0),
00102 itsPosition(0.0, 0.0, 0.0),
00103 itsError(0.0, 0.0, 0.0),
00104 itsRealCamera(&OPT_RealCamera, this, 0),
00105 itsEstop(true),
00106 itsIState(0.0),
00107 itsDState(0.0),
00108 itsPGain(1.0),
00109 itsIGain(0.01),
00110 itsDGain(0.0)
00111 {
00112 addSubComponent(itsOfs);
00113
00114 itsStatus = C_PROCEDURE_INACTIVE;
00115
00116 openDB(sformat("%s/%s/%s.conf",FOLDER,DBNAME,DBNAME));
00117 }
00118
00119
00120 void CornerNavigation::openDB(const std::string& path)
00121 {
00122 FILE *dbconf = fopen(path.c_str(),"r");
00123 if(dbconf == NULL){
00124 LFATAL("Can not open file: %s",path.c_str());
00125 }else{
00126 char line[512];
00127 while(fgets(line,sizeof line,dbconf)!= NULL)
00128 {
00129
00130 if(line[0] != '#')
00131 {
00132 char subdb[256];
00133 char type;
00134 int start,end;
00135 int ret = sscanf(line,"%s %d %d %c",subdb,&start,&end,&type);
00136 if(ret == 4){
00137 LINFO("Got [%s],start[%d],end[%d],type[%c]",subdb,start,end,type);
00138 cornerDB tmpDB;
00139 tmpDB.path = sformat("%s/%s/%s/%s",FOLDER,DBNAME,subdb,IMAGE_PREFIX);
00140 tmpDB.start = start;
00141 tmpDB.end = end;
00142 tmpDB.type = type;
00143 loadDB(tmpDB);
00144
00145 }
00146 }
00147
00148 }
00149
00150
00151 }
00152 }
00153
00154
00155 void CornerNavigation::initFFN()
00156 { }
00157
00158
00159 CornerNavigation::~CornerNavigation()
00160 { }
00161
00162
00163 void CornerNavigation::start1()
00164 {
00165
00166 if(!itsRealCamera.getVal())
00167 itsDBnum = 0;
00168 else
00169 itsDBnum = -1;
00170 LINFO("itsDBNUM: %d", itsDBnum);
00171 }
00172
00173
00174 void CornerNavigation::registerTopics()
00175 {
00176
00177
00178 this->registerSubscription("GistSalMessageTopic");
00179 this->registerSubscription("MotorMessageTopic");
00180 this->registerSubscription("CornerLocationMessageTopic");
00181
00182 this->registerPublisher("CornerMotorRequestTopic");
00183
00184 }
00185
00186
00187 void CornerNavigation::evolve()
00188 {
00189
00190 its_Curr_Img_mutex.lock();
00191 bool newImageFlag = (itsPrevProcImgID < itsCurrImgID);
00192 its_Curr_Img_mutex.unlock();
00193
00194
00195 if(!itsRealCamera.getVal())
00196 {
00197 navigation();
00198 }
00199
00200
00201 else
00202 {
00203
00204 if(newImageFlag)
00205 {
00206
00207 itsTimer.reset();
00208 its_Curr_Img_mutex.lock();
00209 itsProcImg = itsCurrImg;
00210 itsPrevProcImgID = itsCurrImgID;
00211 its_Curr_Img_mutex.unlock();
00212
00213
00214 its_Corner_Loc_mutex.lock();
00215 int dbNum = itsDBnum;
00216 int status = itsStatus;
00217 its_Corner_Loc_mutex.unlock();
00218
00219
00220 if(dbNum != -1 && status != C_PROCEDURE_INACTIVE)
00221 {
00222 LINFO("size: %"ZU, itsVisualObjectDBs.size() );
00223 int cornerSize = itsVisualObjectDBs[dbNum].vdb->numObjects();
00224
00225 if(itsTeachImgID >= cornerSize)
00226 {
00227 itsStatus = C_PROCEDURE_INACTIVE;
00228 }
00229 else if(itsTeachImgID > int(cornerSize*0.9))
00230 {
00231 itsStatus = C_PROCEDURE_CONCLUDING;
00232 }
00233 else
00234 {
00235 itsStatus = C_PROCEDURE_ACTIVE;
00236 }
00237 LINFO("5");
00238 navigation();
00239 LINFO("6");
00240 }
00241 }
00242 }
00243
00244 if(!itsRealCamera.getVal() || newImageFlag)
00245 {
00246 drawState();
00247 itsOfs->writeRGB(itsDispImg, "CornerNav",
00248 FrameInfo("CornerNav",SRC_POS));
00249 }
00250
00251
00252
00253
00254
00255
00256 }
00257
00258
00259 void CornerNavigation::recovery()
00260 {
00261 int trytimes = 0;
00262 do{
00263 loadFrame();
00264 std::vector< rutz::shared_ptr<VisualObjectMatch> > matches;
00265
00266 its_Corner_Loc_mutex.lock();
00267 int dbNum = itsDBnum;
00268 its_Corner_Loc_mutex.unlock();
00269
00270 int nmatches =
00271 itsVisualObjectDBs[dbNum].vdb->getObjectMatches
00272 (itsReplayVo,matches,VOMA_SIMPLE,
00273 10U,
00274 0.5F,
00275 0.5F,
00276 1.0F,
00277 4U,
00278 100U,
00279 false
00280 );
00281 std::string objName;
00282 int closestFrame = 999999999;
00283 int tmpFrameID = itsTeachImgID;
00284 LINFO("Searching For Nearest Key Frame in the Database");
00285 if (nmatches > 0 )
00286 {
00287 for(int i = 0; i < nmatches; i++)
00288 {
00289 LINFO("Found [%d] frames matches Frame[%d]", nmatches, i);
00290
00291
00292 rutz::shared_ptr<VisualObject> obj;
00293 rutz::shared_ptr<VisualObjectMatch> vom;
00294 vom = matches[i];
00295 obj = vom->getVoTest();
00296
00297
00298
00299
00300 objName = obj->getName();
00301 int tmpID = atoi(objName.c_str());
00302 int dx = tmpID - itsTeachImgID;
00303
00304 LINFO("Dist. from current teach frame[%d]=======new ID[%d]",
00305 dx,tmpID);
00306
00307
00308 if(dx < closestFrame)
00309 {
00310 closestFrame = dx;
00311 tmpFrameID = tmpID;
00312 }
00313 }
00314 LINFO("Recovery Found:TID[%d]RID[%d] Match[%d]",
00315 itsTeachImgID,itsReplayImgID,tmpFrameID);
00316 itsTeachImgID = tmpFrameID;
00317 itsEstop = true;
00318 itsTransSpeed = 0.8;
00319 loadFrame();
00320 computeSIFT();
00321 }
00322 else
00323 {
00324 LINFO("No Match Point,Try get new frame and try again");
00325 loadFrame();
00326 trytimes++;
00327 }
00328 }
00329 while(!itsEstop && trytimes < 10);
00330 }
00331
00332
00333
00334 void CornerNavigation::navigation()
00335 {
00336
00337
00338 loadFrame();
00339
00340
00341
00342 double error = computeDirection2(itsTeachImgID);
00343
00344
00345
00346 if(error != 0.0 && itsMatchList->size()!=0 &&
00347 (itsMatchList->checkSIFTaffine() || itsFalseErrRate > 1.0)
00348 ){
00349 updateMotor(itsTransSpeed, itsRotSpeed,itsStatus);
00350 updateKeyframe(error);
00351 itsEstop = true;
00352
00353
00354 updateKeyframe(error);
00355 itsEstop = true;
00356 }
00357
00358
00359
00360 else
00361 {
00362 itsEstop = false;
00363 LINFO("lost matching; start recover mechanism");
00364 itsTransSpeed = 0.0;
00365 itsRotSpeed = 0.0;
00366
00367 if(itsRealCamera.getVal())
00368 {
00369 its_Corner_Loc_mutex.lock();
00370 itsStatus = C_PROCEDURE_INACTIVE;
00371 int status = itsStatus;
00372 itsDBnum = -1;
00373 its_Corner_Loc_mutex.unlock();
00374 updateMotor(itsTransSpeed, itsRotSpeed, status);
00375 }else{
00376 updateMotor(itsTransSpeed, itsRotSpeed, 0);
00377
00378
00379 }
00380 }
00381 }
00382
00383
00384 void CornerNavigation::loadDB(cornerDB db)
00385 {
00386
00387
00388
00389
00390 db.vdb.reset(new VisualObjectDB());
00391 bool rt = db.vdb->loadFrom(sformat("%s.sift",db.path.c_str()),false);
00392 if(rt)
00393 {
00394 LINFO("Load SIFT Database");
00395 itsVisualObjectDBs.push_back(db);
00396
00397
00398 if(db.type =='R')
00399 itsReplayDBnum = int(itsVisualObjectDBs.size())-1;
00400 }
00401 else
00402 {
00403 LINFO("SIFT Database %s not exist, create new", db.path.c_str());
00404 saveDB(db.start,db.end,db.path.c_str());
00405 }
00406 }
00407
00408 void CornerNavigation::saveDB(int start,int end,const std::string& path)
00409 {
00410 cornerDB tmp;
00411 tmp.vdb.reset(new VisualObjectDB());
00412 for(int i = start; i < end; i++)
00413 {
00414 itsTimer.reset();
00415 std::string teachFileName(sformat("%s%05d.ppm",path.c_str(),i));
00416 Image< PixRGB<byte> > img = Raster::ReadRGB(teachFileName);
00417 rutz::shared_ptr<VisualObject> vo1
00418 (new VisualObject(sformat("%d",i),
00419 sformat("%s%05d.png",path.c_str(),i),
00420 rescale(img,img.getWidth()/2, img.getHeight()/2)));
00421 tmp.vdb->addObject(vo1);
00422 LINFO("Time[%f] Compute SIFT for Frame %d/%d",
00423 itsTimer.get()/1000.0,i-start+1,end-start+1);
00424 }
00425 std::string teachDB(sformat("%s.sift",path.c_str()));
00426
00427 tmp.vdb->saveTo(teachDB);
00428 }
00429
00430
00431 void CornerNavigation::loadFrame()
00432 {
00433
00434 itsTimer.reset();
00435
00436 its_Corner_Loc_mutex.lock();
00437 int dbNum = itsDBnum;
00438 its_Corner_Loc_mutex.unlock();
00439
00440
00441 if(itsTeachImgID < (int)itsVisualObjectDBs[dbNum].vdb->numObjects())
00442 {
00443 itsTeachVo = itsVisualObjectDBs[dbNum].vdb->getObject(itsTeachImgID);
00444 itsTeachImg = itsTeachVo->getImage();
00445 }
00446 else
00447 {
00448 LINFO("=======Teach DB End=====");
00449 itsTeachImgID = 0;
00450
00451 }
00452
00453 LINFO("Time for Computing SIFT on TeachImg %f",
00454 itsTimer.get()/1000.0);
00455 itsTimer.reset();
00456
00457
00458
00459
00460 if(!itsRealCamera.getVal())
00461 {
00462 if(itsReplayImgID < (int)itsVisualObjectDBs[itsReplayDBnum].vdb->numObjects())
00463 {
00464 if(itsReplayImgID <(int)itsVisualObjectDBs[itsReplayDBnum].vdb->numObjects())
00465 {
00466 itsReplayVo = itsVisualObjectDBs[itsReplayDBnum].vdb-> getObject(itsReplayImgID);
00467 itsReplayImg = itsReplayVo->getImage();
00468 itsProcImg = itsReplayImg;
00469 itsReplayImgID++;
00470 }
00471 }
00472 }
00473
00474
00475 else
00476 {
00477 itsReplayImg = itsProcImg;
00478 itsReplayImgID = itsPrevProcImgID;
00479 rutz::shared_ptr<VisualObject> vo2 (new VisualObject ("1", "", itsReplayImg));
00480 itsReplayVo = vo2;
00481 }
00482 LINFO("Time for Computing SIFT on ReplayImg %f",
00483 itsTimer.get()/1000.0);
00484 }
00485
00486
00487 bool CornerNavigation::computeSIFT()
00488 {
00489 itsTimer.reset();
00490 VisualObjectMatchAlgo voma(VOMA_SIMPLE);
00491 itsMatchList.reset(new VisualObjectMatch(itsTeachVo, itsReplayVo, voma));
00492 LINFO("=========================================");
00493
00494
00495
00496
00497 itsMatchList->prune();
00498
00499 LINFO("Match size now is %u ", itsMatchList->size());
00500
00501
00502
00503
00504
00505
00506
00507 if (itsMatchList->checkSIFTaffine() == false)
00508 LINFO("### Affine is too weird -- BOGUS MATCH");
00509
00510
00511 LINFO("Time for Matching SIFT %f",itsTimer.get()/1000.0);
00512
00513
00514 return (itsMatchList->size()!=0 && itsMatchList->checkSIFTaffine());
00515 }
00516
00517
00518 double CornerNavigation::computeDirection2(int teachID)
00519 {
00520 int dirF = 0,dirL = 0,dirR = 0;
00521 rutz::shared_ptr<VisualObjectMatch> bestMatch;
00522 int bestMatchSize = -1;
00523 int bestID = 0;
00524 LINFO("Direction2 Start");
00525
00526
00527 if((teachID-2) < 0) teachID = 2;
00528
00529
00530 for(int id = teachID-2; id < teachID+10; id++)
00531 {
00532
00533 its_Corner_Loc_mutex.lock();
00534 int dbNum = itsDBnum;
00535 its_Corner_Loc_mutex.unlock();
00536
00537
00538 rutz::shared_ptr<VisualObject> vo1;
00539 if(id < (int)itsVisualObjectDBs[dbNum].vdb->numObjects()){
00540 vo1 = itsVisualObjectDBs[dbNum].vdb->getObject(id);
00541 }
00542 else{
00543 LINFO("DB END");
00544 return 0.0;
00545 }
00546 VisualObjectMatchAlgo voma(VOMA_SIMPLE);
00547 rutz::shared_ptr<VisualObjectMatch>
00548 match(new VisualObjectMatch(vo1, itsReplayVo, voma));
00549 match->prune();
00550
00551
00552
00553 float theta = 2.0, sx = 2.0, sy = 2.0, str = 0;
00554
00555
00556 if (match->checkSIFTaffine())
00557 {
00558 match->getSIFTaffine().decompose(theta, sx, sy, str);
00559 }
00560 int msize = match->size();
00561 if((msize > bestMatchSize && sx < 1.0 && sy < 1.0) ||
00562 (bestMatchSize == -1 && id==teachID))
00563 {
00564 bestMatchSize = msize;
00565 bestMatch = match;
00566 bestID = id;
00567 }
00568 LDEBUG("Best Match Size %d,",bestMatchSize);
00569 itsMatchList = bestMatch;
00570
00571 int dirGain = 1; if(id == bestID) dirGain = 2;
00572
00573
00574 for (int i = 0; i < msize; i ++)
00575 {
00576 rutz::shared_ptr<Keypoint> refk = match->getKeypointMatch(i).refkp;
00577 rutz::shared_ptr<Keypoint> tstk = match->getKeypointMatch(i).tstkp;
00578
00579 double ut = tstk->getX() - itsReplayVo->getImage().getWidth()/2;
00580 double ud = refk->getX() - itsTeachVo->getImage().getWidth()/2;
00581
00582 if(ut > 0.0 && ud < 0.0)
00583 {
00584 dirR += dirGain;
00585 }
00586 else if(ut < 0.0 && ud > 0.0)
00587 {
00588 dirL += dirGain;
00589 }
00590 else if(ut > 0.0 && ut > ud)
00591 {
00592 dirR += dirGain;
00593 }
00594 else if(ut < 0.0 && ut < ud)
00595 {
00596 dirL += dirGain;
00597 }
00598 else
00599 {
00600 dirF +=dirGain;
00601 }
00602 }
00603 }
00604
00605
00606 double stdx = 0.0,stdy = 0.0;
00607 double avgdx = 0.0,avgdy = 0.0;
00608
00609
00610 for (int i = 0; i < bestMatchSize; i ++)
00611 {
00612
00613 rutz::shared_ptr<Keypoint> refk = bestMatch->getKeypointMatch(i).refkp;
00614 rutz::shared_ptr<Keypoint> tstk = bestMatch->getKeypointMatch(i).tstkp;
00615 double dx = fabs(tstk->getX() - refk->getX())+ 0.000001;
00616 stdx += dx * dx;
00617 avgdx+= dx;
00618
00619 double dy = fabs(tstk->getY() - refk->getY())+ 0.000001;
00620 stdy += dy * dy;
00621 avgdy+= dy;
00622 LDEBUG("Error! i=[%d] BestMatchSize[%d] "
00623 "avgdx[%f] avgdy[%f],dx[%f], dy[%f]",
00624 i,bestMatchSize,avgdx,avgdy,dx,dy);
00625 }
00626 if(bestMatchSize != 0)
00627 {
00628 avgdx/= bestMatchSize;
00629 avgdy/= bestMatchSize;
00630 stdx -= (avgdx*avgdx);
00631 stdy -= (avgdy*avgdy);
00632 stdx /= bestMatchSize;
00633 stdx = sqrt(stdx);
00634 stdy /= bestMatchSize;
00635 stdy = sqrt(stdy);
00636 LDEBUG("Error! BestMatchSize[%d] avgdx[%f] avgdy[%f]",
00637 bestMatchSize,avgdx,avgdy);
00638 }
00639 else
00640 {
00641 avgdx = 0;
00642 avgdy = 0;
00643 stdx = 0;
00644 stdy = 0;
00645 }
00646
00647 LDEBUG("stdx %f stdy %f",stdx,stdy);
00648 uint stdcount = 0;
00649 double newAvgX = 0.0,newAvgY = 0.0;
00650
00651
00652 for (int i = 0; i < bestMatchSize; i ++)
00653 {
00654 rutz::shared_ptr<Keypoint> refk = bestMatch->getKeypointMatch(i).refkp;
00655 rutz::shared_ptr<Keypoint> tstk = bestMatch->getKeypointMatch(i).tstkp;
00656 double dx = fabs(tstk->getX() - refk->getX())+ 0.000001;
00657 double dy = fabs(tstk->getY() - refk->getY())+ 0.000001 ;
00658 double ddx = fabs(dx - avgdx);
00659 double ddy = fabs(dy - avgdy);
00660
00661 if(ddx < stdx && ddy < stdy)
00662 {
00663 newAvgX += dx;
00664 newAvgY += dy;
00665 stdcount++;
00666 }
00667 }
00668
00669 if(stdcount != 0)
00670 {
00671 newAvgX/= stdcount;
00672 newAvgY/= stdcount;
00673 }
00674 double newAvgerr = sqrt(newAvgX*newAvgX + newAvgY*newAvgY);
00675 double avgerr = sqrt(avgdx*avgdx + avgdy*avgdy);
00676 double angle = (newAvgX*(16.0/33.0));
00677 itsError.x = newAvgX;
00678 itsError.y = newAvgY;
00679 itsError.z = newAvgerr;
00680
00681 if(newAvgerr == 0.0)
00682 {
00683
00684 newAvgerr = avgerr;
00685 itsFalseErrRate = 0;
00686 }
00687 else
00688 {
00689 itsFalseErrRate = avgerr/newAvgerr;
00690 }
00691 LDEBUG("False Error Rate %1.3f",itsFalseErrRate);
00692 if(itsFalseErrRate == 0.0)
00693 {
00694 LDEBUG("Error!!!! stdcount[%d] avgerr[%f]",
00695 stdcount,avgerr);
00696 LDEBUG("Error!!!! bestMatchSize[%d] stdx[%f] stdy[%f]",
00697 bestMatchSize,stdx,stdy);
00698
00699 }
00700
00701
00702 if(bestID > itsTeachImgID && newAvgerr < 10.0)
00703 itsTeachImgID = bestID;
00704
00705
00706 if (bestMatch->checkSIFTaffine())
00707 {
00708 float theta = 0.0 , sx = 0.0, sy = 0.0, str = 0.0 ;
00709 bestMatch->getSIFTaffine().decompose(theta, sx, sy, str);
00710
00711 double rms = 1.0 -(sqrt(sx*sx+sy*sy)/sqrt(2));
00712
00713 double gain = 1.0;
00714 if(rms > 0.0)
00715 itsTransSpeed = 0.8 + rms * gain;
00716 if(itsTransSpeed > 1.0)itsTransSpeed = 1.0;
00717 if(itsTransSpeed < 0.0)itsTransSpeed = 0.0;
00718 }
00719 else
00720 {
00721 itsTransSpeed = 0.8;
00722 }
00723
00724
00725 if(dirF >= abs(dirR + dirL))
00726 {
00727 updatePosition(0);
00728 itsRotSpeed = 0.4;
00729 if(itsDir == 0)
00730 {
00731 itsDirCount++;
00732 }
00733 else
00734 {
00735 itsDirCount = 0;
00736 itsDir = 0;
00737 }
00738 }
00739 else if(dirR > dirL)
00740 {
00741 updatePosition(angle);
00742
00743 itsRotSpeed -= newAvgX/100.0;
00744 itsRotSpeed /= 2.0;
00745 if(itsDir == 1)
00746 {
00747 itsDirCount++;
00748 }
00749 else
00750 {
00751 itsDirCount = 0;
00752 itsDir = 1;
00753 }
00754 }
00755 else
00756 {
00757 updatePosition(-1*angle);
00758
00759 itsRotSpeed += newAvgX/100.0+1.0;
00760 itsRotSpeed /= 2.0;
00761 if(itsDir == -1)
00762 {
00763 itsDirCount++;
00764 }else{
00765 itsDirCount = 0;
00766 itsDir = -1;
00767 }
00768 }
00769 return newAvgerr;
00770 }
00771
00772
00773 double CornerNavigation::computeDirection()
00774 {
00775 itsTimer.reset();
00776 int dirF = 0,dirL = 0,dirR = 0;
00777 double avgdx = 0.0,avgdy = 0.0;
00778 uint msize = itsMatchList->size();
00779
00780
00781 for (uint i = 0; i < msize; i ++)
00782 {
00783 rutz::shared_ptr<Keypoint> refk =
00784 itsMatchList->getKeypointMatch(i).refkp;
00785 rutz::shared_ptr<Keypoint> tstk =
00786 itsMatchList->getKeypointMatch(i).tstkp;
00787
00788 double ut = tstk->getX() - itsReplayVo->getImage().getWidth()/2;
00789 double ud = refk->getX() - itsTeachVo->getImage().getWidth()/2;
00790 double dx = fabs(ut - ud);
00791 double dy = fabs(tstk->getY() - refk->getY());
00792 avgdx += dx;
00793 avgdy += dy;
00794 std::string dir;
00795
00796 if(ut > 0.0 && ud < 0.0)
00797 {
00798 dir = std::string("RIGHT");
00799 dirR ++;
00800 }
00801 else if(ut < 0.0 && ud > 0.0)
00802 {
00803 dir = std::string("LEFT");
00804 dirL ++;
00805 }
00806 else if(ut > 0.0 && ut > ud )
00807 {
00808 dir = std::string("RIGHT");
00809 dirR ++;
00810 }
00811 else if(ut < 0.0 && ut < ud)
00812 {
00813 dir = std::string("LEFT");
00814 dirL ++;
00815 }
00816 else
00817 {
00818 dir = std::string("Forward");
00819 dirF ++;
00820 }
00821 LDEBUG("MatchPoint[%d] Teach(%f,%f) Replay(%f,%f), "
00822 "ud:[%f],ut:[%f],dx:[%f],dy:[%f] Turn %s",
00823 i,
00824 (refk->getX()),
00825 (refk->getY()),
00826 (tstk->getX()),
00827 (tstk->getY()),
00828 ud,ut,dx,dy,dir.c_str()
00829 );
00830 }
00831 avgdx/= msize;
00832 avgdy/= msize;
00833 double stdx = 0.0,stdy = 0.0;
00834
00835
00836 for (uint i = 0; i < msize; i ++)
00837 {
00838 rutz::shared_ptr<Keypoint> refk =
00839 itsMatchList->getKeypointMatch(i).refkp;
00840 rutz::shared_ptr<Keypoint> tstk =
00841 itsMatchList->getKeypointMatch(i).tstkp;
00842 double ddx = fabs(tstk->getX() - refk->getX()) - avgdx;
00843 stdx += ddx * ddx;
00844 double ddy = fabs(tstk->getY() - refk->getY()) - avgdy;
00845 stdy += ddy * ddy;
00846 }
00847 stdx /= msize;
00848
00849 stdy /= msize;
00850
00851 uint stdcount = 0;
00852 double newAvgX = 0.0,newAvgY = 0.0;
00853
00854
00855 for (uint i = 0; i < msize; i ++)
00856 {
00857 rutz::shared_ptr<Keypoint> refk =
00858 itsMatchList->getKeypointMatch(i).refkp;
00859 rutz::shared_ptr<Keypoint> tstk =
00860 itsMatchList->getKeypointMatch(i).tstkp;
00861 double dx = fabs(tstk->getX() - refk->getX()) ;
00862 double dy = fabs(tstk->getY() - refk->getY()) ;
00863 double ddx = fabs(dx - avgdx);
00864 double ddy = fabs(dy - avgdy);
00865
00866 if(ddx < sqrt(stdx) && ddy < sqrt(stdy))
00867 {
00868 newAvgX += dx;
00869 newAvgY += dy;
00870 stdcount++;
00871 }
00872 }
00873 if(stdcount != 0)
00874 {
00875 newAvgX/=stdcount;
00876 newAvgY/=stdcount;
00877 }
00878
00879 double stdeverr = sqrt(stdx+stdy);
00880 double avgerr = sqrt(avgdx*avgdx + avgdy*avgdy);
00881 double newAvgerr = sqrt(newAvgX*newAvgX + newAvgY*newAvgY);
00882 double df = (itsTeachImgID - itsReplayImgID );
00883 double angle = (newAvgX*(56.0/33.0))/df;
00884
00885 LDEBUG("StdError[%f],StdErrX[%f],StdErrY[%f],Frame[%1.0f]",
00886 stdeverr,sqrt(stdx),sqrt(stdy),df);
00887 LDEBUG("AvgErr[%f],AvgX[%f],AvgY[%f]",avgerr,avgdx,avgdy);
00888 LDEBUG("StdAvgErr[%f],StdAvgX[%f],StdAvgY[%f]",newAvgerr,newAvgX,newAvgY);
00889 LDEBUG("Forward[%d], Right[%d], Left[%d] Angle[%f]",dirF,dirR,dirL,angle);
00890 itsError.x = newAvgX;
00891 itsError.y = newAvgY;
00892 itsError.z = newAvgerr;
00893
00894 if(newAvgerr == 0.0)
00895 {
00896
00897 newAvgerr = avgerr;
00898 }
00899
00900 itsFalseErrRate = avgerr/newAvgerr;
00901
00902 LINFO("Time for QT Navigation %f",itsTimer.get()/1000.0);
00903 return newAvgerr;
00904 }
00905
00906
00907 void CornerNavigation::updateKeyframe(double error)
00908 {
00909 LINFO("itsMerror %f,new error %f", itsMilestoneErr, error);
00910
00911
00912 if (itsMatchList->checkSIFTaffine())
00913 {
00914 float theta, sx, sy, str;
00915 itsMatchList->getSIFTaffine().decompose(theta, sx, sy, str);
00916 LDEBUG("SIFT SCALE SX[%f] SY[%f] Theta[%f] Str[%f]",sx,sy,theta,str);
00917
00918
00919
00920
00921
00922
00923
00924 if(((sx >=0.9 && sy >=0.9) && error <50.0 ) && itsMatchList->size()>2){
00925 itsMilestoneErr = 999.99;
00926 itsTeachImgID += 20;
00927 LINFO("*********=========Switch Keyframe=========**********");
00928 }
00929
00930 }
00931 }
00932
00933
00934
00935
00936 int CornerNavigation::computeEntropy()
00937 {
00938 return 1;
00939 }
00940
00941
00942 void CornerNavigation::drawState()
00943 {
00944 its_Corner_Loc_mutex.lock();
00945 int dbNum = itsDBnum;
00946 its_Corner_Loc_mutex.unlock();
00947
00948 uint w = itsProcImg.getWidth()*2, h = itsProcImg.getHeight()*2;
00949
00950 LINFO("TeachImg w=%d,h=%d, dbNum: %d", w, h, dbNum);
00951 itsDispImg.resize(w*2, 3*h, NO_INIT);
00952 char buffer[128];
00953
00954
00955 inplacePaste(itsDispImg, itsProcImg, Point2D<int>(0, 0));
00956
00957 if(dbNum != -1)
00958 {
00959
00960 Image< PixRGB<byte> > replayImg = rescale(itsReplayImg,w,h);
00961 sprintf(buffer,"img%5d",itsReplayImgID);
00962 writeText(replayImg, Point2D<int>(5,5),
00963 buffer, PixRGB<byte>(255,255,255),
00964 PixRGB<byte>(0,0,0),SimpleFont::FIXED(8));
00965 inplacePaste(itsDispImg, replayImg, Point2D<int>(0, 2*h));
00966
00967
00968 Image< PixRGB<byte> > teachImg = rescale(itsTeachImg,w,h);
00969 sprintf(buffer,"img%5d",itsTeachImgID);
00970 writeText(teachImg, Point2D<int>(5,5),
00971 buffer, PixRGB<byte>(255,255,255),
00972 PixRGB<byte>(0,0,0), SimpleFont::FIXED(8));
00973 inplacePaste(itsDispImg, teachImg, Point2D<int>(0, h));
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984 if(itsEstop)
00985 {
00986 Image< PixRGB<byte> > mimg = itsMatchList->getMatchImage(1.0F);
00987 LDEBUG("itsdispImg[%d,%d] mimg[%d,%d] pt[%d,%d]",
00988 itsDispImg.getWidth(), itsDispImg.getHeight(),
00989 mimg.getWidth(), mimg.getHeight(), int(w*1.5), h);
00990
00991 inplacePaste(itsDispImg, mimg, Point2D<int>(w*1.5, h));
00992 }
00993
00994
00995 double mapScale = 0.20;
00996 Point2D<int> drawPos
00997 (int(itsPosition.x*mapScale + itsMapImg.getWidth()/2),
00998 int(itsPosition.y*mapScale + itsMapImg.getHeight()/2));
00999 if(itsMapImg.coordsOk(drawPos))
01000 itsMapImg.setVal(drawPos, PixRGB<byte>(0,255,0));
01001 inplacePaste(itsDispImg, itsMapImg, Point2D<int>(w, h*2));
01002 }
01003
01004
01005 inplacePaste(itsDispImg, drawInfoImg(), Point2D<int>(w, 0));
01006 }
01007
01008
01009
01010 Image<PixRGB<byte> > CornerNavigation::drawInfoImg()
01011 {
01012 char buffer[128];
01013 Image<PixRGB<byte> > dirImg(320,240,ZEROS);
01014
01015 its_Corner_Loc_mutex.lock();
01016 int dbNum = itsDBnum;
01017 int status = itsStatus;
01018 its_Corner_Loc_mutex.unlock();
01019
01020
01021 sprintf(buffer, "DB# :[%d] Status:[%d]", dbNum, status);
01022 writeText(dirImg, Point2D<int>(10,70),
01023 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01024 SimpleFont::FIXED(8));
01025 if (dbNum == -1) return dirImg;
01026
01027
01028 if(itsDir == 0) { sprintf(buffer, "||| "); }
01029 else if(itsDir > 0){ sprintf(buffer, "--> "); }
01030 else { sprintf(buffer, "<-- "); }
01031 writeText(dirImg, Point2D<int>(dirImg.getWidth()/2-20,
01032 dirImg.getHeight()/2-20),
01033 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01034 SimpleFont::FIXED(20));
01035
01036
01037 sprintf(buffer, "[%d]",itsDirCount);
01038 writeText(dirImg, Point2D<int>(dirImg.getWidth()/2-10,
01039 dirImg.getHeight()/2+40),
01040 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01041 SimpleFont::FIXED(20));
01042
01043
01044 sprintf(buffer, "False Error Rate:[%1.3f]",itsFalseErrRate);
01045 writeText(dirImg, Point2D<int>(10,10),
01046 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01047 SimpleFont::FIXED(8));
01048 if(itsEstop)
01049 {
01050 sprintf(buffer, "Match:[%d]",itsMatchList->size());
01051 writeText(dirImg, Point2D<int>(210,10),
01052 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01053 SimpleFont::FIXED(8));
01054 }
01055 sprintf(buffer, "Error:[%1.3f] X:[%1.3f] Y:[%1.3f]",
01056 itsError.z,itsError.x,itsError.y);
01057 writeText(dirImg, Point2D<int>(10,25),
01058 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01059 SimpleFont::FIXED(8));
01060
01061
01062 if (itsEstop && itsMatchList->checkSIFTaffine())
01063 {
01064 float theta, sx, sy, str;
01065 itsMatchList->getSIFTaffine().decompose(theta, sx, sy, str);
01066 sprintf(buffer, "Affine T:[%1.3f] X:[%1.3f] Y:[%1.3f]",theta,sx,sy);
01067 writeText(dirImg, Point2D<int>(10,40),
01068 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01069 SimpleFont::FIXED(8));
01070 }
01071 sprintf(buffer, "Motor Speed :[%1.3f] Motor Rot:[%1.3f]",
01072 itsTransSpeed, itsRotSpeed);
01073 writeText(dirImg, Point2D<int>(10,55),
01074 buffer, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0),
01075 SimpleFont::FIXED(8));
01076 return dirImg;
01077 }
01078
01079
01080 void CornerNavigation::updatePosition(double turn)
01081 {
01082 itsDirVector += turn;
01083 if(itsDirVector > 360.0) itsDirVector = 0.0;
01084 if(itsDirVector < 0.0) itsDirVector = 360.0;
01085
01086 itsPosition.x -= sin(itsDirVector*(M_PI/180.0));
01087 itsPosition.y -= cos(itsDirVector*(M_PI/180.0));
01088 }
01089
01090
01091 void CornerNavigation::updateMessage
01092 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&)
01093 {
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113 if(eMsg->ice_isA("::BeobotEvents::GistSalMessage"))
01114 {
01115 BeobotEvents::GistSalMessagePtr gistSalMsg =
01116 BeobotEvents::GistSalMessagePtr::dynamicCast(eMsg);
01117
01118
01119 int currRequestID = gistSalMsg->RequestID;
01120 Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> >(gistSalMsg->currIma);
01121
01122 its_Curr_Img_mutex.lock();
01123 itsCurrImg = img;
01124 itsCurrImgID = gistSalMsg->RequestID;
01125 its_Curr_Img_mutex.unlock();
01126
01127 LINFO("Got a GSMessage with Request ID = %d", currRequestID);
01128 }
01129
01130
01131 else if(eMsg->ice_isA("::BeobotEvents::MotorMessage"))
01132 {
01133 BeobotEvents::MotorMessagePtr mtrMsg =
01134 BeobotEvents::MotorMessagePtr::dynamicCast(eMsg);
01135 LDEBUG("Got a MotorMessage with Request ID = %d: RC Trans %f, Rot %f",
01136 mtrMsg->RequestID, itsRcTransSpeed, itsRcRotSpeed);
01137 its_Curr_Mtr_mutex.lock();
01138 itsRemoteMode = mtrMsg->rcMode;
01139 itsRcTransSpeed = mtrMsg->rcTransVel;
01140 itsRcRotSpeed = mtrMsg->rcRotVel;
01141 its_Curr_Mtr_mutex.unlock();
01142 }
01143
01144
01145 else if(eMsg->ice_isA("::BeobotEvents::CornerLocationMessage"))
01146 {
01147 BeobotEvents::CornerLocationMessagePtr clMsg =
01148 BeobotEvents::CornerLocationMessagePtr::dynamicCast(eMsg);
01149 LINFO("Turn on on corner %d", clMsg->cornerLocation);
01150
01151
01152 int index = clMsg->cornerLocation;
01153 LINFO("Got Corner location Message Corner:[%d]",index);
01154
01155
01156 its_Corner_Loc_mutex.lock();
01157 int status = itsStatus;
01158 its_Corner_Loc_mutex.unlock();
01159
01160 if(status == C_PROCEDURE_INACTIVE)
01161 {
01162 if(index >= (int)itsVisualObjectDBs.size()) index = -1;
01163 its_Corner_Loc_mutex.lock();
01164 itsStatus = C_PROCEDURE_ACTIVE;
01165 itsTeachImgID = 0;
01166 itsDBnum = index;
01167 its_Corner_Loc_mutex.unlock();
01168 }
01169 }
01170 }
01171
01172
01173 void CornerNavigation::updateMotorPID(double tran, double rot,double error)
01174 {
01175 error/=100.0;
01176 if(itsDir == 1)
01177 error *= -1.0;
01178 double pTerm,iTerm,dTerm;
01179 pTerm = itsPGain * error;
01180 itsIState += error;
01181 if(itsIState > IMAX)
01182 itsIState = IMAX;
01183 else if(itsIState < IMIN)
01184 itsIState = IMIN;
01185 iTerm = itsIGain * itsIState;
01186 dTerm = itsDGain * (rot - itsDState);
01187 itsDState = rot;
01188 double pid = pTerm + iTerm - dTerm;
01189
01190 LINFO("P[%1.2f] I[%1.2f] D[%1.2f], Istate[%1.2f] DState[%1.2f]",
01191 pTerm,iTerm,dTerm,itsIState,itsDState);
01192 LINFO("pid[%1.2f],rot[%1.2f]",pid,rot);
01193 updateMotor(tran,pid,itsStatus);
01194 }
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208 void CornerNavigation::updateMotor(double tran, double rot, int status)
01209 {
01210 BeobotEvents::CornerMotorRequestPtr msg =
01211 new BeobotEvents::CornerMotorRequest;
01212 msg->transVel = tran;
01213 msg->rotVel = rot;
01214 msg->status = status;
01215 this->publish("CornerMotorRequestTopic", msg);
01216 LINFO("[%d] Publish corner motor request Trans %f Rotation %f",
01217 itsPrevProcImgID, tran, rot);
01218 }
01219
01220
01221
01222
01223
01224