Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rolling shutter smart factors #827

Merged
merged 53 commits into from
Aug 28, 2021
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
d4eaa15
rolling shutter projection factor
Apr 22, 2021
cd1d4b4
added templates for factors
Jul 19, 2021
00387b3
setting up .h and tests - compiles and tests pass.
Jul 19, 2021
82844b5
put in place initial functions
Jul 19, 2021
1e2a1d2
removed cpp
Jul 19, 2021
16d624d
now I need to move to testing and interpolation
Jul 19, 2021
a0ca338
added interpolation function from shteren1
Jul 20, 2021
b8fa0cc
Merge branch 'feature/rollingShutterSmartFactors' into rolling_factor
lucacarlone Jul 20, 2021
b5286d3
Merge pull request #826 from shteren1/rolling_factor
lucacarlone Jul 20, 2021
4c997e5
removed interp from Pose3, starting to take pass on projection factor…
Jul 21, 2021
a204f6d
amended
Jul 21, 2021
2812eeb
pass on projection factor, but looks great overall
Jul 21, 2021
0d1c3f1
everything working out so far with the tests
Jul 21, 2021
a480b2d
all tests are passing!
Jul 21, 2021
02d2d97
added nice test on cheirality exception - done with projectionFactorR…
Jul 21, 2021
30f304e
started serious testing: all tests pass for now
Jul 21, 2021
306393a
solidified add and equal
Jul 21, 2021
6f8d639
finding best way to test RS errors
Jul 21, 2021
5d55e15
yay! error test passes!
Jul 21, 2021
4669213
jacobians are good to go!
Jul 21, 2021
e6ff03f
jacobians and errors are well tested now
Jul 21, 2021
d4b88ba
got to the final monster. Now I need to implement createHessian
Jul 22, 2021
a439cf0
stuck on compile issue
Jul 22, 2021
d7e8912
all pass!
Jul 23, 2021
477dd5b
all pass!
Jul 23, 2021
91a6613
moved common function to cameraSet. commented issues with templated c…
Jul 23, 2021
48a7afa
removed comments. Code is complete now. Need few more unit tests and …
Jul 23, 2021
1c3ff05
removed printout, solved CI issue
Jul 23, 2021
9344135
fixed another test, few more to go
Jul 23, 2021
aeb1d35
fixed test with lmk distance
Jul 23, 2021
a7b7770
test with EPI fixed
Jul 23, 2021
9c288d9
working on testing + cosmetic improvements to print for smart factors
Jul 23, 2021
81526e8
fixed another test.
Jul 23, 2021
5350e34
done with tests, now I only have to rename gamma to keep consistency …
Jul 23, 2021
1f07142
renamed params. need one last test
Jul 23, 2021
a10d495
extra cleanup
Jul 24, 2021
e838d01
added timing test
Jul 24, 2021
e4f1bb1
CHECK -> EXPECT
Jul 24, 2021
9834042
test still in progress; removed a tmp function
Jul 24, 2021
2f03e58
fixed last test - this is good to go!
Jul 24, 2021
5e0a6b4
fixing ci issue
Jul 24, 2021
0b002e6
Merge branch 'develop' into feature/rollingShutterSmartFactors
Aug 12, 2021
cbd6a2a
now using MakeJacobian
Aug 13, 2021
9f19077
simplified jacobian computation, improved comments
Aug 13, 2021
a3ee695
reformatted using google style
Aug 14, 2021
0a8ebdf
renamed interp param to alpha, improved comments, added cpp
Aug 14, 2021
37b0013
plot twist: templating new factor on CAMERA
Aug 26, 2021
f712d62
Added override
dellaert Aug 28, 2021
0c62229
Some formatting
dellaert Aug 28, 2021
2b3709e
Got rid of SchurComplementAndRearrangeBlocks_3_12_6
dellaert Aug 28, 2021
d0505d4
Check equals not assert_equal
dellaert Aug 28, 2021
bafcde9
Google-style formatting in new files.
dellaert Aug 28, 2021
9798bfa
Cleaned up interpolate
dellaert Aug 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions gtsam/base/Lie.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* @author Frank Dellaert
* @author Mike Bosse
* @author Duy Nguyen Ta
* @author Yotam Stern
*/


