00001
00002 #include "ptam/Bundle.h"
00003 #include "ptam/MEstimator.h"
00004 #include <TooN/helpers.h>
00005 #include <TooN/Cholesky.h>
00006 #include <fstream>
00007 #include <iomanip>
00008 #//include <gvars3/instances.h>
00009
00010
00011 using namespace std;
00012
00013 #ifdef WIN32
00014 inline bool isnan(double d) {return !(d==d);}
00015 #endif
00016
00017
00018 #define cout if(defDebugBundleMessages()) cout
00019
00020 inline bool defDebugBundleMessages()
00021 {
00022 return PtamParameters::varparams().BundleDebugMessages;
00023 }
00024
00025
00026
00027
00028 inline void BundleTriangle_UpdateM6U_LL(Matrix<6> &m6U, Matrix<2,6> &m26A)
00029 {
00030 for(int r=0; r<6; r++)
00031 for(int c=0; c<=r; c++)
00032 m6U(r,c)+= m26A.T()(r,0)*m26A(0,c) + m26A.T()(r,1)*m26A(1,c);
00033 }
00034 inline void BundleTriangle_UpdateM3V_LL(Matrix<3> &m3V, Matrix<2,3> &m23B)
00035 {
00036 for(int r=0; r<3; r++)
00037 for(int c=0; c<=r; c++)
00038 m3V(r,c)+= m23B.T()(r,0)*m23B(0,c) + m23B.T()(r,1)*m23B(1,c);
00039 }
00040
00041
00042 Bundle::Bundle(const ATANCamera &TCam)
00043 : mCamera(TCam)
00044 {
00045 mnCamsToUpdate = 0;
00046 mnStartRow = 0;
00047
00048
00049
00050
00051
00052 };
00053
00054
00055 int Bundle::AddCamera(SE3<> se3CamFromWorld, bool bFixed)
00056 {
00057 int n = mvCameras.size();
00058 Camera c;
00059 c.bFixed = bFixed;
00060 c.se3CfW = se3CamFromWorld;
00061 if(!bFixed)
00062 {
00063 c.nStartRow = mnStartRow;
00064 mnStartRow += 6;
00065 mnCamsToUpdate++;
00066 }
00067 else
00068 c.nStartRow = -999999999;
00069 mvCameras.push_back(c);
00070
00071 return n;
00072 }
00073
00074
00075 int Bundle::AddPoint(Vector<3> v3Pos)
00076 {
00077 int n = mvPoints.size();
00078 Point p;
00079 if(isnan(v3Pos * v3Pos))
00080 {
00081 cerr << " You sucker, tried to give me a nan " << v3Pos << endl;
00082 v3Pos = Zeros;
00083 }
00084 p.v3Pos = v3Pos;
00085 mvPoints.push_back(p);
00086 return n;
00087 }
00088
00089
00090 void Bundle::AddMeas(int nCam, int nPoint, Vector<2> v2Pos, double dSigmaSquared)
00091 {
00092 assert(nCam < (int) mvCameras.size());
00093 assert(nPoint < (int) mvPoints.size());
00094 mvPoints[nPoint].nMeasurements++;
00095 mvPoints[nPoint].sCameras.insert(nCam);
00096 Meas m;
00097 m.p = nPoint;
00098 m.c = nCam;
00099 m.v2Found = v2Pos;
00100 m.dSqrtInvNoise = sqrt(1.0 / dSigmaSquared);
00101 mMeasList.push_back(m);
00102 }
00103
00104
00105 void Bundle::ClearAccumulators()
00106 {
00107 for(size_t i=0; i<mvPoints.size(); ++i)
00108 {
00109 mvPoints[i].m3V = Zeros;
00110 mvPoints[i].v3EpsilonB = Zeros;
00111 }
00112 for(size_t i=0; i<mvCameras.size(); ++i)
00113 {
00114 mvCameras[i].m6U = Zeros;
00115 mvCameras[i].v6EpsilonA = Zeros;
00116 }
00117 }
00118
00119
00120
00121
00122
00123
00124 int Bundle::Compute(bool *pbAbortSignal)
00125 {
00126 mpbAbortSignal = pbAbortSignal;
00127
00128
00129 GenerateMeasLUTs();
00130 GenerateOffDiagScripts();
00131
00132
00133 mdLambda = 0.0001;
00134 mdLambdaFactor = 2.0;
00135 mbConverged = false;
00136 mbHitMaxIterations = false;
00137 mnCounter = 0;
00138 mnAccepted = 0;
00139
00140
00141
00142
00143
00144 const FixParams& pPars = PtamParameters::fixparams();
00145 static std::string gvsMEstimator = pPars.BundleMEstimator;
00146
00147
00148
00149 while(!mbConverged && !mbHitMaxIterations && !*pbAbortSignal)
00150 {
00151 bool bNoError;
00152 if(gvsMEstimator == "Cauchy")
00153 bNoError = Do_LM_Step<Cauchy>(pbAbortSignal);
00154 else if(gvsMEstimator == "Tukey")
00155 bNoError = Do_LM_Step<Tukey>(pbAbortSignal);
00156 else if(gvsMEstimator == "Huber")
00157 bNoError = Do_LM_Step<Huber>(pbAbortSignal);
00158 else
00159 {
00160 cout << "Invalid BundleMEstimator selected !! " << endl;
00161 cout << "Defaulting to Tukey." << endl;
00162 gvsMEstimator = "Tukey";
00163 bNoError = Do_LM_Step<Tukey>(pbAbortSignal);
00164 };
00165
00166 if(!bNoError)
00167 return -1;
00168 }
00169
00170 if(mbHitMaxIterations)
00171 cout << " Hit max iterations." << endl;
00172 cout << "Final Sigma Squared: " << mdSigmaSquared << " (= " << sqrt(mdSigmaSquared) / 4.685 << " pixels.)" << endl;
00173 return mnAccepted;
00174 };
00175
00176
00177 inline void Bundle::ProjectAndFindSquaredError(Meas &meas)
00178 {
00179 Camera &cam = mvCameras[meas.c];
00180 Point &point = mvPoints[meas.p];
00181
00182
00183 meas.v3Cam = cam.se3CfW * point.v3Pos;
00184 if(meas.v3Cam[2] <= 0)
00185 {
00186 meas.bBad = true;
00187 return;
00188 }
00189 meas.bBad = false;
00190 Vector<2> v2ImPlane = project(meas.v3Cam);
00191 Vector<2> v2Image = mCamera.Project(v2ImPlane);
00192 meas.m2CamDerivs = mCamera.GetProjectionDerivs();
00193 meas.v2Epsilon = meas.dSqrtInvNoise * (meas.v2Found - v2Image);
00194 meas.dErrorSquared = meas.v2Epsilon * meas.v2Epsilon;
00195 }
00196
00197 template<class MEstimator>
00198 bool Bundle::Do_LM_Step(bool *pbAbortSignal)
00199 {
00200
00201 ClearAccumulators();
00202
00203
00204
00205
00206 vector<double> vdErrorSquared;
00207 for(list<Meas>::iterator itr = mMeasList.begin(); itr!=mMeasList.end(); itr++)
00208 {
00209 Meas &meas = *itr;
00210 ProjectAndFindSquaredError(meas);
00211 if(!meas.bBad)
00212 vdErrorSquared.push_back(meas.dErrorSquared);
00213 };
00214
00215
00216
00217
00218 const FixParams& pPars = PtamParameters::fixparams();
00219 static double gvdMinSigma = pPars.MinTukeySigma;
00220
00221
00222
00223
00224
00225
00226 mdSigmaSquared = MEstimator::FindSigmaSquared(vdErrorSquared);
00227
00228
00229
00230 const double dMinSigmaSquared = gvdMinSigma * gvdMinSigma;
00231 if(mdSigmaSquared < dMinSigmaSquared)
00232 mdSigmaSquared = dMinSigmaSquared;
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 double dCurrentError = 0.0;
00246 for(list<Meas>::iterator itr = mMeasList.begin(); itr!=mMeasList.end(); itr++)
00247 {
00248 Meas &meas = *itr;
00249 Camera &cam = mvCameras[meas.c];
00250 Point &point = mvPoints[meas.p];
00251
00252
00253
00254 if(meas.bBad)
00255 {
00256 dCurrentError += 1.0;
00257 continue;
00258 };
00259
00260
00261
00262
00263
00264
00265 double dWeight= MEstimator::SquareRootWeight(meas.dErrorSquared, mdSigmaSquared);
00266
00267 meas.v2Epsilon = dWeight * meas.v2Epsilon;
00268
00269 if(dWeight == 0)
00270 {
00271 meas.bBad = true;
00272 dCurrentError += 1.0;
00273 continue;
00274 }
00275
00276 dCurrentError += MEstimator::ObjectiveScore(meas.dErrorSquared, mdSigmaSquared);
00277
00278
00279
00280 Matrix<2> m2CamDerivs = dWeight * meas.m2CamDerivs;
00281
00282 const double dOneOverCameraZ = 1.0 / meas.v3Cam[2];
00283 const Vector<4> v4Cam = unproject(meas.v3Cam);
00284
00285
00286 if(cam.bFixed)
00287 meas.m26A = Zeros;
00288 else
00289 {
00290 for(int m=0;m<6;m++)
00291 {
00292 const Vector<4> v4Motion = SE3<>::generator_field(m, v4Cam);
00293 Vector<2> v2CamFrameMotion;
00294 v2CamFrameMotion[0] = (v4Motion[0] - v4Cam[0] * v4Motion[2] * dOneOverCameraZ) * dOneOverCameraZ;
00295 v2CamFrameMotion[1] = (v4Motion[1] - v4Cam[1] * v4Motion[2] * dOneOverCameraZ) * dOneOverCameraZ;
00296 meas.m26A.T()[m] = meas.dSqrtInvNoise * m2CamDerivs * v2CamFrameMotion;
00297 };
00298 }
00299
00300
00301 for(int m=0;m<3;m++)
00302 {
00303 const Vector<3> v3Motion = cam.se3CfW.get_rotation().get_matrix().T()[m];
00304 Vector<2> v2CamFrameMotion;
00305 v2CamFrameMotion[0] = (v3Motion[0] - v4Cam[0] * v3Motion[2] * dOneOverCameraZ) * dOneOverCameraZ;
00306 v2CamFrameMotion[1] = (v3Motion[1] - v4Cam[1] * v3Motion[2] * dOneOverCameraZ) * dOneOverCameraZ;
00307 meas.m23B.T()[m] = meas.dSqrtInvNoise * m2CamDerivs * v2CamFrameMotion;
00308 };
00309
00310
00311 if(!cam.bFixed)
00312 {
00313
00314 BundleTriangle_UpdateM6U_LL(cam.m6U, meas.m26A);
00315 cam.v6EpsilonA += meas.m26A.T() * meas.v2Epsilon;
00316
00317 }
00318
00319
00320 BundleTriangle_UpdateM3V_LL(point.m3V, meas.m23B);
00321 point.v3EpsilonB += meas.m23B.T() * meas.v2Epsilon;
00322
00323 if(cam.bFixed)
00324 meas.m63W = Zeros;
00325 else
00326 meas.m63W = meas.m26A.T() * meas.m23B;
00327 }
00328
00329
00330
00331
00332 double dNewError = dCurrentError + 9999;
00333 while(dNewError > dCurrentError && !mbConverged && !mbHitMaxIterations && !*pbAbortSignal)
00334 {
00335
00336 for(vector<Point>::iterator itr = mvPoints.begin(); itr!=mvPoints.end(); itr++)
00337 {
00338 Point &point = *itr;
00339 Matrix<3> m3VStar = point.m3V;
00340 if(m3VStar[0][0] * m3VStar[1][1] * m3VStar[2][2] == 0)
00341 point.m3VStarInv = Zeros;
00342 else
00343 {
00344
00345 m3VStar[0][1] = m3VStar[1][0];
00346 m3VStar[0][2] = m3VStar[2][0];
00347 m3VStar[1][2] = m3VStar[2][1];
00348
00349 for(int i=0; i<3; i++)
00350 m3VStar[i][i] *= (1.0 + mdLambda);
00351 Cholesky<3> chol(m3VStar);
00352 point.m3VStarInv = chol.get_inverse();
00353 };
00354 }
00355
00356
00357
00358
00359
00360 Matrix<> mS(mnCamsToUpdate * 6, mnCamsToUpdate * 6);
00361 mS = Zeros;
00362 Vector<> vE(mnCamsToUpdate * 6);
00363 vE = Zeros;
00364
00365 Matrix<6> m6;
00366 Vector<6> v6;
00367
00368
00369 for(unsigned int j=0; j<mvCameras.size(); j++)
00370 {
00371 Camera &cam_j = mvCameras[j];
00372 if(cam_j.bFixed) continue;
00373 int nCamJStartRow = cam_j.nStartRow;
00374
00375
00376
00377 for(int r=0; r<6; r++)
00378 {
00379 for(int c=0; c<r; c++)
00380 m6[r][c] = m6[c][r] = cam_j.m6U[r][c];
00381 m6[r][r] = cam_j.m6U[r][r];
00382 };
00383
00384 for(int nn = 0; nn< 6; nn++)
00385 m6[nn][nn] *= (1.0 + mdLambda);
00386
00387 v6 = cam_j.v6EpsilonA;
00388
00389 vector<Meas*> &vMeasLUTj = mvMeasLUTs[j];
00390
00391 for(unsigned int i=0; i<mvPoints.size(); i++)
00392 {
00393 Meas* pMeas = vMeasLUTj[i];
00394 if(pMeas == NULL || pMeas->bBad)
00395 continue;
00396 m6 -= pMeas->m63W * mvPoints[i].m3VStarInv * pMeas->m63W.T();
00397 v6 -= pMeas->m63W * (mvPoints[i].m3VStarInv * mvPoints[i].v3EpsilonB);
00398 }
00399 mS.slice(nCamJStartRow, nCamJStartRow, 6, 6) = m6;
00400 vE.slice(nCamJStartRow,6) = v6;
00401 }
00402
00403
00404
00405 for(unsigned int i=0; i<mvPoints.size(); i++)
00406 {
00407 Point &p = mvPoints[i];
00408 int nCurrentJ = -1;
00409 int nJRow = -1;
00410 Meas* pMeas_ij;
00411 Meas* pMeas_ik;
00412 Matrix<6,3> m63_MIJW_times_m3VStarInv;
00413
00414 for(vector<OffDiagScriptEntry>::iterator it=p.vOffDiagonalScript.begin();
00415 it!=p.vOffDiagonalScript.end();
00416 it++)
00417 {
00418 OffDiagScriptEntry &e = *it;
00419 pMeas_ik = mvMeasLUTs[e.k][i];
00420 if(pMeas_ik == NULL || pMeas_ik->bBad)
00421 continue;
00422 if(e.j != nCurrentJ)
00423 {
00424 pMeas_ij = mvMeasLUTs[e.j][i];
00425 if(pMeas_ij == NULL || pMeas_ij->bBad)
00426 continue;
00427 nCurrentJ = e.j;
00428 nJRow = mvCameras[e.j].nStartRow;
00429 m63_MIJW_times_m3VStarInv = pMeas_ij->m63W * p.m3VStarInv;
00430 }
00431 int nKRow = mvCameras[pMeas_ik->c].nStartRow;
00432 #ifndef WIN32
00433 mS.slice(nJRow, nKRow, 6, 6) -= m63_MIJW_times_m3VStarInv * pMeas_ik->m63W.T();
00434 #else
00435 Matrix<6> m = mS.slice(nJRow, nKRow, 6, 6);
00436 m -= m63_MIJW_times_m3VStarInv * pMeas_ik->m63W.T();
00437 mS.slice(nJRow, nKRow, 6, 6) = m;
00438 #endif
00439 assert(nKRow < nJRow);
00440 }
00441 }
00442
00443
00444
00445
00446 for(int i=0; i<mS.num_rows(); i++)
00447 for(int j=0; j<i; j++)
00448 mS[j][i] = mS[i][j];
00449
00450
00451
00452 Vector<> vCamerasUpdate(mS.num_rows());
00453 vCamerasUpdate = Cholesky<>(mS).backsub(vE);
00454
00455
00456 Vector<> vMapUpdates(mvPoints.size() * 3);
00457 for(unsigned int i=0; i<mvPoints.size(); i++)
00458 {
00459 Vector<3> v3Sum;
00460 v3Sum = Zeros;
00461 for(unsigned int j=0; j<mvCameras.size(); j++)
00462 {
00463 Camera &cam = mvCameras[j];
00464 if(cam.bFixed)
00465 continue;
00466 Meas *pMeas = mvMeasLUTs[j][i];
00467 if(pMeas == NULL || pMeas->bBad)
00468 continue;
00469 v3Sum+=pMeas->m63W.T() * vCamerasUpdate.slice(cam.nStartRow,6);
00470 }
00471 Vector<3> v3 = mvPoints[i].v3EpsilonB - v3Sum;
00472 vMapUpdates.slice(i * 3, 3) = mvPoints[i].m3VStarInv * v3;
00473 if(isnan(vMapUpdates.slice(i * 3, 3) * vMapUpdates.slice(i * 3, 3)))
00474 {
00475 cerr << "NANNERY! " << endl;
00476 cerr << mvPoints[i].m3VStarInv << endl;
00477 };
00478 }
00479
00480
00481
00482
00483
00484
00485 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
00486 double dSumSquaredUpdate = vCamerasUpdate * vCamerasUpdate + vMapUpdates * vMapUpdates;
00487 if(dSumSquaredUpdate< pPars.UpdateSquaredConvergenceLimit)
00488 mbConverged = true;
00489
00490
00491
00492
00493
00494 for(unsigned int j=0; j<mvCameras.size(); j++)
00495 {
00496 if(mvCameras[j].bFixed)
00497 mvCameras[j].se3CfWNew = mvCameras[j].se3CfW;
00498 else
00499 mvCameras[j].se3CfWNew = SE3<>::exp(vCamerasUpdate.slice(mvCameras[j].nStartRow, 6)) * mvCameras[j].se3CfW;
00500 }
00501 for(unsigned int i=0; i<mvPoints.size(); i++)
00502 mvPoints[i].v3PosNew = mvPoints[i].v3Pos + vMapUpdates.slice(i*3, 3);
00503
00504 dNewError = FindNewError<MEstimator>();
00505
00506 cout <<setprecision(1) << "L" << mdLambda << setprecision(3) << "\tOld " << dCurrentError << " New " << dNewError << " Diff " << dCurrentError - dNewError << "\t";
00507
00508
00509
00510 if(dNewError > dCurrentError)
00511 {
00512 cout << " TRY AGAIN " << endl;
00513 ModifyLambda_BadStep();
00514 };
00515
00516
00517 mnCounter++;
00518 if(mnCounter >= pPars.MaxIterations)
00519 mbHitMaxIterations = true;
00520
00521 }
00522
00523 if(dNewError < dCurrentError)
00524 {
00525 cout << " WINNER ------------ " << endl;
00526
00527 ModifyLambda_GoodStep();
00528 for(unsigned int j=0; j<mvCameras.size(); j++)
00529 mvCameras[j].se3CfW = mvCameras[j].se3CfWNew;
00530 for(unsigned int i=0; i<mvPoints.size(); i++)
00531 mvPoints[i].v3Pos = mvPoints[i].v3PosNew;
00532 mnAccepted++;
00533 }
00534
00535
00536 vector<list<Meas>::iterator> vit;
00537 for(list<Meas>::iterator itr = mMeasList.begin(); itr!=mMeasList.end(); itr++)
00538 if(itr->bBad)
00539 {
00540 vit.push_back(itr);
00541 mvOutlierMeasurementIdx.push_back(make_pair(itr->p, itr->c));
00542 mvPoints[itr->p].nOutliers++;
00543 mvMeasLUTs[itr->c][itr->p] = NULL;
00544 };
00545
00546 for(unsigned int i=0; i<vit.size(); i++)
00547 mMeasList.erase(vit[i]);
00548
00549 cout << "Nuked " << vit.size() << " measurements." << endl;
00550 return true;
00551 }
00552
00553
00554
00555 template<class MEstimator>
00556 double Bundle::FindNewError()
00557 {
00558 ofstream ofs;
00559 double dNewError = 0;
00560 vector<double> vdErrorSquared;
00561 for(list<Meas>::iterator itr = mMeasList.begin(); itr!=mMeasList.end(); itr++)
00562 {
00563 Meas &meas = *itr;
00564
00565 Vector<3> v3Cam = mvCameras[meas.c].se3CfWNew * mvPoints[meas.p].v3PosNew;
00566 if(v3Cam[2] <= 0)
00567 {
00568 dNewError += 1.0;
00569 cout << ".";
00570 continue;
00571 };
00572 Vector<2> v2ImPlane = project(v3Cam);
00573 Vector<2> v2Image = mCamera.Project(v2ImPlane);
00574 Vector<2> v2Error = meas.dSqrtInvNoise * (meas.v2Found - v2Image);
00575 double dErrorSquared = v2Error * v2Error;
00576 dNewError += MEstimator::ObjectiveScore(dErrorSquared, mdSigmaSquared);
00577 }
00578 return dNewError;
00579 }
00580
00581
00582
00583
00584 void Bundle::GenerateMeasLUTs()
00585 {
00586 mvMeasLUTs.clear();
00587 for(unsigned int nCam = 0; nCam < mvCameras.size(); nCam++)
00588 {
00589 mvMeasLUTs.push_back(vector<Meas*>());
00590 mvMeasLUTs.back().resize(mvPoints.size(), NULL);
00591 };
00592 for(list<Meas>::iterator it = mMeasList.begin(); it!=mMeasList.end(); it++)
00593 mvMeasLUTs[it->c][it->p] = &(*it);
00594 }
00595
00596
00597
00598
00599 void Bundle::GenerateOffDiagScripts()
00600 {
00601 for(unsigned int i=0; i<mvPoints.size(); i++)
00602 {
00603 Point &p = mvPoints[i];
00604 p.vOffDiagonalScript.clear();
00605 for(set<int>::iterator it_j = p.sCameras.begin(); it_j!=p.sCameras.end(); it_j++)
00606 {
00607 int j = *it_j;
00608 if(mvCameras[j].bFixed)
00609 continue;
00610 Meas *pMeas_j = mvMeasLUTs[j][i];
00611 assert(pMeas_j != NULL);
00612
00613 for(set<int>::iterator it_k = p.sCameras.begin(); it_k!=it_j; it_k++)
00614 {
00615 int k = *it_k;
00616 if(mvCameras[k].bFixed)
00617 continue;
00618
00619 Meas *pMeas_k = mvMeasLUTs[k][i];
00620 assert(pMeas_k != NULL);
00621
00622 OffDiagScriptEntry e;
00623 e.j = j;
00624 e.k = k;
00625 p.vOffDiagonalScript.push_back(e);
00626 }
00627 }
00628 }
00629 }
00630
00631 void Bundle::ModifyLambda_GoodStep()
00632 {
00633 mdLambdaFactor = 2.0;
00634 mdLambda *= 0.3;
00635 };
00636
00637 void Bundle::ModifyLambda_BadStep()
00638 {
00639 mdLambda = mdLambda * mdLambdaFactor;
00640 mdLambdaFactor = mdLambdaFactor * 2;
00641 };
00642
00643
00644 Vector<3> Bundle::GetPoint(int n)
00645 {
00646 return mvPoints.at(n).v3Pos;
00647 }
00648
00649 SE3<> Bundle::GetCamera(int n)
00650 {
00651 return mvCameras.at(n).se3CfW;
00652 }
00653
00654 set<int> Bundle::GetOutliers()
00655 {
00656 set<int> sOutliers;
00657 set<int>::iterator hint = sOutliers.begin();
00658 for(unsigned int i=0; i<mvPoints.size(); i++)
00659 {
00660 Point &p = mvPoints[i];
00661 if(p.nMeasurements > 0 && p.nMeasurements == p.nOutliers)
00662 hint = sOutliers.insert(hint, i);
00663 }
00664 return sOutliers;
00665 };
00666
00667
00668 vector<pair<int, int> > Bundle::GetOutlierMeasurements()
00669 {
00670 return mvOutlierMeasurementIdx;
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680