19#include <Eigen/Geometry>
22#include "ceres/product_manifold.h"
23#include "ceres/autodiff_manifold.h"
24#include "ceres/ceres.h"
29#include <ceres/crs_matrix.h>
34namespace xrt::tracking::constellation::optimizer {
64using namespace xrt::auxiliary::tracking;
69using Eigen::MatrixBase;
71using Eigen::Quaternion;
72using Eigen::Quaterniond;
91 using VectorType = Vector<T, N>;
119 assert(this->seeded);
120 return this->vec.data();
137 assert(this->seeded);
143 this->first_estimate = this->vec;
151 return this->
anchored ? this->first_estimate.data() :
nullptr;
165 this->seeded =
false;
172typedef Eigen::Matrix<double, kPoseCovarianceSize, kPoseCovarianceSize> PoseStateCovarianceMatrix;
188 static_assert(!std::is_const_v<T>,
189 "block scalar must not be const — did a `T*` overload deduce T = const double?");
191 static constexpr int kNumParameters = 1;
193 static constexpr int kGravityMagIndex = 0;
202 WorldGravity(Eigen::Ref<
const Vector<T, kNumParameters>> parameters) :
gravity_mag(parameters[kGravityMagIndex])
206 pack(Eigen::Ref<Vector<T, kNumParameters>> parameters)
const
215 return Vector3<T>(T(0), this->gravity_mag, T(0));
222 static_assert(!std::is_const_v<T>,
223 "block scalar must not be const — did a `T*` overload deduce T = const double?");
225 static constexpr int kNumParameters = 2;
239 Eigen::Transform<T, 3, Eigen::Isometry>
243 this->toQuaternion(q);
245 return Eigen::Transform<T, 3, Eigen::Isometry>(q);
248 PitchRoll(Eigen::Ref<
const Vector<T, kNumParameters>> parameters) : pitch_roll(parameters) {}
257template <
typename T>
struct Pose
259 static_assert(!std::is_const_v<T>,
260 "block scalar must not be const — did a `T*` overload deduce T = const double?");
266 static constexpr int kNumResiduals = 6;
275 this->translation =
Vector3<T>(pose.position.x, pose.position.y, pose.position.z);
278 Pose(Eigen::Ref<
const Vector<T, kNumParameters>> parameters)
279 : translation(parameters.template segment<3>(kPoseStatePosStart)),
280 rotation(
Quaternion<T>(parameters.template segment<4>(kPoseStateRotStart)))
283 template <
typename TransformType> Pose(
const Eigen::Transform<TransformType, 3, Eigen::Isometry> &transform)
285 this->translation = transform.translation().template cast<T>();
287 this->rotation = q.template cast<T>();
291 pack(Eigen::Ref<Vector<T, kNumParameters>> parameters)
const
293 parameters.template segment<3>(kPoseStatePosStart) = this->translation;
294 parameters.template segment<4>(kPoseStateRotStart) = this->rotation.coeffs();
297 Eigen::Transform<T, 3, Eigen::Isometry>
300 return Eigen::Translation<T, 3>(translation.x(), translation.y(), translation.z()) *
301 Eigen::Transform<T, 3, Eigen::Isometry>(this->rotation);
315 map_vec3(pose.position) = this->translation.template cast<float>();
316 map_quat(pose.orientation) = this->rotation.coeffs().template cast<float>();
335 static_assert(!std::is_const_v<T>,
336 "block scalar must not be const — did a `T*` overload deduce T = const double?");
345 template <
typename Derived>
347 :
Pose<T>(p), velocity(velocity.template cast<T>())
356 pack(Eigen::Ref<Vector<T, kNumParameters>> parameters)
const
365 static_assert(!std::is_const_v<T>,
366 "block scalar must not be const — did a `T*` overload deduce T = const double?");
377 ImuExtrinsics(Eigen::Ref<
const Vector<T, kNumParameters>> parameters)
378 : Q_imu_model(
Quaternion<T>(parameters.template segment<4>(0)))
382 pack(Eigen::Ref<Vector<T, kNumParameters>> parameters)
const
384 parameters.template segment<4>(0) = this->Q_imu_model.coeffs();
399 template <
typename T>
401 Plus(
const T *x,
const T *delta, T *x_plus_delta)
const
403 const Eigen::Map<const Eigen::Quaternion<T>> q(x);
404 const Eigen::Map<const Eigen::Vector3<T>> w(delta);
405 Eigen::Map<Eigen::Quaternion<T>> result(x_plus_delta);
411 template <
typename T>
413 Minus(
const T *y,
const T *x, T *y_minus_x)
const
415 const Eigen::Map<const Eigen::Quaternion<T>> q_y(y);
416 const Eigen::Map<const Eigen::Quaternion<T>> q_x(x);
417 Eigen::Map<Eigen::Vector3<T>> result(y_minus_x);
419 result =
quat_ln_so3(Eigen::Quaternion<T>(q_x.conjugate() * q_y));
431typedef ceres::ProductManifold<ceres::EuclideanManifold<3>,
433 ceres::EuclideanManifold<3>>
444inline Eigen::Isometry3f
447 return {Eigen::Translation3f{
map_vec3(p.position)} *
map_quat(p.orientation)};
462 for (
size_t i = 0; i < leds_model->
led_count; i++) {
463 if (leds_model->
leds[i].
id == led_id) {
464 return static_cast<int32_t
>(i);
480evaluateFactorFitness(ceres::Problem &problem,
const std::vector<ceres::ResidualBlockId> &residual_blocks);
494 const MatrixXd &jacobian,
495 const int num_base_states,
520 const Eigen::Quaternion<T> &Q_cam_model,
521 const Eigen::Vector3<T> &T_cam_model,
522 const Eigen::Vector3<T> &T_model_led,
523 Eigen::Vector2<T> &out_projected_point,
527 Eigen::Vector3<T> T_cam_led = Q_cam_model * T_model_led;
529 T_cam_led += T_cam_model;
531 if (led_depth_m !=
nullptr) {
532 *led_depth_m = T_cam_led.z();
535 Eigen::Vector2<T> projected_point = {T(1e6), T(1e6)};
537 if (T_cam_led.z() <= T(0)) {
539 out_projected_point = projected_point;
545 (void)camera_models::project(dist,
550 projected_point.y());
552 out_projected_point = projected_point;
555template <
typename T,
typename Derived>
558 const Eigen::Vector3<T> &T_cam_model,
559 const Eigen::Quaternion<T> &Q_cam_model,
560 const Eigen::Vector2<T> &blob_position_2d,
561 const Eigen::Vector3<T> &T_model_led,
562 Eigen::MatrixBase<Derived> &residual)
564 Eigen::Vector2<T> predicted_point;
566 project_led<T>(params,
574 if constexpr (std::is_same_v<T, double>) {
575 U_LOG_W(
"meas=(%f,%f)", blob_position_2d.x(), blob_position_2d.y());
576 U_LOG_W(
"pred=(%f,%f)", predicted_point.x(), predicted_point.y());
578 U_LOG_W(
"pose=(%f,%f,%f), (%f,%f,%f)", T_cam_model.x(), T_cam_model.y(), T_cam_model.z(),
579 Q_cam_model.x(), Q_cam_model.y(), Q_cam_model.z());
581 if (std::isnan(predicted_point.x()) || std::isnan(predicted_point.y())) {
582 U_LOG_W(
"Projected point is NaN, led_depth=%f", led_depth);
587 U_LOG_W(
"meas=(%f,%f)", blob_position_2d.x().a, blob_position_2d.y().a);
588 U_LOG_W(
"pred=(%f,%f)", predicted_point.x().a, predicted_point.y().a);
590 U_LOG_W(
"pose=(%f,%f,%f), (%f,%f,%f)", T_cam_model.x().a, T_cam_model.y().a, T_cam_model.z().a,
591 Q_cam_model.x().a, Q_cam_model.y().a, Q_cam_model.z().a);
593 if (std::isnan(predicted_point.x().a) || std::isnan(predicted_point.y().a)) {
594 U_LOG_W(
"Projected point is NaN, led_depth=%f", led_depth.a);
602 residual = predicted_point - blob_position_2d;
609 if (led_depth < T(0.001)) {
610 residual += Eigen::Vector2<T>::Constant(T(1000) * (T(0.001) - T(led_depth)));
Definition utility_northstar.h:779
Definition utility_northstar.h:270
Definition utility_northstar.h:16
#define U_LOG_W(...)
Log a message at U_LOGGING_WARN level, conditional on the global log level.
Definition u_logging.h:439
#define MATH_GRAVITY_M_S2
Standard gravity acceleration constant.
Definition m_api.h:53
void marginalize(const VectorXd &residual, const MatrixXd &jacobian, const int num_base_states, VectorXd &out_e0, MatrixXd &out_j)
Marginalize the first num_base_states states out of the linearized system given by jacobian and resid...
Definition internal_math.cpp:313
void matrixCrsToEigen(const ceres::CRSMatrix &mat_crs, Eigen::MatrixXd &mat)
Converts a CRS matrix to a dense Eigen matrix.
Definition internal_math.cpp:293
FactorFitness evaluateFactorFitness(ceres::Problem &problem, const std::vector< ceres::ResidualBlockId > &residual_blocks)
Measures how well one kind of factor was fit, at whatever the problem's parameters currently hold.
Definition internal_math.cpp:272
constexpr size_t kMinCorrespondencesPerObservation
Fewer correspondences than this and the observation is dropped.
Definition internal_math.hpp:51
constexpr double kCameraHuberDeltaSigmas
Where a camera observation stops being treated as data and starts being treated as a mistake,...
Definition internal_math.hpp:61
ceres::ProductManifold< ceres::EuclideanManifold< 3 >, QuaternionManifold, ceres::EuclideanManifold< 3 > > PoseWithVelocityManifold
Pose plus linear velocity, (tX, tY, tZ), (qX, qY, qZ, qW), (vX, vY, vZ). 10 ambient,...
Definition internal_math.hpp:434
static int32_t findLedIndexById(const t_constellation_tracker_led_model *leds_model, t_constellation_led_id_it led_id)
Finds a LED in the model by its id.
Definition internal_math.hpp:460
constexpr bool kResidualDebugPrint
Print debug info about the residuals as we're computing them.
Definition internal_math.hpp:43
Eigen::Isometry3f isometryFromPose(const xrt_pose &p)
Converts an xrt_pose into an Eigen Isometry3f.
Definition internal_math.hpp:445
ceres::ProductManifold< ceres::EuclideanManifold< 3 >, QuaternionManifold > PoseManifold
Pose manifold, (tX, tY, tZ), (qX, qY, qZ, qW)
Definition internal_math.hpp:428
constexpr int kNumLedResiduals
X and Y in the image, for one LED.
Definition internal_math.hpp:506
constexpr double kBlobPositionSigmaPixels
How well a blob centroid locates the LED that lit it, in pixels.
Definition internal_math.hpp:515
ceres::AutoDiffManifold< QuaternionManifoldFunctor, 4, 3 > QuaternionManifold
Our quaternion manifold functor.
Definition internal_math.hpp:425
constexpr bool kOptimizeUndistortedPoints
Optimize directly on the pre-undistorted points, don't compute residuals in distorted pixel space.
Definition internal_math.hpp:41
Interoperability helpers connecting internal math types and Eigen.
Base implementations for math library.
Helpers for quatexpmap math for bigceres usage.
Generic math helpers for constellation optimizer code.
C++-only functionality in the Math helper library.
Definition m_documentation.hpp:15
Eigen::Quaternion< typename Derived::Scalar > quat_exp_so3(Eigen::MatrixBase< Derived > const &vec)
Fully-templated free function for quaternion exponentiation, SO(3) version as described by Grassia.
Definition m_quatexpmap.hpp:119
static Eigen::Map< const Eigen::Quaternionf > map_quat(const struct xrt_quat &q)
Wrap an internal quaternion struct in an Eigen type, const overload.
Definition m_eigen_interop.hpp:40
static Eigen::Map< const Eigen::Quaternionf > orientation(const struct xrt_pose &pose)
Return a Eigen type wrapping a pose's orientation (const).
Definition m_eigen_interop.hpp:232
Eigen::Matrix< Scalar, 3, 1 > quat_ln_so3(Eigen::Quaternion< Scalar > const &quat)
Fully-templated free function for quaternion log map, SO(3) version.
Definition m_quatexpmap.hpp:148
static Eigen::Map< const Eigen::Vector3f > map_vec3(const struct xrt_vec3 &v)
Wrap an internal 3D vector struct in an Eigen type, const overload.
Definition m_eigen_interop.hpp:90
RANSAC PnP pose refinement.
Definition camera_model.h:21
struct t_camera_model_params calib_pinhole
An identity calibration model.
Definition camera_model.h:38
struct t_camera_model_params calib_true
The true calibration of the camera.
Definition camera_model.h:36
Floating point calibration data for a single calibrated camera.
Definition t_camera_models.h:62
The LED model is a series of points which define the real-world positions of all LEDs.
Definition t_constellation.h:301
size_t led_count
The number of LEDs in this model.
Definition t_constellation.h:305
struct t_constellation_tracker_led * leds
The LEDs in this model.
Definition t_constellation.h:303
t_constellation_led_id_it id
A unique ID for this LED, which distinguishes it from all other LEDs.
Definition t_constellation.h:278
How well one kind of sensor was fit, so that a bad solve can be attributed to the sensor that could n...
Definition math.hpp:31
Definition internal_math.hpp:364
static constexpr int kNumTangentParameters
Degrees of freedom.
Definition internal_math.hpp:371
static constexpr int kNumParameters
(qX, qY, qZ, qW)
Definition internal_math.hpp:369
A parameter block for a camera with 2 degrees of freedom, pitch and roll. Yaw is fixed to 0,...
Definition internal_math.hpp:221
Pose with 6 degrees of freedom, translation and rotation.
Definition internal_math.hpp:258
static constexpr int kNumParameters
Size of the parameter block handed to Ceres: (tX, tY, tZ), (qX, qY, qZ, qW).
Definition internal_math.hpp:263
static constexpr int kNumTangentParameters
Degrees of freedom the manifold exposes to the solver.
Definition internal_math.hpp:265
Pose with 9 degrees of freedom, translation, rotation, and linear velocity.
Definition internal_math.hpp:334
Right-multiplying quaternion manifold, matches our local convention.
Definition internal_math.hpp:398
Definition internal_math.hpp:90
void unseed()
Drops everything held here, for a slot about to be handed to a state of its own.
Definition internal_math.hpp:163
bool anchored
Whether first_estimate has been taken.
Definition internal_math.hpp:108
const T * anchorData() const
The frozen linearization point, or null for a state that has never been anchored.
Definition internal_math.hpp:149
T * data()
Returns the data to use for a parameter, asserts you have seeded the data before this.
Definition internal_math.hpp:117
VectorType first_estimate
The value this state is held linearized around, once it has been anchored.
Definition internal_math.hpp:105
VectorType & seedVec()
Returns the vector for you to write into and seed.
Definition internal_math.hpp:127
void releaseAnchor()
Forgets the frozen linearization point, so the state linearizes wherever it currently is again.
Definition internal_math.hpp:156
void anchor()
Freezes the current value as the point this state is linearized at, unless it already has one.
Definition internal_math.hpp:135
The strength of gravity in the world, as a parameter block of its own.
Definition internal_math.hpp:187
T gravity_mag
Gravity in meters per second squared.
Definition internal_math.hpp:196
Vector3< T > toVector() const
Gravity as a vector, which points along +Y since world up is -Y in the OpenCV space the optimizer wor...
Definition internal_math.hpp:213
A pose composed of a position and orientation.
Definition xrt_defines.h:513
Camera (un)projection C++ API for various camera models.