Bundle.cc
Go to the documentation of this file.
00001 // Copyright 2008 Isis Innovation Limited
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 //using namespace GVars3;
00011 using namespace std;
00012 
00013 #ifdef WIN32
00014 inline bool isnan(double d) {return !(d==d);}
00015 #endif
00016 
00017 //Weiss{
00018 #define cout if(defDebugBundleMessages()) cout
00019 
00020 inline bool defDebugBundleMessages()
00021 {
00022   return PtamParameters::varparams().BundleDebugMessages;
00023 }
00024 //}
00025 
00026 // Some inlines which replace standard matrix multiplications 
00027 // with LL-triangle-only versions.
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 // Constructor copies MapMaker's camera parameters
00042 Bundle::Bundle(const ATANCamera &TCam)
00043 : mCamera(TCam)
00044 {
00045   mnCamsToUpdate = 0;
00046   mnStartRow = 0;
00047   //Weiss{
00048   //GV3::Register(mgvnMaxIterations, "Bundle.MaxIterations", 20,  SILENT);
00049   //GV3::Register(mgvdUpdateConvergenceLimit, "Bundle.UpdateSquaredConvergenceLimit", 1e-06, SILENT);
00050   //GV3::Register(mgvnBundleCout, "Bundle.Cout", 0, SILENT);
00051   //}
00052 };
00053 
00054 // Add a camera to the system, return value is the bundle adjuster's ID for the camera
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 // Add a map point to the system, return value is the bundle adjuster's ID for the point
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 // Add a measurement of one point with one camera
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 // Zero temporary quantities stored in cameras and points
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 // Perform bundle adjustment. The parameter points to a signal bool 
00120 // which mapmaker will set to high if another keyframe is incoming
00121 // and bundle adjustment needs to be aborted.
00122 // Returns number of accepted iterations if all good, negative 
00123 // value for big error.
00124 int Bundle::Compute(bool *pbAbortSignal)
00125 {
00126   mpbAbortSignal = pbAbortSignal;
00127 
00128   // Some speedup data structures
00129   GenerateMeasLUTs();
00130   GenerateOffDiagScripts();
00131 
00132   // Initially behave like gauss-newton
00133   mdLambda = 0.0001;
00134   mdLambdaFactor = 2.0;
00135   mbConverged = false;
00136   mbHitMaxIterations = false;
00137   mnCounter = 0;
00138   mnAccepted = 0;
00139 
00140   // What MEstimator are we using today?
00141   //Weiss{
00142   //static std::string gvsMEstimator = "Tukey";
00143 
00144   const FixParams& pPars = PtamParameters::fixparams();
00145   static std::string gvsMEstimator = pPars.BundleMEstimator;
00146   //static gvar3<string> gvsMEstimator("BundleMEstimator", "Tukey", SILENT);
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 // Reproject a single measurement, find error
00177 inline void Bundle::ProjectAndFindSquaredError(Meas &meas)
00178 {
00179   Camera &cam = mvCameras[meas.c];
00180   Point &point = mvPoints[meas.p];
00181 
00182   // Project the point.
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   // Reset all accumulators to zero
00201   ClearAccumulators();
00202 
00203   //  Do a LM step according to Hartley and Zisserman Algo A6.4 in MVG 2nd Edition
00204   //  Actual work starts a bit further down - first we have to work out the 
00205   //  projections and errors for each point, so we can do tukey reweighting
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   //Weiss{
00216   //static double gvdMinSigma = 0.4;
00217 
00218   const FixParams& pPars = PtamParameters::fixparams();
00219   static double gvdMinSigma = pPars.MinTukeySigma;
00220   //static gvar3<double> gvdMinSigma("Bundle.MinTukeySigma", 0.4, SILENT);
00221   //}
00222 
00223   // Projected all points and got vector of errors; find the median, 
00224   // And work out robust estimate of sigma, then scale this for the tukey
00225   // estimator
00226   mdSigmaSquared = MEstimator::FindSigmaSquared(vdErrorSquared);
00227 
00228   // Initially the median error might be very small - set a minimum
00229   // value so that good measurements don't get erased!
00230   const double dMinSigmaSquared = gvdMinSigma * gvdMinSigma;
00231   if(mdSigmaSquared < dMinSigmaSquared)
00232     mdSigmaSquared = dMinSigmaSquared;
00233 
00234 
00235   //  OK - good to go! weights can now be calced on second run through the loop.
00236   //  Back to Hartley and Zisserman....
00237   //  `` (i) Compute the derivative matrices Aij = [dxij/daj]
00238   //      and Bij = [dxij/dbi] and the error vectors eij''
00239   //
00240   //  Here we do this by looping over all measurements
00241   // 
00242   //  While we're here, might as well update the accumulators U, ea, B, eb
00243   //  from part (ii) as well, and let's calculate Wij while we're here as well.
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     // Project the point.
00253     // We've done this before - results are still cached in meas.
00254     if(meas.bBad)
00255     {
00256       dCurrentError += 1.0;
00257       continue;
00258     };
00259 
00260     // What to do with the weights? The easiest option is to independently weight
00261     // The two jacobians, A and B, with sqrt of the tukey weight w;
00262     // And also weight the error vector v2Epsilon.
00263     // That makes everything else automatic.
00264     // Calc the square root of the tukey weight:
00265     double dWeight= MEstimator::SquareRootWeight(meas.dErrorSquared, mdSigmaSquared);
00266     // Re-weight error:
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     // To re-weight the jacobians, I'll just re-weight the camera param matrix
00279     // This is only used for the jacs and will save a few fmuls
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     // Calculate A: (the proj derivs WRT the camera)
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     // Calculate B: (the proj derivs WRT the point)
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     // Update the accumulators
00311     if(!cam.bFixed)
00312     {
00313       //          cam.m6U += meas.m26A.T() * meas.m26A;           // SLOW SLOW this matrix is symmetric
00314       BundleTriangle_UpdateM6U_LL(cam.m6U, meas.m26A);
00315       cam.v6EpsilonA += meas.m26A.T() * meas.v2Epsilon;
00316       // NOISE COVAR OMITTED because it's the 2-Identity
00317     }
00318 
00319     //            point.m3V += meas.m23B.T() * meas.m23B;             // SLOW-ish this is symmetric too
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   // OK, done (i) and most of (ii) except calcing Yij; this depends on Vi, which should 
00330   // be finished now. So we can find V*i (by adding lambda) and then invert.
00331   // The next bits depend on mdLambda! So loop this next bit until error goes down.
00332   double dNewError = dCurrentError + 9999;
00333   while(dNewError > dCurrentError && !mbConverged && !mbHitMaxIterations && !*pbAbortSignal)
00334   {
00335     // Rest of part (ii) : find V*i inverse
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         // Fill in the upper-r triangle from the LL;
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     // Done part (ii), except calculating Yij;
00357     // But we can do this inline when we calculate S in part (iii).
00358 
00359     // Part (iii): Construct the the big block-matrix S which will be inverted.
00360     Matrix<> mS(mnCamsToUpdate * 6, mnCamsToUpdate * 6);
00361     mS = Zeros;
00362     Vector<> vE(mnCamsToUpdate * 6);
00363     vE = Zeros;
00364 
00365     Matrix<6> m6; // Temp working space
00366     Vector<6> v6; // Temp working space
00367 
00368     // Calculate on-diagonal blocks of S (i.e. only one camera at a time:)
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       // First, do the diagonal elements.
00376       //m6= cam_j.m6U;     // can't do this anymore because cam_j.m6U is LL!!
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       // Sum over measurements (points):
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();  // SLOW SLOW should by 6x6sy
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     // Now find off-diag elements of S. These are camera-point-camera combinations, of which there are lots.
00404     // New code which doesn't waste as much time finding i-jk pairs; these are pre-stored in a per-i list.
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     // Did this purely LL triangle - now update the TR bit as well!
00444     // (This is actually unneccessary since the lapack cholesky solver
00445     // uses only one triangle, but I'm leaving it in here anyway.)
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     // Got fat matrix S and vector E from part(iii). Now Cholesky-decompose
00451     // the matrix, and find the camera update vector.
00452     Vector<> vCamerasUpdate(mS.num_rows());
00453     vCamerasUpdate = Cholesky<>(mS).backsub(vE);
00454 
00455     // Part (iv): Compute the map updates
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     // OK, got the two update vectors.
00481     // First check for convergence..
00482     // (this is a very poor convergence test)
00483     //Weiss{
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     // Now re-project everything and measure the error;
00491     // NB we don't keep these projections, SLOW, bit of a waste.
00492 
00493     // Temp versions of updated pose and pos:
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     // Calculate new error by re-projecting, doing tukey, etc etc:
00504     dNewError = FindNewError<MEstimator>();
00505 
00506     cout <<setprecision(1) << "L" << mdLambda << setprecision(3) <<  "\tOld " << dCurrentError << "  New " << dNewError << "  Diff " << dCurrentError - dNewError << "\t";
00507 
00508     // Was the step good? If not, modify lambda and try again!!
00509     // (if it was good, will break from this loop.)
00510     if(dNewError > dCurrentError)
00511     {
00512       cout << " TRY AGAIN " << endl;
00513       ModifyLambda_BadStep();
00514     };
00515 
00516     //Weiss{
00517     mnCounter++;
00518     if(mnCounter >= pPars.MaxIterations)
00519       mbHitMaxIterations = true;
00520     //}
00521   }   // End of while error too big loop
00522 
00523   if(dNewError < dCurrentError) // Was the last step a good one?
00524   {
00525     cout << " WINNER            ------------ " << endl;
00526     // Woo! got somewhere. Update lambda and make changes permanent.
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   // Finally, ditch all the outliers.
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 // Find the new total error if cameras and points used their 
00554 // new coordinates
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     // Project the point.
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 // Optimisation: make a bunch of tables, one per camera
00582 // which point to measurements (if any) for each point
00583 // This is faster than a std::map lookup.
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 // Optimisation: make a per-point list of all
00597 // observation camera-camera pairs; this is then
00598 // scanned to make the off-diagonal elements of matrix S
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 


ptam
Author(s): Markus Achtelik , Stephan Weiss , Simon Lynen
autogenerated on Sun Oct 5 2014 23:52:33