00001 /*!@file RCBot/SceneRec.C Recognize scenes */ 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: Lior Elazary <elazary@usc.edu> 00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/RCBot/SceneRec.C $ 00034 // $Id: SceneRec.C 14125 2010-10-12 06:29:08Z itti $ 00035 // 00036 00037 #include "RCBot/SceneRec.H" 00038 #include "Component/OptionManager.H" 00039 #include "Image/CutPaste.H" 00040 #include <cstdio> // for sprintf 00041 00042 #define DEBUG 00043 #ifdef DEBUG 00044 00045 #include "GUI/XWinManaged.H" 00046 #include "Image/DrawOps.H" 00047 XWinManaged xwin(Dims(320,240), -1, -1, "SceneRec"); 00048 00049 #endif 00050 00051 // ###################################################################### 00052 // The working Thread 00053 void *SceneRecWorkTh(void *c) 00054 { 00055 SceneRec *d = (SceneRec*)c; 00056 d->computeLocation(); 00057 return NULL; 00058 } 00059 00060 // ###################################################################### 00061 SceneRec::SceneRec(OptionManager& mgr, const std::string& descrName, 00062 const std::string& tagName): 00063 ModelComponent(mgr, descrName, tagName) 00064 { } 00065 00066 // ###################################################################### 00067 void SceneRec::start1() 00068 { 00069 pthread_mutex_init(&jobLock, NULL); 00070 pthread_mutex_init(&locLock, NULL); 00071 pthread_mutex_init(&vdbLock, NULL); 00072 pthread_cond_init(&jobCond, NULL); 00073 00074 currentLeg = 0; 00075 jobDone = true; 00076 00077 currentLegVdb = NULL; 00078 nextLegVdb = NULL; 00079 loadVisualDB(currentLeg); 00080 00081 // start the working thread 00082 worker = new pthread_t[1]; 00083 pthread_create(&worker[0], NULL, SceneRecWorkTh, (void *)this); 00084 usleep(100000); 00085 } 00086 00087 // ###################################################################### 00088 void SceneRec::stop2() 00089 { 00090 delete [] worker; 00091 } 00092 00093 // ###################################################################### 00094 SceneRec::~SceneRec() 00095 { } 00096 00097 // ###################################################################### 00098 void SceneRec::newInput(const Image< PixRGB<byte> > img) 00099 { 00100 pthread_mutex_lock(&jobLock); 00101 workImg = img; 00102 jobDone = false; 00103 pthread_mutex_unlock(&jobLock); 00104 00105 // let the thread know we are ready for processing 00106 pthread_cond_broadcast(&jobCond); 00107 } 00108 00109 // ###################################################################### 00110 bool SceneRec::outputReady() 00111 { 00112 bool ret = false; 00113 00114 pthread_mutex_lock(&jobLock); 00115 if (jobDone) ret = true; 00116 pthread_mutex_unlock(&jobLock); 00117 00118 return ret; 00119 } 00120 00121 // ###################################################################### 00122 short SceneRec::getLandmarkLoc(Point2D<int> &loc) 00123 { 00124 pthread_mutex_lock(&locLock); 00125 loc = landmarkLoc; 00126 pthread_mutex_unlock(&locLock); 00127 00128 return currentLeg; 00129 } 00130 00131 // ###################################################################### 00132 void SceneRec::trainFeature(Image<PixRGB<byte> > &img, Point2D<int> loc, 00133 Dims window, short leg) 00134 { 00135 int width = img.getWidth(); 00136 int height = img.getHeight(); 00137 winsize = window; 00138 00139 try { 00140 LDEBUG("Training loc (%i,%i) Win(%i,%i) leg=%i currentLeg=%i", 00141 loc.i, loc.j, window.w(), window.h(), leg, currentLeg); 00142 00143 // if we are on a different leg, the load the correct vdb 00144 if (currentLeg != leg){ 00145 pthread_mutex_lock(&vdbLock); 00146 loadVisualDB(leg); 00147 pthread_mutex_unlock(&vdbLock); 00148 } 00149 00150 char name[255]; char fileName[255]; 00151 sprintf(name, "Loc%i_%i", objNum, currentLeg); 00152 sprintf(fileName, "Loc%i_%i.png", objNum, currentLeg); 00153 00154 // the location is at the center, move it to the top left 00155 Point2D<int> topLeft(loc.i-((window.w()-1)/2), loc.j-((window.h()-1)/2)); 00156 00157 // fix the window so that it does not go outside the image 00158 if (topLeft.i < 0 ) topLeft.i = 0; 00159 if (topLeft.i > width - window.w()) topLeft.i = width - window.w(); 00160 00161 if (topLeft.j < 0 ) topLeft.j = 0; 00162 if (topLeft.j > height - window.h()) topLeft.j = height - window.h(); 00163 00164 Image<PixRGB<byte> > templLoc = crop(img,topLeft, window); 00165 rutz::shared_ptr<VisualObject> voTempl(new VisualObject(name,fileName, templLoc)); 00166 00167 LINFO("Saving %s to %s", name, fileName); 00168 pthread_mutex_lock(&vdbLock); 00169 currentLegVdb->addObject(voTempl); 00170 sprintf(fileName, "path%i.vdb", currentLeg); 00171 currentLegVdb->saveTo(fileName); 00172 pthread_mutex_unlock(&vdbLock); 00173 objNum++; 00174 00175 } catch(...) { 00176 LDEBUG("Error in training"); 00177 pthread_mutex_unlock(&vdbLock); 00178 } 00179 } 00180 00181 // ###################################################################### 00182 void SceneRec::computeLocation() 00183 { 00184 while (true){ 00185 // wait until a job comes 00186 pthread_mutex_lock(&jobLock); 00187 pthread_cond_wait(&jobCond, &jobLock); 00188 00189 // got a job 00190 Image<PixRGB<byte> > img = workImg; 00191 pthread_mutex_unlock(&jobLock); 00192 00193 LDEBUG("Got a location to recognize, currentLeg = %i", currentLeg); 00194 pthread_mutex_lock(&locLock); 00195 landmarkLoc.i = -1; landmarkLoc.j = -1; 00196 pthread_mutex_unlock(&locLock); 00197 00198 try { 00199 std::vector< rutz::shared_ptr<VisualObjectMatch> > matches; 00200 unsigned int nmatch = 0; 00201 if (img.initialized()){ 00202 rutz::shared_ptr<VisualObject> voimg(new VisualObject("PIC", "PIC", img)); 00203 00204 float scale; Point2D<int> loc; bool landmarkFound = false; 00205 00206 // search the next location, if we do not look at the current one 00207 if (nextLegVdb->numObjects()) { // do we have any objects 00208 pthread_mutex_lock(&vdbLock); 00209 nmatch = nextLegVdb->getObjectMatches(voimg, matches, 00210 VOMA_KDTREEBBF); 00211 pthread_mutex_unlock(&vdbLock); 00212 00213 getLandmarkInfo(scale, loc, nmatch, matches, img); 00214 LINFO("Next DB: Found landmark at (%i,%i), scale = %f", loc.i, loc.j, scale); 00215 if (nmatch > 0 && scale > 0.75) { //We found the next location 00216 loadVisualDB(currentLeg+1); //load the next vdbs 00217 landmarkFound = true; 00218 } 00219 } 00220 00221 // the next Landmark is not found, search the current db 00222 if (!landmarkFound){ 00223 if (currentLegVdb->numObjects()) { // do we have any objects 00224 pthread_mutex_lock(&vdbLock); 00225 nmatch = currentLegVdb->getObjectMatches(voimg, matches, 00226 VOMA_KDTREEBBF); 00227 pthread_mutex_unlock(&vdbLock); 00228 00229 getLandmarkInfo(scale, loc, nmatch, matches, img); 00230 LINFO("Curr DB: Found landmark at (%i,%i), scale = %f", loc.i, loc.j, scale); 00231 if (nmatch > 0){ //match at any scale 00232 landmarkFound = true; 00233 } 00234 } 00235 } 00236 00237 if (landmarkFound) { // if we found the landmark then store the position 00238 pthread_mutex_lock(&locLock); 00239 landmarkLoc = loc; 00240 pthread_mutex_unlock(&locLock); 00241 } 00242 } 00243 00244 } catch (...){ 00245 LDEBUG("Got an error " ); 00246 pthread_mutex_unlock(&vdbLock); 00247 pthread_mutex_unlock(&locLock); 00248 } 00249 00250 // sleep(1); 00251 pthread_mutex_lock(&jobLock); 00252 jobDone = true; 00253 pthread_mutex_unlock(&jobLock); 00254 } 00255 } 00256 00257 // ###################################################################### 00258 void SceneRec::getLandmarkInfo(float &scale, Point2D<int> &loc, 00259 unsigned int nmatch, 00260 std::vector< rutz::shared_ptr<VisualObjectMatch> > &matches, 00261 Image<PixRGB<byte> > &img) 00262 { 00263 LDEBUG("Found %i currentLeg %i\n", nmatch, currentLeg); 00264 if (nmatch > 0 ) 00265 { 00266 // look at the first match 00267 for(unsigned int i = 0; i < 1; i++) 00268 { 00269 rutz::shared_ptr<VisualObjectMatch> vom = matches[i]; 00270 rutz::shared_ptr<VisualObject> obj = vom->getVoTest(); 00271 00272 // get the number of the object 00273 const char *nameNum = obj->getName().c_str(); 00274 int objNum = atoi(nameNum+3); // skip over Loc 00275 00276 LDEBUG("### Object match with '%s' score=%f Number %i", 00277 obj->getName().c_str(), vom->getScore(), objNum); 00278 Point2D<int> tl, tr, br, bl; 00279 vom->getTransfTestOutline(tl, tr, br, bl); 00280 00281 // find the center: 00282 Point2D<int> landmarkCenter( tl.i + ((br.i - tl.i)/2), 00283 tl.j + ((br.j - tl.j)/2)); 00284 loc = landmarkCenter; 00285 00286 #ifdef DEBUG 00287 drawLine(img, tl, tr, PixRGB<byte>(255, 0, 0)); 00288 drawLine(img, tr, br, PixRGB<byte>(255, 0, 0)); 00289 drawLine(img, br, bl, PixRGB<byte>(255, 0, 0)); 00290 drawLine(img, bl, tl, PixRGB<byte>(255, 0, 0)); 00291 drawDisk(img, Point2D<int>(landmarkCenter), 00292 4, PixRGB<byte>(255, 0, 0)); 00293 xwin.drawImage(img); 00294 #endif 00295 00296 float size = (br.i - tl.i)*(br.j - tl.j); 00297 LINFO("Size: %i %i %f", br.i - tl.i, br.j - tl.j, size); 00298 00299 scale = size / (winsize.w()*winsize.h()); 00300 } 00301 } else { 00302 scale = 0; 00303 loc.i = -1; loc.j = -1; 00304 } 00305 } 00306 00307 // ###################################################################### 00308 void SceneRec::loadVisualDB(short leg) 00309 { 00310 char fileName[255]; 00311 00312 //save the old dbs 00313 if (currentLegVdb) { 00314 if (currentLegVdb->numObjects()){ 00315 sprintf(fileName, "path%i.vdb", currentLeg); 00316 currentLegVdb->saveTo(fileName); 00317 } 00318 delete currentLegVdb; 00319 } 00320 00321 if (nextLegVdb){ 00322 if (nextLegVdb->numObjects()){ 00323 sprintf(fileName, "path%i.vdb", currentLeg+1); 00324 nextLegVdb->saveTo(fileName); 00325 } 00326 delete nextLegVdb; 00327 } 00328 00329 // load dbs 00330 sprintf(fileName, "path%i.vdb", leg); 00331 currentLegVdb = new VisualObjectDB(); 00332 currentLegVdb->loadFrom(fileName); 00333 objNum = currentLegVdb->numObjects(); 00334 LINFO("Load current=%i(%i) next=%i", leg, objNum, leg+1); 00335 00336 sprintf(fileName, "path%i.vdb", leg+1); 00337 nextLegVdb = new VisualObjectDB(); 00338 nextLegVdb->loadFrom(fileName); 00339 00340 currentLeg = leg; 00341 } 00342 00343 // ###################################################################### 00344 /* So things look consistent in everyone's emacs... */ 00345 /* Local Variables: */ 00346 /* indent-tabs-mode: nil */ 00347 /* End: */