00001 /*!@file */ 00002 // //////////////////////////////////////////////////////////////////// // 00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00004 // University of Southern California (USC) and the iLab at USC. // 00005 // See http://iLab.usc.edu for information about this project. // 00006 // //////////////////////////////////////////////////////////////////// // 00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00009 // in Visual Environments, and Applications'' by Christof Koch and // 00010 // Laurent Itti, California Institute of Technology, 2001 (patent // 00011 // pending; application number 09/912,225 filed July 23, 2001; see // 00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00015 // // 00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00017 // redistribute it and/or modify it under the terms of the GNU General // 00018 // Public License as published by the Free Software Foundation; either // 00019 // version 2 of the License, or (at your option) any later version. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00024 // PURPOSE. See the GNU General Public License for more details. // 00025 // // 00026 // You should have received a copy of the GNU General Public License // 00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00029 // Boston, MA 02111-1307 USA. // 00030 // //////////////////////////////////////////////////////////////////// // 00031 // 00032 // Primary maintainer for this file: Christian Siagian <siagian@usc.edu> 00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/Beobot2/Localization/Beobot2_GistSalLocalizerWorker.C $ 00034 // $Id: Beobot2_GistSalLocalizerWorker.C 12962 2010-03-06 02:13:53Z irock $ 00035 // 00036 00037 00038 #include "Robots/Beobot2/Localization/Beobot2_GistSalLocalizerWorker.H" 00039 00040 #include "Image/MathOps.H" // for inPlaceNormalize() 00041 #include "Image/CutPaste.H" // for inplacePaste() 00042 #include "Image/DrawOps.H" // for drawing 00043 #include "Image/ShapeOps.H" // for decXY() 00044 #include "Image/MatrixOps.H" // for matrixMult(), matrixInv(), etc 00045 00046 #ifndef BEOBOT2_GISTSALLOCALIZERWORKERI_C 00047 #define BEOBOT2_GISTSALLOCALIZERWORKERI_C 00048 00049 // ###################################################################### 00050 Beobot2_GistSalLocalizerWorkerI::Beobot2_GistSalLocalizerWorkerI 00051 (OptionManager& mgr,const std::string& descrName, const std::string& tagName) : 00052 RobotBrainComponent(mgr, descrName, tagName), 00053 itsInputFnum(-1), 00054 itsLastSearchDone(-1) 00055 { 00056 itsWorkerIndex = 0; 00057 itsNumWorkers = 1; 00058 itsEmptyQueue = false; 00059 } 00060 00061 // ###################################################################### 00062 void Beobot2_GistSalLocalizerWorkerI::start1() 00063 { 00064 //uint w = 160; uint h = 120; 00065 //itsInputWin.reset(new XWinManaged(Dims(w, h), 0, 2*(h+30), 00066 // "GSL_W:Input" )); 00067 } 00068 00069 // ###################################################################### 00070 Beobot2_GistSalLocalizerWorkerI::~Beobot2_GistSalLocalizerWorkerI() 00071 { } 00072 00073 // ###################################################################### 00074 void Beobot2_GistSalLocalizerWorkerI::registerTopics() 00075 { 00076 this->registerSubscription("LandmarkSearchQueueMessageTopic"); 00077 this->registerSubscription("LandmarkMatchResultMessageTopic"); 00078 this->registerSubscription("CancelSearchMessageTopic"); 00079 00080 this->registerPublisher("LandmarkMatchResultMessageTopic"); 00081 this->registerPublisher("LandmarkSearchStatMessageTopic"); 00082 this->registerPublisher("SearchDoneMessageTopic"); 00083 } 00084 00085 // ###################################################################### 00086 void Beobot2_GistSalLocalizerWorkerI::evolve() 00087 { 00088 // always check if we are emptying queue first 00089 its_job_queue_mutex.lock(); 00090 if(itsEmptyQueue) 00091 { 00092 itsJobQueue.clear(); 00093 itsEmptyQueue = false; 00094 00095 if(itsLastSearchDone < itsInputFnum) 00096 { 00097 BeobotEvents::SearchDoneMessagePtr msg = 00098 new BeobotEvents::SearchDoneMessage; 00099 00100 LINFO("Publishing SearchDoneMessage"); 00101 publish("SearchDoneMessageTopic", msg); 00102 itsLastSearchDone = itsInputFnum; 00103 } 00104 } 00105 bool jobQueueEmpty = itsJobQueue.empty(); 00106 its_job_queue_mutex.unlock(); 00107 00108 if (!jobQueueEmpty) 00109 { 00110 // get the next job 00111 its_job_queue_mutex.lock(); 00112 bool hasJob = false; 00113 GSlocJobData cjob(0, 0, 0, 0, 0); 00114 00115 while(!hasJob && !itsJobQueue.empty()) 00116 { 00117 // pop jobs itsNumWorkers at a time 00118 for(uint i = 0; i < itsNumWorkers; i++) 00119 { 00120 if(i == itsWorkerIndex) 00121 { cjob = itsJobQueue.front(); hasJob = true; } 00122 if(!itsJobQueue.empty()) 00123 itsJobQueue.pop_front(); 00124 else 00125 i = itsNumWorkers; 00126 } 00127 00128 // if the current object has been found, skip 00129 its_results_mutex.lock(); 00130 if(itsMatchFound[cjob.objNum]) hasJob = false; 00131 its_results_mutex.unlock(); 00132 } 00133 its_job_queue_mutex.unlock(); 00134 00135 if(hasJob) compute(cjob); 00136 if(itsJobQueue.empty()) itsEmptyQueue = true; 00137 } 00138 else itsEmptyQueue = false; 00139 } 00140 00141 // ###################################################################### 00142 void Beobot2_GistSalLocalizerWorkerI::updateMessage 00143 (const RobotSimEvents::EventMessagePtr& eMsg, const Ice::Current&) 00144 { 00145 // Get a gist-sal message 00146 if(eMsg->ice_isA("::BeobotEvents::LandmarkSearchQueueMessage")) 00147 { 00148 BeobotEvents::LandmarkSearchQueueMessagePtr lsqMsg = 00149 BeobotEvents::LandmarkSearchQueueMessagePtr::dynamicCast(eMsg); 00150 00151 //Get the current request ID 00152 int currRequestID = lsqMsg->RequestID; 00153 itsInputFnum = currRequestID; 00154 00155 LINFO("Got a lsqMessage with Request ID = %d", currRequestID); 00156 00157 // get the inputImage 00158 its_input_info_mutex.lock(); 00159 itsInputImage = Ice2Image<PixRGB<byte> >(lsqMsg->currIma); 00160 //itsInputWin->setTitle(sformat("WM: %d",itsInputFnum).c_str()); 00161 //itsInputWin->drawImage(itsInputImage, 0, 0); 00162 00163 // get the salient region information 00164 itsInputVO.clear(); 00165 itsVOKeypointsComputed.clear(); 00166 itsInputObjOffset.clear(); 00167 uint inputSize = lsqMsg->salientRegions.size(); 00168 for(uint i = 0; i < inputSize; i++) 00169 { 00170 BeobotEvents::SalientRegion salReg = lsqMsg->salientRegions[i]; 00171 LDEBUG("W[%4d] sp[%4d,%4d] rect[%4d,%4d,%4d,%4d]", 00172 i, salReg.salpt.i, salReg.salpt.j, 00173 salReg.objRect.tl.i, salReg.objRect.tl.j, 00174 salReg.objRect.br.i, salReg.objRect.br.j); 00175 00176 // print the pre-attentive feature vector 00177 std::vector<float> features; 00178 uint fsize = salReg.salFeatures.size(); 00179 for(uint j = 0; j < fsize; j++) 00180 { 00181 features.push_back(salReg.salFeatures[j]); 00182 LDEBUG("[%4d]:%7f", j, salReg.salFeatures[j]); 00183 } 00184 00185 Point2D<int> salpt(salReg.salpt.i, salReg.salpt.j); 00186 Point2D<int> offset( salReg.objRect.tl.i, salReg.objRect.tl.j); 00187 Rectangle rect = Rectangle::tlbrO 00188 (salReg.objRect.tl.j, salReg.objRect.tl.i, 00189 salReg.objRect.br.j, salReg.objRect.br.i); 00190 00191 // create a visual object for the salient region 00192 Image<PixRGB<byte> > objImg = crop(itsInputImage, rect); 00193 00194 std::string testRunFPrefix("testRunFPrefix"); 00195 std::string iname("iname"); 00196 std::string saveFilePath("saveFilePath"); 00197 00198 std::string 00199 iName(sformat("%s_SAL_%07d_%02d", 00200 testRunFPrefix.c_str(), currRequestID, i)); 00201 std::string ifName = iName + std::string(".png"); 00202 ifName = saveFilePath + ifName; 00203 rutz::shared_ptr<VisualObject> 00204 vo(new VisualObject 00205 (iName, ifName, objImg, salpt - offset, features, 00206 std::vector< rutz::shared_ptr<Keypoint> >(), false, false)); 00207 itsInputVO.push_back(vo); 00208 itsVOKeypointsComputed.push_back(false); 00209 itsInputObjOffset.push_back(offset); 00210 00211 LDEBUG("[%d] image[%d]: %s sal:[%d,%d] offset:[%d,%d]", 00212 currRequestID, i, iName.c_str(), 00213 (salpt - offset).i, (salpt - offset).j, 00214 offset.i, offset.j); 00215 } 00216 its_input_info_mutex.unlock(); 00217 00218 its_results_mutex.lock(); 00219 itsMatchFound.clear(); 00220 itsVOmatch.clear(); itsVOmatch.resize(inputSize); 00221 itsLmkMatch.clear(); itsLmkMatch.resize(inputSize); 00222 itsSegNumMatch.clear(); itsSegNumMatch.resize(inputSize); 00223 itsLenTravMatch.clear(); itsLenTravMatch.resize(inputSize); 00224 itsNumObjectSearch.clear(); itsNumObjectSearch.resize(inputSize); 00225 for(uint i = 0; i < inputSize; i++) itsMatchFound.push_back(false); 00226 for(uint i = 0; i < inputSize; i++) itsNumObjectSearch[i] = 0; 00227 itsNumJobsProcessed = 0; 00228 its_results_mutex.unlock(); 00229 00230 // fill the job queue 00231 its_job_queue_mutex.lock(); 00232 itsJobQueue.clear(); 00233 uint njobs = lsqMsg->jobs.size(); 00234 for(uint i = 0; i < njobs; i++) 00235 { 00236 BeobotEvents::LandmarkSearchJob tempJob = lsqMsg->jobs[i]; 00237 itsJobQueue.push_back 00238 (GSlocJobData(tempJob.inputSalRegID, 00239 tempJob.dbSegNum, 00240 tempJob.dbLmkNum, 00241 tempJob.dbVOStart, 00242 tempJob.dbVOEnd)); 00243 } 00244 00245 // print the job queue 00246 std::list<GSlocJobData>::iterator itr = itsJobQueue.begin(); 00247 uint count = 0; 00248 while (itr != itsJobQueue.end()) 00249 { 00250 LDEBUG("[%5d] match obj[%d] lDB[%3d][%3d]:[%3d,%3d]", count, 00251 (*itr).objNum, (*itr).segNum, (*itr).lmkNum, 00252 (*itr).voStartNum,(*itr).voEndNum); 00253 itr++; count++; 00254 } 00255 its_job_queue_mutex.unlock(); 00256 } 00257 00258 // Got a landmark match results - stop searching for that salient region 00259 else if(eMsg->ice_isA("::BeobotEvents::LandmarkMatchResultMessage")) 00260 { 00261 BeobotEvents::LandmarkMatchResultMessagePtr lmrMsg = 00262 BeobotEvents::LandmarkMatchResultMessagePtr::dynamicCast(eMsg); 00263 00264 //Get the current request ID 00265 //int currRequestID = gistSalMsg->RequestID; 00266 00267 BeobotEvents::LandmarkSearchJob tempJob = lmrMsg->matchInfo; 00268 LINFO("Got an lmrMessage"); 00269 00270 LINFO("LMR -> found match[%d]: with itsLandmarkDB[%d][%d]", 00271 tempJob.inputSalRegID, tempJob.dbSegNum, tempJob.dbLmkNum); 00272 00273 its_results_mutex.lock(); 00274 if(!itsMatchFound[tempJob.inputSalRegID]) 00275 { 00276 itsMatchFound[tempJob.inputSalRegID] = true; 00277 itsSegNumMatch[tempJob.inputSalRegID] = lmrMsg->segNumMatch; 00278 itsLenTravMatch[tempJob.inputSalRegID] = lmrMsg->lenTravMatch; 00279 } 00280 its_results_mutex.unlock(); 00281 } 00282 00283 else if(eMsg->ice_isA("::BeobotEvents::CancelSearchMessage")) 00284 { 00285 its_job_queue_mutex.lock(); 00286 itsEmptyQueue = true; 00287 its_job_queue_mutex.unlock(); 00288 00289 its_results_mutex.lock(); 00290 LINFO("CancelSearchMessage: %d processed here", itsNumJobsProcessed); 00291 its_results_mutex.unlock(); 00292 } 00293 } 00294 00295 // ###################################################################### 00296 void Beobot2_GistSalLocalizerWorkerI::setEnvironment 00297 (rutz::shared_ptr<Environment> env) 00298 { 00299 itsEnvironment = env; 00300 00301 //! from its environment: topological map 00302 itsTopologicalMap = env->getTopologicalMap(); 00303 00304 //! from its environment: visual landmark database 00305 itsLandmarkDB = env->getLandmarkDB(); 00306 } 00307 00308 // ###################################################################### 00309 void Beobot2_GistSalLocalizerWorkerI::setWorkerInformation 00310 (uint index, uint totalNumWorkers) 00311 { 00312 itsWorkerIndex = index; 00313 itsNumWorkers = totalNumWorkers; 00314 } 00315 00316 // ###################################################################### 00317 void Beobot2_GistSalLocalizerWorkerI::compute(GSlocJobData cjob) 00318 { 00319 LDEBUG("T[%4d] match object[%d] itsLandmarkDB[%d][%d]: [ %d, %d ]", 00320 itsWorkerIndex, cjob.objNum, cjob.segNum, cjob.lmkNum, 00321 cjob.voStartNum, cjob.voEndNum); 00322 00323 its_input_info_mutex.lock(); 00324 uint nvo = itsInputVO.size(); 00325 its_input_info_mutex.unlock(); 00326 00327 if(nvo <= uint(cjob.objNum) || 00328 itsLandmarkDB->getNumSegment() <= uint(cjob.segNum) || 00329 itsLandmarkDB->getNumSegLandmark(cjob.segNum) <= uint(cjob.lmkNum) || 00330 cjob.voStartNum < 0 || 00331 itsLandmarkDB->getLandmark(cjob.segNum, cjob.lmkNum)->numObjects() 00332 <= uint(cjob.voStartNum) || 00333 cjob.voEndNum < 0 || 00334 itsLandmarkDB->getLandmark(cjob.segNum, cjob.lmkNum)->numObjects() 00335 <= uint(cjob.voEndNum)) 00336 { 00337 LINFO("Invalid job[%4d] object[%d] itsLandmarkDB[%d][%d]: [ %d, %d ]", 00338 itsWorkerIndex, cjob.objNum, cjob.segNum, cjob.lmkNum, 00339 cjob.voStartNum, cjob.voEndNum); 00340 return; 00341 } 00342 00343 // make sure the VO keypoints are computed 00344 its_input_info_mutex.lock(); 00345 if(!itsVOKeypointsComputed[cjob.objNum]) 00346 { 00347 itsInputVO[cjob.objNum]->computeKeypoints(); 00348 itsVOKeypointsComputed[cjob.objNum] = true; 00349 } 00350 its_input_info_mutex.unlock(); 00351 00352 // match the object with the range of database 00353 // we limit the maxScale range to [2/3 ... 3/2] by entering 1.5 00354 // Now (2/10/2010): 00355 // we limit the maxScale range to [3/4 ... 4/3] by entering 1.33 00356 its_input_info_mutex.lock(); 00357 rutz::shared_ptr<VisualObjectMatch> cmatch; 00358 int ind = itsLandmarkDB->getLandmark(cjob.segNum, cjob.lmkNum)-> 00359 match(itsInputVO[cjob.objNum], 00360 cmatch, cjob.voStartNum, cjob.voEndNum, 00361 15.0F, 0.5F, 2.5F, 4, M_PI/4, 1.33F, .25F); 00362 its_input_info_mutex.unlock(); 00363 00364 // if match is found 00365 uint nObjSearch = 0; 00366 if(ind != -1) 00367 { 00368 LINFO("-> found match[%d]: %s with itsLandmarkDB[%d][%d]\n %s : %s", 00369 cjob.objNum, itsInputVO[cjob.objNum]->getName().c_str(), 00370 cjob.segNum, cjob.lmkNum, 00371 cmatch->getVoRef()->getName().c_str(), 00372 cmatch->getVoTest()->getName().c_str()); 00373 nObjSearch = (ind - cjob.voStartNum + 1); 00374 00375 // store the match information 00376 // since there is a possibility that there are concurrent threads 00377 // that also just found it we will choose the first match 00378 its_results_mutex.lock(); 00379 itsVOmatch[cjob.objNum] = cmatch; 00380 itsLmkMatch[cjob.objNum] = 00381 GSlocJobData(cjob.objNum, cjob.segNum, cjob.lmkNum, ind, ind); 00382 itsSegNumMatch[cjob.objNum] = cjob.segNum; 00383 itsLenTravMatch[cjob.objNum] = 00384 itsLandmarkDB->getLenTrav(cjob.segNum, cjob.lmkNum, ind); 00385 itsMatchFound[cjob.objNum] = true; 00386 its_results_mutex.unlock(); 00387 00388 // send the result back to GSLoc_master 00389 BeobotEvents::LandmarkMatchResultMessagePtr msg = 00390 new BeobotEvents::LandmarkMatchResultMessage; 00391 00392 msg->RequestID = itsInputFnum; 00393 msg->voMatchImage = 00394 Image2Ice(getMatchImage(cjob.objNum, itsInputImage.getDims())); 00395 BeobotEvents::LandmarkSearchJob tempJob; 00396 tempJob.inputSalRegID = cjob.objNum; 00397 tempJob.dbSegNum = cjob.segNum; 00398 tempJob.dbLmkNum = cjob.lmkNum; 00399 tempJob.dbVOStart = ind; 00400 tempJob.dbVOEnd = ind; 00401 msg->matchInfo = tempJob; 00402 00403 // location of the matched database salient region 00404 msg->segNumMatch = cjob.segNum; 00405 msg->lenTravMatch = itsLenTravMatch[cjob.objNum]; 00406 00407 LINFO("Publishing lmrMessage with ID: %d[%4d,%10.7f]", 00408 itsInputFnum, msg->segNumMatch, msg->lenTravMatch); 00409 publish("LandmarkMatchResultMessageTopic", msg); 00410 } 00411 else 00412 { 00413 nObjSearch = cjob.voEndNum - cjob.voStartNum + 1; 00414 } 00415 00416 BeobotEvents::LandmarkSearchStatMessagePtr msg = 00417 new BeobotEvents::LandmarkSearchStatMessage; 00418 00419 msg->RequestID = itsInputFnum; 00420 msg->inputSalRegID = cjob.objNum; 00421 msg->numObjSearch = nObjSearch; 00422 msg->found = (ind != -1); 00423 00424 LDEBUG("Publishing LandmarkSearchStatMessage"); 00425 publish("LandmarkSearchStatMessageTopic", msg); 00426 00427 its_results_mutex.lock(); 00428 itsNumJobsProcessed++; 00429 its_results_mutex.unlock(); 00430 } 00431 00432 // ###################################################################### 00433 Image<PixRGB<byte> > 00434 Beobot2_GistSalLocalizerWorkerI::getMatchImage(uint index, Dims d) 00435 { 00436 Image< PixRGB<byte> > result; 00437 00438 its_results_mutex.lock(); 00439 uint size = itsMatchFound.size(); 00440 its_results_mutex.unlock(); 00441 00442 ASSERT(index < size); 00443 Point2D<int> objOffset1 = itsInputObjOffset[index]; 00444 Point2D<int> objOffset2 = 00445 itsLandmarkDB->getLandmark(itsLmkMatch[index].segNum, 00446 itsLmkMatch[index].lmkNum) 00447 ->getOffsetCoords(itsLmkMatch[index].voStartNum); 00448 00449 bool isODmatch = (itsInputVO[index] == itsVOmatch[index]->getVoRef()); 00450 bool isDOmatch = (itsInputVO[index] == itsVOmatch[index]->getVoTest()); 00451 00452 if(isODmatch) 00453 result = itsVOmatch[index]->getMatchImage(d, objOffset1, objOffset2); 00454 else if(isDOmatch) 00455 result = itsVOmatch[index]->getMatchImage(d, objOffset2, objOffset1); 00456 else 00457 { 00458 LINFO("obj[%d] %s : %s, %s", 00459 index, itsInputVO[index]->getName().c_str(), 00460 itsVOmatch[index]->getVoRef()->getName().c_str(), 00461 itsVOmatch[index]->getVoTest()->getName().c_str()); 00462 LFATAL("object neither ref nor tst"); 00463 } 00464 00465 return result; 00466 } 00467 00468 #endif 00469 00470 // ###################################################################### 00471 /* So things look consistent in everyone's emacs... */ 00472 /* Local Variables: */ 00473 /* indent-tabs-mode: nil */ 00474 /* End: */ 00475