fivePointAlgorithm.h

Go to the documentation of this file.
00001 
00015 #ifndef DLR_COMPUTERVISION_FIVEPOINTALGORITHM_H
00016 #define DLR_COMPUTERVISION_FIVEPOINTALGORITHM_H
00017 
00018 #include <dlrNumeric/array1D.h>
00019 #include <dlrNumeric/array2D.h>
00020 #include <dlrNumeric/transform3D.h>
00021 #include <dlrNumeric/vector2D.h>
00022 #include <dlrRandom/pseudoRandom.h>
00023 
00024 
00025 namespace dlr {
00026 
00027   namespace computerVision {
00028 
00099     template<class Iterator>
00100     std::vector< dlr::numeric::Array2D<double> >
00101     fivePointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00102                        Iterator sequence1Begin);
00103 
00104 
00162     template<class Iterator>
00163     dlr::numeric::Array2D<double>
00164     fivePointAlgorithmRobust(Iterator sequence0Begin, Iterator sequence0End,
00165                              Iterator sequence1Begin,
00166                              size_t iterations,
00167                              double inlierProportion,
00168                              double& score,
00169                              dlr::random::PseudoRandom pRandom
00170                              = dlr::random::PseudoRandom());
00171 
00172 
00234     template<class Iterator>
00235     void
00236     fivePointAlgorithmRobust(Iterator sequence0Begin, Iterator sequence0End,
00237                              Iterator sequence1Begin,
00238                              Iterator sequence2Begin,
00239                              size_t iterations,
00240                              double inlierProportion,
00241                              dlr::numeric::Array2D<double>& cam2Ecam0,
00242                              dlr::numeric::Transform3D& cam0Tcam2,
00243                              dlr::numeric::Transform3D& cam1Tcam2,
00244                              double& score,
00245                              dlr::random::PseudoRandom pRandom
00246                              = dlr::random::PseudoRandom());
00247     
00248     
00249     // Return value is residual in pix^2.
00250     double
00251     checkEpipolarConstraint(dlr::numeric::Array2D<double> const& fundamentalMx,
00252                             dlr::numeric::Vector2D& point0,
00253                             dlr::numeric::Vector2D& point1);
00254 
00255 
00256     // WARNING(xxx): We have observed at least one case in which the
00257     // return value from this function is fishy.  We currently do not
00258     // trust it.
00259     // 
00260     // Warning Think of this function as being "private."  Gets cam1Tcam0.
00261     // Might throw if test points are on parallel rays.
00262     dlr::numeric::Transform3D
00263     getCameraMotionFromEssentialMatrix(
00264       dlr::numeric::Array2D<double> const& EE,
00265       dlr::numeric::Vector2D const& testPointCamera0,
00266       dlr::numeric::Vector2D const& testPointCamera1);
00267 
00268 
00269     // Returns point in CS of camera 0.  Note that argument is the
00270     // inverse of what's returned by
00271     // getCameraMotionFromEssentialMatrix().  Might throw if test
00272     // points are on parallel rays.
00273     dlr::numeric::Vector3D
00274     triangulateCalibratedImagePoint(
00275       dlr::numeric::Transform3D const& c0Tc1,
00276       dlr::numeric::Vector2D const& testPointCamera0,
00277       dlr::numeric::Vector2D const& testPointCamera1);
00278     
00279 
00307     dlr::numeric::Array2D<double>
00308     generateFivePointConstraintMatrix(
00309       dlr::numeric::Array2D<double> const& E0Array,
00310       dlr::numeric::Array2D<double> const& E1Array,
00311       dlr::numeric::Array2D<double> const& E2Array,
00312       dlr::numeric::Array2D<double> const& E3Array);
00313 
00314   } // namespace computerVision
00315     
00316 } // namespace dlr
00317 
00318 
00319 /* ============ Definitions of inline & template functions ============ */
00320 
00321 
00322 #include <cmath>
00323 #include <complex>
00324 #include <limits>
00325 #include <dlrComputerVision/cameraIntrinsicsPinhole.h>
00326 #include <dlrComputerVision/threePointAlgorithm.h>
00327 #include <dlrGeometry/ray2D.h>
00328 #include <dlrGeometry/utilities2D.h>
00329 #include <dlrLinearAlgebra/linearAlgebra.h>
00330 #include <dlrNumeric/subArray2D.h>
00331 #include <dlrNumeric/utilities.h>
00332 
00333 namespace dlr {
00334 
00335   namespace computerVision {
00336 
00337 
00338     template<class Iterator>
00339     std::vector< dlr::numeric::Array2D<double> >
00340     fivePointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00341                        Iterator sequence1Begin)
00342     {
00343       // The five (or more) pairs of input points give at least five
00344       // linear constraints on the essential matrix, E.  Since E has
00345       // nine elements, this means there's a four-dimentional null
00346       // space of these constraints.  We solve for an orthogonal basis
00347       // of this null space here.
00348 
00349       // For each pair of points q, q', the essential matrix, E,
00350       // satisfies the equation:
00351       //
00352       //   transpose(q') * E * q = 0
00353       //
00354       // where the points q are drawn from sequence0, and the points
00355       // q' are drawn from sequence1.
00356       // 
00357       // We rearrange this equation to get
00358       //
00359       //   ||e_00*q_x*q'_x + e_01*q_y*q'_x + e_02*q'_x
00360       //     + e_10*q_x*q'_y + e_11*q_y*q'_y + e_12*q'_y
00361       //     + e_20*q_x + e_21*q_y + e_22|| = 0
00362       //
00363       // where e_ij is the element of E in the i^th row and the j^th
00364       // column, q_x & q_y are the x & y components of q,
00365       // respectively, and q'_x & q'_y are the x & y components of q',
00366       // respectively.
00367       //
00368       // or,
00369       // 
00370       //   ||A * vec(E)|| = 0
00371       //
00372       // With the matrix A as specified in the code below.
00373       size_t numberOfCorrespondences = sequence0End - sequence0Begin;
00374       dlr::numeric::Array2D<double> AMatrix(numberOfCorrespondences, 9);
00375       for(size_t rowIndex = 0; rowIndex < numberOfCorrespondences; ++rowIndex) {
00376         dlr::numeric::Array1D<double> currentRow = AMatrix.getRow(rowIndex);
00377         const dlr::numeric::Vector2D& qq = *sequence0Begin;
00378         const dlr::numeric::Vector2D& qPrime = *sequence1Begin;
00379         currentRow[0] = qq.x() * qPrime.x();
00380         currentRow[1] = qq.y() * qPrime.x();
00381         currentRow[2] = qPrime.x();
00382         currentRow[3] = qq.x() * qPrime.y();
00383         currentRow[4] = qq.y() * qPrime.y();
00384         currentRow[5] = qPrime.y();
00385         currentRow[6] = qq.x();
00386         currentRow[7] = qq.y();
00387         currentRow[8] = 1.0;
00388         ++sequence0Begin;
00389         ++sequence1Begin;
00390       }
00391 
00392       // Following [1], we solve for the four dimensional null space
00393       // using SVD.
00394       dlr::numeric::Array2D<double> uArray;
00395       dlr::numeric::Array1D<double> sigmaArray;
00396       dlr::numeric::Array2D<double> vTransposeArray;
00397       dlr::linearAlgebra::singularValueDecomposition(
00398         AMatrix, uArray, sigmaArray, vTransposeArray, true);
00399       dlr::numeric::Array2D<double> E0Array(3, 3);
00400       dlr::numeric::Array2D<double> E1Array(3, 3);
00401       dlr::numeric::Array2D<double> E2Array(3, 3);
00402       dlr::numeric::Array2D<double> E3Array(3, 3);
00403       std::copy(vTransposeArray.getRow(5).begin(),
00404                 vTransposeArray.getRow(5).end(),
00405                 E0Array.begin());
00406       std::copy(vTransposeArray.getRow(6).begin(),
00407                 vTransposeArray.getRow(6).end(),
00408                 E1Array.begin());
00409       std::copy(vTransposeArray.getRow(7).begin(),
00410                 vTransposeArray.getRow(7).end(),
00411                 E2Array.begin());
00412       std::copy(vTransposeArray.getRow(8).begin(),
00413                 vTransposeArray.getRow(8).end(),
00414                 E3Array.begin());
00415 
00416       // Let E = x*E0 + y*E1 + z*E2 + w*E3, and assume w == 1 (Yuck.
00417       // We will fix this soon).  We have (equations (2) and (3) of [1])
00418       //
00419       //   det(E) = 0
00420       //
00421       // and
00422       // 
00423       //   2 * E * transpose(E) * E - trace(E * transpose(E)) * E = 0
00424       //
00425       // These two equations give us ten cubic constraints on x, y,
00426       // and z.  As described in the paper, we write these constraints
00427       // as the matrix product of a 10x20 coefficient matrix, M, and a
00428       // monomials vector X.
00429       //
00430       //   M * X = [0]
00431       //
00432       //   X = [x^3, x^2*y, x^2*z, x*y^2, x*y*z, x*z^2, y^3, y^2*z, y*z^2, z^3,
00433       //        x^2, x*y, x*z, y^2, y*z, z^2, x, y, z, 1]
00434       //
00435       // Although computing M just involves doing a bunch of matrix
00436       // multiplications, tranposes, determinants, etc., the
00437       // computation is quite tedious.  In fact, even typing in the
00438       // result is quite tedious.  For this reason, we use
00439       // automatically generated C code exported from the computer
00440       // algebra system Maxima.
00441       dlr::numeric::Array2D<double> M = generateFivePointConstraintMatrix(
00442         E0Array, E1Array, E2Array, E3Array);
00443 
00444 #if 0
00445       dlr::numeric::Array2D<double> diff = M - MnL;
00446       dlr::numeric::Array2D<bool> flags(diff.rows(), diff.columns());
00447       for(size_t nn = 0; nn < diff.size(); ++nn) {
00448         flags[nn] = std::fabs(diff[nn]) < 1.0E-9;
00449       }
00450 
00451       std::cout << "===================" << std::endl;
00452       double target = MnL(0, 0);
00453       for(size_t mm = 0; mm < M.rows(); ++mm) {
00454         for(size_t nn = 0; nn < M.columns(); ++nn) {
00455           if(std::fabs(M(mm, nn) - target) < 1.0E-9) {
00456             std::cout << " [" << mm << ", " << nn << "] matches." << std::endl;
00457           }
00458         }
00459       }
00460       std::cout << "===================" << std::endl;
00461 #endif
00462       
00463       // The paper calls for Gauss-Jordan elimination to reduce the
00464       // first 10 columns of M to the identity matrix, so that the
00465       // rows of the eliminated matrix form a Groebner basis of the
00466       // ideal of the 10 original cubic constraints (see [3] for more
00467       // information on Groebner bases, ideals, and algebraic geometry
00468       // in general).  We don't have a Gauss-Jordan elimination
00469       // routine coded up, so we use what we have available.
00470 
00471       // Extract the first 10 columns of M.
00472       dlr::numeric::Array2D<double> M0 = dlr::numeric::subArray(
00473         M, dlr::numeric::Slice(), dlr::numeric::Slice(0, 10));
00474 
00475       // Invert them (presumably using Gauss-Jordan elimination.
00476       dlr::numeric::Array2D<double> M0Inv = dlr::linearAlgebra::inverse(M0);
00477 
00478       // Extract the 10th through 20th columns of M.
00479       dlr::numeric::Array2D<double> M1 = dlr::numeric::subArray(
00480         M, dlr::numeric::Slice(), dlr::numeric::Slice(10, 0));
00481 
00482       // And manipulate them so that they look like they went through
00483       // the same elimination process.  Following the paper, we call
00484       // the result of this manipulation B, although the real Brobner
00485       // basis is the set of polynomials whose coefficients are drawn
00486       // from the 10x20 matrix resulting from the elimination (first
00487       // 10 columns are 10x10 identity matrix, remaining columns equal
00488       // to our 10x10 matrix B.
00489       dlr::numeric::Array2D<double> B = dlr::numeric::matrixMultiply(M0Inv, M1);
00490 
00491       // Since we eliminated the left half of M, we're safe to assume
00492       // that the leading terms of the Groebner basis we just computed
00493       // do not include the monomials x, y, or z.  This means that x,
00494       // y, and z will be in the quotient ring of complex third-order
00495       // polynomials over the ideal of the polynomials expressed in M.
00496       // 
00497       // Theorem xxx in [3] gives us that, at the solutions, x, of the
00498       // polynomials in M,
00499       //
00500       //   f(x) * transpose(u(x)) = transpose(u(x)) * A_f
00501       // 
00502       // Where f(x) is an arbitrary polynomial in the quotient ring,
00503       // u(x) is the vector of basis monomials of the quotient ring,
00504       // and A_f is the action matrix associated with f(x).
00505       //
00506       // This is useful because it means that, at the solutions to our
00507       // system of third order polynomials, the values of the
00508       // monomials in u(x) correspond to the left eigenvectors of A_f.
00509       // But we've already agreed that x, y, and z are three of the
00510       // monomials in u(x), so if we can just find A_f for an
00511       // arbitrary polynomial in the quotient ring, then we can take
00512       // its left eigenvectors and grab the elements corresponding to
00513       // x, y, and z to find our solutions!
00514       //
00515       // We'll use the action matrix for the polynomial x, and
00516       // transpose it so that we can use our normal right-eigenvector
00517       // solver to find the eigenvectors.
00518 
00519       // Warning(xxx): We'll use the action matrix from Stewenius &
00520       // Nister's paper, which doesn't appear to correspond to
00521       // suggested degree-then-lexicographic order of monomials.  The
00522       // right solution to this is to generate the correct action
00523       // matrix below, but instead we temporarily shuffle the columns
00524       // of our constraint matrix to match the action matrix.  This
00525       // shuffling happens under the hood in the call to
00526       // generateFivePointConstraintMatrix(), above.
00527       dlr::numeric::Array2D<double> At(10, 10);
00528       At = 0.0;
00529       for(size_t ii = 0; ii < 10; ++ii) {
00530         At(0, ii) = -B(0, ii);
00531         At(1, ii) = -B(1, ii);
00532         At(2, ii) = -B(2, ii);
00533         At(3, ii) = -B(4, ii);
00534         At(4, ii) = -B(5, ii);
00535         At(5, ii) = -B(7, ii);
00536       }
00537       At(6, 0) = 1.0;
00538       At(7, 1) = 1.0;
00539       At(8, 3) = 1.0;
00540       At(9, 6) = 1.0;
00541 
00542       // Solutions for x, y, z can be found from the 10 eigenvectors
00543       // of this (tranposed) action matrix.  We normalize the final
00544       // element of each eigenvector to 1.0.
00545       dlr::numeric::Array1D< std::complex<Float64> > eigenvalues;
00546       dlr::numeric::Array2D< std::complex<Float64> > eigenvectors;
00547       dlr::linearAlgebra::eigenvectors(At, eigenvalues, eigenvectors);
00548       
00549       // Now that we have solutions for x, y, and z, we can go back
00550       // and use them to reconstruct potential solutions for the
00551       // essential matrix.
00552       std::vector< dlr::numeric::Array2D<double> > result;
00553       for(size_t ii = 0; ii < 10; ++ii) {
00554         if(eigenvalues[ii].imag() == 0) {
00555           double xx = eigenvectors(6, ii).real() / eigenvectors(9, ii).real();
00556           double yy = eigenvectors(7, ii).real() / eigenvectors(9, ii).real();
00557           double zz = eigenvectors(8, ii).real() / eigenvectors(9, ii).real();
00558           Array2D<double> solution =
00559             (xx * E0Array) + (yy * E1Array) + (zz * E2Array) + E3Array;
00560           result.push_back(solution);
00561         }
00562       }
00563 
00564       return result;
00565     }
00566 
00567 
00568     template<class Iterator>
00569     dlr::numeric::Array2D<double>
00570     fivePointAlgorithmRobust(Iterator sequence0Begin, Iterator sequence0End,
00571                              Iterator sequence1Begin,
00572                              size_t iterations,
00573                              double inlierProportion,
00574                              double& score,
00575                              dlr::random::PseudoRandom pRandom)
00576     {
00577       // State variables so we'll remember the correct essential
00578       // matrix once we find it.
00579       double bestErrorSoFar = std::numeric_limits<double>::max();
00580       dlr::numeric::Array2D<double> selectedCandidate(3, 3);
00581       selectedCandidate = 0.0;
00582       
00583       // Copy input points into local buffers.
00584       size_t numberOfPoints = sequence0End - sequence0Begin;
00585       std::vector<dlr::numeric::Vector2D> qVector(numberOfPoints);
00586       std::vector<dlr::numeric::Vector2D> qPrimeVector(numberOfPoints);
00587       std::copy(sequence0Begin, sequence0End, qVector.begin());
00588       std::copy(sequence1Begin, sequence1Begin + numberOfPoints,
00589                 qPrimeVector.begin());
00590 
00591       for(size_t ii = 0; ii < iterations; ++ii) {
00592         // Select five points.
00593         for(size_t jj = 0; jj < 5; ++jj) {
00594           int selectedIndex = pRandom.uniformInt(jj, numberOfPoints);
00595           if(selectedIndex != static_cast<int>(jj)) {
00596             std::swap(qVector[jj], qVector[selectedIndex]);
00597             std::swap(qPrimeVector[jj], qPrimeVector[selectedIndex]);
00598           }
00599         }
00600 
00601         // Get candidate essential matrices.
00602         std::vector< dlr::numeric::Array2D<double> > EVector =
00603           fivePointAlgorithm(qVector.begin(), qVector.begin() + 5,
00604                              qPrimeVector.begin());
00605 
00606         // Test each candidate.
00607         for(size_t jj = 0; jj < EVector.size(); ++jj) {
00608           Array2D<double> EE = EVector[jj];
00609 
00610           // Compute residuals for all input points.
00611           std::vector<double> residualVector(numberOfPoints);
00612           for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00613             residualVector[kk] = checkEpipolarConstraint(
00614               EE, qVector[kk], qPrimeVector[kk]);
00615           }
00616 
00617           // Compute robust error statistic.
00618           //
00619           // Note(xxx): Better not to sort here, since it changes the
00620           // algorithm to O(NlogN).
00621           std::sort(residualVector.begin(), residualVector.end());
00622           int testIndex = static_cast<int>(
00623             inlierProportion * residualVector.size() + 0.5);
00624           double errorValue = residualVector[testIndex];
00625 
00626           // Remember candidate if it's the best so far.
00627           if(errorValue < bestErrorSoFar) {
00628             selectedCandidate = EE;
00629             bestErrorSoFar = errorValue;
00630           }
00631         }
00632       }
00633       score = bestErrorSoFar;
00634       return selectedCandidate;
00635     }
00636 
00637     
00638     template<class Iterator>
00639     void
00640     fivePointAlgorithmRobust(Iterator sequence0Begin, Iterator sequence0End,
00641                              Iterator sequence1Begin,
00642                              Iterator sequence2Begin,
00643                              size_t iterations,
00644                              double inlierProportion,
00645                              dlr::numeric::Array2D<double>& cam2Ecam0,
00646                              dlr::numeric::Transform3D& cam0Tcam2,
00647                              dlr::numeric::Transform3D& cam1Tcam2,
00648                              double& score,
00649                              dlr::random::PseudoRandom pRandom)
00650     {
00651       // Since we're using calibrated image points, all cameras have
00652       // the same intrinsics.
00653       CameraIntrinsicsPinhole intrinsics(1, 1, 1.0, 1.0, 1.0, 0.0, 0.0);
00654       
00655       // State variables so we'll remember the correct essential
00656       // matrices once we find them.
00657       double bestErrorSoFar = std::numeric_limits<double>::max();
00658       dlr::numeric::Array2D<double> selectedCam2Ecam0(3, 3);
00659       dlr::numeric::Transform3D selectedCam0Tcam2;
00660       dlr::numeric::Transform3D selectedCam1Tcam2;
00661       selectedCam2Ecam0 = 0.0;
00662       
00663       // Copy input points into local buffers.
00664       size_t numberOfPoints = sequence0End - sequence0Begin;
00665       std::vector<dlr::numeric::Vector2D> points2D_cam0(numberOfPoints);
00666       std::vector<dlr::numeric::Vector2D> points2D_cam1(numberOfPoints);
00667       std::vector<dlr::numeric::Vector2D> points2D_cam2(numberOfPoints);
00668       std::copy(sequence0Begin, sequence0End, points2D_cam0.begin());
00669       std::copy(sequence1Begin, sequence1Begin + numberOfPoints,
00670                 points2D_cam1.begin());
00671       std::copy(sequence2Begin, sequence2Begin + numberOfPoints,
00672                 points2D_cam2.begin());
00673 
00674       // Allocate storage for temporary values prior to starting loop.
00675       std::vector<dlr::numeric::Vector3D> points3D_cam0(numberOfPoints);
00676       std::vector<dlr::numeric::Vector3D> points3D_cam1(numberOfPoints);
00677       std::vector<dlr::numeric::Vector3D> points3D_cam2(numberOfPoints);
00678       std::vector<double> residualVector(numberOfPoints);
00679 
00680       // Loop over many sets of random samples.
00681       for(size_t ii = 0; ii < iterations; ++ii) {
00682 
00683         // Select five points.
00684         for(size_t jj = 0; jj < 5; ++jj) {
00685           int selectedIndex = pRandom.uniformInt(jj, numberOfPoints);
00686           if(selectedIndex != static_cast<int>(jj)) {
00687             std::swap(points2D_cam0[jj], points2D_cam0[selectedIndex]);
00688             std::swap(points2D_cam1[jj], points2D_cam1[selectedIndex]);
00689             std::swap(points2D_cam2[jj], points2D_cam2[selectedIndex]);
00690           }
00691         }
00692 
00693         // Get candidate essential matrices.
00694         std::vector< dlr::numeric::Array2D<double> > EVector =
00695           fivePointAlgorithm(points2D_cam0.begin(), points2D_cam0.begin() + 5,
00696                              points2D_cam2.begin());
00697 
00698         // Test each candidate.
00699         for(size_t jj = 0; jj < EVector.size(); ++jj) {
00700           Array2D<double> EE = EVector[jj];
00701 
00702           // Recover relative motion between cameras, assuming EE is
00703           // correct.
00704           dlr::numeric::Transform3D c2Tc0;
00705           try {
00706             c2Tc0 = getCameraMotionFromEssentialMatrix(
00707               EE, points2D_cam0[0], points2D_cam2[0]);
00708           } catch(dlr::common::ValueException&) {
00709             // Input points were on parallel rays!  No point in evaluating
00710             // this candidate.
00711             continue;
00712           }
00713 
00714           // Given relative motion, recover 3D position of each input
00715           // point in camera 2 coordinates.
00716           for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00717             points3D_cam2[kk] = triangulateCalibratedImagePoint(
00718               c2Tc0, points2D_cam2[kk], points2D_cam0[kk]);
00719           }
00720 
00721           // Recover 3D position and orientation of camera 1.
00722           double internalScore;
00723           dlr::numeric::Transform3D c1Tc2 = threePointAlgorithmRobust(
00724             points3D_cam2.begin(), points3D_cam2.begin() + 5,
00725             points2D_cam1.begin(), intrinsics, 1, 1.0, internalScore, pRandom);
00726 
00727           // We expect the model to fit these five points better than
00728           // it fits other points in the set.  If internalScore
00729           // doesn't beat the average residual over all points for our
00730           // best so far, then there's no point in continuing with
00731           // this candidate.
00732           if(internalScore >= bestErrorSoFar) {
00733             continue;
00734           }
00735           
00736           // Compute the 3D position of each input point in camera 1
00737           // coordinates.
00738           for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00739             points3D_cam1[kk] = c1Tc2 * points3D_cam2[kk];
00740           }
00741           
00742           // Recover 3D position of each of the input points in camera
00743           // 0 coordinates.
00744           dlr::numeric::Transform3D c0Tc2 = c2Tc0.invert();
00745           for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00746             points3D_cam0[kk] = c0Tc2 * points3D_cam2[kk];
00747           }
00748           
00749           // Project 3D points into each image, and compute residual.
00750           for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00751             dlr::numeric::Vector2D residualVec0(
00752               points3D_cam0[kk].x() / points3D_cam0[kk].z(),
00753               points3D_cam0[kk].y() / points3D_cam0[kk].z());
00754             residualVec0 -= points2D_cam0[kk];
00755             dlr::numeric::Vector2D residualVec1(
00756               points3D_cam1[kk].x() / points3D_cam1[kk].z(),
00757               points3D_cam1[kk].y() / points3D_cam1[kk].z());
00758             residualVec1 -= points2D_cam1[kk];
00759             dlr::numeric::Vector2D residualVec2(
00760               points3D_cam2[kk].x() / points3D_cam2[kk].z(),
00761               points3D_cam2[kk].y() / points3D_cam2[kk].z());
00762             residualVec2 -= points2D_cam2[kk];
00763 
00764             residualVector[kk] =
00765               (dlr::numeric::magnitudeSquared(residualVec0)
00766                + dlr::numeric::magnitudeSquared(residualVec1)
00767                + dlr::numeric::magnitudeSquared(residualVec2)) / 3.0;
00768           }
00769 
00770           // Compute robust error statistic.
00771           //
00772           // Note(xxx): Better not to sort here, since it changes the
00773           // algorithm to O(NlogN).
00774           std::sort(residualVector.begin(), residualVector.end());
00775           int testIndex = static_cast<int>(
00776             inlierProportion * residualVector.size() + 0.5);
00777           double errorValue = residualVector[testIndex];
00778 
00779           // Remember candidate if it's the best so far.
00780           if(errorValue < bestErrorSoFar) {
00781             selectedCam2Ecam0 = EE;
00782             selectedCam0Tcam2 = c0Tc2;
00783             selectedCam1Tcam2 = c1Tc2;
00784             bestErrorSoFar = errorValue;
00785           }
00786         }
00787       }
00788       score = bestErrorSoFar;
00789       cam2Ecam0 = selectedCam2Ecam0;
00790       cam0Tcam2 = selectedCam0Tcam2;
00791       cam1Tcam2 = selectedCam1Tcam2;
00792     }
00793 
00794   } // namespace computerVision
00795     
00796 } // namespace dlr
00797 
00798 #endif /* #ifndef DLR_COMPUTERVISION_FIVEPOINTALGORITHM_H */

Generated on Wed Nov 25 12:15:05 2009 for dlrComputerVision Utility Library by  doxygen 1.5.8