V4.C

Go to the documentation of this file.
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 
Generated on Sun May 8 08:05:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3