00001 /*!@file SceneUnderstanding/V4.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 <elazary@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/plugins/SceneUnderstanding/V4.C $ 00035 // $Id: V4.C 13551 2010-06-10 21:56:32Z itti $ 00036 // 00037 00038 #ifndef V4_C_DEFINED 00039 #define V4_C_DEFINED 00040 00041 #include "plugins/SceneUnderstanding/V4.H" 00042 00043 #include "Image/DrawOps.H" 00044 #include "Image/MathOps.H" 00045 #include "Image/Kernels.H" 00046 #include "Image/FilterOps.H" 00047 #include "Image/Convolutions.H" 00048 #include "Image/fancynorm.H" 00049 #include "Image/Point3D.H" 00050 #include "Simulation/SimEventQueue.H" 00051 #include "Neuro/EnvVisualCortex.H" 00052 #include "GUI/DebugWin.H" 00053 #include "Util/CpuTimer.H" 00054 #include "Util/JobServer.H" 00055 #include "Util/JobWithSemaphore.H" 00056 #include <math.h> 00057 #include <fcntl.h> 00058 #include <limits> 00059 #include <string> 00060 #include <queue> 00061 00062 const ModelOptionCateg MOC_V4 = { 00063 MOC_SORTPRI_3, "V4-Related Options" }; 00064 00065 // Used by: SimulationViewerEyeMvt 00066 const ModelOptionDef OPT_V4ShowDebug = 00067 { MODOPT_ARG(bool), "V4ShowDebug", &MOC_V4, OPTEXP_CORE, 00068 "Show debug img", 00069 "v4-debug", '\0', "<true|false>", "false" }; 00070 00071 namespace 00072 { 00073 class GHTJob : public JobWithSemaphore 00074 { 00075 public: 00076 00077 GHTJob(V4* v4, Image<float>& acc, int angIdx, std::vector<V4::RTableEntry>& rTable) : 00078 itsV4(v4), 00079 itsAcc(acc), 00080 itsAngIdx(angIdx), 00081 itsRTable(rTable) 00082 {} 00083 00084 virtual ~GHTJob() {} 00085 00086 virtual void run() 00087 { 00088 itsV4->voteForFeature(itsAcc, itsAngIdx, itsRTable); 00089 00090 this->markFinished(); 00091 } 00092 00093 virtual const char* jobType() const { return "GHTJob"; } 00094 V4* itsV4; 00095 Image<float>& itsAcc; 00096 int itsAngIdx; 00097 std::vector<V4::RTableEntry>& itsRTable; 00098 }; 00099 } 00100 00101 00102 // ###################################################################### 00103 V4::V4(OptionManager& mgr, const std::string& descrName, 00104 const std::string& tagName) : 00105 SimModule(mgr, descrName, tagName), 00106 SIMCALLBACK_INIT(SimEventV2Output), 00107 SIMCALLBACK_INIT(SimEventV4dOutput), 00108 SIMCALLBACK_INIT(SimEventUserInput), 00109 SIMCALLBACK_INIT(SimEventSaveOutput), 00110 itsShowDebug(&OPT_V4ShowDebug, this), 00111 itsMaxVal(0), 00112 itsGHTAngStep(5), 00113 itsObjectsDist(370.00) 00114 { 00115 itsThreadServer.reset(new WorkThreadServer("V4", 100)); 00116 00117 00118 itsDebugImg = Image<PixRGB<byte> >(302,240,ZEROS); 00119 00120 //Camera parameters 00121 itsCamera = Camera(Point3D<float>(0,0,0.0), 00122 Point3D<float>(0, 0,0), 00123 450, //Focal length 00124 320, //width 00125 240); //height 00126 00127 ///Geons 00128 itsGeons.resize(3); 00129 00130 GeonOutline triangle; 00131 triangle.geonType = TRIANGLE; 00132 triangle.outline.push_back(Point3D<float>(0.0,0, 0.0)); 00133 triangle.outline.push_back(Point3D<float>(0.0,-40.0, 0.0)); 00134 triangle.outline.push_back(Point3D<float>(40.0, 0.0, 0.0)); 00135 00136 triangle.NAFTemplate.push_back( 00137 V4d::NAFState(Point3D<float>(0,0,0), 135*M_PI/180, V4d::VERTIX, 00138 Point3D<float>(10,10,1), 1*M_PI/180)); 00139 triangle.NAFTemplate.push_back( 00140 V4d::NAFState(Point3D<float>(0,40.0,0), -90*M_PI/180, V4d::RIGHT_VERTIX, 00141 Point3D<float>(10,10,1), 1*M_PI/180)); 00142 triangle.NAFTemplate.push_back( 00143 V4d::NAFState(Point3D<float>(40.0,40.0,0), -90*M_PI/180, V4d::VERTIX, 00144 Point3D<float>(10,10,1), 1*M_PI/180)); 00145 00146 00147 alignToCenterOfMass(triangle); 00148 itsGeons[TRIANGLE] = triangle; 00149 00150 00151 //Add a square Geon 00152 GeonOutline square; 00153 square.geonType = SQUARE; 00154 square.outline.push_back(Point3D<float>(0.0,0, 0.0)); 00155 square.outline.push_back(Point3D<float>(0.0, 30.0, 0.0)); 00156 square.outline.push_back(Point3D<float>(30, 30.0, 0.0)); 00157 square.outline.push_back(Point3D<float>(30,0.0, 0.0)); 00158 00159 square.NAFTemplate.push_back( 00160 V4d::NAFState(Point3D<float>(0,0,0), 0*M_PI/180, V4d::RIGHT_VERTIX, 00161 Point3D<float>(10,10,1), 1*M_PI/180)); 00162 square.NAFTemplate.push_back( 00163 V4d::NAFState(Point3D<float>(0,30.0,0), -90*M_PI/180, V4d::RIGHT_VERTIX, 00164 Point3D<float>(10,10,1), 1*M_PI/180)); 00165 square.NAFTemplate.push_back( 00166 V4d::NAFState(Point3D<float>(30.0,30.0,0), 180*M_PI/180, V4d::RIGHT_VERTIX, 00167 Point3D<float>(10,10,1), 1*M_PI/180)); 00168 square.NAFTemplate.push_back( 00169 V4d::NAFState(Point3D<float>(30.0,0.0,0), 90*M_PI/180, V4d::RIGHT_VERTIX, 00170 Point3D<float>(10,10,1), 1*M_PI/180)); 00171 00172 alignToCenterOfMass(square); 00173 itsGeons[SQUARE] = square; 00174 00175 //Add a circle Geon 00176 GeonOutline circle; 00177 circle.geonType = CIRCLE; 00178 circle.outline.push_back(Point3D<float>(0.0,0, 0.0)); 00179 circle.outline.push_back(Point3D<float>(0.0, 30.0, 0.0)); 00180 circle.outline.push_back(Point3D<float>(30, 30.0, 0.0)); 00181 circle.outline.push_back(Point3D<float>(30,0.0, 0.0)); 00182 00183 circle.NAFTemplate.push_back( 00184 V4d::NAFState(Point3D<float>(-11.511111,-9.044445,0.000000), 5.829400, V4d::ARC, 00185 Point3D<float>(10,10,1), 1*M_PI/180)); 00186 circle.NAFTemplate.push_back( 00187 V4d::NAFState(Point3D<float>(-12.333334,12.333332,0.000000), 4.572762, V4d::ARC, 00188 Point3D<float>(10,10,1), 1*M_PI/180)); 00189 circle.NAFTemplate.push_back( 00190 V4d::NAFState(Point3D<float>(15.622223,14.799999,0.000000), 2.757620, V4d::ARC, 00191 Point3D<float>(10,10,1), 1*M_PI/180)); 00192 circle.NAFTemplate.push_back( 00193 V4d::NAFState(Point3D<float>(13.155556,-12.333336,0.000000), 1.134464, V4d::ARC, 00194 Point3D<float>(10,10,1), 1*M_PI/180)); 00195 00196 alignToCenterOfMass(circle); 00197 itsGeons[CIRCLE] = circle; 00198 00199 itsGeonsParticles.resize(1000); 00200 for(uint i=0; i<itsGeonsParticles.size(); i++) 00201 { 00202 itsGeonsParticles[i].pos = Point3D<float>(0,0,0); 00203 itsGeonsParticles[i].rot = 0; 00204 itsGeonsParticles[i].geonType = CIRCLE; 00205 itsGeonsParticles[i].weight = 1.0/double(itsGeonsParticles.size()); 00206 itsGeonsParticles[i].prob = 0; 00207 } 00208 00209 00210 itsBestProb = 0; //Out bet probability so far 00211 itsHashedEdgesState.set_empty_key(-1); 00212 buildRTables(); 00213 00214 // for(uint geonId=0; geonId<itsGeons.size(); geonId++) 00215 // showGeon(itsGeons[geonId]); 00216 // 00217 } 00218 00219 // ###################################################################### 00220 V4::~V4() 00221 { 00222 00223 } 00224 00225 // ###################################################################### 00226 void V4::alignToCenterOfMass(GeonOutline& featureTemplate) 00227 { 00228 //Set the 0,0 location around the center of mass 00229 //get the center of the object; 00230 float centerX = 0, centerY = 0, centerZ = 0; 00231 for(uint i=0; i<featureTemplate.outline.size(); i++) 00232 { 00233 centerX += featureTemplate.outline[i].x; 00234 centerY += featureTemplate.outline[i].y; 00235 centerZ += featureTemplate.outline[i].z; 00236 } 00237 centerX /= featureTemplate.outline.size(); 00238 centerY /= featureTemplate.outline.size(); 00239 centerZ /= featureTemplate.outline.size(); 00240 00241 for(uint i=0; i<featureTemplate.outline.size(); i++) 00242 featureTemplate.outline[i] -= Point3D<float>(centerX, centerY, centerZ); 00243 00244 if (featureTemplate.NAFTemplate.size() > 0) 00245 { 00246 centerX = 0; centerY = 0; centerZ = 0; 00247 for(uint i=0; i<featureTemplate.NAFTemplate.size(); i++) 00248 { 00249 centerX += featureTemplate.NAFTemplate[i].pos.x; 00250 centerY += featureTemplate.NAFTemplate[i].pos.y; 00251 centerZ += featureTemplate.NAFTemplate[i].pos.z; 00252 } 00253 centerX /= featureTemplate.NAFTemplate.size(); 00254 centerY /= featureTemplate.NAFTemplate.size(); 00255 centerZ /= featureTemplate.NAFTemplate.size(); 00256 00257 for(uint i=0; i<featureTemplate.NAFTemplate.size(); i++) 00258 { 00259 featureTemplate.NAFTemplate[i].pos -= Point3D<float>(centerX, centerY, centerZ); 00260 //change angle to 0 - 360; 00261 if (featureTemplate.NAFTemplate[i].rot < 0) 00262 featureTemplate.NAFTemplate[i].rot += M_PI*2; 00263 } 00264 } 00265 00266 } 00267 00268 // ###################################################################### 00269 void V4::buildRTables() 00270 { 00271 00272 //Position relative to the camera 00273 for(uint geonId=0; geonId<itsGeons.size(); geonId++) 00274 { 00275 if (itsGeons[geonId].outline.size() > 0) 00276 { 00277 Point3D<float> pos(0,0,itsObjectsDist); 00278 float rot = 0; 00279 00280 for(uint fid = 0; fid < itsGeons[geonId].NAFTemplate.size(); fid++) 00281 { 00282 V4d::NAFState nafState = itsGeons[geonId].NAFTemplate[fid]; 00283 00284 nafState.rot += rot; 00285 float x = nafState.pos.x; 00286 float y = nafState.pos.y; 00287 float z = nafState.pos.z; 00288 nafState.pos.x = (cos(rot)*x - sin(rot)*y) + pos.x; 00289 nafState.pos.y = (sin(rot)*x + cos(rot)*y) + pos.y; 00290 nafState.pos.z = z + pos.z; 00291 00292 Point2D<int> loc = (Point2D<int>)itsCamera.project(nafState.pos); 00293 00294 RTableEntry rTableEntry; 00295 rTableEntry.featureType = nafState.featureType; 00296 rTableEntry.loc.i = loc.i - 320/2; 00297 rTableEntry.loc.j = loc.j - 240/2; 00298 rTableEntry.rot = nafState.rot; 00299 00300 itsGeons[geonId].rTable.push_back(rTableEntry); 00301 } 00302 //showGeon(itsGeons[geonId], (GEON_TYPE)geonId); 00303 } 00304 } 00305 00306 00307 } 00308 00309 // ###################################################################### 00310 void V4::showGeon(GeonOutline& geon) 00311 { 00312 00313 //Position relative to the camera 00314 Point3D<float> pos(0,0,itsObjectsDist); 00315 float rot = 0; 00316 00317 Image<PixRGB<byte> > geonDisp(320, 240, ZEROS); 00318 00319 //for(uint fid = 0; fid < geon.NAFTemplate.size(); fid++) 00320 //{ 00321 // V4d::NAFState nafState = geon.NAFTemplate[fid]; 00322 00323 // nafState.rot += rot; 00324 // float x = nafState.pos.x; 00325 // float y = nafState.pos.y; 00326 // float z = nafState.pos.z; 00327 // nafState.pos.x = (cos(rot)*x - sin(rot)*y) + pos.x; 00328 // nafState.pos.y = (sin(rot)*x + cos(rot)*y) + pos.y; 00329 // nafState.pos.z = z + pos.z; 00330 00331 // std::vector<Point2D<int> > outline = itsV4dCells.getImageOutline(nafState); 00332 00333 // for(uint i=0; i<outline.size()-1; i++) 00334 // drawLine(geonDisp, outline[i], outline[i+1], PixRGB<byte>(0, 255,0), 1); 00335 //} 00336 00337 GeonState geonState; 00338 geonState.pos = pos; 00339 geonState.rot = rot; 00340 geonState.geonType = geon.geonType; 00341 00342 std::vector<Point2D<int> > outline = getImageGeonOutline(geonState); 00343 for(uint i=0; i<outline.size(); i++) 00344 drawLine(geonDisp, outline[i], outline[(i+1)%outline.size()], PixRGB<byte>(255, 0,0), 1); 00345 00346 SHOWIMG(geonDisp); 00347 } 00348 00349 00350 // ###################################################################### 00351 void V4::init(Dims numCells) 00352 { 00353 00354 } 00355 00356 // ###################################################################### 00357 std::vector<V4::GeonState> V4::getOutput() 00358 { 00359 return itsGeonsParticles; 00360 } 00361 00362 00363 // ###################################################################### 00364 void V4::onSimEventV2Output(SimEventQueue& q, 00365 rutz::shared_ptr<SimEventV2Output>& e) 00366 { 00367 std::vector<V1::EdgeState> edgesState; // = e->getEdges(); 00368 00369 itsHashedEdgesState.clear(); 00370 for(uint i=0; i<edgesState.size(); i++) 00371 { 00372 int key = edgesState[i].pos.i + 320*edgesState[i].pos.j; 00373 itsHashedEdgesState[key] = edgesState[i]; 00374 } 00375 00376 } 00377 00378 // ###################################################################### 00379 void V4::onSimEventV4dOutput(SimEventQueue& q, 00380 rutz::shared_ptr<SimEventV4dOutput>& e) 00381 { 00382 itsNAFParticles = e->getCells(); 00383 evolve(); 00384 00385 00386 q.post(rutz::make_shared(new SimEventV4Output(this, itsGeonsParticles))); 00387 00388 //Send out the bias 00389 std::vector<V4d::NAFState> bias = getBias(); 00390 q.post(rutz::make_shared(new SimEventV4BiasOutput(this, bias))); 00391 } 00392 00393 // ###################################################################### 00394 void V4::onSimEventUserInput(SimEventQueue& q, rutz::shared_ptr<SimEventUserInput>& e) 00395 { 00396 00397 LINFO("Got event %s %ix%i key=%i", 00398 e->getWinName(), 00399 e->getMouseClick().i, 00400 e->getMouseClick().j, 00401 e->getKey()); 00402 00403 if (e->getMouseClick().isValid()) 00404 { 00405 Point3D<float> iPoint = itsCamera.inverseProjection((Point2D<float>)e->getMouseClick(), itsObjectsDist); 00406 itsGeonsParticles[0].pos = iPoint; 00407 } 00408 00409 itsGeonsParticles[0].geonType = CIRCLE; 00410 itsGeonsParticles[0].weight = 1.0/double(itsGeonsParticles.size()); 00411 itsGeonsParticles[0].prob = 0; 00412 00413 } 00414 00415 // ###################################################################### 00416 void V4::onSimEventSaveOutput(SimEventQueue& q, rutz::shared_ptr<SimEventSaveOutput>& e) 00417 { 00418 if (itsShowDebug.getVal()) 00419 { 00420 // get the OFS to save to, assuming sinfo is of type 00421 // SimModuleSaveInfo (will throw a fatal exception otherwise): 00422 nub::ref<FrameOstream> ofs = 00423 dynamic_cast<const SimModuleSaveInfo&>(e->sinfo()).ofs; 00424 Layout<PixRGB<byte> > disp = getDebugImage(); 00425 ofs->writeRgbLayout(disp, "V4", FrameInfo("V4", SRC_POS)); 00426 // ofs->writeRGB(itsDebugImg, "V4Debug", FrameInfo("V4Debug", SRC_POS)); 00427 00428 } 00429 } 00430 00431 00432 // ###################################################################### 00433 void V4::setInput(const std::vector<V1::EdgeState> &edgesState) 00434 { 00435 00436 itsHashedEdgesState.clear(); 00437 for(uint i=0; i<edgesState.size(); i++) 00438 { 00439 int key = edgesState[i].pos.i + 320*edgesState[i].pos.j; 00440 itsHashedEdgesState[key] = edgesState[i]; 00441 } 00442 } 00443 00444 // ###################################################################### 00445 void V4::setInput(const std::vector<V4d::NAFState> &nafStates) 00446 { 00447 itsNAFParticles = nafStates; 00448 00449 evolve(); 00450 } 00451 00452 00453 00454 // ###################################################################### 00455 void V4::evolve() 00456 { 00457 00458 ////Resample 00459 //resampleParticles2(itsGeonsParticles); 00460 proposeParticles(itsGeonsParticles, 0.0F); 00461 00462 //////Evaluate the particles; 00463 evaluateGeonParticles(itsGeonsParticles); 00464 00465 } 00466 00467 // ###################################################################### 00468 std::vector<V4d::NAFState> V4::getBias() 00469 { 00470 std::vector<V4d::NAFState> bias; 00471 double totalProb = 0; 00472 for(uint p=0; p<itsGeonsParticles.size(); p++) 00473 { 00474 00475 if (itsGeonsParticles[p].prob > 0) 00476 { 00477 Point2D<int> loc = (Point2D<int>)itsCamera.project(itsGeonsParticles[p].pos); 00478 float rot = itsGeonsParticles[p].rot + M_PI; 00479 GeonOutline geonOutline = itsGeons[itsGeonsParticles[p].geonType]; 00480 00481 for(uint rIdx = 0; rIdx < geonOutline.rTable.size(); rIdx++) 00482 { 00483 float ang = rot; 00484 float a0 = loc.i - (geonOutline.rTable[rIdx].loc.i*cos(ang) - geonOutline.rTable[rIdx].loc.j*sin(ang)); 00485 float b0 = loc.j - (geonOutline.rTable[rIdx].loc.i*sin(ang) + geonOutline.rTable[rIdx].loc.j*cos(ang)); 00486 00487 V4d::NAFState nafState; 00488 nafState.pos = itsCamera.inverseProjection(Point2D<float>(a0,b0), itsObjectsDist); 00489 nafState.rot = rot + geonOutline.rTable[rIdx].rot + M_PI; 00490 nafState.featureType = geonOutline.rTable[rIdx].featureType; 00491 nafState.prob = itsGeonsParticles[p].prob; 00492 totalProb += nafState.prob; 00493 00494 while (nafState.rot < 0) 00495 nafState.rot += M_PI*2; 00496 while(nafState.rot > M_PI*2) 00497 nafState.rot -= M_PI*2; 00498 00499 bias.push_back(nafState); 00500 } 00501 } 00502 } 00503 00504 for(uint i=0; i<bias.size(); i++) 00505 bias[i].prob /= totalProb; 00506 00507 return bias; 00508 00509 } 00510 00511 // ###################################################################### 00512 float V4::evaluateGeonParticles(std::vector<GeonState>& geonParticles) 00513 { 00514 00515 LINFO("Evaluate particles"); 00516 for(uint p=0; p<geonParticles.size(); p++) 00517 getGeonLikelihood(geonParticles[p]); 00518 //getOutlineLikelihood(geonParticles[p]); 00519 00520 //Normalize the particles; 00521 double sum = 0; 00522 double Neff = 0; //Number of efictive particles 00523 for(uint i=0; i<geonParticles.size(); i++) 00524 sum += geonParticles[i].prob; 00525 00526 for(uint i=0; i<geonParticles.size(); i++) 00527 { 00528 geonParticles[i].weight = geonParticles[i].prob/sum; 00529 Neff += squareOf(geonParticles[i].weight); 00530 } 00531 00532 Neff = 1/Neff; 00533 00534 return Neff; 00535 00536 } 00537 00538 00539 void V4::GHT(std::vector<V4::GHTAcc>& accRet, GeonOutline &geonOutline) 00540 { 00541 ImageSet<float> acc(360, Dims(320,240), ZEROS); 00542 00543 CpuTimer timer; 00544 timer.reset(); 00545 00546 //Parallel votes 00547 std::vector<rutz::shared_ptr<GHTJob> > jobs; 00548 00549 for(int angIdx = 0; angIdx < 360; angIdx++) 00550 { 00551 jobs.push_back(rutz::make_shared(new GHTJob(this, acc[angIdx], angIdx, geonOutline.rTable))); 00552 itsThreadServer->enqueueJob(jobs.back()); 00553 //voteForFeature(acc[angIdx], angIdx, geonOutline.rTable); 00554 } 00555 ////wait for jobs to finish 00556 while(itsThreadServer->size() > 0) 00557 usleep(10000); 00558 00559 timer.mark(); 00560 LINFO("Total time %0.2f sec", timer.real_secs()); 00561 00562 00563 //Image<float> tmp(320, 240, ZEROS); 00564 //for(uint angIdx=0; angIdx<acc.size(); angIdx++) 00565 //{ 00566 // for(uint i=0; i<acc[angIdx].size(); i++) 00567 // { 00568 // if (acc[angIdx].getVal(i) > tmp.getVal(i)) 00569 // tmp.setVal(i, acc[angIdx].getVal(i)); 00570 // } 00571 //} 00572 //SHOWIMG(tmp); 00573 00574 00575 for(uint rot=0; rot<acc.size(); rot++) 00576 for(int y=0; y<acc[rot].getHeight(); y++) 00577 for(int x=0; x<acc[rot].getWidth(); x++) 00578 if (acc[rot].getVal(x,y) > 0) 00579 { 00580 GHTAcc ghtAcc; 00581 ghtAcc.geonType = geonOutline.geonType; 00582 ghtAcc.pos = Point2D<int>(x,y); 00583 ghtAcc.ang = rot; 00584 ghtAcc.scale = -1; 00585 ghtAcc.sum = acc[rot].getVal(x,y); 00586 accRet.push_back(ghtAcc); 00587 } 00588 00589 } 00590 00591 void V4::voteForFeature(Image<float>& acc, int angIdx, std::vector<RTableEntry>& rTable) 00592 { 00593 00594 00595 for(uint p=0; p < itsNAFParticles.size(); p++) 00596 { 00597 V4d::NAFState nafState = itsNAFParticles[p]; 00598 if (nafState.prob > 0) 00599 { 00600 Point2D<int> loc = (Point2D<int>)itsCamera.project(nafState.pos); 00601 00602 // std::vector<Point2D<int> > outline = itsV4dCells.getImageOutline(nafState); 00603 // for(uint i=0; i<outline.size()-1; i++) 00604 // drawLine(tmp, outline[i], outline[i+1], 1.0F, 1); 00605 00606 for(uint rIdx = 0; rIdx < rTable.size(); rIdx++) 00607 { 00608 if (rTable[rIdx].featureType == nafState.featureType) 00609 { 00610 //LINFO("Next feature"); 00611 float ang = angIdx * M_PI/180; 00612 00613 float featureAng = rTable[rIdx].rot + ang; 00614 if (featureAng < 0) 00615 featureAng += M_PI*2; 00616 if (featureAng > M_PI*2) 00617 featureAng -= M_PI*2; 00618 00619 float diffRot = acos(cos(nafState.rot - featureAng)); 00620 00621 00622 00623 //float diffRot = nafState.rot - (rTable[rIdx].rot - ang); 00624 //diffRot = atan(sin(diffRot)/cos(diffRot)); //wrap to 180 deg to 0 00625 00626 float stddevRot = 1.5; 00627 int sizeRot = int(ceil(stddevRot * sqrt(-2.0F * log(exp(-5.0F))))); 00628 00629 if (fabs(diffRot) < sizeRot*M_PI/180) //TODO change to a for loop with hash 00630 { 00631 float rRot = exp(-((diffRot*diffRot)/(stddevRot*stddevRot))); 00632 00633 //Apply a variance over position and angle 00634 //TODO change to a veriance in feature position, not its endpoint 00635 float stddevX = 1.5; 00636 float stddevY = 1.5; 00637 int sizeX = int(ceil(stddevX * sqrt(-2.0F * log(exp(-5.0F))))); 00638 int sizeY = int(ceil(stddevY * sqrt(-2.0F * log(exp(-5.0F))))); 00639 00640 for(int y=loc.j-sizeY; y<loc.j+sizeY; y++) 00641 { 00642 float diffY = y-loc.j; 00643 float ry = exp(-((diffY*diffY)/(stddevY*stddevY))); 00644 for(int x=loc.i-sizeX; x<loc.i+sizeX; x++) 00645 { 00646 float diffX = x-loc.i; 00647 float rx = exp(-((diffX*diffX)/(stddevX*stddevX))); 00648 //float weight = nafState.prob + rRot*rx*ry; 00649 float weight = rRot*rx*ry; 00650 00651 int a0 = x - int(rTable[rIdx].loc.i*cos(ang) - rTable[rIdx].loc.j*sin(ang)); 00652 int b0 = y - int(rTable[rIdx].loc.i*sin(ang) + rTable[rIdx].loc.j*cos(ang)); 00653 if (acc.coordsOk(a0, b0)) 00654 { 00655 float val = acc.getVal(a0, b0); 00656 val += weight; 00657 acc.setVal(a0, b0, val); 00658 } 00659 } 00660 } 00661 } 00662 } 00663 } 00664 } 00665 } 00666 } 00667 00668 Image<PixRGB<byte> > V4::showParticles(const std::vector<GeonState>& particles) 00669 { 00670 Image<float> probImg(320,240, ZEROS); 00671 Image<PixRGB<byte> > particlesImg(probImg.getDims(),ZEROS); 00672 for(uint i=0; i<particles.size(); i++) 00673 { 00674 Point2D<int> loc = (Point2D<int>)itsCamera.project(particles[i].pos); 00675 if (particlesImg.coordsOk(loc) && 00676 particles[i].weight > probImg.getVal(loc) ) 00677 { 00678 PixRGB<byte> col; 00679 if (particles[i].geonType == SQUARE) 00680 col = PixRGB<byte>(0, 255, 0); 00681 else 00682 col = PixRGB<byte>(255, 0, 0); 00683 probImg.setVal(loc, particles[i].weight); 00684 00685 particlesImg.setVal(loc, col); 00686 } 00687 } 00688 inplaceNormalize(probImg, 0.0F, 255.0F); 00689 00690 particlesImg *= probImg; 00691 00692 return particlesImg; 00693 } 00694 00695 void V4::proposeParticles(std::vector<GeonState>& particles, const double Neff) 00696 { 00697 00698 LINFO("Propose Particles"); 00699 //SEt the veriance to the number of effective particles 00700 //Basicly we always want all the particles to cover the space with 00701 //some probability 00702 //double posVar = 10*Neff/geonParticles.size(); 00703 // LINFO("NEff %0.2f %lu", 00704 // Neff, geonParticles.size()); 00705 // 00706 float probThresh = 1.0e-10; 00707 00708 //If we have good hypothisis then just adjest them 00709 uint particlesAboveProb = 0; 00710 for(uint i=0; i<particles.size(); i++) 00711 { 00712 if (particles[i].prob > probThresh) 00713 { 00714 particles[i].pos.x += randomDoubleFromNormal(1.0); 00715 particles[i].pos.y += randomDoubleFromNormal(1.0); 00716 particles[i].pos.z = itsObjectsDist + randomDoubleFromNormal(0.05); 00717 particles[i].rot += randomDoubleFromNormal(1)*M_PI/180; 00718 particles[i].weight = 1.0/(float)particles.size(); 00719 particlesAboveProb++; 00720 } 00721 } 00722 00723 //LINFO("Particles Above prob %i/%lu", 00724 // particlesAboveProb, particles.size()); 00725 00726 if (particlesAboveProb < particles.size()) 00727 { 00728 LINFO("GHT "); 00729 std::vector<GHTAcc> acc; 00730 GHT(acc, itsGeons[TRIANGLE]); 00731 GHT(acc, itsGeons[SQUARE]); 00732 GHT(acc, itsGeons[CIRCLE]); 00733 LINFO("GHT Done "); 00734 00735 if (acc.size() == 0) 00736 return; 00737 ////Normalize to values from 0 to 1 00738 normalizeAcc(acc); 00739 00740 //Image<float> tmp(320,240,ZEROS); 00741 //for(uint i=0; i<acc.size(); i++) 00742 //{ 00743 // if (acc[i].sum > tmp.getVal(acc[i].pos)) 00744 // tmp.setVal(acc[i].pos, acc[i].sum); 00745 //} 00746 //SHOWIMG(tmp); 00747 00748 std::priority_queue <GHTAcc> pAcc; 00749 for(uint i=0; i<acc.size(); i++) 00750 pAcc.push(acc[i]); 00751 00752 ////Sample from acc 00753 for(uint i=0; i<particles.size(); i++) 00754 { 00755 if (particles[i].prob <= probThresh) 00756 { 00757 //add this point to the list 00758 if (pAcc.empty()) 00759 break; 00760 GHTAcc p = pAcc.top(); pAcc.pop(); 00761 00762 Point3D<float> iPoint = itsCamera.inverseProjection(Point2D<float>(p.pos), itsObjectsDist); 00763 particles[i].pos.x = iPoint.x + randomDoubleFromNormal(1); 00764 particles[i].pos.y = iPoint.y + randomDoubleFromNormal(1); 00765 particles[i].pos.z = itsObjectsDist + randomDoubleFromNormal(0.05); 00766 particles[i].rot = (p.ang + randomDoubleFromNormal(1))*M_PI/180; 00767 particles[i].geonType = p.geonType; 00768 particles[i].weight = 1.0/(float)particles.size(); 00769 particles[i].prob = 1.0e-50; 00770 } 00771 } 00772 } 00773 } 00774 00775 void V4::normalizeAcc(std::vector<GHTAcc>& acc) 00776 { 00777 00778 double sum = 0; 00779 for(uint i=0; i<acc.size(); i++) 00780 sum += acc[i].sum; 00781 00782 for(uint i=0; i<acc.size(); i++) 00783 acc[i].sum /= sum; 00784 } 00785 00786 void V4::resampleParticles2(std::vector<GeonState>& particles) 00787 { 00788 std::vector<GeonState> newParticles; 00789 00790 while(newParticles.size() < particles.size()) 00791 { 00792 //Find max 00793 int maxP = 0; double maxVal = particles[maxP].weight; 00794 for(uint j=1; j<particles.size(); j++) 00795 { 00796 if (particles[j].weight > maxVal) 00797 { 00798 maxP = j; 00799 maxVal = particles[j].weight; 00800 } 00801 } 00802 00803 if (maxVal > 0) 00804 { 00805 for(int np=0; np<10; np++) 00806 { 00807 //Add the particle to the list 00808 GeonState p = particles[maxP]; 00809 p.weight = 1.0/double(particles.size()); 00810 newParticles.push_back(p); 00811 } 00812 00813 //IOR 00814 float sigmaX = 0.1, sigmaY = 0.1; 00815 float fac = 0.5f / (M_PI * sigmaX * sigmaY); 00816 float vx = -0.5f / (sigmaX * sigmaX); 00817 float vy = -0.5f / (sigmaY * sigmaY); 00818 00819 for(uint j=0; j<particles.size(); j++) 00820 { 00821 float x = particles[j].pos.x; 00822 float y = particles[j].pos.y; 00823 00824 float vydy2 = y - particles[maxP].pos.y; vydy2 *= vydy2 * vy; 00825 float dx2 = x - particles[maxP].pos.x; dx2 *= dx2; 00826 particles[j].weight -= particles[j].weight * fac*expf(vx * dx2 + vydy2); 00827 if (particles[j].weight < 0) 00828 particles[j].weight = 0; 00829 00830 } 00831 particles[maxP].weight = 0; 00832 } else { 00833 GeonState p = particles[0]; 00834 p.weight = 1.0/double(particles.size()); 00835 newParticles.push_back(p); 00836 } 00837 00838 } 00839 00840 particles = newParticles; 00841 00842 } 00843 00844 void V4::resampleParticles(std::vector<GeonState>& geonParticles) 00845 { 00846 LINFO("Resample"); 00847 00848 std::vector<GeonState> newParticles; 00849 00850 //Calculate a Cumulative Distribution Function for our particle weights 00851 std::vector<double> CDF; 00852 CDF.resize(geonParticles.size()); 00853 00854 CDF.at(0) = geonParticles.at(0).weight; 00855 for(uint i=1; i<CDF.size(); i++) 00856 CDF.at(i) = CDF.at(i-1) + geonParticles.at(i).weight; 00857 00858 uint i = 0; 00859 double u = randomDouble()* 1.0/double(geonParticles.size()); 00860 00861 for(uint j=0; j < geonParticles.size(); j++) 00862 { 00863 while(u > CDF.at(i)) 00864 i++; 00865 00866 GeonState p = geonParticles.at(i); 00867 p.weight = 1.0/double(geonParticles.size()); 00868 newParticles.push_back(p); 00869 00870 u += 1.0/double(geonParticles.size()); 00871 } 00872 00873 geonParticles = newParticles; 00874 00875 } 00876 00877 std::vector<Point2D<int> > V4::getImageGeonOutline(GeonState& geon) 00878 { 00879 00880 GeonOutline cameraOutline = itsGeons[geon.geonType]; 00881 00882 //Transofrm the object relative to the camera 00883 for(uint i=0; i<itsGeons[geon.geonType].outline.size(); i++) 00884 { 00885 float x = itsGeons[geon.geonType].outline[i].x; 00886 float y = itsGeons[geon.geonType].outline[i].y; 00887 float z = itsGeons[geon.geonType].outline[i].z; 00888 cameraOutline.outline[i].x = (cos(geon.rot)*x - sin(geon.rot)*y) + geon.pos.x; 00889 cameraOutline.outline[i].y = (sin(geon.rot)*x + cos(geon.rot)*y) + geon.pos.y; 00890 cameraOutline.outline[i].z = z + geon.pos.z; 00891 } 00892 00893 //Project the object to camera cordinats 00894 std::vector<Point2D<int> > outline; 00895 for(uint i=0; i<cameraOutline.outline.size(); i++) 00896 { 00897 Point2D<float> loc = itsCamera.project(cameraOutline.outline[i]); 00898 outline.push_back(Point2D<int>(loc)); 00899 } 00900 00901 return outline; 00902 00903 } 00904 00905 00906 void V4::getOutlineLikelihood(GeonState& geon) 00907 { 00908 00909 //Transofrm the object position relative to the camera 00910 std::vector<Point2D<int> > geonOutline = getImageGeonOutline(geon); 00911 00912 double totalProb = 1; //.0e-5; 00913 for(uint i=0; i<geonOutline.size(); i++) 00914 { 00915 Point2D<int> pLoc1 = geonOutline[i]; 00916 Point2D<int> pLoc2 = geonOutline[(i+1)%geonOutline.size()]; 00917 double prob = getLineProbability(pLoc1, pLoc2); 00918 totalProb *= prob; 00919 } 00920 geon.prob = totalProb; 00921 } 00922 00923 00924 void V4::getGeonLikelihood(GeonState& geon) 00925 { 00926 double totalProb = 1; 00927 Point2D<int> loc = (Point2D<int>)itsCamera.project(geon.pos); 00928 float rot = geon.rot + M_PI; 00929 GeonOutline geonOutline = itsGeons[geon.geonType]; 00930 00931 //Image<float> tmp(320,240,ZEROS); 00932 00933 for(uint rIdx = 0; rIdx < geonOutline.rTable.size(); rIdx++) 00934 { 00935 float ang = rot; 00936 float a0 = loc.i - (geonOutline.rTable[rIdx].loc.i*cos(ang) - geonOutline.rTable[rIdx].loc.j*sin(ang)); 00937 float b0 = loc.j - (geonOutline.rTable[rIdx].loc.i*sin(ang) + geonOutline.rTable[rIdx].loc.j*cos(ang)); 00938 00939 V4d::NAFState nafState; 00940 nafState.pos = itsCamera.inverseProjection(Point2D<float>(a0,b0), itsObjectsDist); 00941 nafState.rot = rot + geonOutline.rTable[rIdx].rot + M_PI; 00942 nafState.featureType = geonOutline.rTable[rIdx].featureType; 00943 nafState.prob = -1; 00944 00945 while (nafState.rot < 0) 00946 nafState.rot += M_PI*2; 00947 while(nafState.rot > M_PI*2) 00948 nafState.rot -= M_PI*2; 00949 00950 //Find the closest naf 00951 int nearPart = 0; 00952 float partDist = 1.0e100; 00953 for(uint i=0; i<itsNAFParticles.size(); i++) 00954 { 00955 if (itsNAFParticles[i].prob > 0) 00956 { 00957 float distance = nafState.distance(itsNAFParticles[i]); 00958 if (distance < partDist) 00959 { 00960 partDist = distance; 00961 nearPart = i; 00962 } 00963 } 00964 } 00965 00966 float sig = 0.75F; 00967 00968 // float prob = itsNAFParticles[nearPart].prob*(1.0F/(sig*sqrt(2*M_PI))*exp(-0.5*squareOf(partDist)/squareOf(sig))); 00969 float prob = (1.0F/(sig*sqrt(2*M_PI))*exp(-0.5*squareOf(partDist)/squareOf(sig))); 00970 totalProb *= prob; 00971 00972 // LINFO("Near %f,%f,%f rot %f type %i", 00973 // itsNAFParticles[nearPart].pos.x - geon.pos.x, 00974 // itsNAFParticles[nearPart].pos.y - geon.pos.y, 00975 // itsNAFParticles[nearPart].pos.z - geon.pos.z, 00976 // itsNAFParticles[nearPart].rot, 00977 // itsNAFParticles[nearPart].featureType); 00978 // LINFO("Dist %f prob %e", partDist, prob); 00979 // 00980 // if (tmp.coordsOk(a0,b0)) 00981 // tmp.setVal(Point2D<int>(a0,b0), 1.0F); 00982 // 00983 // Point2D<int> loc = (Point2D<int>)itsCamera.project(itsNAFParticles[nearPart].pos); 00984 // drawLine(tmp, loc, itsNAFParticles[nearPart].rot, 5.0F, 1.0F); 00985 00986 00987 } 00988 // LINFO("Total prob %e", totalProb); 00989 // 00990 // inplaceNormalize(tmp, 0.0F, 255.0F); 00991 // itsDebugImg = toRGB(tmp); 00992 00993 geon.prob = totalProb; 00994 00995 00996 } 00997 00998 00999 double V4::getLineProbability(const Point2D<int>& p1, const Point2D<int>& p2) 01000 { 01001 01002 int dx = p2.i - p1.i, ax = abs(dx) << 1, sx = signOf(dx); 01003 int dy = p2.j - p1.j, ay = abs(dy) << 1, sy = signOf(dy); 01004 int x = p1.i, y = p1.j; 01005 01006 const int w = 320; 01007 01008 double prob = 1; //1.0e-5; 01009 01010 int wSize = 1; 01011 if (ax > ay) 01012 { 01013 int d = ay - (ax >> 1); 01014 for (;;) 01015 { 01016 //search for a max edge prob in a window 01017 float maxProb = 1.0e-20; 01018 for(int yy = y-wSize; yy < y+wSize; yy++) 01019 for(int xx = x-wSize; xx < x+wSize; xx++) 01020 { 01021 int key = xx + w * yy; 01022 if (key > 0) 01023 { 01024 dense_hash_map<int, V1::EdgeState>::const_iterator iter = itsHashedEdgesState.find(key); 01025 if (iter != itsHashedEdgesState.end()) 01026 { 01027 if (iter->second.prob > maxProb) 01028 maxProb = iter->second.prob; 01029 } 01030 } 01031 } 01032 //if (maxProb == 0) return 0; 01033 prob *= maxProb; 01034 01035 if (x == p2.i) return prob; 01036 if (d >= 0) { y += sy; d -= ax; } 01037 x += sx; d += ay; 01038 } 01039 } else { 01040 int d = ax - (ay >> 1); 01041 for (;;) 01042 { 01043 float maxProb = 1.0e-20; 01044 for(int yy = y-wSize; yy < y+wSize; yy++) 01045 for(int xx = x-wSize; xx < x+wSize; xx++) 01046 { 01047 int key = xx + w * yy; 01048 if (key > 0) 01049 { 01050 dense_hash_map<int, V1::EdgeState>::const_iterator iter = itsHashedEdgesState.find(key); 01051 if (iter != itsHashedEdgesState.end()) 01052 { 01053 if (iter->second.prob > maxProb) 01054 maxProb = iter->second.prob; 01055 } 01056 } 01057 } 01058 prob *= maxProb; 01059 //if (maxProb == 0) return 0; 01060 if (y == p2.j) return prob; 01061 01062 if (d >= 0) { x += sx; d -= ay; } 01063 y += sy; d += ax; 01064 } 01065 } 01066 01067 return prob; 01068 01069 01070 } 01071 01072 Layout<PixRGB<byte> > V4::getDebugImage() 01073 { 01074 Layout<PixRGB<byte> > outDisp; 01075 01076 //Show the gabor states 01077 Image<float> perc(320,240, ZEROS); 01078 01079 //Draw the edges 01080 dense_hash_map<int, V1::EdgeState>::const_iterator iter; 01081 for(iter = itsHashedEdgesState.begin(); iter != itsHashedEdgesState.end(); iter++) 01082 perc.setVal(iter->second.pos, iter->second.prob); 01083 01084 inplaceNormalize(perc, 0.0F, 255.0F); 01085 01086 Image<PixRGB<byte> > geonDisp = toRGB(Image<byte>(perc)); 01087 01088 //inplace normalize 01089 //Get min max 01090 //float minVal = itsGeonsParticles[0].prob; 01091 //float maxVal = itsGeonsParticles[0].prob; 01092 //for(uint p=0; p<itsGeonsParticles.size(); p++) 01093 //{ 01094 // if (itsGeonsParticles[p].prob < minVal) 01095 // minVal = itsGeonsParticles[p].prob; 01096 // if (itsGeonsParticles[p].prob > maxVal) 01097 // maxVal = itsGeonsParticles[p].prob; 01098 //} 01099 01100 01101 //float scale = maxVal - minVal; 01102 //float nScale = (255.0F - 0.0F)/scale; 01103 01104 for(uint p=0; p<itsGeonsParticles.size(); p++) 01105 { 01106 //set the color to the probability 01107 //float normProb = 0.0F + ((itsGeonsParticles[p].prob - minVal) * nScale); 01108 //if (normProb > 0) //itsGeonsParticles[p].prob > 0) 01109 if (itsGeonsParticles[p].prob > 0) 01110 { 01111 float normProb = 255.0; 01112 PixRGB<byte> col; 01113 if (itsGeonsParticles[p].geonType == TRIANGLE) 01114 col = PixRGB<byte>(0,int(normProb),0); 01115 else if (itsGeonsParticles[p].geonType == SQUARE) 01116 col = PixRGB<byte>(int(normProb),0,0); 01117 else 01118 col = PixRGB<byte>(0,0,int(normProb)); 01119 01120 if (itsGeonsParticles[p].geonType == CIRCLE) 01121 { 01122 Point2D<float> loc = itsCamera.project(itsGeonsParticles[p].pos); 01123 drawCircle(geonDisp, Point2D<int>(loc), 20, col); 01124 } else { 01125 std::vector<Point2D<int> > outline = getImageGeonOutline(itsGeonsParticles[p]); 01126 for(uint i=0; i<outline.size(); i++) 01127 drawLine(geonDisp, outline[i], outline[(i+1)%outline.size()], col, 1); 01128 } 01129 } 01130 } 01131 01132 01133 //Show the normalized particles 01134 Image<PixRGB<byte> > particlesImg = showParticles(itsGeonsParticles); 01135 01136 char msg[255]; 01137 sprintf(msg, "V4"); 01138 writeText(geonDisp, Point2D<int>(0,0), msg, PixRGB<byte>(255,255,255), PixRGB<byte>(0,0,0)); 01139 01140 outDisp = hcat(geonDisp, particlesImg); 01141 01142 return outDisp; 01143 01144 } 01145 01146 // ###################################################################### 01147 /* So things look consistent in everyone's emacs... */ 01148 /* Local Variables: */ 01149 /* indent-tabs-mode: nil */ 01150 /* End: */ 01151 01152 #endif 01153