diff --git a/gtsam_unstable/slam/SmartStereoProjectionFactorPP.h b/gtsam_unstable/slam/SmartStereoProjectionFactorPP.h index ab43ef0d7..da8a0d976 100644 --- a/gtsam_unstable/slam/SmartStereoProjectionFactorPP.h +++ b/gtsam_unstable/slam/SmartStereoProjectionFactorPP.h @@ -192,12 +192,12 @@ class SmartStereoProjectionFactorPP : public SmartStereoProjectionFactor { const Values& values, const double lambda = 0.0, bool diagonalDamping = false) const { - size_t nrKeys = keys_.size(); + size_t nrUniqueKeys = keys_.size(); // Create structures for Hessian Factors KeyVector js; - std::vector Gs(nrKeys * (nrKeys + 1) / 2); - std::vector gs(nrKeys); + std::vector Gs(nrUniqueKeys * (nrUniqueKeys + 1) / 2); + std::vector gs(nrUniqueKeys); if (this->measured_.size() != cameras(values).size()) throw std::runtime_error("SmartStereoProjectionHessianFactor: this->" @@ -223,34 +223,28 @@ class SmartStereoProjectionFactorPP : public SmartStereoProjectionFactor { computeJacobiansWithTriangulatedPoint(Fs, E, b, values); // Whiten using noise model -// std::cout << "noise model1 \n " << std::endl; noiseModel_->WhitenSystem(E, b); -// std::cout << "noise model2 \n " << std::endl; for (size_t i = 0; i < Fs.size(); i++) Fs[i] = noiseModel_->Whiten(Fs[i]); -// std::cout << "noise model3 \n " << std::endl; // build augmented hessian Matrix3 P; Cameras::ComputePointCovariance<3>(P, E, lambda, diagonalDamping); -// std::cout << "ComputePointCovariance done!!! \n " << std::endl; -// std::cout << "Fs.size() = " << Fs.size() << std::endl; -// std::cout << "E = " << E << std::endl; -// std::cout << "P = " << P << std::endl; -// std::cout << "b = " << b << std::endl; + // marginalize point SymmetricBlockMatrix augmentedHessian = // Cameras::SchurComplement<3,Dim>(Fs, E, P, b); - std::vector dims(nrKeys + 1); // this also includes the b term + // now pack into an Hessian factor + std::vector dims(nrUniqueKeys + 1); // this also includes the b term std::fill(dims.begin(), dims.end() - 1, 6); dims.back() = 1; size_t nrNonuniqueKeys = w_P_body_keys_.size() + body_P_cam_keys_.size(); - SymmetricBlockMatrix augmentedHessianPP; - if ( nrKeys == nrNonuniqueKeys ){ // 1 calibration per camera - augmentedHessianPP = SymmetricBlockMatrix(dims, Matrix(augmentedHessian.selfadjointView())); - }else{ + SymmetricBlockMatrix augmentedHessianUniqueKeys; + if ( nrUniqueKeys == nrNonuniqueKeys ){ // if there is 1 calibration key per camera + augmentedHessianUniqueKeys = SymmetricBlockMatrix(dims, Matrix(augmentedHessian.selfadjointView())); + }else{ // if multiple cameras share a calibration std::vector nonuniqueDims(nrNonuniqueKeys + 1); // this also includes the b term std::fill(nonuniqueDims.begin(), nonuniqueDims.end() - 1, 6); nonuniqueDims.back() = 1; @@ -263,54 +257,55 @@ class SmartStereoProjectionFactorPP : public SmartStereoProjectionFactor { nonuniqueKeys.push_back(body_P_cam_keys_.at(i)); } - // get map from key to location in the new augmented Hessian matrix + // get map from key to location in the new augmented Hessian matrix (the one including only unique keys) std::map keyToSlotMap; - for(size_t k=0; kj: " << std::endl; - augmentedHessianPP.updateOffDiagonalBlock( keyToSlotMap[key_i] , keyToSlotMap[key_j], - augmentedHessian.aboveDiagonalBlock(j,i)); + augmentedHessianUniqueKeys.updateOffDiagonalBlock( keyToSlotMap[key_i] , keyToSlotMap[key_j], + augmentedHessian.aboveDiagonalBlock(j,i).transpose()); } } } + augmentedHessianUniqueKeys.updateDiagonalBlock(nrUniqueKeys, augmentedHessian.diagonalBlock(nrNonuniqueKeys)); + + std::cout << "MAtrix \n " << Matrix(augmentedHessianUniqueKeys.selfadjointView()) < >(keys_, augmentedHessianPP); + + return boost::make_shared >(keys_, augmentedHessianUniqueKeys); //std::cout << "Matrix(augmentedHessian.selfadjointView()) \n" << Matrix(augmentedHessian.selfadjointView()) < measurements_l1 = stereo_projectToMultipleCameras(cam1, + cam2, cam3, landmark1); + vector measurements_l2 = stereo_projectToMultipleCameras(cam1, + cam2, cam3, landmark2); + vector measurements_l3 = stereo_projectToMultipleCameras(cam1, + cam2, cam3, landmark3); + + double initialError_expected, initialError_actual; + { + KeyVector poseKeys; + poseKeys.push_back(x1); + poseKeys.push_back(x2); + poseKeys.push_back(x3); + + KeyVector extrinsicKeys; + extrinsicKeys.push_back(body_P_cam1_key); + extrinsicKeys.push_back(body_P_cam2_key); + extrinsicKeys.push_back(body_P_cam3_key); + + SmartStereoProjectionParams smart_params; + smart_params.triangulation.enableEPI = true; + SmartStereoProjectionFactorPP::shared_ptr smartFactor1(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor1->add(measurements_l1, poseKeys, extrinsicKeys, K2); + + SmartStereoProjectionFactorPP::shared_ptr smartFactor2(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor2->add(measurements_l2, poseKeys, extrinsicKeys, K2); + + SmartStereoProjectionFactorPP::shared_ptr smartFactor3(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor3->add(measurements_l3, poseKeys, extrinsicKeys, K2); + + const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6, 0.10); + + // Values + Pose3 body_Pose_cam1 = Pose3(Rot3::Ypr(-M_PI, 1., 0.1),Point3(0, 1, 0)); + Pose3 body_Pose_cam2 = body_Pose_cam1; + Pose3 body_Pose_cam3 = body_Pose_cam1; + Pose3 w_Pose_body1 = w_Pose_cam1.compose(body_Pose_cam1.inverse()); + Pose3 w_Pose_body2 = w_Pose_cam2.compose(body_Pose_cam2.inverse()); + Pose3 w_Pose_body3 = w_Pose_cam3.compose(body_Pose_cam3.inverse()); + + Values values; + Pose3 noise_pose = Pose3(Rot3::Ypr(-M_PI / 100, 0., -M_PI / 100), Point3(0.1, 0.1, 0.1)); // smaller noise + values.insert(x1, w_Pose_body1); + values.insert(x2, w_Pose_body2); + values.insert(x3, w_Pose_body3); + values.insert(body_P_cam1_key, body_Pose_cam1 * noise_pose); + values.insert(body_P_cam2_key, body_Pose_cam2 * noise_pose); + // initialize third calibration with some noise, we expect it to move back to original pose3 + values.insert(body_P_cam3_key, body_Pose_cam3 * noise_pose); + + // Graph + NonlinearFactorGraph graph; + graph.push_back(smartFactor1); + graph.push_back(smartFactor2); + graph.push_back(smartFactor3); + graph.addPrior(x1, w_Pose_body1, noisePrior); + graph.addPrior(x2, w_Pose_body2, noisePrior); + graph.addPrior(x3, w_Pose_body3, noisePrior); + + initialError_expected = graph.error(values); + } + + { + KeyVector poseKeys; + poseKeys.push_back(x1); + poseKeys.push_back(x2); + poseKeys.push_back(x3); + + KeyVector extrinsicKeys; + extrinsicKeys.push_back(body_P_cam1_key); + extrinsicKeys.push_back(body_P_cam1_key); + extrinsicKeys.push_back(body_P_cam1_key); + + SmartStereoProjectionParams smart_params; + smart_params.triangulation.enableEPI = true; + SmartStereoProjectionFactorPP::shared_ptr smartFactor1(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor1->add(measurements_l1, poseKeys, extrinsicKeys, K2); + + SmartStereoProjectionFactorPP::shared_ptr smartFactor2(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor2->add(measurements_l2, poseKeys, extrinsicKeys, K2); + + SmartStereoProjectionFactorPP::shared_ptr smartFactor3(new SmartStereoProjectionFactorPP(model, smart_params)); + smartFactor3->add(measurements_l3, poseKeys, extrinsicKeys, K2); + + const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6, 0.10); + + // Values + Pose3 body_Pose_cam1 = Pose3(Rot3::Ypr(-M_PI, 1., 0.1),Point3(0, 1, 0)); + Pose3 w_Pose_body1 = w_Pose_cam1.compose(body_Pose_cam1.inverse()); + Pose3 w_Pose_body2 = w_Pose_cam2.compose(body_Pose_cam1.inverse()); + Pose3 w_Pose_body3 = w_Pose_cam3.compose(body_Pose_cam1.inverse()); + + Values values; + Pose3 noise_pose = Pose3(Rot3::Ypr(-M_PI / 100, 0., -M_PI / 100), Point3(0.1, 0.1, 0.1)); // smaller noise + values.insert(x1, w_Pose_body1); + values.insert(x2, w_Pose_body2); + values.insert(x3, w_Pose_body3); + values.insert(body_P_cam1_key, body_Pose_cam1 * noise_pose); + + // Graph + NonlinearFactorGraph graph; + graph.push_back(smartFactor1); + graph.push_back(smartFactor2); + graph.push_back(smartFactor3); + graph.addPrior(x1, w_Pose_body1, noisePrior); + graph.addPrior(x2, w_Pose_body2, noisePrior); + graph.addPrior(x3, w_Pose_body3, noisePrior); + + initialError_actual = graph.error(values); + } + + std::cout << " initialError_expected " << initialError_expected << std::endl; + EXPECT_DOUBLES_EQUAL(initialError_expected, initialError_actual, 1e-7); +} + /* *************************************************************************/ TEST( SmartStereoProjectionFactorPP, 3poses_smart_projection_factor_optimization_sameExtrinsicKey ) { @@ -689,6 +825,10 @@ TEST( SmartStereoProjectionFactorPP, 3poses_smart_projection_factor_optimization double initialErrorSmart = graph.error(values); EXPECT_DOUBLES_EQUAL(31986.961831653316, initialErrorSmart, 1e-5); // initial guess is noisy, so nonzero error + std::cout << " 1: " << smartFactor1->error(values) <error(values) <error(values) <