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
00250 double
00251 checkEpipolarConstraint(dlr::numeric::Array2D<double> const& fundamentalMx,
00252 dlr::numeric::Vector2D& point0,
00253 dlr::numeric::Vector2D& point1);
00254
00255
00256
00257
00258
00259
00260
00261
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
00270
00271
00272
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 }
00315
00316 }
00317
00318
00319
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
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
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
00393
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
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
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
00464
00465
00466
00467
00468
00469
00470
00471
00472 dlr::numeric::Array2D<double> M0 = dlr::numeric::subArray(
00473 M, dlr::numeric::Slice(), dlr::numeric::Slice(0, 10));
00474
00475
00476 dlr::numeric::Array2D<double> M0Inv = dlr::linearAlgebra::inverse(M0);
00477
00478
00479 dlr::numeric::Array2D<double> M1 = dlr::numeric::subArray(
00480 M, dlr::numeric::Slice(), dlr::numeric::Slice(10, 0));
00481
00482
00483
00484
00485
00486
00487
00488
00489 dlr::numeric::Array2D<double> B = dlr::numeric::matrixMultiply(M0Inv, M1);
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
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
00543
00544
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
00550
00551
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
00578
00579 double bestErrorSoFar = std::numeric_limits<double>::max();
00580 dlr::numeric::Array2D<double> selectedCandidate(3, 3);
00581 selectedCandidate = 0.0;
00582
00583
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
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
00602 std::vector< dlr::numeric::Array2D<double> > EVector =
00603 fivePointAlgorithm(qVector.begin(), qVector.begin() + 5,
00604 qPrimeVector.begin());
00605
00606
00607 for(size_t jj = 0; jj < EVector.size(); ++jj) {
00608 Array2D<double> EE = EVector[jj];
00609
00610
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
00618
00619
00620
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
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
00652
00653 CameraIntrinsicsPinhole intrinsics(1, 1, 1.0, 1.0, 1.0, 0.0, 0.0);
00654
00655
00656
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
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
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
00681 for(size_t ii = 0; ii < iterations; ++ii) {
00682
00683
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
00694 std::vector< dlr::numeric::Array2D<double> > EVector =
00695 fivePointAlgorithm(points2D_cam0.begin(), points2D_cam0.begin() + 5,
00696 points2D_cam2.begin());
00697
00698
00699 for(size_t jj = 0; jj < EVector.size(); ++jj) {
00700 Array2D<double> EE = EVector[jj];
00701
00702
00703
00704 dlr::numeric::Transform3D c2Tc0;
00705 try {
00706 c2Tc0 = getCameraMotionFromEssentialMatrix(
00707 EE, points2D_cam0[0], points2D_cam2[0]);
00708 } catch(dlr::common::ValueException&) {
00709
00710
00711 continue;
00712 }
00713
00714
00715
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
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
00728
00729
00730
00731
00732 if(internalScore >= bestErrorSoFar) {
00733 continue;
00734 }
00735
00736
00737
00738 for(size_t kk = 0; kk < numberOfPoints; ++kk) {
00739 points3D_cam1[kk] = c1Tc2 * points3D_cam2[kk];
00740 }
00741
00742
00743
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
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
00771
00772
00773
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
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 }
00795
00796 }
00797
00798 #endif