Expand Down Expand Up @@ -319,11 +320,33 @@ T expm(const Vector& x, int K=7) {
}

/**
* Linear interpolation between X and Y by coefficient t in [0, 1].
* Linear interpolation between X and Y by coefficient t in [0, 1.5] (t>1 implies extrapolation), with optional jacobians.
*/
template <typename T>
T interpolate(const T& X, const T& Y, double t) {
assert(t >= 0 && t <= 1);
T interpolate(const T& X, const T& Y, double t,
OptionalJacobian< traits<T>::dimension, traits<T>::dimension > Hx = boost::none,
lucacarlone marked this conversation as resolved.
Show resolved Hide resolved
OptionalJacobian< traits<T>::dimension, traits<T>::dimension > Hy = boost::none) {
assert(t >= 0.0 && t <= 1.5);
if (Hx || Hy) {
typedef Eigen::Matrix<double, traits<T>::dimension, traits<T>::dimension> Jacobian;
lucacarlone marked this conversation as resolved.
Show resolved Hide resolved
typename traits<T>::TangentVector log_Xinv_Y;
Jacobian Hx_tmp, Hy_tmp, H1, H2;
lucacarlone marked this conversation as resolved.
Show resolved Hide resolved

T Xinv_Y = traits<T>::Between(X, Y, Hx_tmp, Hy_tmp);
log_Xinv_Y = traits<T>::Logmap(Xinv_Y, H1);
Hx_tmp = H1 * Hx_tmp;
Hy_tmp = H1 * Hy_tmp;
Xinv_Y = traits<T>::Expmap(t * log_Xinv_Y, H1);
Hx_tmp = t * H1 * Hx_tmp;
Hy_tmp = t * H1 * Hy_tmp;
Xinv_Y = traits<T>::Compose(X, Xinv_Y, H1, H2);
Hx_tmp = H1 + H2 * Hx_tmp;
Hy_tmp = H2 * Hy_tmp;

if(Hx) *Hx = Hx_tmp;
if(Hy) *Hy = Hy_tmp;
return Xinv_Y;
}
return traits<T>::Compose(X, traits<T>::Expmap(t * traits<T>::Logmap(traits<T>::Between(X, Y))));
}

Expand Down
105 changes: 102 additions & 3 deletions gtsam/geometry/CameraSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class CameraSet : public std::vector<CAMERA, Eigen::aligned_allocator<CAMERA> >
* g = F' * (b - E * P * E' * b)
* Fixed size version
*/
template<int N, int ND> // N = 2 or 3, ND is the camera dimension
template<int N, int ND> // N = 2 or 3 (point dimension), ND is the camera dimension
static SymmetricBlockMatrix SchurComplement(
const std::vector< Eigen::Matrix<double, ZDim, ND>, Eigen::aligned_allocator< Eigen::Matrix<double, ZDim, ND> > >& Fs,
const Matrix& E, const Eigen::Matrix<double, N, N>& P, const Vector& b) {
Expand Down Expand Up @@ -193,6 +193,105 @@ class CameraSet : public std::vector<CAMERA, Eigen::aligned_allocator<CAMERA> >
return augmentedHessian;
}

