-
-
Notifications
You must be signed in to change notification settings - Fork 873
Expand file tree
/
Copy pathTriangulation.hpp
More file actions
213 lines (180 loc) · 7.7 KB
/
Triangulation.hpp
File metadata and controls
213 lines (180 loc) · 7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// Copyright (c) 2010 libmv contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#pragma once
#include <aliceVision/numeric/numeric.hpp>
#include <aliceVision/robustEstimation/ISolver.hpp>
#include <aliceVision/numeric/algebra.hpp>
#include <vector>
#include <random>
namespace aliceVision {
namespace multiview {
/**
* @brief Compute a 3D position of a point from several images of it. In particular,
* compute the projective point X in R^4 such that x = PX.
* Algorithm is the standard DLT; for derivation see appendix of Keir's thesis.
* It also allows to specify some (optional) weight for each point (solving the
* weighted least squared problem)
*
* @param[in] x are 2D coordinates (x,y,1) in each image
* @param[in] Ps is the list of projective matrices for each camera
* @param[out] X is the estimated 3D point
* @param[in] weights a (optional) list of weights for each point
*/
void TriangulateNView(const Mat2X& x, const std::vector<Mat34>& Ps, Vec4& X, const std::vector<double>* weights = nullptr);
/**
* @brief Compute a 3D position of a point from several images of it. In particular,
* compute the projective point X in R^4 such that x ~ PX.
* Algorithm is the standard DLT
* It also allows to specify some (optional) weight for each point (solving the
* weighted least squared problem)
*
* @param[in] x are 2D coordinates (x,y) in each image
* @param[in] Ps is the list of projective matrices for each camera
* @param[out] X is the estimated 3D point
* @param[in] weights a (optional) list of weights for each point
*/
template<class ContainerT>
void TriangulateNViewAlgebraic(const ContainerT& x, const std::vector<Mat34>& Ps, Vec4& X, const std::vector<double>* weights = nullptr)
{
Mat2X::Index nviews = CountElements(x);
assert(static_cast<std::size_t>(nviews) == Ps.size());
Mat design(2 * nviews, 4);
for (Mat2X::Index i = 0; i < nviews; ++i)
{
design.block<2, 4>(2 * i, 0) = SkewMatMinimal(getElement<ContainerT>(x, i)) * Ps[i];
if (weights != nullptr)
{
design.block<2, 4>(2 * i, 0) *= (*weights)[i];
}
}
Nullspace(design, X);
}
/**
* @brief Compute a 3D position of a point from several images of it. In particular,
* compute the projective point X in R^4 such that x ~ PX.
* Algorithm is the standard DLT
* It also allows to specify some (optional) weight for each point (solving the
* weighted least squared problem)
*
* @param[in] xs are 2D coordinates (x,y) in each image
* @param[in] Ps is the list of Transformation matrices for each camera
* @param[out] X is the estimated 3D point
* @param[in] weights a (optional) list of weights for each point
*/
void TriangulateNViewAlgebraicSpherical(const std::vector<Vec3> &xs,
const std::vector<Eigen::Matrix4d> & Ts,
Vec4 & X,
const std::vector<double> *weights = nullptr);
/**
* @brief Compute a 3D position of a point from several images of it. In particular,
* compute the projective point X in R^4 such that x ~ PX.
* Algorithm is Lo-RANSAC
* It can return the list of the cameras set as inlier by the Lo-RANSAC algorithm.
*
* @param[in] x are 2D coordinates (x,y,1) in each image
* @param[in] Ps is the list of projective matrices for each camera
* @param[out] X is the estimated 3D point
* @param[out] inliersIndex (optional) store the index of the cameras (following Ps ordering, not the view_id) set as Inliers by Lo-RANSAC
* @param[in] thresholdError (optional) set a threshold value to the Lo-RANSAC scorer
*/
void TriangulateNViewLORANSAC(const std::vector<Vec2>& x,
const std::vector<Mat34>& Ps,
std::mt19937& generator,
Vec4& X,
std::vector<std::size_t>* inliersIndex = NULL,
const double& thresholdError = 4.0);
// Iterated linear method
class Triangulation
{
public:
std::size_t size() const { return views.size(); }
void clear() { views.clear(); }
void add(const Mat34& projMatrix, const Vec2& p) { views.emplace_back(projMatrix, p); }
// Return squared L2 sum of error
double error(const Vec3& X) const;
Vec3 compute(int iter = 3) const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Accessors
// These values are defined after a successful call to compute
double minDepth() const { return zmin; }
double maxDepth() const { return zmax; }
double error() const { return err; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Data members
protected:
mutable double zmin; // min depth, mutable since modified in compute(...) const;
mutable double zmax; // max depth, mutable since modified in compute(...) const;
mutable double err; // re-projection error, mutable since modified in compute(...) const;
std::vector<std::pair<Mat34, Vec2>> views; // Proj matrix and associated image point
};
template<class ContainerT>
struct TriangulateNViewsSolver
{
/**
* @brief Return the minimum number of required samples
* @return minimum number of required samples
*/
inline std::size_t getMinimumNbRequiredSamples() const { return 2; }
/**
* @brief Return the maximum number of models
* @return maximum number of models
*/
inline std::size_t getMaximumNbModels() const { return 1; }
void solve(const ContainerT& x, const std::vector<Mat34>& Ps, std::vector<robustEstimation::MatrixModel<Vec4>>& X) const
{
Vec4 pt3d;
TriangulateNViewAlgebraic(x, Ps, pt3d);
X.push_back(robustEstimation::MatrixModel<Vec4>(pt3d));
assert(X.size() == 1);
}
void solve(const ContainerT& x,
const std::vector<Mat34>& Ps,
std::vector<robustEstimation::MatrixModel<Vec4>>& X,
const std::vector<double>& weights) const
{
Vec4 pt3d;
TriangulateNViewAlgebraic(x, Ps, pt3d, &weights);
X.push_back(robustEstimation::MatrixModel<Vec4>(pt3d));
assert(X.size() == 1);
}
};
struct TriangulateNViewsSphericalSolver
{
/**
* @brief Return the minimum number of required samples
* @return minimum number of required samples
*/
inline std::size_t getMinimumNbRequiredSamples() const
{
return 2;
}
/**
* @brief Return the maximum number of models
* @return maximum number of models
*/
inline std::size_t getMaximumNbModels() const
{
return 1;
}
void solve(const std::vector<Vec3> & x, const std::vector<Eigen::Matrix4d>& Ts, std::vector<robustEstimation::MatrixModel<Vec4>>& X) const
{
Vec4 pt3d;
TriangulateNViewAlgebraicSpherical(x, Ts, pt3d);
X.push_back(robustEstimation::MatrixModel<Vec4>(pt3d));
assert(X.size() == 1);
}
void solve(const std::vector<Vec3> & x, const std::vector<Eigen::Matrix4d>& Ts, std::vector<robustEstimation::MatrixModel<Vec4>>& X, const std::vector<double>& weights) const
{
Vec4 pt3d;
TriangulateNViewAlgebraicSpherical(x, Ts, pt3d, &weights);
X.push_back(robustEstimation::MatrixModel<Vec4>(pt3d));
assert(X.size() == 1);
}
};
} // namespace multiview
} // namespace aliceVision