00001 /*!@file Neuro/VisualTrackerService.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/VisualTrackerService.C $ 00035 // $Id: VisualTrackerService.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "NeovisionII/VisualTrackerService.H" 00039 #include "Image/ColorOps.H" 00040 00041 const ModelOptionCateg MOC_VT = { 00042 MOC_SORTPRI_2, "Visual Tracker Related Options" }; 00043 00044 static const ModelOptionDef OPT_VT_TrackIOR = 00045 { MODOPT_ARG(int), "VCTrackIOR", &MOC_VT, OPTEXP_CORE, 00046 "Number of frames to wait before deciding to stop the tracker", 00047 "vt-track-ior", '\0', "<int>", "-1" }; 00048 00049 VisualTrackerI::VisualTrackerI(OptionManager& mgr, 00050 const std::string& descrName, 00051 const std::string& tagName ) : 00052 ModelComponent(mgr, descrName, tagName), 00053 itsTrackIOR(&OPT_VT_TrackIOR, this, ALLOW_ONLINE_CHANGES) 00054 { 00055 //Subscribe to the various topics 00056 IceStorm::TopicPrx topicPrx; 00057 itsTopicsSubscriptions.push_back(TopicInfo("RetinaTopic", topicPrx)); 00058 itsTopicsSubscriptions.push_back(TopicInfo("PrefrontalCortexTopic", topicPrx)); 00059 00060 #ifdef HAVE_OPENCV 00061 this->points[0] = NULL; 00062 this->points[1] = NULL; 00063 this->status = NULL; 00064 this->track_error = NULL; 00065 this->pyramid = NULL; 00066 this->prev_pyramid = NULL; 00067 #endif 00068 itsInitTracker = true; 00069 itsInitTargets = true; 00070 itsTracking = false; 00071 itsTrackFrames = 0; 00072 00073 } 00074 00075 VisualTrackerI::~VisualTrackerI() 00076 { 00077 unsubscribeSimEvents(); 00078 #ifdef HAVE_OPENCV 00079 //cvFree(&this->points[0]); 00080 //cvFree(&this->points[1]); 00081 //cvFree(&this->status); 00082 cvReleaseImage(&this->pyramid); 00083 cvReleaseImage(&this->prev_pyramid); 00084 #endif 00085 00086 } 00087 00088 void VisualTrackerI::initSimEvents(Ice::CommunicatorPtr icPtr, Ice::ObjectPrx objectPrx) 00089 { 00090 //Get the IceStorm object 00091 Ice::ObjectPrx obj = icPtr->stringToProxy("SimEvents/TopicManager:tcp -p 11111"); 00092 IceStorm::TopicManagerPrx topicManager = 00093 IceStorm::TopicManagerPrx::checkedCast(obj); 00094 00095 //Create a VisualTracker Topic 00096 IceStorm::TopicPrx topic; 00097 try { 00098 topic = topicManager->retrieve("VisualTrackerTopic"); //check if the Retina topic exists 00099 } catch (const IceStorm::NoSuchTopic&) { 00100 topic = topicManager->create("VisualTrackerTopic"); //The retina topic does not exists, create 00101 } 00102 //Make a one way visualCortex message publisher for efficency 00103 Ice::ObjectPrx pub = topic->getPublisher()->ice_oneway(); 00104 itsEventsPub = SimEvents::EventsPrx::uncheckedCast(pub); 00105 00106 //Subscribe the SimulationViewer to theTopics 00107 itsObjectPrx = objectPrx; 00108 //subscribe to the topics 00109 for(uint i=0; i<itsTopicsSubscriptions.size(); i++) 00110 { 00111 try { 00112 IceStorm::QoS qos; 00113 itsTopicsSubscriptions[i].topicPrx = 00114 topicManager->retrieve(itsTopicsSubscriptions[i].name.c_str()); //Get the 00115 itsTopicsSubscriptions[i].topicPrx->subscribeAndGetPublisher(qos, itsObjectPrx); //Subscribe to the retina topic 00116 } catch (const IceStorm::NoSuchTopic&) { 00117 LFATAL("Error! No %s topic found!", itsTopicsSubscriptions[i].name.c_str()); 00118 } catch (const char* msg) { 00119 LINFO("Error %s", msg); 00120 } catch (const Ice::Exception& e) { 00121 cerr << e << endl; 00122 } 00123 00124 } 00125 } 00126 00127 void VisualTrackerI::unsubscribeSimEvents() 00128 { 00129 //Unsubscribe from all the topics we are registerd to 00130 for(uint i=0; i<itsTopicsSubscriptions.size(); i++) 00131 { 00132 itsTopicsSubscriptions[i].topicPrx->unsubscribe(itsObjectPrx); 00133 } 00134 } 00135 00136 00137 //The VC excepts a retina image and posts a saliency map 00138 void VisualTrackerI::evolve(const SimEvents::EventMessagePtr& eMsg, 00139 const Ice::Current&) 00140 { 00141 if (eMsg->ice_isA("::SimEvents::VisualTrackerBiasMessage")){ //Set the tracker location 00142 SimEvents::VisualTrackerBiasMessagePtr msg = SimEvents::VisualTrackerBiasMessagePtr::dynamicCast(eMsg); 00143 itsTrackLocs.clear(); 00144 for(uint i=0; i<msg->locToTrack.size(); i++) 00145 { 00146 itsTrackLocs.push_back(msg->locToTrack[i]); 00147 Point2D<int> trackLoc = Point2D<int>(msg->locToTrack[i].pos.i, msg->locToTrack[i].pos.j); 00148 LINFO("Tracking %ix%i", trackLoc.i, trackLoc.j); 00149 break; //only track one point at this time; 00150 } 00151 itsInitTargets = true; //Let the system know we want to reinit 00152 } else if(eMsg->ice_isA("::SimEvents::RetinaMessage")){ 00153 SimEvents::RetinaMessagePtr msg = SimEvents::RetinaMessagePtr::dynamicCast(eMsg); 00154 Image<PixRGB<byte> > img = Ice2Image<PixRGB<byte> > (msg->img); 00155 //We got the first image, initalize the tracker 00156 if (itsInitTracker) 00157 initTracker(img.getDims()); 00158 00159 if (itsInitTargets) 00160 setTargets(luminance(img)); 00161 00162 Point2D<int> targetLoc(-1,-1); 00163 if (itsTracking) 00164 { 00165 targetLoc = trackObjects(luminance(img)); 00166 } 00167 00168 SimEvents::VisualTrackerMessagePtr bMsg = new SimEvents::VisualTrackerMessage; 00169 if (targetLoc.isValid()) //If we lost the track then send an empty message 00170 { 00171 //return the current track location 00172 SimEvents::TrackInfo trackInfo; 00173 trackInfo.pos.i = targetLoc.i; 00174 trackInfo.pos.j = targetLoc.j; 00175 bMsg->trackLocs.push_back(trackInfo); 00176 } 00177 itsEventsPub->evolve(bMsg); 00178 } 00179 } 00180 00181 void VisualTrackerI::initTracker(Dims imageDims, int nPoints, int wz ) 00182 { 00183 win_size = 30; 00184 00185 #ifdef HAVE_OPENCV 00186 MAX_COUNT = nPoints; 00187 count = 0; 00188 points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0])); 00189 points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0])); 00190 00191 prev_grey = Image<byte>(imageDims, ZEROS); 00192 pyramid = cvCreateImage( cvSize(imageDims.w(), imageDims.h()), 8, 1 ); 00193 prev_pyramid = cvCreateImage( cvSize(imageDims.w(), imageDims.h()), 8, 1 ); 00194 status = (char*)cvAlloc(MAX_COUNT); 00195 track_error = (float*)cvAlloc(MAX_COUNT); 00196 #endif 00197 flags = 0; 00198 itsInitTracker = false; 00199 itsTrackFrames = 0; 00200 00201 //Send an init message to indicate that we are not tracking 00202 00203 SimEvents::VisualTrackerMessagePtr bMsg = new SimEvents::VisualTrackerMessage; 00204 itsEventsPub->evolve(bMsg); 00205 00206 } 00207 00208 // ###################################################################### 00209 void VisualTrackerI::setTargets(const Image<byte>& grey) 00210 { 00211 #ifdef HAVE_OPENCV 00212 count = MAX_COUNT; 00213 00214 IplImage* tmp = img2ipl(grey); 00215 for(uint i=0; i<itsTrackLocs.size(); i++) 00216 { 00217 Point2D<int> trackLoc = Point2D<int>(itsTrackLocs[i].pos.i, itsTrackLocs[i].pos.j); 00218 LINFO("Setting target to %ix%i", trackLoc.i, trackLoc.j); 00219 points[1][0].x = trackLoc.i; 00220 points[1][0].y = trackLoc.j; 00221 00222 cvFindCornerSubPix(tmp, points[1], count, 00223 cvSize(win_size,win_size), cvSize(-1,-1), 00224 cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 00225 20,0.03)); 00226 cvReleaseImageHeader(&tmp); 00227 00228 prev_grey = grey; 00229 break; //only a single point is allowed for now 00230 } 00231 flags = 0; 00232 IplImage *swap_temp; 00233 CV_SWAP( prev_pyramid, pyramid, swap_temp ); 00234 CV_SWAP( points[0], points[1], swap_points ); 00235 00236 #endif 00237 00238 itsTracking = true; 00239 itsInitTargets = false; 00240 itsTrackFrames = 0; 00241 00242 } 00243 00244 // ###################################################################### 00245 Point2D<int> VisualTrackerI::trackObjects(const Image<byte>& grey) 00246 { 00247 Point2D<int> targetLoc(-1,-1); 00248 00249 //Apply the track IOR 00250 if (itsTrackIOR.getVal() != -1 && 00251 (int)itsTrackFrames >= itsTrackIOR.getVal()) 00252 { 00253 LINFO("Appling IOR"); 00254 itsTrackFrames = 0; 00255 itsTracking = false; 00256 return targetLoc; 00257 } 00258 00259 00260 #ifdef HAVE_OPENCV 00261 if (count > 0) 00262 { 00263 IplImage* tmp1 = img2ipl(prev_grey); 00264 IplImage* tmp2 = img2ipl(grey); 00265 00266 //flags = CV_LKFLOW_INITIAL_GUESSES; 00267 00268 cvCalcOpticalFlowPyrLK(tmp1, tmp2, prev_pyramid, pyramid, 00269 points[0], points[1], count, 00270 cvSize(win_size,win_size), 3, status, track_error, 00271 cvTermCriteria(CV_TERMCRIT_ITER 00272 |CV_TERMCRIT_EPS, 00273 20,0.03), flags); 00274 00275 flags = CV_LKFLOW_PYR_A_READY | CV_LKFLOW_PYR_B_READY; 00276 00277 cvReleaseImageHeader(&tmp1); 00278 cvReleaseImageHeader(&tmp2); 00279 00280 00281 //show track points 00282 int k, i; 00283 for(i = k = 0; i<count; i++) 00284 { 00285 if (!status[i]) 00286 continue; 00287 00288 points[1][k++] = points[1][i]; 00289 //LINFO("Error %i: %f", i, track_error[i]); 00290 if (track_error[i] < 2000) 00291 { 00292 targetLoc.i = std::min(grey.getWidth()-1, std::max(0, (int)points[0][i].x)); 00293 targetLoc.j = std::min(grey.getHeight()-1, std::max(0, (int)points[0][i].y)); 00294 ASSERT(grey.coordsOk(targetLoc)); 00295 } 00296 } 00297 count = k; 00298 00299 } 00300 00301 IplImage *swap_temp; 00302 CV_SWAP( prev_pyramid, pyramid, swap_temp ); 00303 CV_SWAP( points[0], points[1], swap_points ); 00304 00305 prev_grey = grey; 00306 #endif 00307 00308 itsTrackFrames++; 00309 00310 return targetLoc; 00311 } 00312 00313 00314 00315 00316 /////////////////////////// The VC Service to init the retina and start as a deamon /////////////// 00317 class VisualTrackerService : public Ice::Service { 00318 protected: 00319 virtual bool start(int, char* argv[]); 00320 virtual bool stop() { 00321 if (itsMgr) 00322 delete itsMgr; 00323 return true; 00324 } 00325 00326 private: 00327 Ice::ObjectAdapterPtr itsAdapter; 00328 ModelManager *itsMgr; 00329 }; 00330 00331 bool VisualTrackerService::start(int argc, char* argv[]) 00332 { 00333 00334 itsMgr = new ModelManager("VisualTrackerService"); 00335 00336 nub::ref<VisualTrackerI> vt(new VisualTrackerI(*itsMgr)); 00337 itsMgr->addSubComponent(vt); 00338 00339 itsMgr->parseCommandLine((const int)argc, (const char**)argv, "", 0, 0); 00340 00341 char adapterStr[255]; 00342 sprintf(adapterStr, "default -p %i", BrainObjects::VisualTrackerPort); 00343 itsAdapter = communicator()->createObjectAdapterWithEndpoints("VisualTrackerAdapter", 00344 adapterStr); 00345 00346 Ice::ObjectPtr object = vt.get(); 00347 Ice::ObjectPrx objectPrx = itsAdapter->add(object, communicator()->stringToIdentity("VisualTracker")); 00348 vt->initSimEvents(communicator(), objectPrx); 00349 itsAdapter->activate(); 00350 00351 itsMgr->start(); 00352 00353 return true; 00354 } 00355 00356 // ###################################################################### 00357 int main(int argc, char** argv) { 00358 00359 VisualTrackerService svc; 00360 return svc.main(argc, argv); 00361 } 00362 00363