/**
* Do Schur complement, given Jacobian as Fs,E,P, return SymmetricBlockMatrix
* G = F' * F - F' * E * P * E' * F
* g = F' * (b - E * P * E' * b)
* In this version, we allow for the case where the keys in the Jacobian are organized
* differents from the keys in the output SymmetricBlockMatrix
lucacarlone marked this conversation as resolved.
Show resolved Hide resolved
* In particular: each block of the Jacobian captures 2 poses (useful for rolling shutter and extrinsic calibration)
lucacarlone marked this conversation as resolved.
Show resolved Hide resolved
*/
template<int N, int ND, int NDD> // N = 2 or 3 (point dimension), ND is the Jacobian block dimension, NDD is the Hessian block dimension
static SymmetricBlockMatrix SchurComplementAndRearrangeBlocks(
const std::vector<Eigen::Matrix<double, ZDim, ND>,
Eigen::aligned_allocator<Eigen::Matrix<double, ZDim, ND> > >& Fs,
const Matrix& E, const Eigen::Matrix<double, N, N>& P, const Vector& b,
const KeyVector jacobianKeys, const KeyVector hessianKeys) {

size_t nrNonuniqueKeys = jacobianKeys.size();
size_t nrUniqueKeys = hessianKeys.size();

// marginalize point: note - we reuse the standard SchurComplement function
SymmetricBlockMatrix augmentedHessian = SchurComplement<N, ND>(Fs,E,P,b);

// now pack into an Hessian factor
std::vector<DenseIndex> dims(nrUniqueKeys + 1); // this also includes the b term
std::fill(dims.begin(), dims.end() - 1, NDD);
dims.back() = 1;
SymmetricBlockMatrix augmentedHessianUniqueKeys;

// here we have to deal with the fact that some blocks may share the same keys
if (nrUniqueKeys == nrNonuniqueKeys) { // if there is 1 calibration key per camera
augmentedHessianUniqueKeys = SymmetricBlockMatrix(
dims, Matrix(augmentedHessian.selfadjointView()));
} else { // if multiple cameras share a calibration we have to rearrange
// the results of the Schur complement matrix
std::vector<DenseIndex> nonuniqueDims(nrNonuniqueKeys + 1); // this also includes the b term
std::fill(nonuniqueDims.begin(), nonuniqueDims.end() - 1, NDD);
nonuniqueDims.back() = 1;
augmentedHessian = SymmetricBlockMatrix(
nonuniqueDims, Matrix(augmentedHessian.selfadjointView()));

// get map from key to location in the new augmented Hessian matrix (the one including only unique keys)
std::map<Key, size_t> keyToSlotMap;
for (size_t k = 0; k < nrUniqueKeys; k++) {
keyToSlotMap[hessianKeys[k]] = k;
}

// initialize matrix to zero
augmentedHessianUniqueKeys = SymmetricBlockMatrix(
dims, Matrix::Zero(NDD * nrUniqueKeys + 1, NDD * nrUniqueKeys + 1));

// add contributions for each key: note this loops over the hessian with nonUnique keys (augmentedHessian)
// and populates an Hessian that only includes the unique keys (that is what we want to return)
for (size_t i = 0; i < nrNonuniqueKeys; i++) { // rows
Key key_i = jacobianKeys.at(i);

// update information vector
augmentedHessianUniqueKeys.updateOffDiagonalBlock(
keyToSlotMap[key_i], nrUniqueKeys,
augmentedHessian.aboveDiagonalBlock(i, nrNonuniqueKeys));

// update blocks
for (size_t j = i; j < nrNonuniqueKeys; j++) { // cols
Key key_j = jacobianKeys.at(j);
if (i == j) {
augmentedHessianUniqueKeys.updateDiagonalBlock(
keyToSlotMap[key_i], augmentedHessian.diagonalBlock(i));
} else { // (i < j)
if (keyToSlotMap[key_i] != keyToSlotMap[key_j]) {
augmentedHessianUniqueKeys.updateOffDiagonalBlock(
keyToSlotMap[key_i], keyToSlotMap[key_j],
augmentedHessian.aboveDiagonalBlock(i, j));
} else {
augmentedHessianUniqueKeys.updateDiagonalBlock(
keyToSlotMap[key_i],
augmentedHessian.aboveDiagonalBlock(i, j)
+ augmentedHessian.aboveDiagonalBlock(i, j).transpose());
}
}
}
}
// update bottom right element of the matrix
augmentedHessianUniqueKeys.updateDiagonalBlock(
nrUniqueKeys, augmentedHessian.diagonalBlock(nrNonuniqueKeys));
}
return augmentedHessianUniqueKeys;
}

