Remove a whole lot of copy/paste
parent
f21ba05679
commit
a60e13dd09
|
@ -18,10 +18,7 @@
|
||||||
* @date Sept 2013
|
* @date Sept 2013
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#include "BundlerDefinitions.h"
|
|
||||||
#include <gtsam/slam/SmartProjectionCameraFactor.h>
|
#include <gtsam/slam/SmartProjectionCameraFactor.h>
|
||||||
//#include "../SmartFactorsTestProblems.h"
|
|
||||||
//#include "../LevenbergMarquardtOptimizerCERES.h"
|
|
||||||
|
|
||||||
#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
|
#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
|
||||||
#include <gtsam/slam/PoseTranslationPrior.h>
|
#include <gtsam/slam/PoseTranslationPrior.h>
|
||||||
|
@ -39,17 +36,11 @@ using namespace std;
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
using namespace gtsam;
|
using namespace gtsam;
|
||||||
|
|
||||||
typedef PinholeCamera<Cal3Bundler> Camera;
|
|
||||||
|
|
||||||
static bool isDebugTest = false;
|
static bool isDebugTest = false;
|
||||||
|
|
||||||
// make a realistic calibration matrix
|
// make a realistic calibration matrix
|
||||||
static double fov = 60; // degrees
|
static double fov = 60; // degrees
|
||||||
static size_t w=640,h=480;
|
static size_t w = 640, h = 480;
|
||||||
|
|
||||||
static Cal3_S2::shared_ptr K(new Cal3_S2(fov,w,h));
|
|
||||||
static Cal3_S2::shared_ptr K2(new Cal3_S2(1500, 1200, 0, 640, 480));
|
|
||||||
static boost::shared_ptr<Cal3Bundler> Kbundler(new Cal3Bundler(500, 1e-3, 1e-3, 0, 0));
|
|
||||||
|
|
||||||
static double rankTol = 1.0;
|
static double rankTol = 1.0;
|
||||||
static double linThreshold = -1.0;
|
static double linThreshold = -1.0;
|
||||||
|
@ -61,20 +52,20 @@ static SharedNoiseModel model(noiseModel::Unit::Create(2));
|
||||||
using symbol_shorthand::X;
|
using symbol_shorthand::X;
|
||||||
using symbol_shorthand::L;
|
using symbol_shorthand::L;
|
||||||
|
|
||||||
// tests data
|
static Key x1(1);
|
||||||
Key x1 = 1;
|
|
||||||
|
|
||||||
Symbol l1('l', 1), l2('l', 2), l3('l', 3);
|
Symbol l1('l', 1), l2('l', 2), l3('l', 3);
|
||||||
Key c1 = 1, c2 = 2, c3 = 3;
|
Key c1 = 1, c2 = 2, c3 = 3;
|
||||||
|
|
||||||
static Key poseKey1(x1);
|
// First camera pose, looking along X-axis, 1 meter above ground plane (x-y)
|
||||||
static Point2 measurement1(323.0, 240.0);
|
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI / 2, 0., -M_PI / 2), Point3(0, 0, 1));
|
||||||
static Pose3 body_P_sensor1(Rot3::RzRyRx(-M_PI_2, 0.0, -M_PI_2), Point3(0.25, -0.10, 1.0));
|
// Second camera 1 meter to the right of first camera
|
||||||
|
Pose3 pose_right = level_pose * Pose3(Rot3(), Point3(1, 0, 0));
|
||||||
|
// Third camera 1 meter above the first camera
|
||||||
|
Pose3 pose_up = level_pose * Pose3(Rot3(), Point3(0, -1, 0));
|
||||||
|
|
||||||
typedef PinholeCamera<Cal3_S2> CameraCal3_S2;
|
static Point2 measurement1(323.0, 240.0);
|
||||||
typedef SmartProjectionCameraFactor<Cal3_S2> SmartFactor;
|
static Pose3 body_P_sensor1(Rot3::RzRyRx(-M_PI_2, 0.0, -M_PI_2),
|
||||||
typedef SmartProjectionCameraFactor<Cal3Bundler> SmartFactorBundler;
|
Point3(0.25, -0.10, 1.0));
|
||||||
typedef GeneralSFMFactor<Camera, Point3> SFMFactor;
|
|
||||||
|
|
||||||
template<class CALIBRATION>
|
template<class CALIBRATION>
|
||||||
PinholeCamera<CALIBRATION> perturbCameraPose(
|
PinholeCamera<CALIBRATION> perturbCameraPose(
|
||||||
|
@ -95,7 +86,8 @@ PinholeCamera<CALIBRATION> perturbCameraPoseAndCalibration(
|
||||||
Pose3 cameraPose = camera.pose();
|
Pose3 cameraPose = camera.pose();
|
||||||
Pose3 perturbedCameraPose = cameraPose.compose(noise_pose);
|
Pose3 perturbedCameraPose = cameraPose.compose(noise_pose);
|
||||||
typename gtsam::traits<CALIBRATION>::TangentVector d;
|
typename gtsam::traits<CALIBRATION>::TangentVector d;
|
||||||
d.setRandom(); d*=0.1;
|
d.setRandom();
|
||||||
|
d *= 0.1;
|
||||||
CALIBRATION perturbedCalibration = camera.calibration().retract(d);
|
CALIBRATION perturbedCalibration = camera.calibration().retract(d);
|
||||||
return PinholeCamera<CALIBRATION>(perturbedCameraPose, perturbedCalibration);
|
return PinholeCamera<CALIBRATION>(perturbedCameraPose, perturbedCalibration);
|
||||||
}
|
}
|
||||||
|
@ -114,70 +106,83 @@ void projectToMultipleCameras(const PinholeCamera<CALIBRATION>& cam1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, perturbCameraPose) {
|
// default Cal3_S2 cameras
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
namespace vanilla {
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
typedef PinholeCamera<Cal3_S2> Camera;
|
||||||
CameraCal3_S2 level_camera(level_pose, *K2);
|
static Cal3_S2 K(fov, w, h);
|
||||||
Pose3 noise_pose = Pose3(Rot3::ypr(-M_PI/10, 0., -M_PI/10), Point3(0.5,0.1,0.3));
|
static Cal3_S2 K2(1500, 1200, 0, 640, 480);
|
||||||
Pose3 perturbed_level_pose = level_pose.compose(noise_pose);
|
Camera level_camera(level_pose, K2);
|
||||||
CameraCal3_S2 actualCamera(perturbed_level_pose, *K2);
|
Camera level_camera_right(pose_right, K2);
|
||||||
|
Camera cam1(level_pose, K2);
|
||||||
|
Camera cam2(pose_right, K2);
|
||||||
|
Camera cam3(pose_up, K2);
|
||||||
|
typedef GeneralSFMFactor<Camera, Point3> SFMFactor;
|
||||||
|
typedef SmartProjectionCameraFactor<Cal3_S2> SmartFactor;
|
||||||
|
}
|
||||||
|
|
||||||
CameraCal3_S2 expectedCamera = perturbCameraPose(level_camera);
|
/* ************************************************************************* */
|
||||||
|
TEST( SmartProjectionCameraFactor, perturbCameraPose) {
|
||||||
|
using namespace vanilla;
|
||||||
|
Pose3 noise_pose = Pose3(Rot3::ypr(-M_PI / 10, 0., -M_PI / 10),
|
||||||
|
Point3(0.5, 0.1, 0.3));
|
||||||
|
Pose3 perturbed_level_pose = level_pose.compose(noise_pose);
|
||||||
|
Camera actualCamera(perturbed_level_pose, K2);
|
||||||
|
|
||||||
|
Camera expectedCamera = perturbCameraPose(level_camera);
|
||||||
CHECK(assert_equal(expectedCamera, actualCamera));
|
CHECK(assert_equal(expectedCamera, actualCamera));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, Constructor) {
|
TEST( SmartProjectionCameraFactor, Constructor) {
|
||||||
|
using namespace vanilla;
|
||||||
SmartFactor::shared_ptr factor1(new SmartFactor());
|
SmartFactor::shared_ptr factor1(new SmartFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, Constructor2) {
|
TEST( SmartProjectionCameraFactor, Constructor2) {
|
||||||
|
using namespace vanilla;
|
||||||
SmartFactor factor1(rankTol, linThreshold);
|
SmartFactor factor1(rankTol, linThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, Constructor3) {
|
TEST( SmartProjectionCameraFactor, Constructor3) {
|
||||||
|
using namespace vanilla;
|
||||||
SmartFactor::shared_ptr factor1(new SmartFactor());
|
SmartFactor::shared_ptr factor1(new SmartFactor());
|
||||||
factor1->add(measurement1, poseKey1, model);
|
factor1->add(measurement1, x1, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, Constructor4) {
|
TEST( SmartProjectionCameraFactor, Constructor4) {
|
||||||
|
using namespace vanilla;
|
||||||
SmartFactor factor1(rankTol, linThreshold);
|
SmartFactor factor1(rankTol, linThreshold);
|
||||||
factor1.add(measurement1, poseKey1, model);
|
factor1.add(measurement1, x1, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, ConstructorWithTransform) {
|
TEST( SmartProjectionCameraFactor, ConstructorWithTransform) {
|
||||||
|
using namespace vanilla;
|
||||||
bool manageDegeneracy = true;
|
bool manageDegeneracy = true;
|
||||||
bool isImplicit = false;
|
bool isImplicit = false;
|
||||||
bool enableEPI = false;
|
bool enableEPI = false;
|
||||||
SmartFactor factor1(rankTol, linThreshold, manageDegeneracy, isImplicit, enableEPI, body_P_sensor1);
|
SmartFactor factor1(rankTol, linThreshold, manageDegeneracy, isImplicit,
|
||||||
factor1.add(measurement1, poseKey1, model);
|
enableEPI, body_P_sensor1);
|
||||||
|
factor1.add(measurement1, x1, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST( SmartProjectionCameraFactor, Equals ) {
|
TEST( SmartProjectionCameraFactor, Equals ) {
|
||||||
|
using namespace vanilla;
|
||||||
SmartFactor::shared_ptr factor1(new SmartFactor());
|
SmartFactor::shared_ptr factor1(new SmartFactor());
|
||||||
factor1->add(measurement1, poseKey1, model);
|
factor1->add(measurement1, x1, model);
|
||||||
|
|
||||||
SmartFactor::shared_ptr factor2(new SmartFactor());
|
SmartFactor::shared_ptr factor2(new SmartFactor());
|
||||||
factor2->add(measurement1, poseKey1, model);
|
factor2->add(measurement1, x1, model);
|
||||||
//CHECK(assert_equal(*factor1, *factor2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, noiseless ){
|
TEST( SmartProjectionCameraFactor, noiseless ) {
|
||||||
// cout << " ************************ SmartProjectionCameraFactor: noisy ****************************" << endl;
|
// cout << " ************************ SmartProjectionCameraFactor: noisy ****************************" << endl;
|
||||||
|
using namespace vanilla;
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
CameraCal3_S2 level_camera(level_pose, *K2);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
CameraCal3_S2 level_camera_right(level_pose_right, *K2);
|
|
||||||
|
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
|
@ -194,90 +199,41 @@ TEST( SmartProjectionCameraFactor, noiseless ){
|
||||||
factor1->add(level_uv, c1, model);
|
factor1->add(level_uv, c1, model);
|
||||||
factor1->add(level_uv_right, c2, model);
|
factor1->add(level_uv_right, c2, model);
|
||||||
|
|
||||||
double actualError = factor1->error(values);
|
|
||||||
|
|
||||||
double expectedError = 0.0;
|
double expectedError = 0.0;
|
||||||
DOUBLES_EQUAL(expectedError, actualError, 1e-7);
|
DOUBLES_EQUAL(expectedError, factor1->error(values), 1e-7);
|
||||||
|
CHECK(assert_equal(zero(4), factor1->reprojectionError(values), 1e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, noiselessBundler ){
|
TEST( SmartProjectionCameraFactor, noisy ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace vanilla;
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
Camera level_camera(level_pose, *Kbundler);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera level_camera_right(level_pose_right, *Kbundler);
|
|
||||||
|
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
|
|
||||||
// 1. Project two landmarks into two cameras and triangulate
|
// 1. Project two landmarks into two cameras and triangulate
|
||||||
Point2 level_uv = level_camera.project(landmark);
|
Point2 pixelError(0.2, 0.2);
|
||||||
Point2 level_uv_right = level_camera_right.project(landmark);
|
|
||||||
|
|
||||||
Values values;
|
|
||||||
values.insert(c1, level_camera);
|
|
||||||
values.insert(c2, level_camera_right);
|
|
||||||
|
|
||||||
SmartFactorBundler::shared_ptr factor1(new SmartFactorBundler());
|
|
||||||
factor1->add(level_uv, c1, model);
|
|
||||||
factor1->add(level_uv_right, c2, model);
|
|
||||||
|
|
||||||
double actualError = factor1->error(values);
|
|
||||||
|
|
||||||
double expectedError = 0.0;
|
|
||||||
DOUBLES_EQUAL(expectedError, actualError, 1e-3);
|
|
||||||
|
|
||||||
Point3 oldPoint; // this takes the point stored in the factor (we are not interested in this)
|
|
||||||
if(factor1->point())
|
|
||||||
oldPoint = *(factor1->point());
|
|
||||||
|
|
||||||
Point3 expectedPoint;
|
|
||||||
if(factor1->point(values))
|
|
||||||
expectedPoint = *(factor1->point(values));
|
|
||||||
|
|
||||||
EXPECT(assert_equal(expectedPoint,landmark, 1e-3));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *************************************************************************/
|
|
||||||
TEST( SmartProjectionCameraFactor, noisy ){
|
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
CameraCal3_S2 level_camera(level_pose, *K2);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
CameraCal3_S2 level_camera_right(level_pose_right, *K2);
|
|
||||||
|
|
||||||
// landmark ~5 meters infront of camera
|
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
|
||||||
|
|
||||||
// 1. Project two landmarks into two cameras and triangulate
|
|
||||||
Point2 pixelError(0.2,0.2);
|
|
||||||
Point2 level_uv = level_camera.project(landmark) + pixelError;
|
Point2 level_uv = level_camera.project(landmark) + pixelError;
|
||||||
Point2 level_uv_right = level_camera_right.project(landmark);
|
Point2 level_uv_right = level_camera_right.project(landmark);
|
||||||
|
|
||||||
Values values;
|
Values values;
|
||||||
values.insert(c1, level_camera);
|
values.insert(c1, level_camera);
|
||||||
CameraCal3_S2 perturbed_level_camera_right = perturbCameraPose(level_camera_right);
|
Camera perturbed_level_camera_right = perturbCameraPose(level_camera_right);
|
||||||
values.insert(c2, perturbed_level_camera_right);
|
values.insert(c2, perturbed_level_camera_right);
|
||||||
|
|
||||||
SmartFactor::shared_ptr factor1(new SmartFactor());
|
SmartFactor::shared_ptr factor1(new SmartFactor());
|
||||||
factor1->add(level_uv, c1, model);
|
factor1->add(level_uv, c1, model);
|
||||||
factor1->add(level_uv_right, c2, model);
|
factor1->add(level_uv_right, c2, model);
|
||||||
|
|
||||||
double actualError1= factor1->error(values);
|
double actualError1 = factor1->error(values);
|
||||||
|
|
||||||
SmartFactor::shared_ptr factor2(new SmartFactor());
|
SmartFactor::shared_ptr factor2(new SmartFactor());
|
||||||
vector<Point2> measurements;
|
vector<Point2> measurements;
|
||||||
measurements.push_back(level_uv);
|
measurements.push_back(level_uv);
|
||||||
measurements.push_back(level_uv_right);
|
measurements.push_back(level_uv_right);
|
||||||
|
|
||||||
vector< SharedNoiseModel > noises;
|
vector<SharedNoiseModel> noises;
|
||||||
noises.push_back(model);
|
noises.push_back(model);
|
||||||
noises.push_back(model);
|
noises.push_back(model);
|
||||||
|
|
||||||
|
@ -287,26 +243,15 @@ TEST( SmartProjectionCameraFactor, noisy ){
|
||||||
|
|
||||||
factor2->add(measurements, views, noises);
|
factor2->add(measurements, views, noises);
|
||||||
|
|
||||||
double actualError2= factor2->error(values);
|
double actualError2 = factor2->error(values);
|
||||||
|
|
||||||
DOUBLES_EQUAL(actualError1, actualError2, 1e-7);
|
DOUBLES_EQUAL(actualError1, actualError2, 1e-7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, perturbPoseAndOptimize ){
|
TEST( SmartProjectionCameraFactor, perturbPoseAndOptimize ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace vanilla;
|
||||||
Pose3 pose1 = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
CameraCal3_S2 cam1(pose1, *K2);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 pose2 = pose1 * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
CameraCal3_S2 cam2(pose2, *K2);
|
|
||||||
|
|
||||||
// create third camera 1 meter above the first camera
|
|
||||||
Pose3 pose3 = pose1 * Pose3(Rot3(), Point3(0,-1,0));
|
|
||||||
CameraCal3_S2 cam3(pose3, *K2);
|
|
||||||
|
|
||||||
// three landmarks ~5 meters infront of camera
|
// three landmarks ~5 meters infront of camera
|
||||||
Point3 landmark1(5, 0.5, 1.2);
|
Point3 landmark1(5, 0.5, 1.2);
|
||||||
|
@ -334,24 +279,27 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimize ){
|
||||||
SmartFactor::shared_ptr smartFactor3(new SmartFactor());
|
SmartFactor::shared_ptr smartFactor3(new SmartFactor());
|
||||||
smartFactor3->add(measurements_cam3, views, model);
|
smartFactor3->add(measurements_cam3, views, model);
|
||||||
|
|
||||||
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6+5, 1e-5);
|
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6 + 5, 1e-5);
|
||||||
|
|
||||||
NonlinearFactorGraph graph;
|
NonlinearFactorGraph graph;
|
||||||
graph.push_back(smartFactor1);
|
graph.push_back(smartFactor1);
|
||||||
graph.push_back(smartFactor2);
|
graph.push_back(smartFactor2);
|
||||||
graph.push_back(smartFactor3);
|
graph.push_back(smartFactor3);
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c1, cam1, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c1, cam1, noisePrior));
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c2, cam2, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c2, cam2, noisePrior));
|
||||||
|
|
||||||
Values values;
|
Values values;
|
||||||
values.insert(c1, cam1);
|
values.insert(c1, cam1);
|
||||||
values.insert(c2, cam2);
|
values.insert(c2, cam2);
|
||||||
values.insert(c3, perturbCameraPose(cam3));
|
values.insert(c3, perturbCameraPose(cam3));
|
||||||
if(isDebugTest) values.at<CameraCal3_S2>(c3).print("Smart: Pose3 before optimization: ");
|
if (isDebugTest)
|
||||||
|
values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
||||||
|
|
||||||
LevenbergMarquardtParams params;
|
LevenbergMarquardtParams params;
|
||||||
if(isDebugTest) params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
if (isDebugTest)
|
||||||
if(isDebugTest) params.verbosity = NonlinearOptimizerParams::ERROR;
|
params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
||||||
|
if (isDebugTest)
|
||||||
|
params.verbosity = NonlinearOptimizerParams::ERROR;
|
||||||
|
|
||||||
Values result;
|
Values result;
|
||||||
gttic_(SmartProjectionCameraFactor);
|
gttic_(SmartProjectionCameraFactor);
|
||||||
|
@ -363,28 +311,21 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimize ){
|
||||||
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
||||||
// VectorValues delta = GFG->optimize();
|
// VectorValues delta = GFG->optimize();
|
||||||
|
|
||||||
if(isDebugTest) result.at<CameraCal3_S2>(c3).print("Smart: Pose3 after optimization: ");
|
if (isDebugTest)
|
||||||
EXPECT(assert_equal(cam1,result.at<CameraCal3_S2>(c1)));
|
result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
||||||
EXPECT(assert_equal(cam2,result.at<CameraCal3_S2>(c2)));
|
EXPECT(assert_equal(cam1, result.at<Camera>(c1)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).pose(), cam3.pose(), 1e-4));
|
EXPECT(assert_equal(cam2, result.at<Camera>(c2)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).calibration(), cam3.calibration(), 2));
|
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-4));
|
||||||
if(isDebugTest) tictoc_print_();
|
EXPECT(
|
||||||
|
assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 2));
|
||||||
|
if (isDebugTest)
|
||||||
|
tictoc_print_();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ){
|
TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace vanilla;
|
||||||
Pose3 pose1 = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
CameraCal3_S2 cam1(pose1, *K2);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 pose2 = pose1 * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
CameraCal3_S2 cam2(pose2, *K2);
|
|
||||||
|
|
||||||
// create third camera 1 meter above the first camera
|
|
||||||
Pose3 pose3 = pose1 * Pose3(Rot3(), Point3(0,-1,0));
|
|
||||||
CameraCal3_S2 cam3(pose3, *K2);
|
|
||||||
|
|
||||||
// three landmarks ~5 meters infront of camera
|
// three landmarks ~5 meters infront of camera
|
||||||
Point3 landmark1(5, 0.5, 1.2);
|
Point3 landmark1(5, 0.5, 1.2);
|
||||||
|
@ -403,9 +344,9 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ){
|
||||||
views.push_back(c3);
|
views.push_back(c3);
|
||||||
|
|
||||||
SfM_Track track1;
|
SfM_Track track1;
|
||||||
for(size_t i=0;i<3;++i){
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
SfM_Measurement measures;
|
SfM_Measurement measures;
|
||||||
measures.first = i+1;// cameras are from 1 to 3
|
measures.first = i + 1; // cameras are from 1 to 3
|
||||||
measures.second = measurements_cam1.at(i);
|
measures.second = measurements_cam1.at(i);
|
||||||
track1.measurements.push_back(measures);
|
track1.measurements.push_back(measures);
|
||||||
}
|
}
|
||||||
|
@ -413,9 +354,9 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ){
|
||||||
smartFactor1->add(track1, model);
|
smartFactor1->add(track1, model);
|
||||||
|
|
||||||
SfM_Track track2;
|
SfM_Track track2;
|
||||||
for(size_t i=0;i<3;++i){
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
SfM_Measurement measures;
|
SfM_Measurement measures;
|
||||||
measures.first = i+1;// cameras are from 1 to 3
|
measures.first = i + 1; // cameras are from 1 to 3
|
||||||
measures.second = measurements_cam2.at(i);
|
measures.second = measurements_cam2.at(i);
|
||||||
track2.measurements.push_back(measures);
|
track2.measurements.push_back(measures);
|
||||||
}
|
}
|
||||||
|
@ -425,24 +366,27 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ){
|
||||||
SmartFactor::shared_ptr smartFactor3(new SmartFactor());
|
SmartFactor::shared_ptr smartFactor3(new SmartFactor());
|
||||||
smartFactor3->add(measurements_cam3, views, model);
|
smartFactor3->add(measurements_cam3, views, model);
|
||||||
|
|
||||||
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6+5, 1e-5);
|
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6 + 5, 1e-5);
|
||||||
|
|
||||||
NonlinearFactorGraph graph;
|
NonlinearFactorGraph graph;
|
||||||
graph.push_back(smartFactor1);
|
graph.push_back(smartFactor1);
|
||||||
graph.push_back(smartFactor2);
|
graph.push_back(smartFactor2);
|
||||||
graph.push_back(smartFactor3);
|
graph.push_back(smartFactor3);
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c1, cam1, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c1, cam1, noisePrior));
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c2, cam2, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c2, cam2, noisePrior));
|
||||||
|
|
||||||
Values values;
|
Values values;
|
||||||
values.insert(c1, cam1);
|
values.insert(c1, cam1);
|
||||||
values.insert(c2, cam2);
|
values.insert(c2, cam2);
|
||||||
values.insert(c3, perturbCameraPose(cam3));
|
values.insert(c3, perturbCameraPose(cam3));
|
||||||
if(isDebugTest) values.at<CameraCal3_S2>(c3).print("Smart: Pose3 before optimization: ");
|
if (isDebugTest)
|
||||||
|
values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
||||||
|
|
||||||
LevenbergMarquardtParams params;
|
LevenbergMarquardtParams params;
|
||||||
if(isDebugTest) params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
if (isDebugTest)
|
||||||
if(isDebugTest) params.verbosity = NonlinearOptimizerParams::ERROR;
|
params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
||||||
|
if (isDebugTest)
|
||||||
|
params.verbosity = NonlinearOptimizerParams::ERROR;
|
||||||
|
|
||||||
Values result;
|
Values result;
|
||||||
gttic_(SmartProjectionCameraFactor);
|
gttic_(SmartProjectionCameraFactor);
|
||||||
|
@ -454,28 +398,21 @@ TEST( SmartProjectionCameraFactor, perturbPoseAndOptimizeFromSfM_tracks ){
|
||||||
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
||||||
// VectorValues delta = GFG->optimize();
|
// VectorValues delta = GFG->optimize();
|
||||||
|
|
||||||
if(isDebugTest) result.at<CameraCal3_S2>(c3).print("Smart: Pose3 after optimization: ");
|
if (isDebugTest)
|
||||||
EXPECT(assert_equal(cam1,result.at<CameraCal3_S2>(c1)));
|
result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
||||||
EXPECT(assert_equal(cam2,result.at<CameraCal3_S2>(c2)));
|
EXPECT(assert_equal(cam1, result.at<Camera>(c1)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).pose(), cam3.pose(), 1e-4));
|
EXPECT(assert_equal(cam2, result.at<Camera>(c2)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).calibration(), cam3.calibration(), 2));
|
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-4));
|
||||||
if(isDebugTest) tictoc_print_();
|
EXPECT(
|
||||||
|
assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 2));
|
||||||
|
if (isDebugTest)
|
||||||
|
tictoc_print_();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ){
|
TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace vanilla;
|
||||||
Pose3 pose1 = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
CameraCal3_S2 cam1(pose1, *K2);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 pose2 = pose1 * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
CameraCal3_S2 cam2(pose2, *K2);
|
|
||||||
|
|
||||||
// create third camera 1 meter above the first camera
|
|
||||||
Pose3 pose3 = pose1 * Pose3(Rot3(), Point3(0,-1,0));
|
|
||||||
CameraCal3_S2 cam3(pose3, *K2);
|
|
||||||
|
|
||||||
// three landmarks ~5 meters infront of camera
|
// three landmarks ~5 meters infront of camera
|
||||||
Point3 landmark1(5, 0.5, 1.2);
|
Point3 landmark1(5, 0.5, 1.2);
|
||||||
|
@ -485,7 +422,7 @@ TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ){
|
||||||
Point3 landmark5(10, -0.5, 1.2);
|
Point3 landmark5(10, -0.5, 1.2);
|
||||||
|
|
||||||
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
||||||
measurements_cam4, measurements_cam5;
|
measurements_cam4, measurements_cam5;
|
||||||
|
|
||||||
// 1. Project three landmarks into three cameras and triangulate
|
// 1. Project three landmarks into three cameras and triangulate
|
||||||
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
||||||
|
@ -514,7 +451,7 @@ TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ){
|
||||||
SmartFactor::shared_ptr smartFactor5(new SmartFactor());
|
SmartFactor::shared_ptr smartFactor5(new SmartFactor());
|
||||||
smartFactor5->add(measurements_cam5, views, model);
|
smartFactor5->add(measurements_cam5, views, model);
|
||||||
|
|
||||||
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6+5, 1e-5);
|
const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6 + 5, 1e-5);
|
||||||
|
|
||||||
NonlinearFactorGraph graph;
|
NonlinearFactorGraph graph;
|
||||||
graph.push_back(smartFactor1);
|
graph.push_back(smartFactor1);
|
||||||
|
@ -522,21 +459,24 @@ TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ){
|
||||||
graph.push_back(smartFactor3);
|
graph.push_back(smartFactor3);
|
||||||
graph.push_back(smartFactor4);
|
graph.push_back(smartFactor4);
|
||||||
graph.push_back(smartFactor5);
|
graph.push_back(smartFactor5);
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c1, cam1, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c1, cam1, noisePrior));
|
||||||
graph.push_back(PriorFactor<CameraCal3_S2>(c2, cam2, noisePrior));
|
graph.push_back(PriorFactor<Camera>(c2, cam2, noisePrior));
|
||||||
|
|
||||||
Values values;
|
Values values;
|
||||||
values.insert(c1, cam1);
|
values.insert(c1, cam1);
|
||||||
values.insert(c2, cam2);
|
values.insert(c2, cam2);
|
||||||
values.insert(c3, perturbCameraPoseAndCalibration(cam3));
|
values.insert(c3, perturbCameraPoseAndCalibration(cam3));
|
||||||
if(isDebugTest) values.at<CameraCal3_S2>(c3).print("Smart: Pose3 before optimization: ");
|
if (isDebugTest)
|
||||||
|
values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
||||||
|
|
||||||
LevenbergMarquardtParams params;
|
LevenbergMarquardtParams params;
|
||||||
params.relativeErrorTol = 1e-8;
|
params.relativeErrorTol = 1e-8;
|
||||||
params.absoluteErrorTol = 0;
|
params.absoluteErrorTol = 0;
|
||||||
params.maxIterations = 20;
|
params.maxIterations = 20;
|
||||||
if(isDebugTest) params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
if (isDebugTest)
|
||||||
if(isDebugTest) params.verbosity = NonlinearOptimizerParams::ERROR;
|
params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
||||||
|
if (isDebugTest)
|
||||||
|
params.verbosity = NonlinearOptimizerParams::ERROR;
|
||||||
|
|
||||||
Values result;
|
Values result;
|
||||||
gttic_(SmartProjectionCameraFactor);
|
gttic_(SmartProjectionCameraFactor);
|
||||||
|
@ -548,28 +488,36 @@ TEST( SmartProjectionCameraFactor, perturbCamerasAndOptimize ){
|
||||||
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
// GaussianFactorGraph::shared_ptr GFG = graph.linearize(values);
|
||||||
// VectorValues delta = GFG->optimize();
|
// VectorValues delta = GFG->optimize();
|
||||||
|
|
||||||
if(isDebugTest) result.at<CameraCal3_S2>(c3).print("Smart: Pose3 after optimization: ");
|
if (isDebugTest)
|
||||||
EXPECT(assert_equal(cam1,result.at<CameraCal3_S2>(c1)));
|
result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
||||||
EXPECT(assert_equal(cam2,result.at<CameraCal3_S2>(c2)));
|
EXPECT(assert_equal(cam1, result.at<Camera>(c1)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).pose(), cam3.pose(), 1e-1));
|
EXPECT(assert_equal(cam2, result.at<Camera>(c2)));
|
||||||
EXPECT(assert_equal(result.at<CameraCal3_S2>(c3).calibration(), cam3.calibration(), 20));
|
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-1));
|
||||||
if(isDebugTest) tictoc_print_();
|
EXPECT(
|
||||||
|
assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 20));
|
||||||
|
if (isDebugTest)
|
||||||
|
tictoc_print_();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, Cal3Bundler ){
|
// Cal3Bundler cameras
|
||||||
|
namespace bundler {
|
||||||
|
typedef PinholeCamera<Cal3Bundler> Camera;
|
||||||
|
static Cal3Bundler K(500, 1e-3, 1e-3, 0, 0);
|
||||||
|
Camera level_camera(level_pose, K);
|
||||||
|
Camera level_camera_right(pose_right, K);
|
||||||
|
Pose3 pose1 = level_pose;
|
||||||
|
Camera cam1(level_pose, K);
|
||||||
|
Camera cam2(pose_right, K);
|
||||||
|
Camera cam3(pose_up, K);
|
||||||
|
typedef GeneralSFMFactor<Camera, Point3> SFMFactor;
|
||||||
|
typedef SmartProjectionCameraFactor<Cal3Bundler> SmartFactorBundler;
|
||||||
|
}
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
/* *************************************************************************/
|
||||||
Pose3 pose1 = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
TEST( SmartProjectionCameraFactor, Cal3Bundler ) {
|
||||||
Camera cam1(pose1, *Kbundler);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
using namespace bundler;
|
||||||
Pose3 pose2 = pose1 * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera cam2(pose2, *Kbundler);
|
|
||||||
|
|
||||||
// create third camera 1 meter above the first camera
|
|
||||||
Pose3 pose3 = pose1 * Pose3(Rot3(), Point3(0,-1,0));
|
|
||||||
Camera cam3(pose3, *Kbundler);
|
|
||||||
|
|
||||||
// three landmarks ~5 meters infront of camera
|
// three landmarks ~5 meters infront of camera
|
||||||
Point3 landmark1(5, 0.5, 1.2);
|
Point3 landmark1(5, 0.5, 1.2);
|
||||||
|
@ -579,7 +527,7 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler ){
|
||||||
Point3 landmark5(10, -0.5, 1.2);
|
Point3 landmark5(10, -0.5, 1.2);
|
||||||
|
|
||||||
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
||||||
measurements_cam4, measurements_cam5;
|
measurements_cam4, measurements_cam5;
|
||||||
|
|
||||||
// 1. Project three landmarks into three cameras and triangulate
|
// 1. Project three landmarks into three cameras and triangulate
|
||||||
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
||||||
|
@ -622,14 +570,17 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler ){
|
||||||
values.insert(c2, cam2);
|
values.insert(c2, cam2);
|
||||||
// initialize third pose with some noise, we expect it to move back to original pose3
|
// initialize third pose with some noise, we expect it to move back to original pose3
|
||||||
values.insert(c3, perturbCameraPose(cam3));
|
values.insert(c3, perturbCameraPose(cam3));
|
||||||
if(isDebugTest) values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
if (isDebugTest)
|
||||||
|
values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
||||||
|
|
||||||
LevenbergMarquardtParams params;
|
LevenbergMarquardtParams params;
|
||||||
params.relativeErrorTol = 1e-8;
|
params.relativeErrorTol = 1e-8;
|
||||||
params.absoluteErrorTol = 0;
|
params.absoluteErrorTol = 0;
|
||||||
params.maxIterations = 20;
|
params.maxIterations = 20;
|
||||||
if(isDebugTest) params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
if (isDebugTest)
|
||||||
if(isDebugTest) params.verbosity = NonlinearOptimizerParams::ERROR;
|
params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
||||||
|
if (isDebugTest)
|
||||||
|
params.verbosity = NonlinearOptimizerParams::ERROR;
|
||||||
|
|
||||||
Values result;
|
Values result;
|
||||||
gttic_(SmartProjectionCameraFactor);
|
gttic_(SmartProjectionCameraFactor);
|
||||||
|
@ -638,28 +589,21 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler ){
|
||||||
gttoc_(SmartProjectionCameraFactor);
|
gttoc_(SmartProjectionCameraFactor);
|
||||||
tictoc_finishedIteration_();
|
tictoc_finishedIteration_();
|
||||||
|
|
||||||
if(isDebugTest) result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
if (isDebugTest)
|
||||||
EXPECT(assert_equal(cam1,result.at<Camera>(c1), 1e-4));
|
result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
||||||
EXPECT(assert_equal(cam2,result.at<Camera>(c2), 1e-4));
|
EXPECT(assert_equal(cam1, result.at<Camera>(c1), 1e-4));
|
||||||
|
EXPECT(assert_equal(cam2, result.at<Camera>(c2), 1e-4));
|
||||||
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-1));
|
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-1));
|
||||||
EXPECT(assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 1));
|
EXPECT(
|
||||||
if(isDebugTest) tictoc_print_();
|
assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 1));
|
||||||
|
if (isDebugTest)
|
||||||
|
tictoc_print_();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, Cal3Bundler2 ){
|
TEST( SmartProjectionCameraFactor, Cal3Bundler2 ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace bundler;
|
||||||
Pose3 pose1 = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
Camera cam1(pose1, *Kbundler);
|
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 pose2 = pose1 * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera cam2(pose2, *Kbundler);
|
|
||||||
|
|
||||||
// create third camera 1 meter above the first camera
|
|
||||||
Pose3 pose3 = pose1 * Pose3(Rot3(), Point3(0,-1,0));
|
|
||||||
Camera cam3(pose3, *Kbundler);
|
|
||||||
|
|
||||||
// three landmarks ~5 meters infront of camera
|
// three landmarks ~5 meters infront of camera
|
||||||
Point3 landmark1(5, 0.5, 1.2);
|
Point3 landmark1(5, 0.5, 1.2);
|
||||||
|
@ -669,7 +613,7 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler2 ){
|
||||||
Point3 landmark5(10, -0.5, 1.2);
|
Point3 landmark5(10, -0.5, 1.2);
|
||||||
|
|
||||||
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
vector<Point2> measurements_cam1, measurements_cam2, measurements_cam3,
|
||||||
measurements_cam4, measurements_cam5;
|
measurements_cam4, measurements_cam5;
|
||||||
|
|
||||||
// 1. Project three landmarks into three cameras and triangulate
|
// 1. Project three landmarks into three cameras and triangulate
|
||||||
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
projectToMultipleCameras(cam1, cam2, cam3, landmark1, measurements_cam1);
|
||||||
|
@ -712,14 +656,17 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler2 ){
|
||||||
values.insert(c2, cam2);
|
values.insert(c2, cam2);
|
||||||
// initialize third pose with some noise, we expect it to move back to original pose3
|
// initialize third pose with some noise, we expect it to move back to original pose3
|
||||||
values.insert(c3, perturbCameraPoseAndCalibration(cam3));
|
values.insert(c3, perturbCameraPoseAndCalibration(cam3));
|
||||||
if(isDebugTest) values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
if (isDebugTest)
|
||||||
|
values.at<Camera>(c3).print("Smart: Pose3 before optimization: ");
|
||||||
|
|
||||||
LevenbergMarquardtParams params;
|
LevenbergMarquardtParams params;
|
||||||
params.relativeErrorTol = 1e-8;
|
params.relativeErrorTol = 1e-8;
|
||||||
params.absoluteErrorTol = 0;
|
params.absoluteErrorTol = 0;
|
||||||
params.maxIterations = 20;
|
params.maxIterations = 20;
|
||||||
if(isDebugTest) params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
if (isDebugTest)
|
||||||
if(isDebugTest) params.verbosity = NonlinearOptimizerParams::ERROR;
|
params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
|
||||||
|
if (isDebugTest)
|
||||||
|
params.verbosity = NonlinearOptimizerParams::ERROR;
|
||||||
|
|
||||||
Values result;
|
Values result;
|
||||||
gttic_(SmartProjectionCameraFactor);
|
gttic_(SmartProjectionCameraFactor);
|
||||||
|
@ -728,25 +675,56 @@ TEST( SmartProjectionCameraFactor, Cal3Bundler2 ){
|
||||||
gttoc_(SmartProjectionCameraFactor);
|
gttoc_(SmartProjectionCameraFactor);
|
||||||
tictoc_finishedIteration_();
|
tictoc_finishedIteration_();
|
||||||
|
|
||||||
if(isDebugTest) result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
if (isDebugTest)
|
||||||
EXPECT(assert_equal(cam1,result.at<Camera>(c1), 1e-4));
|
result.at<Camera>(c3).print("Smart: Pose3 after optimization: ");
|
||||||
EXPECT(assert_equal(cam2,result.at<Camera>(c2), 1e-4));
|
EXPECT(assert_equal(cam1, result.at<Camera>(c1), 1e-4));
|
||||||
|
EXPECT(assert_equal(cam2, result.at<Camera>(c2), 1e-4));
|
||||||
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-1));
|
EXPECT(assert_equal(result.at<Camera>(c3).pose(), cam3.pose(), 1e-1));
|
||||||
EXPECT(assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 2));
|
EXPECT(
|
||||||
if(isDebugTest) tictoc_print_();
|
assert_equal(result.at<Camera>(c3).calibration(), cam3.calibration(), 2));
|
||||||
|
if (isDebugTest)
|
||||||
|
tictoc_print_();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor ){
|
TEST( SmartProjectionCameraFactor, noiselessBundler ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace bundler;
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
// landmark ~5 meters infront of camera
|
||||||
Camera level_camera(level_pose, *Kbundler);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
|
|
||||||
// create second camera 1 meter to the right of first camera
|
// 1. Project two landmarks into two cameras and triangulate
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
Point2 level_uv = level_camera.project(landmark);
|
||||||
Camera level_camera_right(level_pose_right, *Kbundler);
|
Point2 level_uv_right = level_camera_right.project(landmark);
|
||||||
|
|
||||||
|
Values values;
|
||||||
|
values.insert(c1, level_camera);
|
||||||
|
values.insert(c2, level_camera_right);
|
||||||
|
|
||||||
|
SmartFactorBundler::shared_ptr factor1(new SmartFactorBundler());
|
||||||
|
factor1->add(level_uv, c1, model);
|
||||||
|
factor1->add(level_uv_right, c2, model);
|
||||||
|
|
||||||
|
double actualError = factor1->error(values);
|
||||||
|
|
||||||
|
double expectedError = 0.0;
|
||||||
|
DOUBLES_EQUAL(expectedError, actualError, 1e-3);
|
||||||
|
|
||||||
|
Point3 oldPoint; // this takes the point stored in the factor (we are not interested in this)
|
||||||
|
if (factor1->point())
|
||||||
|
oldPoint = *(factor1->point());
|
||||||
|
|
||||||
|
Point3 expectedPoint;
|
||||||
|
if (factor1->point(values))
|
||||||
|
expectedPoint = *(factor1->point(values));
|
||||||
|
|
||||||
|
EXPECT(assert_equal(expectedPoint, landmark, 1e-3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************************************/
|
||||||
|
TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor ) {
|
||||||
|
|
||||||
|
using namespace bundler;
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
|
|
||||||
|
@ -766,7 +744,7 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor ){
|
||||||
double expectedError = factor1->error(values);
|
double expectedError = factor1->error(values);
|
||||||
double expectedErrorGraph = smartGraph.error(values);
|
double expectedErrorGraph = smartGraph.error(values);
|
||||||
Point3 expectedPoint;
|
Point3 expectedPoint;
|
||||||
if(factor1->point())
|
if (factor1->point())
|
||||||
expectedPoint = *(factor1->point());
|
expectedPoint = *(factor1->point());
|
||||||
// cout << "expectedPoint " << expectedPoint.vector() << endl;
|
// cout << "expectedPoint " << expectedPoint.vector() << endl;
|
||||||
|
|
||||||
|
@ -779,9 +757,10 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor ){
|
||||||
generalGraph.push_back(sfm1);
|
generalGraph.push_back(sfm1);
|
||||||
generalGraph.push_back(sfm2);
|
generalGraph.push_back(sfm2);
|
||||||
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
||||||
Vector e1 = sfm1.evaluateError(values.at< Camera >(c1), values.at< Point3 >(l1));
|
Vector e1 = sfm1.evaluateError(values.at<Camera>(c1), values.at<Point3>(l1));
|
||||||
Vector e2 = sfm2.evaluateError(values.at< Camera >(c2), values.at< Point3 >(l1));
|
Vector e2 = sfm2.evaluateError(values.at<Camera>(c2), values.at<Point3>(l1));
|
||||||
double actualError = 0.5 * (norm_2(e1)*norm_2(e1) + norm_2(e2)*norm_2(e2));
|
double actualError = 0.5
|
||||||
|
* (norm_2(e1) * norm_2(e1) + norm_2(e2) * norm_2(e2));
|
||||||
double actualErrorGraph = generalGraph.error(values);
|
double actualErrorGraph = generalGraph.error(values);
|
||||||
|
|
||||||
DOUBLES_EQUAL(expectedErrorGraph, actualErrorGraph, 1e-7);
|
DOUBLES_EQUAL(expectedErrorGraph, actualErrorGraph, 1e-7);
|
||||||
|
@ -791,14 +770,9 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor ){
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor1 ){
|
TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor1 ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace bundler;
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
Camera level_camera(level_pose, *Kbundler);
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera level_camera_right(level_pose_right, *Kbundler);
|
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
// 1. Project two landmarks into two cameras and triangulate
|
// 1. Project two landmarks into two cameras and triangulate
|
||||||
|
@ -817,7 +791,7 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor1 ){
|
||||||
Matrix expectedHessian = smartGraph.linearize(values)->hessian().first;
|
Matrix expectedHessian = smartGraph.linearize(values)->hessian().first;
|
||||||
Vector expectedInfoVector = smartGraph.linearize(values)->hessian().second;
|
Vector expectedInfoVector = smartGraph.linearize(values)->hessian().second;
|
||||||
Point3 expectedPoint;
|
Point3 expectedPoint;
|
||||||
if(factor1->point())
|
if (factor1->point())
|
||||||
expectedPoint = *(factor1->point());
|
expectedPoint = *(factor1->point());
|
||||||
|
|
||||||
// COMMENTS:
|
// COMMENTS:
|
||||||
|
@ -831,25 +805,23 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor1 ){
|
||||||
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
||||||
Matrix actualFullHessian = generalGraph.linearize(values)->hessian().first;
|
Matrix actualFullHessian = generalGraph.linearize(values)->hessian().first;
|
||||||
Matrix actualFullInfoVector = generalGraph.linearize(values)->hessian().second;
|
Matrix actualFullInfoVector = generalGraph.linearize(values)->hessian().second;
|
||||||
Matrix actualHessian = actualFullHessian.block(0,0,18,18) -
|
Matrix actualHessian = actualFullHessian.block(0, 0, 18, 18)
|
||||||
actualFullHessian.block(0,18,18,3) * (actualFullHessian.block(18,18,3,3)).inverse() * actualFullHessian.block(18,0,3,18);
|
- actualFullHessian.block(0, 18, 18, 3)
|
||||||
Vector actualInfoVector = actualFullInfoVector.block(0,0,18,1) -
|
* (actualFullHessian.block(18, 18, 3, 3)).inverse()
|
||||||
actualFullHessian.block(0,18,18,3) * (actualFullHessian.block(18,18,3,3)).inverse() * actualFullInfoVector.block(18,0,3,1);
|
* actualFullHessian.block(18, 0, 3, 18);
|
||||||
|
Vector actualInfoVector = actualFullInfoVector.block(0, 0, 18, 1)
|
||||||
|
- actualFullHessian.block(0, 18, 18, 3)
|
||||||
|
* (actualFullHessian.block(18, 18, 3, 3)).inverse()
|
||||||
|
* actualFullInfoVector.block(18, 0, 3, 1);
|
||||||
|
|
||||||
EXPECT(assert_equal(expectedHessian,actualHessian, 1e-7));
|
EXPECT(assert_equal(expectedHessian, actualHessian, 1e-7));
|
||||||
EXPECT(assert_equal(expectedInfoVector,actualInfoVector, 1e-7));
|
EXPECT(assert_equal(expectedInfoVector, actualInfoVector, 1e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
// Have to think about how to compare multiplyHessianAdd in generalSfMFactor and smartFactors
|
// Have to think about how to compare multiplyHessianAdd in generalSfMFactor and smartFactors
|
||||||
//TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor2 ){
|
//TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor2 ){
|
||||||
//
|
//
|
||||||
// // create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
|
||||||
// Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
// cameraObjectBundler level_camera(level_pose, *Kbundler);
|
|
||||||
// // create second camera 1 meter to the right of first camera
|
|
||||||
// Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
// cameraObjectBundler level_camera_right(level_pose_right, *Kbundler);
|
|
||||||
// // landmark ~5 meters infront of camera
|
// // landmark ~5 meters infront of camera
|
||||||
// Point3 landmark(5, 0.5, 1.2);
|
// Point3 landmark(5, 0.5, 1.2);
|
||||||
// // 1. Project two landmarks into two cameras
|
// // 1. Project two landmarks into two cameras
|
||||||
|
@ -901,16 +873,10 @@ TEST( SmartProjectionCameraFactor, comparisonGeneralSfMFactor1 ){
|
||||||
//
|
//
|
||||||
// EXPECT(assert_equal(yActual,yExpected, 1e-7));
|
// EXPECT(assert_equal(yActual,yExpected, 1e-7));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, computeImplicitJacobian ){
|
TEST( SmartProjectionCameraFactor, computeImplicitJacobian ) {
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
using namespace bundler;
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
Camera level_camera(level_pose, *Kbundler);
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera level_camera_right(level_pose_right, *Kbundler);
|
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
// 1. Project two landmarks into two cameras and triangulate
|
// 1. Project two landmarks into two cameras and triangulate
|
||||||
|
@ -927,13 +893,13 @@ TEST( SmartProjectionCameraFactor, computeImplicitJacobian ){
|
||||||
Matrix expectedF, expectedE;
|
Matrix expectedF, expectedE;
|
||||||
Vector expectedb;
|
Vector expectedb;
|
||||||
|
|
||||||
CameraSet< Camera > cameras;
|
CameraSet<Camera> cameras;
|
||||||
cameras.push_back(level_camera);
|
cameras.push_back(level_camera);
|
||||||
cameras.push_back(level_camera_right);
|
cameras.push_back(level_camera_right);
|
||||||
|
|
||||||
factor1->error(values); // this is important to have a triangulation of the point
|
factor1->error(values); // this is important to have a triangulation of the point
|
||||||
Point3 expectedPoint;
|
Point3 expectedPoint;
|
||||||
if(factor1->point())
|
if (factor1->point())
|
||||||
expectedPoint = *(factor1->point());
|
expectedPoint = *(factor1->point());
|
||||||
factor1->computeJacobians(expectedF, expectedE, expectedb, cameras);
|
factor1->computeJacobians(expectedF, expectedE, expectedb, cameras);
|
||||||
|
|
||||||
|
@ -944,21 +910,17 @@ TEST( SmartProjectionCameraFactor, computeImplicitJacobian ){
|
||||||
generalGraph.push_back(sfm2);
|
generalGraph.push_back(sfm2);
|
||||||
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
values.insert(l1, expectedPoint); // note: we get rid of possible errors in the triangulation
|
||||||
Matrix actualFullHessian = generalGraph.linearize(values)->hessian().first;
|
Matrix actualFullHessian = generalGraph.linearize(values)->hessian().first;
|
||||||
Matrix actualVinv = (actualFullHessian.block(18,18,3,3)).inverse();
|
Matrix actualVinv = (actualFullHessian.block(18, 18, 3, 3)).inverse();
|
||||||
|
|
||||||
Matrix3 expectedVinv = factor1->PointCov(expectedE);
|
Matrix3 expectedVinv = factor1->PointCov(expectedE);
|
||||||
EXPECT(assert_equal(expectedVinv,actualVinv, 1e-7));
|
EXPECT(assert_equal(expectedVinv, actualVinv, 1e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************************************/
|
/* *************************************************************************/
|
||||||
TEST( SmartProjectionCameraFactor, implicitJacobianFactor ){
|
TEST( SmartProjectionCameraFactor, implicitJacobianFactor ) {
|
||||||
|
|
||||||
|
using namespace bundler;
|
||||||
|
|
||||||
// create first camera. Looking along X-axis, 1 meter above ground plane (x-y)
|
|
||||||
Pose3 level_pose = Pose3(Rot3::ypr(-M_PI/2, 0., -M_PI/2), Point3(0,0,1));
|
|
||||||
Camera level_camera(level_pose, *Kbundler);
|
|
||||||
// create second camera 1 meter to the right of first camera
|
|
||||||
Pose3 level_pose_right = level_pose * Pose3(Rot3(), Point3(1,0,0));
|
|
||||||
Camera level_camera_right(level_pose_right, *Kbundler);
|
|
||||||
// landmark ~5 meters infront of camera
|
// landmark ~5 meters infront of camera
|
||||||
Point3 landmark(5, 0.5, 1.2);
|
Point3 landmark(5, 0.5, 1.2);
|
||||||
// 1. Project two landmarks into two cameras and triangulate
|
// 1. Project two landmarks into two cameras and triangulate
|
||||||
|
@ -975,35 +937,45 @@ TEST( SmartProjectionCameraFactor, implicitJacobianFactor ){
|
||||||
bool isImplicit = false;
|
bool isImplicit = false;
|
||||||
|
|
||||||
// Hessian version
|
// Hessian version
|
||||||
SmartFactorBundler::shared_ptr explicitFactor(new SmartFactorBundler(rankTol,linThreshold, manageDegeneracy, useEPI, isImplicit));
|
SmartFactorBundler::shared_ptr explicitFactor(
|
||||||
|
new SmartFactorBundler(rankTol, linThreshold, manageDegeneracy, useEPI,
|
||||||
|
isImplicit));
|
||||||
explicitFactor->add(level_uv, c1, model);
|
explicitFactor->add(level_uv, c1, model);
|
||||||
explicitFactor->add(level_uv_right, c2, model);
|
explicitFactor->add(level_uv_right, c2, model);
|
||||||
|
|
||||||
GaussianFactor::shared_ptr gaussianHessianFactor = explicitFactor->linearize(values);
|
GaussianFactor::shared_ptr gaussianHessianFactor = explicitFactor->linearize(
|
||||||
HessianFactor& hessianFactor = dynamic_cast<HessianFactor&>(*gaussianHessianFactor);
|
values);
|
||||||
|
HessianFactor& hessianFactor =
|
||||||
|
dynamic_cast<HessianFactor&>(*gaussianHessianFactor);
|
||||||
|
|
||||||
// Implicit Schur version
|
// Implicit Schur version
|
||||||
isImplicit = true;
|
isImplicit = true;
|
||||||
SmartFactorBundler::shared_ptr implicitFactor(new SmartFactorBundler(rankTol,linThreshold, manageDegeneracy, useEPI, isImplicit));
|
SmartFactorBundler::shared_ptr implicitFactor(
|
||||||
|
new SmartFactorBundler(rankTol, linThreshold, manageDegeneracy, useEPI,
|
||||||
|
isImplicit));
|
||||||
implicitFactor->add(level_uv, c1, model);
|
implicitFactor->add(level_uv, c1, model);
|
||||||
implicitFactor->add(level_uv_right, c2, model);
|
implicitFactor->add(level_uv_right, c2, model);
|
||||||
GaussianFactor::shared_ptr gaussianImplicitSchurFactor = implicitFactor->linearize(values);
|
GaussianFactor::shared_ptr gaussianImplicitSchurFactor =
|
||||||
|
implicitFactor->linearize(values);
|
||||||
typedef RegularImplicitSchurFactor<9> Implicit9;
|
typedef RegularImplicitSchurFactor<9> Implicit9;
|
||||||
Implicit9& implicitSchurFactor = dynamic_cast<Implicit9&>(*gaussianImplicitSchurFactor);
|
Implicit9& implicitSchurFactor =
|
||||||
|
dynamic_cast<Implicit9&>(*gaussianImplicitSchurFactor);
|
||||||
|
|
||||||
VectorValues x = map_list_of
|
VectorValues x = map_list_of(c1,
|
||||||
(c1, (Vector(9) << 1,2,3,4,5,6,7,8,9).finished())
|
(Vector(9) << 1, 2, 3, 4, 5, 6, 7, 8, 9).finished())(c2,
|
||||||
(c2, (Vector(9) << 11,12,13,14,15,16,17,18,19).finished());
|
(Vector(9) << 11, 12, 13, 14, 15, 16, 17, 18, 19).finished());
|
||||||
|
|
||||||
VectorValues yExpected, yActual;
|
VectorValues yExpected, yActual;
|
||||||
double alpha = 1.0;
|
double alpha = 1.0;
|
||||||
hessianFactor.multiplyHessianAdd(alpha, x, yActual);
|
hessianFactor.multiplyHessianAdd(alpha, x, yActual);
|
||||||
implicitSchurFactor.multiplyHessianAdd(alpha, x, yExpected);
|
implicitSchurFactor.multiplyHessianAdd(alpha, x, yExpected);
|
||||||
EXPECT(assert_equal(yActual,yExpected, 1e-7));
|
EXPECT(assert_equal(yActual, yExpected, 1e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
int main() {
|
||||||
|
TestResult tr;
|
||||||
|
return TestRegistry::runAllTests(tr);
|
||||||
|
}
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue