2 #ifndef vpgl_em_compute_5_point_hxx_ 3 #define vpgl_em_compute_5_point_hxx_ 12 # include <vcl_msvc_warnings.h> 29 std::vector<vgl_point_2d<T> > normed_right_points, normed_left_points;
31 normalize(right_points, k_right, normed_right_points);
32 normalize(left_points, k_left, normed_left_points);
34 return compute(normed_right_points, normed_left_points, ems);
45 if (normed_right_points.size() != 5 || normed_left_points.size() != 5) {
47 std::cerr<<
"Wrong number of input points!\n" <<
48 "right_points has "<<normed_right_points.size() <<
49 " and left_points has "<<normed_left_points.size() <<
'\n';
55 std::vector<vnl_vector_fixed<T,9> > basis;
56 compute_nullspace_basis(normed_right_points, normed_left_points, basis);
60 std::vector<vnl_real_npolynomial> constraints;
61 compute_constraint_polynomials(basis, constraints);
65 compute_groebner_basis(constraints, groebner_basis);
69 compute_action_matrix(groebner_basis, action_matrix);
73 compute_e_matrices(basis, action_matrix, ems);
89 for (
unsigned int i = 0; i < points.size(); ++i)
110 for (
int i = 0; i < 5; ++i) {
111 A.
put(i, 0, right_points[i].x() * left_points[i].x());
112 A.
put(i, 1, right_points[i].y() * left_points[i].x());
113 A.
put(i, 2, left_points[i].x());
115 A.
put(i, 3, right_points[i].x() * left_points[i].y());
116 A.
put(i, 4, right_points[i].y() * left_points[i].y());
117 A.
put(i, 5, left_points[i].y());
119 A.
put(i, 6, right_points[i].x());
120 A.
put(i, 7, right_points[i].y());
130 for (
int i = 5; i < 9; ++i) {
133 for (
int j = 0; j < 9; ++j) {
134 basis_vector[j] = V.
get(j, i);
137 basis.push_back(basis_vector);
154 std::vector<vnl_real_npolynomial> &constraints)
const 164 std::vector<vnl_real_npolynomial> entry_polynomials(9);
171 for (
int i = 0; i < 9; ++i) {
172 coeffs[0] = basis[0][i];
173 coeffs[1] = basis[1][i];
174 coeffs[2] = basis[2][i];
175 coeffs[3] = basis[3][i];
177 entry_polynomials[i].
set(coeffs, exps);
198 entry_polynomials[0] * entry_polynomials[0];
200 for (
int i = 1; i < 9; ++i) {
201 sum_of_squares = sum_of_squares +
202 entry_polynomials[i] * entry_polynomials[i];
207 for (
int i = 0; i < 9; ++i) {
208 constraints.push_back(
209 entry_polynomials[i%3] *
210 (entry_polynomials[0] * entry_polynomials[3*(i/3) + 0]*2 +
211 entry_polynomials[1] * entry_polynomials[3*(i/3) + 1]*2 +
212 entry_polynomials[2] * entry_polynomials[3*(i/3) + 2]*2)
214 - entry_polynomials[i] * sum_of_squares);
218 for (
int i = 0; i < 9; ++i) {
220 entry_polynomials[(i%3) + 3] *
221 (entry_polynomials[3] * entry_polynomials[3*(i/3) + 0]*2 +
222 entry_polynomials[4] * entry_polynomials[3*(i/3) + 1]*2 +
223 entry_polynomials[5] * entry_polynomials[3*(i/3) + 2]*2);
227 for (
int i = 0; i < 9; ++i) {
228 constraints[i] = (constraints[i] +
229 entry_polynomials[(i%3) + 6] *
230 (entry_polynomials[6] * entry_polynomials[3*(i/3) + 0]*2 +
231 entry_polynomials[7] * entry_polynomials[3*(i/3) + 1]*2 +
232 entry_polynomials[8] * entry_polynomials[3*(i/3) + 2]*2)) * .5;
244 (entry_polynomials[1] * entry_polynomials[5] -
245 entry_polynomials[2] * entry_polynomials[4]);
249 (entry_polynomials[2] * entry_polynomials[3] -
250 entry_polynomials[0] * entry_polynomials[5]);
254 (entry_polynomials[0] * entry_polynomials[4] -
255 entry_polynomials[1] * entry_polynomials[3]);
257 constraints.push_back(det_term_1 + det_term_2 + det_term_3);
270 unsigned int z_p)
const 272 for (
unsigned int i = 0; i < p.
polyn().
rows(); ++i) {
284 const std::vector<vnl_real_npolynomial> &constraints,
287 assert(groebner_basis.
rows() == 10);
288 assert(groebner_basis.
cols() == 10);
292 for (
int i = 0; i < 10; ++i) {
294 A.put(i, 0, get_coeff(constraints[i], 3, 0, 0));
295 A.put(i, 1, get_coeff(constraints[i], 2, 1, 0));
296 A.put(i, 2, get_coeff(constraints[i], 1, 2, 0));
297 A.put(i, 3, get_coeff(constraints[i], 0, 3, 0));
298 A.put(i, 4, get_coeff(constraints[i], 2, 0, 1));
299 A.put(i, 5, get_coeff(constraints[i], 1, 1, 1));
300 A.put(i, 6, get_coeff(constraints[i], 0, 2, 1));
301 A.put(i, 7, get_coeff(constraints[i], 1, 0, 2));
302 A.put(i, 8, get_coeff(constraints[i], 0, 1, 2));
303 A.put(i, 9, get_coeff(constraints[i], 0, 0, 3));
304 A.put(i, 10, get_coeff(constraints[i], 2, 0, 0));
305 A.put(i, 11, get_coeff(constraints[i], 1, 1, 0));
306 A.put(i, 12, get_coeff(constraints[i], 0, 2, 0));
307 A.put(i, 13, get_coeff(constraints[i], 1, 0, 1));
308 A.put(i, 14, get_coeff(constraints[i], 0, 1, 1));
309 A.put(i, 15, get_coeff(constraints[i], 0, 0, 2));
310 A.put(i, 16, get_coeff(constraints[i], 1, 0, 0));
311 A.put(i, 17, get_coeff(constraints[i], 0, 1, 0));
312 A.put(i, 18, get_coeff(constraints[i], 0, 0, 1));
313 A.put(i, 19, get_coeff(constraints[i], 0, 0, 0));
317 for (
int i = 0; i < 10; ++i)
320 double leading = A.get(i, i);
321 A.scale_row(i, 1/leading);
324 for (
int j = i+1; j < 10; ++j) {
325 double leading2 = A.get(j, i);
327 A.get_row(j) - A.get_row(i) * leading2;
329 A.set_row(j, new_row);
334 for (
int i = 9; i >= 0; --i) {
335 for (
int j = 0; j < i; ++j) {
336 double scale = A.
get(j, i);
339 A.get_row(j) - A.get_row(i) * scale;
341 A.set_row(j, new_row);
348 for (
int i = 0; i < 10; ++i) {
349 for (
int j = 0; j < 10; ++j) {
350 groebner_basis.
put(i, j, A.get(i, j+10));
362 action_matrix.
fill(0.0);
372 action_matrix.
put(6, 0, 1.0);
373 action_matrix.
put(7, 1, 1.0);
374 action_matrix.
put(8, 3, 1.0);
375 action_matrix.
put(9, 6, 1.0);
389 for (
unsigned int i = 0; i < eigs.W.
size(); ++i) {
390 if (std::abs(eigs.W[i].imag()) <= tolerance)
394 double w_inv = 1.0 / eigs.R.
get(i, 9).real();
395 double x = eigs.R.
get(i, 6).real() * w_inv;
396 double y = eigs.R.
get(i, 7).real() * w_inv;
397 double z = eigs.R.
get(i, 8).real() * w_inv;
400 x * basis[0] + y * basis[1] + z * basis[2] + basis[3];
401 linear_e /= linear_e[8];
414 static inline void get_distinct_indices(
415 int n,
int *idxs,
int number_entries)
417 for (
int i = 0; i < n; ++i) {
423 idx = std::rand() % number_entries;
425 for (
int j = 0; j < i; ++j) {
426 if (idxs[j] == idx) {
449 if ( right_points.size() != left_points.size()) {
452 <<
"The two vectors of points must be the same size!\n" 453 <<
"right_points is size " << right_points.size()
454 <<
" while left_points is size " << left_points.size()
459 else if (right_points.size() < 5) {
462 <<
"There need to be at least 5 points to run the " 463 <<
"five-point algorithm!\n" 464 <<
"Input only contained " << right_points.size()
471 const size_t num_points = right_points.size();
473 unsigned best_inlier_count = 0u;
478 for (
unsigned int r = 0; r < num_rounds; ++r)
482 std::vector<vgl_point_2d<T> > right_points_to_use;
483 std::vector<vgl_point_2d<T> > left_points_to_use;
485 get_distinct_indices(5, match_idxs, (
int) num_points);
487 for (
int & match_idx : match_idxs) {
488 right_points_to_use.push_back(right_points[match_idx]);
489 left_points_to_use.push_back(left_points[match_idx]);
491 std::vector<vpgl_essential_matrix<T> > ems;
493 right_points_to_use, right_k,
494 left_points_to_use, left_k,
499 typename std::vector<vpgl_essential_matrix<T> >::const_iterator i;
500 for (i = ems.begin(); i != ems.end(); ++i) {
506 unsigned inlier_count = 0;
507 for (
unsigned j = 0; j < num_points; ++j) {
508 point_r.
put(0, 0, right_points[j].x());
509 point_r.
put(1, 0, right_points[j].y());
510 point_r.
put(2, 0, 1.0);
512 point_l.
put(0, 0, left_points[j].x());
513 point_l.
put(1, 0, left_points[j].y());
514 point_l.
put(2, 0, 1.0);
520 double p = (point_r.
transpose() * f_l).get(0,0);
521 double error = (1.0 / (f_l.
get(0,0) * f_l.
get(0,0) + f_l.
get(1,0) * f_l.
get(1,0)) +
522 1.0 / (f_r.
get(0,0) * f_r.
get(0,0) + f_r.
get(1,0) * f_r.
get(1,0))) * (p * p);
524 if ( error <= inlier_threshold) {
529 if (best_inlier_count < inlier_count) {
531 best_inlier_count = inlier_count;
540 #define VPGL_EM_COMPUTE_5_POINT_INSTANTIATE(T) \ 541 template class vpgl_em_compute_5_point<T >; \ 542 template class vpgl_em_compute_5_point_ransac<T > 544 #endif // vpgl_em_compute_5_point_hxx_ unsigned int cols() const
void compute_nullspace_basis(const std::vector< vgl_point_2d< T > > &right_points, const std::vector< vgl_point_2d< T > > &left_points, std::vector< vnl_vector_fixed< T, 9 > > &basis) const
Constructs the 5x9 epipolar constraint matrix based off the constraint that q1' * E * q2 = 0,...
The 5 point algorithm as described by David Nister for computing an essential matrix from point corre...
void compute_groebner_basis(const std::vector< vnl_real_npolynomial > &constraints, vnl_matrix< double > &groebner_basis) const
const vnl_vector< double > & coefficients() const
A class representing the "K" matrix of a perspective camera matrix as described in.
void put(unsigned r, unsigned c, T const &v)
T get(unsigned r, unsigned c) const
double get_coeff(const vnl_real_npolynomial &p, unsigned int x_p, unsigned int y_p, unsigned int z_p) const
Returns the coefficient of a term of a vnl_real_npolynomial in three variables with an x power of x_p...
T get(unsigned r, unsigned c) const
bool compute(std::vector< vgl_point_2d< T > > const &right_points, vpgl_calibration_matrix< T > const &right_k, std::vector< vgl_point_2d< T > > const &left_points, vpgl_calibration_matrix< T > const &left_k, vpgl_essential_matrix< T > &best_em) const
vnl_matrix_fixed< T, num_cols, num_rows > transpose() const
vnl_matrix & fill(double const &)
T const * data_block() const
vnl_vector< double > get_row(unsigned r) const
void compute_constraint_polynomials(const std::vector< vnl_vector_fixed< T, 9 > > &basis, std::vector< vnl_real_npolynomial > &constraints) const
Finds 10 constraint polynomials, based on the following criteria: if X, Y, Z and W are the basis vect...
vnl_matrix & set_row(unsigned i, double const *v)
void normalize(const std::vector< vgl_point_2d< T > > &points, const vpgl_calibration_matrix< T > &k, std::vector< vgl_point_2d< T > > &normed_points) const
Normalization is the process of left-multiplying by the inverse of the calibration matrix.
void compute_action_matrix(const vnl_matrix< double > &groebner_basis, vnl_matrix< double > &action_matrix) const
unsigned int size() const
void compute_e_matrices(const std::vector< vnl_vector_fixed< T, 9 > > &basis, const vnl_matrix< double > &action_matrix, std::vector< vpgl_essential_matrix< T > > &ems) const
unsigned int rows() const
const vnl_matrix< unsigned int > & polyn() const
vnl_vector & set(double const *ptr)
bool compute(const std::vector< vgl_point_2d< T > > &normed_right_points, const std::vector< vgl_point_2d< T > > &normed_left_points, std::vector< vpgl_essential_matrix< T > > &ems) const
Compute from two sets of corresponding points.
vgl_point_2d< T > map_to_focal_plane(vgl_point_2d< T > const &p_image) const
Maps to and from the focal plane.
double get(size_t i) const
vnl_matrix & set_identity()
const vnl_matrix_fixed< T, 3, 3 > & get_matrix() const
Get a copy of the FM in vnl form.
void put(unsigned r, unsigned c, T const &)