/**
* non-templated version of function above
*/
static SymmetricBlockMatrix SchurComplementAndRearrangeBlocks_3_12_6(
dellaert marked this conversation as resolved.
Show resolved Hide resolved
const std::vector<Eigen::Matrix<double,ZDim, 12>,
Eigen::aligned_allocator<Eigen::Matrix<double,ZDim,12> > >& Fs,
const Matrix& E, const Eigen::Matrix<double,3,3>& P, const Vector& b,
const KeyVector jacobianKeys, const KeyVector hessianKeys) {
return SchurComplementAndRearrangeBlocks<3,12,6>(Fs, E, P, b,
jacobianKeys,
hessianKeys);
}

/**
* Do Schur complement, given Jacobian as Fs,E,P, return SymmetricBlockMatrix
* G = F' * F - F' * E * P * E' * F
Expand All @@ -206,7 +305,7 @@ class CameraSet : public std::vector<CAMERA, Eigen::aligned_allocator<CAMERA> >
}

/// Computes Point Covariance P, with lambda parameter
template<int N> // N = 2 or 3
template<int N> // N = 2 or 3 (point dimension)
static void ComputePointCovariance(Eigen::Matrix<double, N, N>& P,
const Matrix& E, double lambda, bool diagonalDamping = false) {

Expand Down Expand Up @@ -258,7 +357,7 @@ class CameraSet : public std::vector<CAMERA, Eigen::aligned_allocator<CAMERA> >
* Applies Schur complement (exploiting block structure) to get a smart factor on cameras,
* and adds the contribution of the smart factor to a pre-allocated augmented Hessian.
*/
template<int N> // N = 2 or 3
template<int N> // N = 2 or 3 (point dimension)
static void UpdateSchurComplement(const FBlocks& Fs, const Matrix& E,
const Eigen::Matrix<double, N, N>& P, const Vector& b,
const KeyVector& allKeys, const KeyVector& keys,
Expand Down
85 changes: 85 additions & 0 deletions gtsam/geometry/tests/testCameraSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include <gtsam/geometry/CameraSet.h>
#include <gtsam/geometry/Cal3_S2.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/base/numericalDerivative.h>
#include <CppUnitLite/TestHarness.h>
Expand Down Expand Up @@ -125,6 +126,90 @@ TEST(CameraSet, Pinhole) {
EXPECT(assert_equal(actualE, E));
}

/* ************************************************************************* */
TEST(CameraSet, SchurComplementAndRearrangeBlocks) {
typedef PinholePose<Cal3Bundler> Camera;
typedef CameraSet<Camera> Set;

// this is the (block) Jacobian with respect to the nonuniqueKeys
std::vector<Eigen::Matrix<double, 2, 12>,
Eigen::aligned_allocator<Eigen::Matrix<double, 2, 12> > > Fs;
Fs.push_back(1 * Matrix::Ones(2, 12)); // corresponding to key pair (0,1)
Fs.push_back(2 * Matrix::Ones(2, 12)); // corresponding to key pair (1,2)
Fs.push_back(3 * Matrix::Ones(2, 12)); // corresponding to key pair (2,0)
Matrix E = 4 * Matrix::Identity(6, 3) + Matrix::Ones(6, 3);
E(0, 0) = 3;
E(1, 1) = 2;
E(2, 2) = 5;
Matrix Et = E.transpose();
Matrix P = (Et * E).inverse();
Vector b = 5 * Vector::Ones(6);

{ // SchurComplement
// Actual
SymmetricBlockMatrix augmentedHessianBM = Set::SchurComplement<3, 12>(Fs, E,
P, b);
Matrix actualAugmentedHessian = augmentedHessianBM.selfadjointView();

// Expected
Matrix F = Matrix::Zero(6, 3 * 12);
F.block<2, 12>(0, 0) = 1 * Matrix::Ones(2, 12);
F.block<2, 12>(2, 12) = 2 * Matrix::Ones(2, 12);
F.block<2, 12>(4, 24) = 3 * Matrix::Ones(2, 12);

Matrix Ft = F.transpose();
Matrix H = Ft * F - Ft * E * P * Et * F;
Vector v = Ft * (b - E * P * Et * b);
Matrix expectedAugmentedHessian = Matrix::Zero(3 * 12 + 1, 3 * 12 + 1);
expectedAugmentedHessian.block<36, 36>(0, 0) = H;
expectedAugmentedHessian.block<36, 1>(0, 36) = v;
expectedAugmentedHessian.block<1, 36>(36, 0) = v.transpose();
expectedAugmentedHessian(36, 36) = b.squaredNorm();

EXPECT(assert_equal(expectedAugmentedHessian, actualAugmentedHessian));
}

{ // SchurComplementAndRearrangeBlocks
KeyVector nonuniqueKeys;
nonuniqueKeys.push_back(0);
nonuniqueKeys.push_back(1);
nonuniqueKeys.push_back(1);
nonuniqueKeys.push_back(2);
nonuniqueKeys.push_back(2);
nonuniqueKeys.push_back(0);

KeyVector uniqueKeys;
uniqueKeys.push_back(0);
uniqueKeys.push_back(1);
uniqueKeys.push_back(2);

// Actual
SymmetricBlockMatrix augmentedHessianBM =
Set::SchurComplementAndRearrangeBlocks_3_12_6(Fs, E, P, b,
nonuniqueKeys,
uniqueKeys);
Matrix actualAugmentedHessian = augmentedHessianBM.selfadjointView();

// Expected
// we first need to build the Jacobian F according to unique keys
Matrix F = Matrix::Zero(6, 18);
F.block<2, 6>(0, 0) = Fs[0].block<2, 6>(0, 0);
F.block<2, 6>(0, 6) = Fs[0].block<2, 6>(0, 6);
F.block<2, 6>(2, 6) = Fs[1].block<2, 6>(0, 0);
F.block<2, 6>(2, 12) = Fs[1].block<2, 6>(0, 6);
F.block<2, 6>(4, 12) = Fs[2].block<2, 6>(0, 0);
F.block<2, 6>(4, 0) = Fs[2].block<2, 6>(0, 6);

Matrix Ft = F.transpose();
Vector v = Ft * (b - E * P * Et * b);
Matrix H = Ft * F - Ft * E * P * Et * F;
Matrix expectedAugmentedHessian(19, 19);
expectedAugmentedHessian << H, v, v.transpose(), b.squaredNorm();

EXPECT(assert_equal(expectedAugmentedHessian, actualAugmentedHessian));
}
}

/* ************************************************************************* */
#include <gtsam/geometry/StereoCamera.h>
TEST(CameraSet, Stereo) {
Expand Down
62 changes: 62 additions & 0 deletions gtsam/geometry/tests/testPose3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,68 @@ TEST(Pose3, interpolate) {
EXPECT(assert_equal(expected2, T2.interpolateRt(T3, t)));
}

/* ************************************************************************* */
Pose3 testing_interpolate(const Pose3& t1, const Pose3& t2, double gamma) { return interpolate(t1,t2,gamma); }

TEST(Pose3, interpolateJacobians) {
{
Pose3 X = Pose3::identity();
Pose3 Y(Rot3::Rz(M_PI_2), Point3(1, 0, 0));
double t = 0.5;
Pose3 expectedPoseInterp(Rot3::Rz(M_PI_4), Point3(0.5, -0.207107, 0)); // note: different from test above: this is full Pose3 interpolation
Matrix actualJacobianX, actualJacobianY;
EXPECT(assert_equal(expectedPoseInterp, interpolate(X, Y, t, actualJacobianX, actualJacobianY), 1e-5));

Matrix expectedJacobianX = numericalDerivative31<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianX,actualJacobianX,1e-6));

Matrix expectedJacobianY = numericalDerivative32<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianY,actualJacobianY,1e-6));
}
{
Pose3 X = Pose3::identity();
Pose3 Y(Rot3::identity(), Point3(1, 0, 0));
double t = 0.3;
Pose3 expectedPoseInterp(Rot3::identity(), Point3(0.3, 0, 0));
Matrix actualJacobianX, actualJacobianY;
EXPECT(assert_equal(expectedPoseInterp, interpolate(X, Y, t, actualJacobianX, actualJacobianY), 1e-5));

Matrix expectedJacobianX = numericalDerivative31<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianX,actualJacobianX,1e-6));

