00001 #include "ShapeSensorModel.h"
00002
00003 #include "Motion/Kinematics.h"
00004 #include "Shared/Config.h"
00005 #include "DualCoding/VRmixin.h"
00006 #include "ShapeLandmarks.h"
00007
00008 #include <cmath>
00009 #include <iostream>
00010
00011 using namespace DualCoding;
00012
00013 float const LocalShapeEvaluator::maxDist = 1e10;
00014 float const LocalShapeEvaluator::stdevSq = 150*150;
00015
00016 LocalShapeEvaluator::LocalShapeEvaluator(ShapeSpace &localShS, ShapeSpace &worldShS) :
00017 localLms(), worldLms() {
00018 PfRoot::loadLms(localShS.allShapes(), false, localLms);
00019 PfRoot::loadLms(worldShS.allShapes(), true, worldLms);
00020
00021
00022 if ( localLms.size()==0 || worldLms.size()==0 ) {
00023 std::cout << "ParticleFilter::loadLms found " << localLms.size() << " local and "
00024 << worldLms.size() << " world landmarks: can't localize!" << std::endl;
00025 }
00026 }
00027
00028 void LocalShapeEvaluator::evaluate(LocalizationParticle& p) {
00029 unsigned int const nLocals = localLms.size();
00030 float particleViewX[nLocals], particleViewY[nLocals], particleViewX2[nLocals], particleViewY2[nLocals];
00031 int localMatches[nLocals];
00032 float localScores[nLocals];
00033 evaluateWorkhorse(p, nLocals, particleViewX, particleViewY, particleViewX2, particleViewY2,
00034 localMatches, localScores);
00035
00036
00037
00038 updateWeight(p, localMatches, localScores);
00039
00040 }
00041
00042 void LocalShapeEvaluator::evaluateWorkhorse
00043 (LocalizationParticle& p, const unsigned int nLocals,
00044 float particleViewX[], float particleViewY[], float particleViewX2[], float particleViewY2[],
00045 int localMatches[], float localScores[]) {
00046
00047 float const cosT = std::cos(-p.theta);
00048 float const sinT = std::sin(-p.theta);
00049 float const negSinT = -sinT;
00050
00051 for ( unsigned int indexL=0; indexL < nLocals; indexL++ ) {
00052 PfRoot &landmark = *(localLms[indexL]);
00053 particleViewX[indexL] = landmark.x * cosT + landmark.y * sinT + p.x;
00054 particleViewY[indexL] = landmark.x * negSinT + landmark.y * cosT + p.y;
00055 if ( landmark.type == lineDataType ) {
00056 const PfLine &line = static_cast<PfLine&>(landmark);
00057 particleViewX2[indexL] = line.x2 * cosT + line.y2 * sinT + p.x;
00058 particleViewY2[indexL] = line.x2 * negSinT + line.y2 * cosT + p.y;
00059 }
00060 }
00061
00062 for ( unsigned int indexL = 0; indexL < nLocals; indexL++ ) {
00063 float distsq = maxDist;
00064 localMatches[indexL] = -1;
00065 for ( unsigned int indexW=0; indexW<worldLms.size(); indexW++ ) {
00066 if ( localLms[indexL]->type == worldLms[indexW]->type &&
00067 localLms[indexL]->color == worldLms[indexW]->color ) {
00068 float const lx = particleViewX[indexL];
00069 float const ly = particleViewY[indexL];
00070 float const wx = worldLms[indexW]->x;
00071 float const wy = worldLms[indexW]->y;
00072 float tempDistsq;
00073
00074
00075 switch ( localLms[indexL]->type ) {
00076 case lineDataType: {
00077 PfLine &localLine = *static_cast<PfLine*>(localLms[indexL]);
00078 PfLine &worldLine = *static_cast<PfLine*>(worldLms[indexW]);
00079 float tempDistsq1, tempDistsq2;
00080
00081
00082
00083
00084
00085
00086 if ( (localLine.valid1 && worldLine.valid1) ||
00087 !( (lx >= std::min(worldLine.x,worldLine.x2) && lx <= std::max(worldLine.x,worldLine.x2)) ||
00088 (ly >= std::min(worldLine.y,worldLine.y2) && ly <= std::max(worldLine.y,worldLine.y2)) ) ) {
00089 tempDistsq1 = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00090 } else {
00091 float const tempDist1 = distanceFromLine(lx,ly,worldLine);
00092 tempDistsq1 = tempDist1 * tempDist1;
00093 }
00094 float const lx2 = particleViewX2[indexL];
00095 float const ly2 = particleViewY2[indexL];
00096 float const wx2 = worldLine.x2;
00097 float const wy2 = worldLine.y2;
00098 if ( (localLine.valid2 && worldLine.valid2) ||
00099 !( (lx2 >= std::min(worldLine.x,worldLine.x2) && lx2 <= std::max(worldLine.x,worldLine.x2)) ||
00100 (ly2 >= std::min(worldLine.y,worldLine.y2) && ly2 <= std::max(worldLine.y,worldLine.y2)) ) )
00101 tempDistsq2 = (lx2-wx2)*(lx2-wx2) + (ly2-wy2)*(ly2-wy2);
00102 else {
00103 float const tempDist2 = distanceFromLine(lx2,ly2,worldLine);
00104 tempDistsq2 = tempDist2 * tempDist2;
00105 }
00106 AngPi const localOrient = localLine.orientation + p.theta;
00107 AngPi odiff = worldLine.orientation - localOrient;
00108 odiff = std::min<float>(odiff, M_PI - odiff);
00109 float const odist = 500 * std::sin(odiff);
00110 float const odistsq = odist * odist;
00111 tempDistsq = tempDistsq1 + tempDistsq2 + odistsq;
00112 if ( false && tempDistsq1 <= 10000 && tempDistsq2 <= 10000 ) {
00113 std::cout << "line " << lx << "," << ly << " : " << wx << "," << wy
00114 << " end1valid=" << localLine.valid1 << ":" << worldLine.valid1
00115 << " tempDistsq1=" << tempDistsq1
00116 << " indexL:W=" << indexL << ":" << indexW << std::endl;
00117 std::cout << " " << lx2 << "," << ly2 << " : " << wx2 << "," << wy2
00118 << " end2valid=" << localLine.valid2 << ":" << worldLine.valid2
00119 << " tempDistsq2=" << tempDistsq2
00120 << " odistsq = " << odistsq << " total=" << tempDistsq << std::endl;
00121 }
00122 }
00123 break;
00124 case ellipseDataType:
00125 case blobDataType:
00126 case cylinderDataType: {
00127 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00128
00129 PfRoot &landmark = *(localLms[indexL]);
00130 AngTwoPi ltheta = atan2(landmark.y,landmark.x);
00131 float ldist = sqrt(landmark.x * landmark.x + landmark.y * landmark.y);
00132 AngTwoPi ptheta = atan2(wy-p.y,wx-p.x) - p.theta;
00133 float pdist = sqrt((wx-p.x)*(wx-p.x) + (wy-p.y)*(wy-p.y));
00134 float thetadiff = angdist(ptheta,ltheta);
00135 tempDistsq = (pdist-ldist)*(pdist-ldist) + 5000*thetadiff;
00136 if ( false && tempDistsq < 50000 )
00137 std::cout << "dists " << ldist << " " << pdist << " thetas " << ltheta << " " << ptheta
00138 << " thetadiff=" << thetadiff << " tempDistsq=" << tempDistsq << std::endl;
00139 break;
00140 }
00141 case markerDataType: {
00142 PfMarker &localMarker = *static_cast<PfMarker*>(localLms[indexL]);
00143 PfMarker &worldMarker = *static_cast<PfMarker*>(worldLms[indexW]);
00144
00145
00146 if (localMarker.data->isMatchingMarker(worldMarker.data))
00147 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00148 else
00149 continue;
00150 break;
00151 }
00152 case aprilTagDataType: {
00153 PfAprilTag &localTag = *static_cast<PfAprilTag*>(localLms[indexL]);
00154 PfAprilTag &worldTag = *static_cast<PfAprilTag*>(worldLms[indexW]);
00155
00156
00157 if ( localTag.data->getTagID() == worldTag.data->getTagID() )
00158 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00159 else
00160 continue;
00161 break;
00162 }
00163 case pointDataType:
00164
00165 tempDistsq = maxDist;
00166 break;
00167 default:
00168 std::cout << "ParticleFilter::computeMatchScore() can't match landmark type "
00169 << localLms[indexL]->type << std::endl;
00170 return;
00171 }
00172
00173
00174 if ( tempDistsq < distsq ) {
00175 distsq = tempDistsq;
00176 localMatches[indexL] = indexW;
00177 }
00178 }
00179 }
00180
00181 if ( localMatches[indexL] != -1 || ! localLms[indexL]->mobile )
00182 localScores[indexL] = distsq;
00183 }
00184 }
00185
00186 void LocalShapeEvaluator::updateWeight(LocalizationParticle &p,
00187 int const localMatches[], float const localScores[]) {
00188 for (unsigned int i=0; i < localLms.size(); i++)
00189 if ( localMatches[i] != -1 )
00190 p.weight += -localScores[i]/stdevSq;
00191 }
00192
00193 float LocalShapeEvaluator::distanceFromLine(coordinate_t x0, coordinate_t y0, PfLine &wline) {
00194 float const &x1 = wline.x;
00195 float const &y1 = wline.y;
00196 float const &x2 = wline.x2;
00197 float const &y2 = wline.y2;
00198 float const &length = wline.length;
00199 float const result = std::fabs((x2-x1)*(y1-y0) - (x1-x0)*(y2-y1)) / length;
00200 return result;
00201 }
00202
00203 bool projectShapeToCamera(const LocalizationParticle &particle, const ShapeRoot *shp, float& px, float& py)
00204 {
00205
00206
00207
00208 BaseData const &bd = shp->getData();
00209 Point worldPt = bd.getCentroid();
00210
00211
00212
00213
00214 Point localPt;
00215 worldPt.coords[0] -= particle.x;
00216 worldPt.coords[1] -= particle.y;
00217
00218 localPt.coords[0] = worldPt.coords[0] * std::cos(particle.theta) + worldPt.coords[1] * std::sin(particle.theta);
00219 localPt.coords[1] = worldPt.coords[0] * -std::sin(particle.theta) + worldPt.coords[1] * std::cos(particle.theta);
00220 localPt.coords[2] = worldPt.coords[2];
00221
00222
00223
00224 if (localPt.coords[0] < 0)
00225 return false;
00226
00227
00228 Point cameraPt(localPt);
00229 #ifdef TGT_HAS_CAMERA
00230 cameraPt.applyTransform(kine->baseToLink(CameraFrameOffset));
00231 #endif
00232
00233
00234 float camXnorm, camYnorm;
00235 config->vision.computePixel(cameraPt.coordX(), cameraPt.coordY(), cameraPt.coordZ(), camXnorm, camYnorm);
00236
00237
00238 px = (camXnorm + 1)/2*VRmixin::camSkS.getWidth();
00239 py = (camYnorm + 1)/2*VRmixin::camSkS.getHeight();
00240 return true;
00241 }
00242
00243 void CameraShapeEvaluator::computeLikelihood(LocalizationParticle &particle)
00244 {
00245
00246
00247
00248 SHAPEROOTVEC_ITERATE(cShS, cs)
00249 switch (cs->getType()) {
00250 case markerDataType : {
00251 BaseData const &bd = cs.getData();
00252
00253 fmat::Column<2> original(bd.getCentroid().coords);
00254
00255 float bestMatch = std::log(pRandom);
00256
00257
00258 SHAPEROOTVEC_ITERATE(wShS, wm)
00259
00260 if (wm->isSameTypeAs(cs)) {
00261
00262
00263 fmat::Column<2> projected;
00264 DualCoding::ShapeRoot *targetLandMark(&wm);
00265 if (projectShapeToCamera(particle, targetLandMark, projected[0], projected[1])) {
00266 float prob = std::log((1- pRandom) * (normpdf(projected[0] - original[0], xvar) *
00267 normpdf(projected[1] - original[1], yvar)) + pRandom) * alpha;
00268 if (prob > bestMatch) {
00269 bestMatch = prob;
00270 }
00271 }
00272 }
00273 END_ITERATE;
00274
00275
00276 particle.weight += bestMatch;
00277 }
00278 break;
00279 default:
00280 break;
00281 }
00282 END_ITERATE;
00283 }