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 = 60*60;
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 std::cout << "LocalShapeEvaluator: " << localShS.allShapes().size() << " local shapes, "
00021 << worldShS.allShapes().size() << " world shapes " << std::endl;
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 for ( unsigned int indexL=0; indexL < nLocals; indexL++ ) {
00051 PfRoot &landmark = *(localLms[indexL]);
00052 particleViewX[indexL] = landmark.x * cosT + landmark.y * sinT + p.x;
00053 particleViewY[indexL] = landmark.x * negSinT + landmark.y * cosT + p.y;
00054 if ( landmark.type == lineDataType ) {
00055 const PfLine &line = static_cast<PfLine&>(landmark);
00056 particleViewX2[indexL] = line.x2 * cosT + line.y2 * sinT + p.x;
00057 particleViewY2[indexL] = line.x2 * negSinT + line.y2 * cosT + p.y;
00058 }
00059 }
00060
00061 for ( unsigned int indexL = 0; indexL < nLocals; indexL++ ) {
00062 float distsq = maxDist;
00063 localMatches[indexL] = -1;
00064 for ( unsigned int indexW=0; indexW<worldLms.size(); indexW++ ) {
00065 if ( localLms[indexL]->type == worldLms[indexW]->type &&
00066 localLms[indexL]->color == worldLms[indexW]->color ) {
00067 float const lx = particleViewX[indexL];
00068 float const ly = particleViewY[indexL];
00069 float const wx = worldLms[indexW]->x;
00070 float const wy = worldLms[indexW]->y;
00071 float tempDistsq;
00072
00073
00074 switch ( localLms[indexL]->type ) {
00075 case lineDataType: {
00076 PfLine &localLine = *static_cast<PfLine*>(localLms[indexL]);
00077 PfLine &worldLine = *static_cast<PfLine*>(worldLms[indexW]);
00078 float tempDistsq1, tempDistsq2;
00079
00080
00081
00082
00083
00084
00085 if ( (localLine.valid1 && worldLine.valid1) ||
00086 !( (lx >= std::min(worldLine.x,worldLine.x2) && lx <= std::max(worldLine.x,worldLine.x2)) ||
00087 (ly >= std::min(worldLine.y,worldLine.y2) && ly <= std::max(worldLine.y,worldLine.y2)) ) )
00088 tempDistsq1 = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00089 else {
00090 float const tempDist1 = distanceFromLine(lx,ly,worldLine);
00091 tempDistsq1 = tempDist1 * tempDist1;
00092 }
00093 float const lx2 = particleViewX2[indexL];
00094 float const ly2 = particleViewY2[indexL];
00095 float const wx2 = worldLine.x2;
00096 float const wy2 = worldLine.y2;
00097 if ( (localLine.valid2 && worldLine.valid2) ||
00098 !( (lx2 >= std::min(worldLine.x,worldLine.x2) && lx2 <= std::max(worldLine.x,worldLine.x2)) ||
00099 (ly2 >= std::min(worldLine.y,worldLine.y2) && ly2 <= std::max(worldLine.y,worldLine.y2)) ) )
00100 tempDistsq2 = (lx2-wx2)*(lx2-wx2) + (ly2-wy2)*(ly2-wy2);
00101 else {
00102 float const tempDist2 = distanceFromLine(lx2,ly2,worldLine);
00103 tempDistsq2 = tempDist2 * tempDist2;
00104 }
00105 AngPi const localOrient = localLine.orientation + p.theta;
00106 AngPi const odiff = worldLine.orientation - localOrient;
00107 float const odist = 500 * std::sin(odiff);
00108 float const odistsq = odist * odist;
00109 tempDistsq = tempDistsq1 + tempDistsq2 + odistsq;
00110 }
00111 break;
00112 case ellipseDataType:
00113 case blobDataType: {
00114 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00115 break;
00116 }
00117 case markerDataType: {
00118 PfMarker &localMarker = *static_cast<PfMarker*>(localLms[indexL]);
00119 PfMarker &worldMarker = *static_cast<PfMarker*>(worldLms[indexW]);
00120
00121
00122 if (localMarker.data->isMatchingMarker(worldMarker.data))
00123 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00124 else
00125 continue;
00126 break;
00127 }
00128 case aprilTagDataType: {
00129 PfAprilTag &localTag = *static_cast<PfAprilTag*>(localLms[indexL]);
00130 PfAprilTag &worldTag = *static_cast<PfAprilTag*>(worldLms[indexW]);
00131
00132
00133 if ( localTag.data->getTagID() == worldTag.data->getTagID() )
00134 tempDistsq = (lx-wx)*(lx-wx) + (ly-wy)*(ly-wy);
00135 else
00136 continue;
00137 break;
00138 }
00139 case pointDataType:
00140
00141 tempDistsq = maxDist;
00142 break;
00143 default:
00144 std::cout << "ParticleFilter::computeMatchScore() can't match landmark type "
00145 << localLms[indexL]->type << std::endl;
00146 return;
00147 }
00148
00149
00150 if ( tempDistsq < distsq ) {
00151 distsq = tempDistsq;
00152 localMatches[indexL] = indexW;
00153 }
00154 }
00155 }
00156
00157 if ( localMatches[indexL] != -1 || ! localLms[indexL]->mobile )
00158 localScores[indexL] = distsq;
00159 }
00160 }
00161
00162 void LocalShapeEvaluator::updateWeight(LocalizationParticle &p,
00163 int const localMatches[], float const localScores[]) {
00164 for (unsigned int i=0; i < localLms.size(); i++)
00165 if ( localMatches[i] != -1 )
00166 p.weight += -localScores[i]/stdevSq;
00167 }
00168
00169 float LocalShapeEvaluator::distanceFromLine(coordinate_t x0, coordinate_t y0, PfLine &wline) {
00170 float const &x1 = wline.x;
00171 float const &y1 = wline.y;
00172 float const &x2 = wline.x2;
00173 float const &y2 = wline.y2;
00174 float const &length = wline.length;
00175 float const result = std::fabs((x2-x1)*(y1-y0) - (x1-x0)*(y2-y1)) / length;
00176 return result;
00177 }
00178
00179 bool projectShapeToCamera(const LocalizationParticle &particle, const ShapeRoot *shp, float& px, float& py)
00180 {
00181
00182
00183
00184 BaseData const &bd = shp->getData();
00185 Point worldPt = bd.getCentroid();
00186
00187
00188
00189
00190 Point localPt;
00191 worldPt.coords[0] -= particle.x;
00192 worldPt.coords[1] -= particle.y;
00193
00194 localPt.coords[0] = worldPt.coords[0] * std::cos(particle.theta) + worldPt.coords[1] * std::sin(particle.theta);
00195 localPt.coords[1] = worldPt.coords[0] * -std::sin(particle.theta) + worldPt.coords[1] * std::cos(particle.theta);
00196 localPt.coords[2] = worldPt.coords[2];
00197
00198
00199
00200 if (localPt.coords[0] < 0)
00201 return false;
00202
00203
00204 Point cameraPt(localPt);
00205 #ifdef TGT_HAS_CAMERA
00206 cameraPt.applyTransform(kine->baseToLink(CameraFrameOffset));
00207 #endif
00208
00209
00210 float camXnorm, camYnorm;
00211 config->vision.computePixel(cameraPt.coordX(), cameraPt.coordY(), cameraPt.coordZ(), camXnorm, camYnorm);
00212
00213
00214 px = (camXnorm + 1)/2*VRmixin::camSkS.getWidth();
00215 py = (camYnorm + 1)/2*VRmixin::camSkS.getHeight();
00216 return true;
00217 }
00218
00219 void CameraShapeEvaluator::computeLikelihood(LocalizationParticle &particle)
00220 {
00221
00222
00223
00224 SHAPEROOTVEC_ITERATE(cShS, cs)
00225 switch (cs->getType()) {
00226 case markerDataType : {
00227 BaseData const &bd = cs.getData();
00228
00229 fmat::Column<2> original(bd.getCentroid().coords);
00230
00231 float bestMatch = std::log(pRandom);
00232
00233
00234 SHAPEROOTVEC_ITERATE(wShS, wm)
00235
00236 if (wm->isSameTypeAs(cs)) {
00237
00238
00239 fmat::Column<2> projected;
00240 DualCoding::ShapeRoot *targetLandMark(&wm);
00241 if (projectShapeToCamera(particle, targetLandMark, projected[0], projected[1])) {
00242 float prob = std::log((1- pRandom) * (normpdf(projected[0] - original[0], xvar) *
00243 normpdf(projected[1] - original[1], yvar)) + pRandom) * alpha;
00244 if (prob > bestMatch) {
00245 bestMatch = prob;
00246 }
00247 }
00248 }
00249 END_ITERATE;
00250
00251
00252 particle.weight += bestMatch;
00253 }
00254 break;
00255 default:
00256 break;
00257 }
00258 END_ITERATE;
00259 }