Matrix expectedJacobianY = numericalDerivative32<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianY,actualJacobianY,1e-6));
}
{
Pose3 X = Pose3::identity();
Pose3 Y(Rot3::Rz(M_PI_2), Point3(0, 0, 0));
double t = 0.5;
Pose3 expectedPoseInterp(Rot3::Rz(M_PI_4), Point3(0, 0, 0));
Matrix actualJacobianX, actualJacobianY;
EXPECT(assert_equal(expectedPoseInterp, interpolate(X, Y, t, actualJacobianX, actualJacobianY), 1e-5));

Matrix expectedJacobianX = numericalDerivative31<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianX,actualJacobianX,1e-6));

Matrix expectedJacobianY = numericalDerivative32<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianY,actualJacobianY,1e-6));
}
{
Pose3 X(Rot3::Ypr(0.1,0.2,0.3), Point3(10, 5, -2));
Pose3 Y(Rot3::Ypr(1.1,-2.2,-0.3), Point3(-5, 1, 1));
double t = 0.3;
Pose3 expectedPoseInterp(Rot3::Rz(M_PI_4), Point3(0, 0, 0));
Matrix actualJacobianX, actualJacobianY;
interpolate(X, Y, t, actualJacobianX, actualJacobianY);

Matrix expectedJacobianX = numericalDerivative31<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianX,actualJacobianX,1e-6));

