/* * @file testEssentialMatrixFactor.cpp * @brief Test EssentialMatrixFactor class * @author Frank Dellaert * @date December 17, 2013 */ #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace boost::assign; using namespace gtsam; //************************************************************************* // Create two cameras and corresponding essential matrix E Rot3 aRb = Rot3::yaw(M_PI_2); Point3 aTb(0.1, 0, 0); Pose3 identity, aPb(aRb, aTb); typedef CalibratedCamera Cam; Cam cameraA(identity), cameraB(aPb); Matrix aEb_matrix = skewSymmetric(aTb.x(), aTb.y(), aTb.z()) * aRb.matrix(); // Create test data, we need at least 5 points Point3 P[5] = { Point3(0, 0, 1), Point3(-0.1, 0, 1), Point3(0.1, 0, 1), // Point3(0, 0.5, 0.5), Point3(0, -0.5, 0.5) }; // Project points in both cameras vector pA(5), pB(5); vector::iterator // it1 = std::transform(P, P + 5, pA.begin(), boost::bind(&Cam::project, &cameraA, _1, boost::none, boost::none)), // it2 = std::transform(P, P + 5, pB.begin(), boost::bind(&Cam::project, &cameraB, _1, boost::none, boost::none)); // Converto to homogenous coordinates vector vA(5), vB(5); vector::iterator // it3 = std::transform(pA.begin(), pA.end(), vA.begin(), &EssentialMatrix::Homogeneous), // it4 = std::transform(pB.begin(), pB.end(), vB.begin(), &EssentialMatrix::Homogeneous); //************************************************************************* TEST (EssentialMatrix, testData) { // Check E matrix Matrix expected(3, 3); expected << 0, 0, 0, 0, 0, -0.1, 0.1, 0, 0; EXPECT(assert_equal(expected, aEb_matrix)); // Check some projections EXPECT(assert_equal(Point2(0,0),pA[0])); EXPECT(assert_equal(Point2(0,0.1),pB[0])); EXPECT(assert_equal(Point2(0,-1),pA[4])); EXPECT(assert_equal(Point2(-1,0.2),pB[4])); // Check homogeneous version EXPECT(assert_equal((Vector(3) << -1,0.2,1),vB[4])); // Check epipolar constraint for (size_t i = 0; i < 5; i++) EXPECT_DOUBLES_EQUAL(0, vA[i].transpose() * aEb_matrix * vB[i], 1e-8); // Check epipolar constraint EssentialMatrix trueE(aRb, aTb); for (size_t i = 0; i < 5; i++) EXPECT_DOUBLES_EQUAL(0, trueE.error(vA[i],vB[i]), 1e-8); } //************************************************************************* TEST (EssentialMatrix, factor) { EssentialMatrix trueE(aRb, aTb); noiseModel::Unit::shared_ptr model = noiseModel::Unit::Create(1); for (size_t i = 0; i < 5; i++) { EssentialMatrixFactor factor(1, pA[i], pB[i], model); // Check evaluation Vector expected(1); expected << 0; Matrix HActual; Vector actual = factor.evaluateError(trueE, HActual); EXPECT(assert_equal(expected, actual, 1e-8)); // Use numerical derivatives to calculate the expected Jacobian Matrix HExpected; HExpected = numericalDerivative11( boost::bind(&EssentialMatrixFactor::evaluateError, &factor, _1, boost::none), trueE); // Verify the Jacobian is correct CHECK(assert_equal(HExpected, HActual, 1e-9)); } } //************************************************************************* TEST (EssentialMatrix, fromConstraints) { // Here we want to optimize directly on essential matrix constraints // Yi Ma's algorithm (Ma01ijcv) is a bit cumbersome to implement, // but GTSAM does the equivalent anyway, provided we give the right // factors. In this case, the factors are the constraints. // We start with a factor graph and add constraints to it // Noise sigma is 1cm, assuming metric measurements NonlinearFactorGraph graph; noiseModel::Isotropic::shared_ptr model = noiseModel::Isotropic::Sigma(1,0.01); for (size_t i = 0; i < 5; i++) graph.add(EssentialMatrixFactor(1, pA[i], pB[i], model)); // Check error at ground truth Values truth; EssentialMatrix trueE(aRb, aTb); truth.insert(1, trueE); EXPECT_DOUBLES_EQUAL(0, graph.error(truth), 1e-8); // Check error at initial estimate Values initial; EssentialMatrix initialE = trueE.retract((Vector(5) << 0.1, -0.1, 0.1, 0.1, -0.1)); initial.insert(1, initialE); EXPECT_DOUBLES_EQUAL(640, graph.error(initial), 1e-2); // Optimize LevenbergMarquardtParams parameters; LevenbergMarquardtOptimizer optimizer(graph, initial, parameters); Values result = optimizer.optimize(); // Check result EssentialMatrix actual = result.at(1); EXPECT(assert_equal(trueE, actual,1e-1)); // Check error at result EXPECT_DOUBLES_EQUAL(0, graph.error(result), 1e-4); // Check errors individually for (size_t i = 0; i < 5; i++) EXPECT_DOUBLES_EQUAL(0, actual.error(vA[i],vB[i]), 1e-6); } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */