35#include <gtsam/slam/TriangulationFactor.h>
44class GTSAM_EXPORT TriangulationUnderconstrainedException:
public std::runtime_error {
46 TriangulationUnderconstrainedException() :
47 std::runtime_error(
"Triangulation Underconstrained Exception.") {
52class GTSAM_EXPORT TriangulationCheiralityException:
public std::runtime_error {
54 TriangulationCheiralityException() :
56 "Triangulation Cheirality Exception: The resulting landmark is behind one or more cameras.") {
68 const std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>>& projection_matrices,
69 const Point2Vector& measurements,
double rank_tol = 1e-9);
80 const std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>>& projection_matrices,
81 const std::vector<Unit3>& measurements,
double rank_tol = 1e-9);
91 const std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>>& projection_matrices,
92 const Point2Vector& measurements,
93 double rank_tol = 1e-9);
99 const std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>>& projection_matrices,
100 const std::vector<Unit3>& measurements,
101 double rank_tol = 1e-9);
114 const Point3Vector& calibratedMeasurements,
115 const SharedIsotropic& measurementNoise,
116 double rank_tol = 1e-9);
127template<
class CALIBRATION>
129 const std::vector<Pose3>& poses, std::shared_ptr<CALIBRATION> sharedCal,
130 const Point2Vector& measurements,
Key landmarkKey,
131 const Point3& initialEstimate,
134 values.
insert(landmarkKey, initialEstimate);
136 for (
size_t i = 0; i < measurements.size(); i++) {
137 const Pose3& pose_i = poses[i];
139 Camera camera_i(pose_i, sharedCal);
141 (camera_i, measurements[i], model, landmarkKey);
143 return {graph, values};
155template<
class CAMERA>
158 const typename CAMERA::MeasurementVector& measurements,
Key landmarkKey,
159 const Point3& initialEstimate,
162 values.
insert(landmarkKey, initialEstimate);
166 for (
size_t i = 0; i < measurements.size(); i++) {
167 const CAMERA& camera_i = cameras[i];
169 (camera_i, measurements[i], model? model : unit, landmarkKey);
171 return {graph, values};
192template<
class CALIBRATION>
194 std::shared_ptr<CALIBRATION> sharedCal,
195 const Point2Vector& measurements,
const Point3& initialEstimate,
200 (poses, sharedCal, measurements,
Symbol(
'p', 0), initialEstimate, model);
212template<
class CAMERA>
215 const typename CAMERA::MeasurementVector& measurements,
const Point3& initialEstimate,
220 (cameras, measurements,
Symbol(
'p', 0), initialEstimate, model);
225template<
class CAMERA>
226std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>>
227projectionMatricesFromCameras(
const CameraSet<CAMERA> &cameras) {
228 std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>> projection_matrices;
229 for (
const CAMERA &camera: cameras) {
230 projection_matrices.push_back(camera.cameraProjectionMatrix());
232 return projection_matrices;
236template<
class CALIBRATION>
237std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>> projectionMatricesFromPoses(
238 const std::vector<Pose3> &poses, std::shared_ptr<CALIBRATION> sharedCal) {
239 std::vector<Matrix34, Eigen::aligned_allocator<Matrix34>> projection_matrices;
240 for (
size_t i = 0; i < poses.size(); i++) {
242 projection_matrices.push_back(camera.cameraProjectionMatrix());
244 return projection_matrices;
254template <
class CALIBRATION>
256 const auto& K = cal.K();
257 return Cal3_S2(K(0, 0), K(1, 1), K(0, 1), K(0, 2), K(1, 2));
262template <
class CALIBRATION,
class MEASUREMENT>
264 const CALIBRATION& cal,
const MEASUREMENT& measurement,
265 std::optional<Cal3_S2> pinholeCal = {}) {
269 return pinholeCal->uncalibrate(cal.calibrate(measurement));
283template <
class CALIBRATION>
285 const Point2Vector& measurements) {
287 Point2Vector undistortedMeasurements;
290 std::transform(measurements.begin(), measurements.end(),
291 std::back_inserter(undistortedMeasurements),
292 [&cal, &pinholeCalibration](
const Point2& measurement) {
293 return undistortMeasurementInternal<CALIBRATION>(
294 cal, measurement, pinholeCalibration);
296 return undistortedMeasurements;
302 const Point2Vector& measurements) {
317template <
class CAMERA>
320 const typename CAMERA::MeasurementVector& measurements) {
321 const size_t nrMeasurements = measurements.size();
323 if (nrMeasurements != cameras.size()) {
327 typename CAMERA::MeasurementVector undistortedMeasurements(nrMeasurements);
328 for (
size_t ii = 0; ii < nrMeasurements; ++ii) {
331 undistortedMeasurements[ii] =
333 cameras[ii].calibration(), measurements[ii]);
335 return undistortedMeasurements;
339template <
class CAMERA = PinholeCamera<Cal3_S2>>
342 const PinholeCamera<Cal3_S2>::MeasurementVector& measurements) {
347template <
class CAMERA = SphericalCamera>
350 const SphericalCamera::MeasurementVector& measurements) {
362template <
class CALIBRATION>
364 const CALIBRATION& cal,
const Point2Vector& measurements) {
365 Point3Vector calibratedMeasurements;
368 std::transform(measurements.begin(), measurements.end(),
369 std::back_inserter(calibratedMeasurements),
370 [&cal](
const Point2& measurement) {
372 p << cal.calibrate(measurement), 1.0;
375 return calibratedMeasurements;
386template <
class CAMERA>
389 const typename CAMERA::MeasurementVector& measurements) {
390 const size_t nrMeasurements = measurements.size();
391 assert(nrMeasurements == cameras.size());
392 Point3Vector calibratedMeasurements(nrMeasurements);
393 for (
size_t ii = 0; ii < nrMeasurements; ++ii) {
394 calibratedMeasurements[ii]
395 << cameras[ii].calibration().calibrate(measurements[ii]),
398 return calibratedMeasurements;
402template <
class CAMERA = SphericalCamera>
405 const SphericalCamera::MeasurementVector& measurements) {
406 Point3Vector calibratedMeasurements(measurements.size());
407 for (
size_t ii = 0; ii < measurements.size(); ++ii) {
408 calibratedMeasurements[ii] << measurements[ii].point3();
410 return calibratedMeasurements;
426template <
class CALIBRATION>
428 std::shared_ptr<CALIBRATION> sharedCal,
429 const Point2Vector& measurements,
430 double rank_tol = 1e-9,
bool optimize =
false,
432 const bool useLOST =
false) {
433 assert(poses.size() == measurements.size());
441 const double measurementSigma = model ? model->sigmas().mean() : 1e-4;
442 SharedIsotropic measurementNoise =
446 auto calibratedMeasurements =
449 point =
triangulateLOST(poses, calibratedMeasurements, measurementNoise,
453 auto projection_matrices = projectionMatricesFromPoses(poses, sharedCal);
456 auto undistortedMeasurements =
460 triangulateDLT(projection_matrices, undistortedMeasurements, rank_tol);
467 (poses, sharedCal, measurements, point,
noiseModel);
470#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION
472 for (
const Pose3& pose : poses) {
473 const Point3& p_local = pose.transformTo(point);
495template <
class CAMERA>
497 const typename CAMERA::MeasurementVector& measurements,
498 double rank_tol = 1e-9,
bool optimize =
false,
500 const bool useLOST =
false) {
501 size_t m = cameras.size();
502 assert(measurements.size() == m);
511 const double measurementSigma = model ? model->sigmas().mean() : 1e-4;
512 SharedIsotropic measurementNoise =
516 std::vector<Pose3> poses;
517 poses.reserve(cameras.size());
518 for (
const auto& camera : cameras) poses.push_back(camera.pose());
522 auto calibratedMeasurements =
525 point =
triangulateLOST(poses, calibratedMeasurements, measurementNoise,
529 auto projection_matrices = projectionMatricesFromCameras(cameras);
532 auto undistortedMeasurements =
536 triangulateDLT(projection_matrices, undistortedMeasurements, rank_tol);
544#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION
546 for (
const CAMERA& camera : cameras) {
547 const Point3& p_local = camera.pose().transformTo(point);
556template <
class CALIBRATION>
558 const Point2Vector& measurements,
559 double rank_tol = 1e-9,
bool optimize =
false,
561 const bool useLOST =
false) {
563 (cameras, measurements, rank_tol,
optimize, model, useLOST);
602 const bool _enableEPI =
false,
double _landmarkDistanceThreshold = -1,
603 double _dynamicOutlierRejectionThreshold = -1,
604 const bool _useLOST =
false,
614 friend std::ostream &operator<<(std::ostream &os,
617 os <<
"enableEPI = " << p.
enableEPI << std::endl;
620 os <<
"dynamicOutlierRejectionThreshold = "
622 os <<
"useLOST = " << p.
useLOST << std::endl;
623 os <<
"noise model" << std::endl;
629#if GTSAM_ENABLE_BOOST_SERIALIZATION
631 friend class boost::serialization::access;
632 template<
class ARCHIVE>
633 void serialize(ARCHIVE & ar,
const unsigned int version) {
634 ar & BOOST_SERIALIZATION_NVP(rankTolerance);
635 ar & BOOST_SERIALIZATION_NVP(enableEPI);
636 ar & BOOST_SERIALIZATION_NVP(landmarkDistanceThreshold);
637 ar & BOOST_SERIALIZATION_NVP(dynamicOutlierRejectionThreshold);
646class TriangulationResult :
public std::optional<Point3> {
648 enum Status { VALID, DEGENERATE, BEHIND_CAMERA, OUTLIER, FAR_POINT };
668 static TriangulationResult FarPoint() {
671 static TriangulationResult BehindCamera() {
674 bool valid()
const {
return status == VALID; }
675 bool degenerate()
const {
return status == DEGENERATE; }
676 bool outlier()
const {
return status == OUTLIER; }
677 bool farPoint()
const {
return status == FAR_POINT; }
678 bool behindCamera()
const {
return status == BEHIND_CAMERA; }
680 if (!has_value())
throw std::runtime_error(
"TriangulationResult has no value");
684 GTSAM_EXPORT
friend std::ostream& operator<<(
685 std::ostream& os,
const TriangulationResult& result) {
687 os <<
"point = " << *result << std::endl;
689 os <<
"no point, status = " << result.status << std::endl;
694#if GTSAM_ENABLE_BOOST_SERIALIZATION
696 friend class boost::serialization::access;
697 template <
class ARCHIVE>
698 void serialize(ARCHIVE& ar,
const unsigned int version) {
699 ar& BOOST_SERIALIZATION_NVP(status);
705template<
class CAMERA>
707 const typename CAMERA::MeasurementVector& measured,
710 size_t m = cameras.size();
714 return TriangulationResult::Degenerate();
724 double maxReprojError = 0.0;
725 for(
const CAMERA& camera: cameras) {
726 const Pose3& pose = camera.pose();
730 return TriangulationResult::FarPoint();
731#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION
735 if (p_local.z() <= 0)
736 return TriangulationResult::BehindCamera();
740 const typename CAMERA::Measurement& zi = measured.at(i);
741 Point2 reprojectionError = camera.reprojectionError(point, zi);
742 maxReprojError = std::max(maxReprojError, reprojectionError.norm());
749 return TriangulationResult::Outlier();
757 return TriangulationResult::Degenerate();
760 return TriangulationResult::BehindCamera();
767template <
class CAMERA>
770 const std::vector<std::map<size_t, typename CAMERA::Measurement>>& tracks,
772 std::vector<TriangulationResult> results;
773 results.reserve(tracks.size());
774 for (
const auto& track : tracks) {
776 typename CAMERA::MeasurementVector measurements;
777 trackCameras.reserve(track.size());
778 measurements.reserve(track.size());
779 for (
const auto& [cameraIndex, measurement] : track) {
780 if (cameraIndex >= cameras.size()) {
781 throw std::out_of_range(
782 "triangulateSafe(batch): cameraIndex out of range for CameraSet");
784 trackCameras.push_back(cameras.at(cameraIndex));
785 measurements.push_back(measurement);
787 results.push_back(
triangulateSafe(trackCameras, measurements, params));
793using CameraSetPinholePoseCal3Bundler = CameraSet<PinholePose<Cal3Bundler>>;
794using CameraSetPinholePoseCal3_S2 = CameraSet<PinholePose<Cal3_S2>>;
795using CameraSetPinholePoseCal3DS2 = CameraSet<PinholePose<Cal3DS2>>;
796using CameraSetPinholePoseCal3Fisheye = CameraSet<PinholePose<Cal3Fisheye>>;
797using CameraSetPinholePoseCal3Unified = CameraSet<PinholePose<Cal3Unified>>;
799using CameraSetCal3Bundler = CameraSet<PinholeCamera<Cal3Bundler>>;
800using CameraSetCal3_S2 = CameraSet<PinholeCamera<Cal3_S2>>;
801using CameraSetCal3DS2 = CameraSet<PinholeCamera<Cal3DS2>>;
802using CameraSetCal3Fisheye = CameraSet<PinholeCamera<Cal3Fisheye>>;
803using CameraSetCal3Unified = CameraSet<PinholeCamera<Cal3Unified>>;
805using CameraSetSpherical = CameraSet<SphericalCamera>;
The most common 5DOF 3D->2D calibration.
Unified Calibration Model, see Mei07icra for details.
Base class to create smart factors on poses or cameras.
Base class for all pinhole cameras.
Calibration used by Bundler.
Calibrated camera with spherical projection.
Calibration of a camera with radial distortion, calculations in base class Cal3DS2_Base.
Calibration of a fisheye camera.
Factor Graph consisting of non-linear factors.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Point3Vector calibrateMeasurementsShared(const CALIBRATION &cal, const Point2Vector &measurements)
Convert pixel measurements in image to homogeneous measurements in the image plane using shared camer...
Definition triangulation.h:363
std::pair< NonlinearFactorGraph, Values > triangulationGraph(const std::vector< Pose3 > &poses, std::shared_ptr< CALIBRATION > sharedCal, const Point2Vector &measurements, Key landmarkKey, const Point3 &initialEstimate, const SharedNoiseModel &model=noiseModel::Unit::Create(2))
Create a factor graph with projection factors from poses and one calibration.
Definition triangulation.h:128
Point3 triangulateLOST(const std::vector< Pose3 > &poses, const Point3Vector &calibratedMeasurements, const SharedIsotropic &measurementNoise, double rank_tol)
Triangulation using the LOST (Linear Optimal Sine Triangulation) algorithm proposed in https://arxiv....
Definition triangulation.cpp:87
Point2Vector undistortMeasurements(const CALIBRATION &cal, const Point2Vector &measurements)
Remove distortion for measurements so as if the measurements came from a pinhole camera.
Definition triangulation.h:284
Cal3_S2 createPinholeCalibration(const CALIBRATION &cal)
Create a pinhole calibration from a different Cal3 object, removing distortion.
Definition triangulation.h:255
Vector3 Point3
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point3 to Vector3...
Definition Point3.h:38
Point3 optimize(const NonlinearFactorGraph &graph, const Values &values, Key landmarkKey)
Optimize for triangulation.
Definition triangulation.cpp:178
MEASUREMENT undistortMeasurementInternal(const CALIBRATION &cal, const MEASUREMENT &measurement, std::optional< Cal3_S2 > pinholeCal={})
Internal undistortMeasurement to be used by undistortMeasurement and undistortMeasurements.
Definition triangulation.h:263
Vector2 Point2
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point2 to Vector2...
Definition Point2.h:32
TriangulationResult triangulateSafe(const CameraSet< CAMERA > &cameras, const typename CAMERA::MeasurementVector &measured, const TriangulationParameters ¶ms)
triangulateSafe: extensive checking of the outcome
Definition triangulation.h:706
noiseModel::Base::shared_ptr SharedNoiseModel
Aliases.
Definition NoiseModel.h:846
Point3 triangulateNonlinear(const std::vector< Pose3 > &poses, std::shared_ptr< CALIBRATION > sharedCal, const Point2Vector &measurements, const Point3 &initialEstimate, const SharedNoiseModel &model=nullptr)
Given an initial estimate , refine a point using measurements in several cameras.
Definition triangulation.h:193
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
double distance3(const Point3 &p1, const Point3 &q, OptionalJacobian< 1, 3 > H1, OptionalJacobian< 1, 3 > H2)
distance between two points
Definition Point3.cpp:29
Point3Vector calibrateMeasurements(const CameraSet< CAMERA > &cameras, const typename CAMERA::MeasurementVector &measurements)
Convert pixel measurements in image to homogeneous measurements in the image plane using camera intri...
Definition triangulation.h:387
Point3 triangulateDLT(const std::vector< Matrix34, Eigen::aligned_allocator< Matrix34 > > &projection_matrices, const Point2Vector &measurements, double rank_tol)
DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312.
Definition triangulation.cpp:150
Point3 triangulatePoint3(const std::vector< Pose3 > &poses, std::shared_ptr< CALIBRATION > sharedCal, const Point2Vector &measurements, double rank_tol=1e-9, bool optimize=false, const SharedNoiseModel &model=nullptr, const bool useLOST=false)
Function to triangulate 3D landmark point from an arbitrary number of poses (at least 2) using the DL...
Definition triangulation.h:427
Vector4 triangulateHomogeneousDLT(const std::vector< Matrix34, Eigen::aligned_allocator< Matrix34 > > &projection_matrices, const Point2Vector &measurements, double rank_tol)
DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312.
Definition triangulation.cpp:28
All noise models live in the noiseModel namespace.
Definition LossFunctions.cpp:33
Base::shared_ptr validOrDefault(const T &value, const Base::shared_ptr &model)
Create.
Definition NoiseModel.h:833
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
The most common 5DOF 3D->2D calibration.
Definition Cal3_S2.h:35
A set of cameras, all with their own calibration.
Definition CameraSet.h:37
A pinhole camera class that has a Pose3 and a Calibration.
Definition PinholeCamera.h:34
A pinhole camera class that has a Pose3 and a fixed Calibration.
Definition PinholePose.h:236
A 3D pose (R,t) : (Rot3,Point3).
Definition Pose3.h:42
const Point3 & translation(OptionalJacobian< 3, 6 > Hself={}) const
get translation
Definition Pose3.cpp:158
Point3 transformTo(const Point3 &point, OptionalJacobian< 3, 6 > Hself={}, OptionalJacobian< 3, 3 > Hpoint={}) const
takes point in world coordinates and transforms it to Pose coordinates
Definition Pose3.cpp:204
Exception thrown by triangulateDLT when SVD returns rank < 3.
Definition triangulation.h:44
Exception thrown by triangulateDLT when landmark is behind one or more of the cameras.
Definition triangulation.h:52
Definition triangulation.h:566
double dynamicOutlierRejectionThreshold
If this is nonnegative the we will check if the average reprojection error is smaller than this thres...
Definition triangulation.h:583
double rankTolerance
threshold to decide whether triangulation is result.degenerate
Definition triangulation.h:568
double landmarkDistanceThreshold
if the landmark is triangulated at distance larger than this, result is flagged as degenerate.
Definition triangulation.h:576
bool enableEPI
if set to true, will refine triangulation using LM
Definition triangulation.h:570
SharedNoiseModel noiseModel
used in the nonlinear triangulation
Definition triangulation.h:590
TriangulationParameters(const double _rankTolerance=1.0, const bool _enableEPI=false, double _landmarkDistanceThreshold=-1, double _dynamicOutlierRejectionThreshold=-1, const bool _useLOST=false, const SharedNoiseModel &_noiseModel=nullptr)
Constructor.
Definition triangulation.h:601
bool useLOST
if true, will use the LOST algorithm instead of DLT
Definition triangulation.h:588
TriangulationResult is an optional point, along with the reasons why it is invalid.
Definition triangulation.h:646
TriangulationResult()
Default constructor, only for serialization.
Definition triangulation.h:658
TriangulationResult(const Point3 &p)
Constructor.
Definition triangulation.h:663
IsDerived< DERIVEDFACTOR > emplace_shared(Args &&... args)
Emplace a shared pointer to factor of given type.
Definition FactorGraph.h:153
Character and index key used to refer to variables.
Definition Symbol.h:37
static shared_ptr Sigma(size_t dim, double sigma, bool smart=true)
An isotropic noise model created by specifying a standard deviation sigma.
Definition NoiseModel.cpp:706
static shared_ptr Create(size_t dim)
Create a unit covariance noise model.
Definition NoiseModel.h:673
Definition NonlinearFactorGraph.h:57
A non-templated config holding any types of Manifold-group elements.
Definition Values.h:65
void insert(Key j, const Value &val)
Add a variable with the given j, throws KeyAlreadyExists<J> if j is already present.
Definition Values.cpp:170
Non-linear factor for a constraint derived from a 2D measurement.
Definition TriangulationFactor.h:33
In nonlinear factors, the error function returns the negative log-likelihood as a non-linear function...