Matrix expectedJacobianY = numericalDerivative32<Pose3,Pose3,Pose3,double>(testing_interpolate, X, Y, t);
EXPECT(assert_equal(expectedJacobianY,actualJacobianY,1e-6));
}
}

/* ************************************************************************* */
TEST(Pose3, Create) {
Matrix63 actualH1, actualH2;
Expand Down
2 changes: 1 addition & 1 deletion gtsam/slam/SmartFactorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class SmartFactorBase: public NonlinearFactor {
DefaultKeyFormatter) const override {
std::cout << s << "SmartFactorBase, z = \n";
for (size_t k = 0; k < measured_.size(); ++k) {
std::cout << "measurement, p = " << measured_[k] << "\t";
std::cout << "measurement " << k<<", px = \n" << measured_[k] << "\n";
noiseModel_->print("noise model = ");
}
if(body_P_sensor_)
Expand Down
2 changes: 1 addition & 1 deletion gtsam/slam/SmartProjectionFactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class SmartProjectionFactor: public SmartFactorBase<CAMERA> {
void print(const std::string& s = "", const KeyFormatter& keyFormatter =
DefaultKeyFormatter) const override {
std::cout << s << "SmartProjectionFactor\n";
std::cout << "linearizationMode:\n" << params_.linearizationMode
std::cout << "linearizationMode: " << params_.linearizationMode
<< std::endl;
std::cout << "triangulationParameters:\n" << params_.triangulation
<< std::endl;
Expand Down
2 changes: 1 addition & 1 deletion gtsam/slam/tests/testSmartProjectionPoseFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static Point2 measurement1(323.0, 240.0);

LevenbergMarquardtParams lmParams;
// Make more verbose like so (in tests):
// params.verbosityLM = LevenbergMarquardtParams::SUMMARY;
// lmParams.verbosityLM = LevenbergMarquardtParams::SUMMARY;

/* ************************************************************************* */
TEST( SmartProjectionPoseFactor, Constructor) {
Expand Down
Loading