00001 /*!@file Neuro/InferotemporalCortexService.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the 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: Lior Elazary 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/NeovisionII/InferotemporalCortexServiceMysql.C $ 00035 // $Id: InferotemporalCortexServiceMysql.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "NeovisionII/InferotemporalCortexService.H" 00039 #include "Image/ColorOps.H" 00040 #include "Image/DrawOps.H" 00041 #include "Util/sformat.H" 00042 00043 InferotemporalCortexI::InferotemporalCortexI(OptionManager& mgr, 00044 nub::ref<OutputFrameSeries> ofs, 00045 const std::string& descrName, 00046 const std::string& tagName ) : 00047 ModelComponent(mgr, descrName, tagName), 00048 itsOfs(ofs) 00049 { 00050 //Subscribe to the various topics 00051 IceStorm::TopicPrx topicPrx; 00052 itsTopicsSubscriptions.push_back(TopicInfo("SegmenterTopic", topicPrx)); 00053 00054 itsDBCon = new mysqlpp::Connection(false); 00055 00056 //Connect to the database 00057 const char* db = "ObjRec", *server = "localhost", *user = "neobrain", *pass = "12341234"; 00058 if (!itsDBCon->connect(db, server, user, pass)) 00059 LFATAL("DB connection failed: "); 00060 // , itsDBCon->error().c_str()); 00061 } 00062 00063 InferotemporalCortexI::~InferotemporalCortexI() 00064 { 00065 unsubscribeSimEvents(); 00066 } 00067 00068 void InferotemporalCortexI::initSimEvents(Ice::CommunicatorPtr icPtr, Ice::ObjectPrx objectPrx) 00069 { 00070 //Get the IceStorm object 00071 Ice::ObjectPrx obj = icPtr->stringToProxy("SimEvents/TopicManager:tcp -h ilab21 -p 11111"); 00072 IceStorm::TopicManagerPrx topicManager = 00073 IceStorm::TopicManagerPrx::checkedCast(obj); 00074 00075 //Create a InferotemporalCortex Topic 00076 IceStorm::TopicPrx topic; 00077 try { 00078 topic = topicManager->retrieve("InferotemporalCortexTopic"); //check if the Retina topic exists 00079 } catch (const IceStorm::NoSuchTopic&) { 00080 topic = topicManager->create("InferotemporalCortexTopic"); //The retina topic does not exists, create 00081 } 00082 //Make a one way visualCortex message publisher for efficency 00083 Ice::ObjectPrx pub = topic->getPublisher()->ice_oneway(); 00084 itsEventsPub = SimEvents::EventsPrx::uncheckedCast(pub); 00085 00086 //Subscribe the SimulationViewer to theTopics 00087 itsObjectPrx = objectPrx; 00088 //subscribe to the topics 00089 for(uint i=0; i<itsTopicsSubscriptions.size(); i++) 00090 { 00091 try { 00092 IceStorm::QoS qos; 00093 itsTopicsSubscriptions[i].topicPrx = 00094 topicManager->retrieve(itsTopicsSubscriptions[i].name.c_str()); //Get the 00095 itsTopicsSubscriptions[i].topicPrx->subscribeAndGetPublisher(qos, itsObjectPrx); //Subscribe to the retina topic 00096 } catch (const IceStorm::NoSuchTopic&) { 00097 LFATAL("Error! No %s topic found!", itsTopicsSubscriptions[i].name.c_str()); 00098 } 00099 } 00100 } 00101 00102 void InferotemporalCortexI::unsubscribeSimEvents() 00103 { 00104 //Unsubscribe from all the topics we are registerd to 00105 for(uint i=0; i<itsTopicsSubscriptions.size(); i++) 00106 { 00107 itsTopicsSubscriptions[i].topicPrx->unsubscribe(itsObjectPrx); 00108 } 00109 } 00110 00111 00112 bool InferotemporalCortexI::initVDB() 00113 { 00114 itsUseColor = false; 00115 itsTrainingMode = false; 00116 itsVDBFile = "objects.vdb"; 00117 itsMaxLabelHistory = 1; 00118 itsVDB.loadFrom(itsVDBFile); 00119 00120 return true; 00121 } 00122 00123 //The VC excepts a retina image and posts a saliency map 00124 void InferotemporalCortexI::evolve(const SimEvents::EventMessagePtr& eMsg, 00125 const Ice::Current&) 00126 { 00127 if (eMsg->ice_isA("::SimEvents::SegmenterMessage")){ 00128 SimEvents::SegmenterMessagePtr msg = SimEvents::SegmenterMessagePtr::dynamicCast(eMsg); 00129 for(uint i=0; i<msg->segLocs.size(); i++) 00130 { 00131 SimEvents::SegInfo segInfo = msg->segLocs[i]; 00132 Image<PixRGB<byte> > segImg = Ice2Image<PixRGB<byte> >(segInfo.img); 00133 Rectangle segRect(Point2D<int>(segInfo.rect.tl.i, segInfo.rect.tl.j), 00134 Dims(segInfo.rect.br.i - segInfo.rect.tl.i, 00135 segInfo.rect.br.j - segInfo.rect.tl.j)); 00136 00137 00138 ////Rescale the image to provide some scale inveriance 00139 //Image<PixRGB<byte> > inputImg = rescale(segImg, 256, 256); 00140 itsImgMutex.lock(); 00141 itsCurrentImg = segImg; 00142 itsImgMutex.unlock(); 00143 } 00144 } 00145 } 00146 00147 void InferotemporalCortexI::run() 00148 { 00149 00150 while(1) 00151 { 00152 itsImgMutex.lock(); 00153 Image<PixRGB<byte> > img = itsCurrentImg; 00154 itsImgMutex.unlock(); 00155 if (!img.initialized()) 00156 continue; 00157 00158 itsTimer.reset(); 00159 rutz::shared_ptr<VisualObject> 00160 vo(new VisualObject("PIC", "PIC", img, 00161 Point2D<int>(-1,-1), 00162 std::vector<double>(), 00163 std::vector< rutz::shared_ptr<Keypoint> >(), 00164 itsUseColor)); 00165 itsTimer.mark(); 00166 LINFO("Keypoint extraction took %f seconds for %i keypoints (%ix%i)", 00167 itsTimer.user_secs(), 00168 vo->numKeypoints(), 00169 img.getWidth(), img.getHeight()); 00170 00171 00172 mysqlpp::Query query = itsDBCon->query(); 00173 //Insert the keypoints into the database if there is not match; 00174 const uint nkp = vo->numKeypoints(); 00175 for(uint kpIdx=0; kpIdx<nkp; kpIdx++) 00176 { 00177 LINFO("Searching for keypoint %i of %i", kpIdx, nkp); 00178 //Get the feature fector 00179 char fv[128]; 00180 rutz::shared_ptr<Keypoint> keyPoint = vo->getKeypoint(kpIdx); 00181 for(uint i=0; i<keyPoint->getFVlength(); i++) 00182 { 00183 fv[i] = keyPoint->getFVelement(i); 00184 //printf("%i ", (unsigned char)fv[i]); 00185 } 00186 //printf("\n"); 00187 00188 LINFO("Check NN"); 00189 itsTimer.reset(); 00190 //check if there is a match in the db 00191 bool foundKeypoint = false; 00192 double foundDist = -1; 00193 int foundMatchCount = -1; 00194 int foundIdx = -1; 00195 00196 string fill(fv, 128); 00197 ostringstream strbuf; 00198 strbuf << "SELECT kid, matchCount, kp_dist(value, \"" << mysqlpp::escape << fill <<"\") as dist from SiftKeypoints order by dist limit 1" << ends; 00199 query << strbuf.str(); 00200 00201 mysqlpp::Result res = query.store(); 00202 if (res) 00203 { 00204 mysqlpp::Row row; 00205 mysqlpp::Row::size_type rowIdx; 00206 for (rowIdx = 0; row = res.at(rowIdx); ++rowIdx) { 00207 foundIdx = row["kid"]; 00208 foundDist = row["dist"]; 00209 foundMatchCount = row["matchCount"]; 00210 00211 if (foundDist < 100000) 00212 foundKeypoint = true; 00213 } 00214 } 00215 itsTimer.mark(); 00216 LINFO("NN Searched (idx=%i matchCount=%i dist=%f) took %f seconds (found=%i)", 00217 foundIdx, 00218 foundMatchCount, 00219 foundDist, 00220 itsTimer.user_secs(), 00221 foundKeypoint); 00222 00223 LINFO("Service Keypoint"); 00224 itsTimer.reset(); 00225 if (!foundKeypoint) 00226 { 00227 LINFO("Keypoint not found adding"); 00228 std::string kpv(fv, 128); 00229 std::ostringstream strbuf; 00230 strbuf << "INSERT INTO SiftKeypoints (value) VALUES (\"" << mysqlpp::escape << kpv <<"\")" << ends; 00231 query.exec(strbuf.str()); 00232 printf("Insert keypoint\n"); 00233 } else { 00234 //update the frequency; 00235 std::ostringstream strbuf; 00236 foundMatchCount++; //incr the number of times this keyp was found 00237 strbuf << "UPDATE SiftKeypoints set matchCount = " << foundMatchCount << " WHERE kid = " << foundIdx << ends; 00238 query.exec(strbuf.str()); 00239 printf("Update keypoint\n"); 00240 } 00241 itsTimer.mark(); 00242 LINFO("Service keypoint took %f seconds", 00243 itsTimer.user_secs()); 00244 00245 //Show the keypoint 00246 PixRGB<byte> color; 00247 if(foundKeypoint) 00248 color = PixRGB<byte>(0,255,0); 00249 else 00250 color = PixRGB<byte>(255,0,0); 00251 00252 float x = keyPoint->getX(); 00253 float y = keyPoint->getY(); 00254 float s = keyPoint->getS(); 00255 float o = keyPoint->getO(); 00256 00257 Point2D<int> keypLoc(int(x + 0.5F), int(y + 0.5F)); 00258 00259 drawDisk(img, keypLoc, 2, color); 00260 if (s > 0.0f) 00261 drawLine(img, keypLoc, 00262 Point2D<int>(int(x + s * cosf(o) + 0.5F), 00263 int(y + s * sinf(o) + 0.5F)), 00264 color); 00265 00266 itsOfs->writeRGB(img, "KeyPoints", FrameInfo("KeyPoints", SRC_POS)); 00267 } 00268 LINFO("Continue"); 00269 00270 00271 LINFO("Done."); 00272 } 00273 } 00274 00275 std::string InferotemporalCortexI::getBestLabel(const size_t mincount) 00276 { 00277 if (itsRecentLabels.size() == 0) 00278 return std::string(); 00279 00280 std::map<std::string, size_t> counts; 00281 00282 size_t bestcount = 0; 00283 size_t bestpos = 0; 00284 00285 for (size_t i = 0; i < itsRecentLabels.size(); ++i) 00286 { 00287 const size_t c = ++(counts[itsRecentLabels[i]]); 00288 00289 if (c >= bestcount) 00290 { 00291 bestcount = c; 00292 bestpos = i; 00293 } 00294 } 00295 00296 if (bestcount >= mincount) 00297 return itsRecentLabels[bestpos]; 00298 00299 return std::string(); 00300 } 00301 00302 std::string InferotemporalCortexI::matchObject(Image<PixRGB<byte> > &ima, float &score) 00303 { 00304 //find object in the database 00305 std::vector< rutz::shared_ptr<VisualObjectMatch> > matches; 00306 rutz::shared_ptr<VisualObject> 00307 vo(new VisualObject("PIC", "PIC", ima, 00308 Point2D<int>(-1,-1), 00309 std::vector<double>(), 00310 std::vector< rutz::shared_ptr<Keypoint> >(), 00311 itsUseColor)); 00312 00313 const uint nmatches = itsVDB.getObjectMatches(vo, matches, VOMA_SIMPLE, 00314 100U, //max objs to return 00315 0.5F, //keypoint distance score default 0.5F 00316 0.5F, //affine distance score default 0.5F 00317 1.0F, //minscore default 1.0F 00318 3U, //min # of keypoint match 00319 100U, //keypoint selection thershold 00320 false //sort by preattentive 00321 ); 00322 00323 score = 0; 00324 float avgScore = 0, affineAvgDist = 0; 00325 int nkeyp = 0; 00326 int objId = -1; 00327 if (nmatches > 0) 00328 { 00329 rutz::shared_ptr<VisualObject> obj; //so we will have a ref to the last matches obj 00330 rutz::shared_ptr<VisualObjectMatch> vom; 00331 //for(unsigned int i=0; i< nmatches; i++){ 00332 for (unsigned int i = 0; i < 1; ++i) 00333 { 00334 vom = matches[i]; 00335 obj = vom->getVoTest(); 00336 score = vom->getScore(); 00337 nkeyp = vom->size(); 00338 avgScore = vom->getKeypointAvgDist(); 00339 affineAvgDist = vom->getAffineAvgDist(); 00340 00341 objId = atoi(obj->getName().c_str()+3); 00342 00343 return obj->getName(); 00344 LINFO("### Object match with '%s' score=%f ID:%i", 00345 obj->getName().c_str(), vom->getScore(), objId); 00346 00347 //calculate the actual distance (location of keypoints) between 00348 //keypoints. If the same patch was found, then the distance should 00349 //be close to 0 00350 double dist = 0; 00351 for (int keyp=0; keyp<nkeyp; keyp++) 00352 { 00353 const KeypointMatch kpm = vom->getKeypointMatch(keyp); 00354 00355 float refX = kpm.refkp->getX(); 00356 float refY = kpm.refkp->getY(); 00357 00358 float tstX = kpm.tstkp->getX(); 00359 float tstY = kpm.tstkp->getY(); 00360 dist += (refX-tstX) * (refX-tstX); 00361 dist += (refY-tstY) * (refY-tstY); 00362 } 00363 00364 // printf("%i:%s %i %f %i %f %f %f\n", objNum, obj->getName().c_str(), 00365 // nmatches, score, nkeyp, avgScore, affineAvgDist, sqrt(dist)); 00366 00367 //analizeImage(); 00368 } 00369 00370 } 00371 00372 return std::string("nomatch"); 00373 } 00374 00375 00376 00377 /////////////////////////// The VC Service to init the retina and start as a deamon /////////////// 00378 class InferotemporalCortexService : public Ice::Service { 00379 protected: 00380 virtual bool start(int, char* argv[]); 00381 virtual bool stop() { 00382 if (itsMgr) 00383 delete itsMgr; 00384 return true; 00385 } 00386 00387 private: 00388 Ice::ObjectAdapterPtr itsAdapter; 00389 ModelManager *itsMgr; 00390 }; 00391 00392 bool InferotemporalCortexService::start(int argc, char* argv[]) 00393 { 00394 00395 itsMgr = new ModelManager("InferotemporalCortexService"); 00396 00397 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(*itsMgr)); 00398 itsMgr->addSubComponent(ofs); 00399 00400 nub::ref<InferotemporalCortexI> itc(new InferotemporalCortexI(*itsMgr, ofs)); 00401 itsMgr->addSubComponent(itc); 00402 00403 itsMgr->parseCommandLine((const int)argc, (const char**)argv, "", 0, 0); 00404 00405 char adapterStr[255]; 00406 sprintf(adapterStr, "default -p %i", BrainObjects::InferoTemporalPort); 00407 itsAdapter = communicator()->createObjectAdapterWithEndpoints("InferotemporalCortexAdapter", 00408 adapterStr); 00409 00410 Ice::ObjectPtr object = itc.get(); 00411 Ice::ObjectPrx objectPrx = itsAdapter->add(object, communicator()->stringToIdentity("InferotemporalCortex")); 00412 itc->initSimEvents(communicator(), objectPrx); 00413 itsAdapter->activate(); 00414 00415 itsMgr->start(); 00416 00417 IceUtil::ThreadPtr itcThread = itc.get(); 00418 itcThread->start(); 00419 00420 00421 return true; 00422 } 00423 00424 // ###################################################################### 00425 int main(int argc, char** argv) { 00426 00427 InferotemporalCortexService svc; 00428 return svc.main(argc, argv); 00429 } 00430 00431