00001 /*!@file BayesFilters/test-UKF.C test the filter*/ 00002 00003 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 00004 // by the 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 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00032 // $HeadURL: $ 00033 // $Id: $ 00034 00035 00036 #include "BayesFilters/UKF.H" 00037 #include "Component/ModelManager.H" 00038 #include "Raster/GenericFrame.H" 00039 #include "Image/Layout.H" 00040 #include "Image/MatrixOps.H" 00041 #include "Image/DrawOps.H" 00042 #include "Image/Point3D.H" 00043 #include "GUI/DebugWin.H" 00044 #include "Util/MathFunctions.H" 00045 #include "Media/FrameSeries.H" 00046 #include "Transport/FrameInfo.H" 00047 00048 //Create a tracker to track a particle with a position and velocity 00049 class ParticleTracker : public UKF 00050 { 00051 public: 00052 ParticleTracker() : 00053 UKF(5, 2) //Position (x,y,theta) Vel and 2 observation 00054 { 00055 00056 //Initial state 00057 itsState.setVal(0,0, 640/2); 00058 itsState.setVal(0,1, 480/2); 00059 itsState.setVal(0,2, 0); 00060 itsState.setVal(0,3, 0); 00061 itsState.setVal(0,4, 0); 00062 00063 ////Initial covariance 00064 itsSigma.setVal(0,0,150.0*150.0); //X Position 00065 itsSigma.setVal(1,1,150.0*150.0); //Y Position 00066 itsSigma.setVal(2,2,(1*M_PI/180)*(1*M_PI/180)); //Theta 00067 itsSigma.setVal(3,3,0.01*0.01); //Trans Velocity 00068 itsSigma.setVal(4,4,(1*M_PI/180)*(1*M_PI/180)); //Ang Velocity 00069 00070 00071 //Initial noise matrix 00072 double posVar=4.0; 00073 double angVar=1.0*M_PI/180; 00074 double tranVelVar=0.1; 00075 double angVelVar=0.1*M_PI/180; 00076 itsR.setVal(0,0,posVar*posVar); 00077 itsR.setVal(1,1,posVar*posVar); 00078 itsR.setVal(2,2,angVar*angVar); 00079 itsR.setVal(3,3,tranVelVar*tranVelVar); 00080 itsR.setVal(4,4,angVelVar*angVelVar); 00081 } 00082 00083 ~ParticleTracker() {}; 00084 00085 Image<double> getNextState(const Image<double>& X, int k) 00086 { 00087 double posX = X.getVal(k,0); 00088 double posY = X.getVal(k,1); 00089 double ang = X.getVal(k,2); 00090 double tranVel = X.getVal(k,3); 00091 double angVel = X.getVal(k,4); 00092 00093 Image<double> Xnew(1,itsNumStates, ZEROS); 00094 double eps = 2.22044604925031e-16; 00095 00096 double xc = posX - tranVel/(angVel+eps)*sin(ang); 00097 double yc = posY + tranVel/(angVel+eps)*cos(ang); 00098 00099 posX = xc + tranVel/(angVel+eps)*sin(ang + angVel); 00100 posY = yc - tranVel/(angVel+eps)*cos(ang + angVel); 00101 ang += angVel; 00102 00103 Xnew[0] = posX; 00104 Xnew[1] = posY; 00105 Xnew[2] = ang; 00106 Xnew[3] = tranVel; 00107 Xnew[4] = angVel; 00108 00109 return Xnew; 00110 } 00111 00112 Image<double> getObservation(const Image<double>& X, int k) 00113 { 00114 double posX = X.getVal(k,0); 00115 double posY = X.getVal(k,1); 00116 00117 00118 Image<double> zNew(1,itsNumObservations, ZEROS); 00119 zNew[0] = sqrt((posX*posX) + (posY*posY)); 00120 zNew[1] = atan2(posY,posX); 00121 return zNew; 00122 } 00123 00124 void getPosEllipse(Point2D<float>& mu, Point2D<float>& sigma) 00125 { 00126 //Set the Mean 00127 mu.i = itsState[0]; 00128 mu.j = itsState[1]; 00129 00130 //Get the 95% uncertainty region 00131 //Set the major/minor axis 00132 sigma = Point2D<float>(2*sqrt(itsSigma.getVal(0,0)), 00133 2*sqrt(itsSigma.getVal(1,1))); 00134 } 00135 00136 00137 }; 00138 00139 00140 int main(int argc, char *argv[]){ 00141 00142 ModelManager manager("Test UKF"); 00143 00144 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00145 manager.addSubComponent(ofs); 00146 00147 // Parse command-line: 00148 if (manager.parseCommandLine(argc, argv, "", 0, 0) == false) return(1); 00149 // let's get all our ModelComponent instances started: 00150 manager.start(); 00151 00152 ParticleTracker pt; //Initialize tracker with 4 states and 2 observations 00153 00154 //Simulate a moving particle with a particular velocity 00155 Image<PixRGB<byte> > worldImg(640,480,ZEROS); 00156 00157 Point3D<double> particlePosition(640/2,480/2-100,0); //Initial position 00158 00159 Point3D<double> distractorPosition(640/2,480/2-100,0); //Initial position 00160 00161 initRandomNumbersZero(); //For checking for correct values 00162 00163 Point2D<int> lastParticlePosition; 00164 Point2D<int> lastSensorPosition; 00165 Point2D<int> lastPredictedPosition; 00166 for(uint t=0; t<360; t++) 00167 { 00168 double rangeNoise = 0; //(drand48()*8.0)-4.0; 00169 double angNoise = 0; //(drand48()*4.0)- 2.0; 00170 00171 //Move the particle along a circular path 00172 00173 //Center of circle 00174 double dR = 5+rangeNoise; 00175 double dA = (2 + angNoise)*M_PI/180; 00176 double eps = 2.22044604925031e-16; 00177 double distRatio = dR/(dA+eps); 00178 double xc = particlePosition.x - distRatio*sin(particlePosition.z); 00179 double yc = particlePosition.y + distRatio*cos(particlePosition.z); 00180 00181 particlePosition.x = xc + distRatio*sin(particlePosition.z + dA); 00182 particlePosition.y = yc - distRatio*cos(particlePosition.z + dA); 00183 particlePosition.z += dA; 00184 00185 //Distractor 00186 double dDR = -5-rangeNoise; 00187 double dDA = (-2 - angNoise)*M_PI/180; 00188 double distDRatio = dDR/(dDA+eps); 00189 double xdc = distractorPosition.x - distDRatio*sin(distractorPosition.z); 00190 double ydc = distractorPosition.y + distDRatio*cos(distractorPosition.z); 00191 00192 distractorPosition.x = xdc + distDRatio*sin(distractorPosition.z + dDA); 00193 distractorPosition.y = ydc - distDRatio*cos(distractorPosition.z + dDA); 00194 distractorPosition.z += dDA; 00195 00196 //Set the Sensor noise 00197 double zrn=10.0; 00198 double zan=5*M_PI/180; //0.5 degrees uncertainty 00199 Image<double> zNoise(2,2,ZEROS); 00200 zNoise.setVal(0,0,zrn*zrn); 00201 zNoise.setVal(1,1,zan*zan); 00202 00203 pt.predictState(); 00204 pt.predictObservation(zNoise); 00205 00206 00207 //Compute the measurements 00208 Image<double> z1(1,2,ZEROS); 00209 z1[0] = sqrt(squareOf(particlePosition.x) + squareOf(particlePosition.y)); 00210 z1[1] = atan2(particlePosition.y, particlePosition.x); 00211 00212 z1[0] += 2; //(drand48()*16.0)- 8.0; 00213 z1[1] += 2*M_PI/180; //((drand48()*5.0) - 2.5)*M_PI/180; 00214 00215 Image<double> z2(1,2,ZEROS); 00216 z2[0] = sqrt(squareOf(distractorPosition.x) + squareOf(distractorPosition.y)); 00217 z2[1] = atan2(distractorPosition.y, distractorPosition.x); 00218 00219 z2[0] += 3; //(drand48()*10.0)- 5.0; 00220 z2[1] += 3*M_PI/180; //((drand48()*3.0) - 1.5)*M_PI/180; 00221 00222 double z1Prob = pt.getLikelihood(z1, Image<double>()); 00223 double z2Prob = pt.getLikelihood(z2, Image<double>()); 00224 00225 Image<double> zUsed; 00226 if (z1Prob > 1.0e-5) 00227 zUsed=z1; 00228 if (z2Prob > 1.0e-5) 00229 zUsed=z1; 00230 00231 00232 //Store prediction for latter display 00233 Point2D<float> muP, sigmaP; 00234 pt.getPosEllipse(muP,sigmaP); 00235 00236 pt.update(zUsed, zNoise); 00237 00238 Point2D<float> mu, sigma; 00239 pt.getPosEllipse(mu,sigma); 00240 00241 LINFO("True Pos: %f,%f predicted Pos: %f,%f Likelihood: z1 = %f z2 = %f", 00242 particlePosition.x, particlePosition.y, 00243 mu.i, mu.j, 00244 z1Prob, z2Prob); 00245 00246 //Show the results 00247 Image<PixRGB<byte> > tmp = worldImg; 00248 00249 //Draw the real particle position 00250 drawCircle(tmp, Point2D<int>(particlePosition.x, particlePosition.y), 2, PixRGB<byte>(0,255,0),2); 00251 drawCircle(tmp, Point2D<int>(distractorPosition.x, distractorPosition.y), 2, PixRGB<byte>(0,255,255),2); 00252 //Show the sensor 00253 Point2D<int> sensorPos(zUsed[0]*cos(zUsed[1]), zUsed[0]*sin(zUsed[1])); 00254 drawCircle(tmp, sensorPos, 2, PixRGB<byte>(0,0,255),2); 00255 00256 //Show the predicted region 00257 drawCircle(tmp, (Point2D<int>)muP, 1, PixRGB<byte>(255,255,0), 1); 00258 if (sigmaP.i < 500 && sigmaP.j < 500) 00259 drawEllipse(tmp, (Point2D<int>)muP, sigmaP.i,sigmaP.j, PixRGB<byte>(255,255,0)); 00260 00261 drawCircle(tmp, (Point2D<int>)mu, 1, PixRGB<byte>(255,0,0), 1); 00262 if (sigma.i < 500 && sigma.j < 500) 00263 drawEllipse(tmp, (Point2D<int>)mu, sigma.i,sigma.j, PixRGB<byte>(255,0,0)); 00264 00265 00266 //Draw history traces 00267 if (!lastParticlePosition.isValid()) 00268 lastParticlePosition = Point2D<int>(particlePosition.x, particlePosition.y); 00269 drawLine(worldImg, lastParticlePosition, 00270 Point2D<int>(particlePosition.x, particlePosition.y), 00271 PixRGB<byte>(0,255,0)); 00272 lastParticlePosition = Point2D<int>(particlePosition.x, 00273 particlePosition.y); 00274 00275 if (!lastSensorPosition.isValid()) 00276 lastSensorPosition = sensorPos; 00277 drawLine(worldImg, lastSensorPosition, sensorPos, PixRGB<byte>(0,0,255)); 00278 lastSensorPosition = sensorPos; 00279 00280 if (!lastPredictedPosition.isValid()) 00281 lastPredictedPosition = (Point2D<int>)mu; 00282 drawLine(worldImg, lastPredictedPosition, (Point2D<int>)mu, PixRGB<byte>(255,0,0)); 00283 lastPredictedPosition = (Point2D<int>)mu; 00284 00285 ofs->writeRGB(tmp, "Particle Tracker", FrameInfo("Particle Tracker", SRC_POS)); 00286 usleep(100000); 00287 } 00288 00289 manager.stop(); 00290 exit(0); 00291 00292 } 00293 00294