00001
00002
00003 #include <iostream>
00004 #include <vector>
00005
00006 #include <math.h>
00007
00008 #include "BaseData.h"
00009 #include "Particle.h"
00010 #include "ParticleShapes.h"
00011 #include "ParticleFilter.h"
00012
00013 namespace DualCoding {
00014
00015 const float ParticleFilter::INITIAL_XY_NOISE;
00016 const float ParticleFilter::INITIAL_THETA_NOISE;
00017 const float ParticleFilter::NOISE_REDUCTION_XY;
00018 const float ParticleFilter::NOISE_REDUCTION_T;
00019 const float ParticleFilter::INFINITE_DISTANCE;
00020 const float ParticleFilter::STDEV;
00021 const float ParticleFilter::ADDITION_PENALTY;
00022 const float ParticleFilter::PERCENT_RANDOM;
00023
00024
00025 void ParticleFilter::reinitialize() {
00026 delete curParticles;
00027 delete newParticles;
00028 curParticles=NULL;
00029 newParticles=NULL;
00030 numParticles = NUM_PARTICLES;
00031 numParticles = NUM_PARTICLES;
00032 numGenerations = NUM_GENERATIONS;
00033 numTries = NUM_TRIES;
00034 noiseFactorXY = INITIAL_XY_NOISE;
00035 noiseFactorT = INITIAL_THETA_NOISE;
00036 worldBounds = Shape<PolygonData>();
00037 bestIndex = -1;
00038 localScores.clear();
00039 localMatches.clear();
00040 }
00041
00042 void ParticleFilter::makeParticles() {
00043 delete curParticles;
00044 delete newParticles;
00045 curParticles = new vector<Particle>(numParticles);
00046 newParticles = new vector<Particle>(numParticles);
00047 }
00048
00049 void ParticleFilter::resizeParticles() {
00050 for ( int i=0; i<numParticles; i++ ) {
00051 (*curParticles)[i].addLocal.resize(nlocal);
00052 (*newParticles)[i].addLocal.resize(nlocal);
00053 }
00054 particleViewX.resize(nlocal);
00055 particleViewY.resize(nlocal);
00056 particleViewX2.resize(nlocal);
00057 particleViewY2.resize(nlocal);
00058 localScores.resize(nlocal);
00059 localMatches.resize(nlocal);
00060 }
00061
00062 void ParticleFilter::loadLms() {
00063 PfRoot::deleteLms(localLms);
00064 PfRoot::deleteLms(worldLms);
00065 localLms = PfRoot::loadLms(localShS.allShapes(), false);
00066 worldLms = PfRoot::loadLms(worldShS.allShapes(), true);
00067 nlocal = localLms->size();
00068 nworld = worldLms->size();
00069 if ( nlocal==0 || nworld==0 ) {
00070 cout << "ParticleFilter::loadLMs found " << nlocal << " local and "
00071 << nworld << " world landmarks: can't localize!" << endl;
00072 return;
00073 }
00074
00075
00076
00077 if ( worldBounds.isValid() ) {
00078 BoundingBox b(worldBounds->getBoundingBox());
00079 xmin = b.xmin;
00080 xmax = b.xmax;
00081 ymin = b.ymin;
00082 ymax = b.ymax;
00083 }
00084 else {
00085 coordinate_t localXmin, localYmin, localXmax, localYmax;
00086 coordinate_t worldXmin, worldYmin, worldXmax, worldYmax;
00087 PfRoot::findBounds(*localLms, localXmin, localYmin, localXmax, localYmax);
00088 PfRoot::findBounds(*worldLms, worldXmin, worldYmin, worldXmax, worldYmax);
00089 const coordinate_t localMax = max(fabs(localXmin),
00090 max(fabs(localYmin),
00091 max(fabs(localXmax), fabs(localYmax))));
00092 xmin = worldXmin - localMax;
00093 xmax = worldXmax + localMax;
00094 ymin = worldYmin - localMax;
00095 ymax = worldYmax + localMax;
00096 }
00097 xrange = xmax - xmin;
00098 yrange = ymax - ymin;
00099
00100
00101 if ( curParticles == NULL ) {
00102 makeParticles();
00103 uniformlyDistribute();
00104 }
00105 if ( (int)((*curParticles)[0].addLocal.size()) != nlocal )
00106 resizeParticles();
00107 }
00108
00109 void ParticleFilter::uniformlyDistribute() {
00110
00111 loadLms();
00112 for (int i = 0; i < numParticles; i++)
00113 randomizeNewParticle(i);
00114 vector<Particle> * const oldParticles = curParticles;
00115 curParticles = newParticles;
00116 newParticles = oldParticles;
00117
00118 }
00119
00120 void ParticleFilter::randomizeNewParticle(int const i) {
00121 Particle &part = (*newParticles)[i];
00122 while (1) {
00123 part.dx = float(rand())/RAND_MAX * xrange + xmin;
00124 part.dy = float(rand())/RAND_MAX * yrange + ymin;
00125 if ( !worldBounds.isValid() ||
00126 worldBounds->isInside(Point(part.dx,part.dy)) )
00127 break;
00128 }
00129 part.theta = float(rand())/RAND_MAX * 2 * M_PI;
00130 }
00131
00132 int ParticleFilter::localize() {
00133 loadLms();
00134 if ( nlocal == 0 || nworld == 0 )
00135 return -1;
00136 getInitialGuess();
00137 noiseFactorXY = INITIAL_XY_NOISE;
00138 noiseFactorT = INITIAL_THETA_NOISE;
00139 for ( int gen = 0; gen < numGenerations; gen++ ) {
00140 resample();
00141 noiseFactorXY = noiseFactorXY * NOISE_REDUCTION_XY;
00142 noiseFactorT = noiseFactorT * NOISE_REDUCTION_T;
00143
00144
00145
00146
00147
00148
00149
00150 }
00151 return bestIndex;
00152 }
00153
00154 void ParticleFilter::moveBy(float const xdelta, float const ydelta, AngPi const tdelta) {
00155 for ( int i = 0; i<numParticles; i++ ) {
00156 Particle &part = (*curParticles)[i];
00157 part.dx += xdelta;
00158 part.dy += ydelta;
00159 part.theta = part.theta + tdelta;
00160 }
00161 computeParticleScores();
00162 }
00163
00164
00165 void ParticleFilter::getInitialGuess() {
00166 float const minAcceptableProb = pow(((double)0.3),((double)nlocal));
00167 for ( int tryCounter = 0; tryCounter < numTries; tryCounter++ ) {
00168 computeParticleScores();
00169 if ( (*curParticles)[bestIndex].prob >= minAcceptableProb )
00170 break;
00171 else
00172 uniformlyDistribute();
00173 }
00174 }
00175
00176 void ParticleFilter::computeParticleScores() {
00177 float bestProb = -1;
00178 bestIndex = -1;
00179 for ( int i = 0; i<numParticles; i++ ) {
00180 setParticleView(i);
00181 (*curParticles)[i].addLocal.assign(nlocal,false);
00182 for ( int j = 0; j<nlocal; j++ )
00183 computeLocalMatch(i,j);
00184 determineAdditions(i);
00185
00186 float s = localScores[0];
00187 for ( int j=1; j<nlocal; j++ )
00188 s *= localScores[j];
00189 (*curParticles)[i].prob = s;
00190 if ( s > bestProb ) {
00191 bestProb = s;
00192 bestIndex = i;
00193 }
00194 }
00195
00196
00197 }
00198
00199 void ParticleFilter::setParticleView(int const i) {
00200 Particle const &part = (*curParticles)[i];
00201 float const partDx = part.dx;
00202 float const partDy = part.dy;
00203 float const cosT = cos(-part.theta);
00204 float const sinT = sin(-part.theta);
00205 float const negSinT = -sinT;
00206 for ( int j=0; j < nlocal; j++ ) {
00207 PfRoot &landmark = *((*localLms)[j]);
00208 particleViewX[j] = landmark.x * cosT + landmark.y * sinT + partDx;
00209 particleViewY[j] = landmark.x * negSinT + landmark.y * cosT + partDy;
00210 if ( landmark.type == lineDataType ) {
00211 const PfLine &line = dynamic_cast<PfLine&>(landmark);
00212 particleViewX2[j] = line.x2 * cosT + line.y2 * sinT + partDx;
00213 particleViewY2[j] = line.x2 * negSinT + line.y2 * cosT + partDy;
00214 }
00215 }
00216 }
00217
00218 void ParticleFilter::computeLocalMatch (int const i, int const j) {
00219 float distsq = INFINITE_DISTANCE;
00220 int worldMatch = -1;
00221 for ( int k=0; k<nworld; k++ ) {
00222 if ( (*localLms)[j]->type == (*worldLms)[k]->type &&
00223 (*localLms)[j]->color == (*worldLms)[k]->color ) {
00224 float const lx = particleViewX[j];
00225 float const ly = particleViewY[j];
00226 float const wx = (*worldLms)[k]->x;
00227 float const wy = (*worldLms)[k]->y;
00228 float tempDistsq;
00229 switch ( (*localLms)[j]->type ) {
00230 case lineDataType: {
00231 PfLine &localLine = *dynamic_cast<PfLine*>((*localLms)[j]);
00232 PfLine &worldLine = *dynamic_cast<PfLine*>((*worldLms)[k]);
00233 float tempDistsq1, tempDistsq2;
00234
00235
00236
00237
00238
00239
00240 if ( (localLine.valid1 && worldLine.valid1) ||
00241 !( lx >= min(worldLine.x,worldLine.x2) &&
00242 lx <= max(worldLine.x,worldLine.x2) ||
00243 ly >= min(worldLine.y,worldLine.y2) &&
00244 ly <= max(worldLine.y,worldLine.y2) ) )
00245 tempDistsq1 = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00246 else {
00247 float const tempDist1 = distanceFromLine(lx,ly,worldLine);
00248 tempDistsq1 = tempDist1 * tempDist1;
00249 }
00250 float const lx2 = particleViewX2[j];
00251 float const ly2 = particleViewY2[j];
00252 float const wx2 = worldLine.x2;
00253 float const wy2 = worldLine.y2;
00254 if ( (localLine.valid2 && worldLine.valid2) ||
00255 !( lx2 >= min(worldLine.x,worldLine.x2) &&
00256 lx2 <= max(worldLine.x,worldLine.x2) ||
00257 ly2 >= min(worldLine.y,worldLine.y2) &&
00258 ly2 <= max(worldLine.y,worldLine.y2) ) )
00259 tempDistsq2 = (lx2-wx2)*(lx2-wx2) + (ly2-wy2)*(ly2-wy2);
00260 else {
00261 float const tempDist2 = distanceFromLine(lx2,ly2,worldLine);
00262 tempDistsq2 = tempDist2 * tempDist2;
00263 }
00264 AngPi const localOrient = localLine.orientation + (*curParticles)[i].theta;
00265 AngPi const odiff = worldLine.orientation - localOrient;
00266 float const odist = 500 * sin(odiff);
00267 float const odistsq = odist * odist;
00268 tempDistsq = tempDistsq1 + tempDistsq2 + odistsq;
00269 }
00270 break;
00271 case ellipseDataType:
00272 case pointDataType:
00273 case blobDataType: {
00274 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00275 break;
00276 }
00277 default:
00278 std::cout << "ParticleFilter::computeMatchScore() can't match landmark type "
00279 << (*localLms)[j]->type << std::endl;
00280 return;
00281 }
00282 if ( tempDistsq < distsq ) {
00283 distsq = tempDistsq;
00284 worldMatch = k;
00285 }
00286 }
00287 }
00288 localMatches[j] = worldMatch;
00289 if ( worldMatch == -1 ) {
00290 (*curParticles)[i].addLocal[j] = true;
00291 localScores[j] = 1.0;
00292 }
00293 else
00294 localScores[j] = normpdf(distsq);
00295 }
00296
00297 float ParticleFilter::distanceFromLine(coordinate_t x0, coordinate_t y0, PfLine &wline) {
00298 float const &x1 = wline.x;
00299 float const &y1 = wline.y;
00300 float const &x2 = wline.x2;
00301 float const &y2 = wline.y2;
00302 float const &length = wline.length;
00303 float const result = fabs((x2-x1)*(y1-y0) - (x1-x0)*(y2-y1)) / length;
00304 return result;
00305 }
00306
00307 void ParticleFilter::resample() {
00308 float const normFactor = (*curParticles)[bestIndex].prob;
00309
00310 int newParticleCount = 0;
00311 (*newParticles)[newParticleCount++] = (*curParticles)[bestIndex];
00312 while (newParticleCount < numParticles) {
00313 for ( int i=0; i<numParticles; i++ ) {
00314 float spawnChance = float(rand())/RAND_MAX;
00315 if ( spawnChance <= 0.8 * (*curParticles)[i].prob / normFactor ) {
00316 spawnInto(i, newParticleCount++);
00317 if ( newParticleCount == numParticles )
00318 break;
00319 }
00320 if ( float(rand())/RAND_MAX < PERCENT_RANDOM ) {
00321 randomizeNewParticle(newParticleCount++);
00322 if ( newParticleCount == numParticles )
00323 break;
00324 }
00325 }
00326 }
00327 vector<Particle> * const oldParticles = curParticles;
00328 curParticles = newParticles;
00329 newParticles = oldParticles;
00330 computeParticleScores();
00331 }
00332
00333 void ParticleFilter::spawnInto(int const i, int const j) {
00334 Particle &parent = (*curParticles)[i];
00335 Particle &spawned = (*newParticles)[j];
00336
00337 while (1) {
00338 float const xRand = 2*float(rand())/RAND_MAX - 1;
00339 float const yRand = 2*float(rand())/RAND_MAX - 1;
00340 spawned.dx = parent.dx + xRand * noiseFactorXY;
00341 spawned.dy = parent.dy + yRand * noiseFactorXY;
00342 if ( !worldBounds.isValid() ||
00343 worldBounds->isInside(Point(spawned.dx, spawned.dy)) ) {
00344 float const tRand = 2*float(rand())/RAND_MAX - 1;
00345 spawned.theta = parent.theta + AngTwoPi(tRand * noiseFactorT);
00346 break;
00347 }
00348 }
00349 }
00350
00351 void ParticleFilter::determineAdditions(int const i) {
00352 Particle &part = (*curParticles)[i];
00353 for (int j = 0; j<nlocal; j++) {
00354 float const randval = float(rand()) / (RAND_MAX*6);
00355 if (randval >= localScores[j]) {
00356 part.addLocal[j] = true;
00357 localScores[j] = ADDITION_PENALTY;
00358 localMatches[j] = -1;
00359 }
00360 else
00361 for (int j2 = (j+1); j2<nlocal; j2++)
00362 if (localMatches[j2] == localMatches[j] && localMatches[j2] != -1)
00363 if (localScores[j2] > localScores[j]) {
00364 part.addLocal[j] = true;
00365 localScores[j] = ADDITION_PENALTY;
00366 localMatches[j] = -1;
00367 } else {
00368 part.addLocal[j2] = true;
00369 localScores[j2] = ADDITION_PENALTY;
00370 localMatches[j2] = -1;
00371 }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 }