eightPointAlgorithm.h

Go to the documentation of this file.
00001 
00015 #ifndef DLR_COMPUTERVISION_EIGHTPOINTALGORITHM_H
00016 #define DLR_COMPUTERVISION_EIGHTPOINTALGORITHM_H
00017 
00018 #include <dlrNumeric/array1D.h>
00019 #include <dlrNumeric/array2D.h>
00020 #include <dlrNumeric/vector2D.h>
00021 
00022 namespace dlr {
00023 
00024   namespace computerVision {
00025 
00067     template<class Iterator>
00068     dlr::numeric::Array2D<double>
00069     eightPointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00070                         Iterator sequence1Begin);
00071     
00072     
00095     template<class Iterator>
00096     dlr::numeric::Array2D<double>
00097     eightPointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00098                         Iterator sequence1Begin,
00099                         dlr::numeric::Array1D<double>& eigenvalues);
00100 
00101 
00102 
00124     void
00125     normalizePointSequence(dlr::numeric::Array2D<double> const& inputPoints,
00126                            dlr::numeric::Array2D<double>& outputPoints,
00127                            dlr::numeric::Array2D<double>& transform);
00128 
00129   } // namespace computerVision
00130     
00131 } // namespace dlr
00132 
00133 
00134 /* ============ Definitions of inline & template functions ============ */
00135 
00136 
00137 #include <cmath>
00138 #include <dlrLinearAlgebra/linearAlgebra.h>
00139 #include <dlrNumeric/utilities.h>
00140 
00141 
00142 namespace dlr {
00143 
00144   namespace computerVision {
00145 
00146 
00147     template<class Iterator>
00148     dlr::numeric::Array2D<double>
00149     eightPointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00150                         Iterator sequence1Begin)
00151     {
00152       dlr::numeric::Array1D<double> eigenvalues;
00153       return eightPointAlgorithm(
00154         sequence0Begin, sequence0End, sequence1Begin, eigenvalues);
00155     }
00156     
00157     
00158     template<class Iterator>
00159     dlr::numeric::Array2D<double>
00160     eightPointAlgorithm(Iterator sequence0Begin, Iterator sequence0End,
00161                         Iterator sequence1Begin,
00162                         dlr::numeric::Array1D<double>& eigenvalues)
00163     {
00164       // Find out how many points we have.  Even if this subtraction
00165       // is O(N), it will be dominated by the matrix multiplication
00166       // below.
00167       size_t numberOfCorrespondences = sequence0End - sequence0Begin;
00168 
00169       
00170       // Following Hartley, precondition the data by translating and
00171       // scaling (independently for each image) so that the points
00172       // roughly form a unit circle.  This greatly improves the
00173       // stability of the math below.
00174       dlr::numeric::Array2D<double> inputArray(numberOfCorrespondences, 3);
00175       dlr::numeric::Array2D<double> inputPrimeArray(numberOfCorrespondences, 3);
00176       Iterator begin0 = sequence0Begin;
00177       Iterator begin1 = sequence1Begin;
00178       size_t pointIndex = 0;
00179       while(begin0 != sequence0End) {
00180         dlr::numeric::Array1D<double> tmpRow = inputArray.getRow(pointIndex);
00181         tmpRow[0] = begin0->x();
00182         tmpRow[1] = begin0->y();
00183         tmpRow[2] = 1.0;
00184 
00185         tmpRow = inputPrimeArray.getRow(pointIndex);
00186         tmpRow[0] = begin1->x();
00187         tmpRow[1] = begin1->y();
00188         tmpRow[2] = 1.0;
00189 
00190         ++pointIndex;
00191         ++begin0;
00192         ++begin1;
00193       }
00194 
00195       dlr::numeric::Array2D<double> KKInv;
00196       dlr::numeric::Array2D<double> normalizedPoints;
00197       normalizePointSequence(inputArray, normalizedPoints, KKInv);
00198 
00199       dlr::numeric::Array2D<double> KPrimeInv;
00200       dlr::numeric::Array2D<double> normalizedPrimePoints;
00201       normalizePointSequence(inputPrimeArray, normalizedPrimePoints, KPrimeInv);
00202 
00203       // For each pair of points u, u', the fundamental matrix, F,
00204       // satisfies the equation:
00205       //
00206       //   transpose(u') * F * u = 0
00207       //
00208       // where the points u are drawn from sequence0, and the points
00209       // u' are drawn from sequence1.
00210       // 
00211       // We rearrange this equation to get
00212       //
00213       //   ||f_00*u_x*u'_x + f_01*u_y*u'_x + f_02*u'_x
00214       //     + f_10*u_x*u'_y + f_11*u_y*u'_y + f_12*u'_y
00215       //     + f_20*u_x + f_21*u_y + f_22|| = 0
00216       //
00217       // where f_ij is the element of F in the i^th row and the j^th
00218       // column, u_x & u_y are the x & y components of u,
00219       // respectively, and u'_x & u'_y are the x & y components of u',
00220       // respectively.
00221       //
00222       // or,
00223       // 
00224       //   ||A * vec(F)|| = 0
00225       //
00226       // With the matrix A as specified in the code below.
00227         
00228       dlr::numeric::Array2D<double> AMatrix(numberOfCorrespondences, 9);
00229       for(size_t rowIndex = 0; rowIndex < numberOfCorrespondences; ++rowIndex) {
00230         dlr::numeric::Array1D<double> currentRow = AMatrix.getRow(rowIndex);
00231         const dlr::numeric::Array1D<double>& uu =
00232           normalizedPoints.getRow(rowIndex);
00233         const dlr::numeric::Array1D<double>& uPrime =
00234           normalizedPrimePoints.getRow(rowIndex);
00235         currentRow[0] = uu[0] * uPrime[0];
00236         currentRow[1] = uu[1] * uPrime[0];
00237         currentRow[2] = uu[2] * uPrime[0];
00238         currentRow[3] = uu[0] * uPrime[1];
00239         currentRow[4] = uu[1] * uPrime[1];
00240         currentRow[5] = uu[2] * uPrime[1];
00241         currentRow[6] = uu[0] * uPrime[2];
00242         currentRow[7] = uu[1] * uPrime[2];
00243         currentRow[8] = uu[2] * uPrime[2];
00244       }
00245 
00246       // Solve for the F that minimizes the residual in the least
00247       // squares sense.
00248       dlr::numeric::Array2D<double> ATA =
00249         dlr::numeric::matrixMultiply(AMatrix.transpose(), AMatrix);
00250       dlr::numeric::Array2D<double> eigenvectors;
00251       dlr::linearAlgebra::eigenvectorsSymmetric(ATA, eigenvalues, eigenvectors);
00252       dlr::numeric::Array2D<double> FMatrix(3, 3);
00253       FMatrix[0] = eigenvectors(0, 8);
00254       FMatrix[1] = eigenvectors(1, 8);
00255       FMatrix[2] = eigenvectors(2, 8);
00256       FMatrix[3] = eigenvectors(3, 8);
00257       FMatrix[4] = eigenvectors(4, 8);
00258       FMatrix[5] = eigenvectors(5, 8);
00259       FMatrix[6] = eigenvectors(6, 8);
00260       FMatrix[7] = eigenvectors(7, 8);
00261       FMatrix[8] = eigenvectors(8, 8);
00262 
00263       // Good.  Now we have an estimate for F.  Here we enforce that F
00264       // must not be full rank.
00265       dlr::numeric::Array2D<double> uArray;
00266       dlr::numeric::Array1D<double> sigmaArray;
00267       dlr::numeric::Array2D<double> vTransposeArray;
00268       dlr::linearAlgebra::singularValueDecomposition(
00269         FMatrix, uArray, sigmaArray, vTransposeArray);
00270       uArray[2] = 0.0;
00271       for(size_t ii = 0; ii < sigmaArray.size(); ++ii) {
00272         vTransposeArray.getRow(ii) *= sigmaArray(ii);
00273       }
00274       FMatrix = matrixMultiply(uArray, vTransposeArray);
00275 
00276       // Transform back to unnormalized coordinates.
00277       FMatrix =
00278         dlr::numeric::matrixMultiply(
00279           dlr::numeric::matrixMultiply(KPrimeInv.transpose(), FMatrix), KKInv);
00280       
00281       return FMatrix;
00282     }
00283 
00284   } // namespace computerVision
00285     
00286 } // namespace dlr
00287 
00288 #endif /* #ifndef DLR_COMPUTERVISION_EIGHTPOINTALGORITHM_H */

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