vpgl_camera_compute.cxx
Go to the documentation of this file.
1 // This is core/vpgl/algo/vpgl_camera_compute.cxx
2 #ifndef vpgl_camera_compute_cxx_
3 #define vpgl_camera_compute_cxx_
4 
5 #include <iostream>
6 #include <cstdlib>
7 #include <cmath>
8 #include "vpgl_camera_compute.h"
9 //:
10 // \file
11 #include <cassert>
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 #include <vnl/vnl_numeric_traits.h>
16 #include <vnl/vnl_det.h>
17 #include <vnl/vnl_inverse.h>
18 #include <vnl/vnl_vector_fixed.h>
19 #include <vnl/vnl_double_3.h>
20 #include <vnl/vnl_matrix_fixed.h>
21 #include <vnl/algo/vnl_svd.h>
22 #include <vnl/algo/vnl_qr.h>
26 #include <vgl/vgl_homg_point_3d.h>
29 #include <vgl/vgl_point_2d.h>
30 #include <vgl/vgl_point_3d.h>
31 #include <vgl/vgl_homg_point_2d.h>
32 #include <vpgl/vpgl_lvcs.h>
34 
35 //#define CAMERA_DEBUG
36 //------------------------------------------
37 bool
39  const std::vector< vgl_point_2d<double> >& image_pts,
40  const std::vector< vgl_point_3d<double> >& world_pts,
41  vpgl_proj_camera<double>& camera )
42 {
43  std::vector< vgl_homg_point_2d<double> > image_pts2;
44  std::vector< vgl_homg_point_3d<double> > world_pts2;
45  image_pts2.reserve(image_pts.size());
46 for (auto image_pt : image_pts)
47  image_pts2.emplace_back( image_pt );
48  world_pts2.reserve(world_pts.size());
49 for (const auto & world_pt : world_pts)
50  world_pts2.emplace_back( world_pt );
51  return compute( image_pts2, world_pts2, camera );
52 }
53 
54 
55 //------------------------------------------
56 bool
58  const std::vector< vgl_homg_point_2d<double> >& image_pts,
59  const std::vector< vgl_homg_point_3d<double> >& world_pts,
60  vpgl_proj_camera<double>& camera )
61 {
62  auto num_correspondences = static_cast<unsigned int>(image_pts.size());
63  if ( world_pts.size() < num_correspondences ) num_correspondences = static_cast<unsigned int>(world_pts.size());
64  assert( num_correspondences >= 6 );
65 
66  // Form the solution matrix.
67  vnl_matrix<double> S( 2*num_correspondences, 12, 0);
68  for ( unsigned i = 0; i < num_correspondences; ++i ) {
69  S(2*i,0) = -image_pts[i].w()*world_pts[i].x();
70  S(2*i,1) = -image_pts[i].w()*world_pts[i].y();
71  S(2*i,2) = -image_pts[i].w()*world_pts[i].z();
72  S(2*i,3) = -image_pts[i].w()*world_pts[i].w();
73  S(2*i,8) = image_pts[i].x()*world_pts[i].x();
74  S(2*i,9) = image_pts[i].x()*world_pts[i].y();
75  S(2*i,10) = image_pts[i].x()*world_pts[i].z();
76  S(2*i,11) = image_pts[i].x()*world_pts[i].w();
77  S(2*i+1,4) = -image_pts[i].w()*world_pts[i].x();
78  S(2*i+1,5) = -image_pts[i].w()*world_pts[i].y();
79  S(2*i+1,6) = -image_pts[i].w()*world_pts[i].z();
80 
81  S(2*i+1,7) = -image_pts[i].w()*world_pts[i].w();
82  S(2*i+1,8) = image_pts[i].y()*world_pts[i].x();
83  S(2*i+1,9) = image_pts[i].y()*world_pts[i].y();
84  S(2*i+1,10) = image_pts[i].y()*world_pts[i].z();
85  S(2*i+1,11) = image_pts[i].y()*world_pts[i].w();
86  }
87  vnl_svd<double> svd( S );
90  cm(0,0)=c(0); cm(0,1)=c(1); cm(0,2)=c(2); cm(0,3)=c(3);
91  cm(1,0)=c(4); cm(1,1)=c(5); cm(1,2)=c(6); cm(1,3)=c(7);
92  cm(2,0)=c(8); cm(2,1)=c(9); cm(2,2)=c(10); cm(2,3)=c(11);
93  camera = vpgl_proj_camera<double>( cm );
94  return true;
95 }
96 
97 
98 //------------------------------------------
99 bool
101  const std::vector< vgl_point_2d<double> >& image_pts,
102  const std::vector< vgl_point_3d<double> >& world_pts,
104 {
105  assert( image_pts.size() == world_pts.size() );
106  assert( image_pts.size() > 3 );
107 
108  // Form the solution matrix.
109  vnl_matrix<double> A(static_cast<unsigned int>(world_pts.size()), 4, 1 );
110  for (unsigned int i = 0; i < world_pts.size(); ++i) {
111  A(i,0) = world_pts[i].x(); A(i,1) = world_pts[i].y(); A(i,2) = world_pts[i].z();
112  }
113  vnl_vector<double> b1( image_pts.size() );
114  vnl_vector<double> b2( image_pts.size() );
115  for (unsigned int i = 0; i < image_pts.size(); ++i) {
116  b1(i) = image_pts[i].x(); b2(i) = image_pts[i].y();
117  }
118  vnl_matrix<double> AtA = A.transpose()*A;
119  vnl_svd<double> svd(AtA);
120  if ( svd.rank() < 4 ) {
121  std::cerr << "vpgl_affine_camera_compute:compute() cannot compute,\n"
122  << " input data has insufficient rank.\n";
123  return false;
124  }
125  vnl_matrix<double> S = svd.inverse()*A.transpose();
127  x1 = S*b1;
128  x2 = S*b2;
129 
130  // Fill in the camera.
131  camera.set_rows( x1, x2 );
132  return true;
133 }
134 
135 
136 //Compute the rotation matrix and translation vector for a
137 //perspective camera given world to image correspondences and
138 //the calibration matrix
140 compute( const std::vector< vgl_point_2d<double> >& image_pts,
141  const std::vector< vgl_point_3d<double> >& world_pts,
144 {
145  auto N = static_cast<unsigned int>(world_pts.size());
146  if (image_pts.size()!=N)
147  {
148  std::cout << "Unequal points sets in"
149  << " vpgl_perspective_camera_compute::compute()\n";
150  return false;
151  }
152  if (N<6)
153  {
154  std::cout << "Need at least 6 points for"
155  << " vpgl_perspective_camera_compute::compute()\n";
156  return false;
157  }
158 
159  //get the inverse calibration map
161  vnl_matrix_fixed<double, 3, 3> k_inv = vnl_inverse<double>(km);
162 
163  //Form the world point matrix
164 
165  //Solve for the unknown point depths (projective scale factors)
166  vnl_matrix<double> wp(4, N);
167  for (unsigned c = 0; c<N; ++c)
168  {
169  vgl_point_3d<double> p = world_pts[c];
170  wp[0][c] = p.x(); wp[1][c] = p.y(); wp[2][c] = p.z();
171  wp[3][c] = 1.0;
172  }
173 #ifdef CAMERA_DEBUG
174  std::cout << "World Points\n" << wp << '\n';
175 #endif
176  vnl_svd<double> svd(wp);
177  unsigned rank = svd.rank();
178  if (rank != 4)
179  {
180  std::cout << "Insufficient rank for world point"
181  << " matrix in vpgl_perspective_camera_compute::compute()\n";
182  return false;
183  }
184  //extract the last N-4 columns of V as the null space of wp
185  vnl_matrix<double> V = svd.V();
186  unsigned nr = V.rows(), nc = V.columns();
187  vnl_matrix<double> null_space(nr, nc-4);
188  for (unsigned c = 4; c<nc; ++c)
189  for (unsigned r = 0; r<nr; ++r)
190  null_space[r][c-4] = V[r][c];
191 #ifdef CAMERA_DEBUG
192  std::cout << "Null Space\n" << null_space << '\n';
193 #endif
194  //form Kronecker product of the null space (transpose) with K inverse
195  unsigned nrk = 3*(nc-4), nck = 3*nr;
196  vnl_matrix<double> v2k(nrk, nck);
197  for (unsigned r = 0; r<(nc-4); ++r)
198  for (unsigned c = 0; c<nr; ++c)
199  for (unsigned rk = 0; rk<3; ++rk)
200  for (unsigned ck = 0; ck<3; ++ck)
201  v2k[rk+3*r][ck+3*c] = k_inv[rk][ck]*null_space[c][r];
202 #ifdef CAMERA_DEBUG
203  std::cout << "V2K\n" << v2k << '\n';
204 #endif
205  //Stack the image points in homogeneous form in a diagonal matrix
206  vnl_matrix<double> D(3*N, N);
207  D.fill(0);
208  for (unsigned c = 0; c<N; ++c)
209  {
210  vgl_point_2d<double> p = image_pts[c];
211  D[3*c][c] = p.x(); D[3*c+1][c] = p.y(); D[3*c+2][c] = 1.0;
212  }
213 #ifdef CAMERA_DEBUG
214  std::cout << "D\n" << D << '\n';
215 #endif
216  //form the singular matrix
217  vnl_matrix<double> M = v2k*D;
218  vnl_svd<double> svdm(M);
219 
220  //The point depth solution
221  vnl_vector<double> depth = svdm.nullvector();
222 
223 #ifdef CAMERA_DEBUG
224  std::cout << "depths\n" << depth << '\n';
225 #endif
226 
227  //Check if depths are all approximately the same (near affine projection)
228  double average_depth = 0;
229  auto nd = static_cast<unsigned int>(depth.size());
230  for (unsigned i = 0; i<nd; ++i)
231  average_depth += depth[i];
232  average_depth /= nd;
233  double max_dev = 0;
234  for (unsigned i = 0; i<nd; ++i)
235  {
236  double dev = std::fabs(depth[i]-average_depth);
237  if (dev>max_dev)
238  max_dev = dev;
239  }
240  double norm_max_dev = max_dev/average_depth;
241  //if depths are nearly the same make them exactly equal
242  //since variations are not meaningful
243  if (norm_max_dev < 0.01)
244  for (unsigned i = 0; i<nd; ++i)
245  depth[i]=std::fabs(average_depth);
246 
247  //Set up point sets for ortho Procrustes
248  vnl_matrix<double> X(3,N), Y(3,N);
249  for (unsigned c = 0; c<N; ++c)
250  {
251  vgl_point_2d<double> pi = image_pts[c];
252  vgl_point_3d<double> pw = world_pts[c];
253  //image points are multiplied by projective scale factor (depth)
254  X[0][c] = pi.x()*depth[c]; X[1][c] = pi.y()*depth[c]; X[2][c] = depth[c];
255  // X[0][c] = pi.x(); X[1][c] = pi.y(); X[2][c] = 1.0;
256  Y[0][c] = pw.x(); Y[1][c] = pw.y(); Y[2][c] = pw.z();
257  }
258 
259  vpgl_ortho_procrustes op(X, Y);
260  if (!op.compute_ok())
261  return false;
262 
263  vgl_rotation_3d<double> R = op.R();
265 
267 #ifdef CAMERA_DEBUG
268  std::cout << "translation\n" << t << '\n'
269  << "scale = " << op.s() << '\n'
270  << "residual = " << op.residual_mean_sq_error() << '\n';
271 #endif
272 
273  vnl_vector_fixed<double, 3> center = -(rr.transpose())*t;
274  vgl_point_3d<double> vgl_center(center[0],center[1],center[2]);
276  tcam.set_calibration(K);
277  tcam.set_camera_center(vgl_center);
278  tcam.set_rotation(R);
279 
280  //perform a final non-linear optimization
281  std::vector<vgl_homg_point_3d<double> > h_world_pts;
282  for (unsigned i = 0; i<N; ++i)
283  h_world_pts.emplace_back(world_pts[i]);
284  camera = vpgl_optimize_camera::opt_orient_pos_cal(tcam, h_world_pts, image_pts, 0.00005, 20000);
285  return true;
286 }
287 
288 
289 //: Uses the direct linear transform algorithm described in "Multiple
290 // View Geometry in Computer Vision" to find the projection matrix,
291 // and extracts the parameters of the camera from this projection matrix.
292 // Requires: image_pts and world_pts are correspondences. image_pts is
293 // the projected form, and world_pts is the unprojected form. There
294 // need to be at least 6 points.
295 // Returns: true if successful. err is filled with the two-norm of the
296 // projection error vector. camera is filled with the perspective
297 // decomposition of the projection matrix
299 compute_dlt (const std::vector< vgl_point_2d<double> >& image_pts,
300  const std::vector< vgl_point_3d<double> >& world_pts,
302  double &err)
303 {
304  if (image_pts.size() < 6) {
305  std::cout<<"vpgl_perspective_camera_compute::compute needs at"
306  << " least 6 points!" << std::endl;
307  return false;
308  }
309  else if (image_pts.size() != world_pts.size()) {
310  std::cout<<"vpgl_perspective_camera_compute::compute needs to"
311  << " have input vectors of the same size!" << std::endl
312  << "Currently, image_pts is size " << image_pts.size()
313  << " and world_pts is size " << world_pts.size() << std::endl;
314  return false;
315  }
316  else //Everything is good!
317  {
318  // Two equations for each point, one for the x's, the other for
319  // the ys
320  int num_eqns = static_cast<int>(2 * image_pts.size());
321 
322  // A 3x4 projection matrix has 11 free vars
323  int num_vars = 11;
324 
325  //---------------Set up and solve a system of linear eqns----
326  vnl_matrix<double> A(num_eqns, num_vars);
327  vnl_vector<double> b(num_eqns);
328 
329  // If the world pt is (x,y,z), and the image pt is (u,v),
330  // A is of the form
331  // [...]
332  // [x, y, z, 1, 0, 0, 0, 0, -u*x, -u*y, -u*z]
333  // [0, 0, 0, 0, x, y, z, 1, -v*x, -v*y, -v*z]
334  // [...]
335  //
336  // and b is of the form [...; v; u; ...]
337  for (unsigned int i = 0; i < image_pts.size(); ++i)
338  {
339  //Set the first row of A
340  A.put(2*i, 0, world_pts[i].x());
341  A.put(2*i, 1, world_pts[i].y());
342  A.put(2*i, 2, world_pts[i].z());
343  A.put(2*i, 3, 1.0);
344 
345  A.put(2*i, 4, 0.0);
346  A.put(2*i, 5, 0.0);
347  A.put(2*i, 6, 0.0);
348  A.put(2*i, 7, 0.0);
349 
350  A.put(2*i, 8, -image_pts[i].x() * world_pts[i].x());
351  A.put(2*i, 9, -image_pts[i].x() * world_pts[i].y());
352  A.put(2*i, 10, -image_pts[i].x() * world_pts[i].z());
353 
354  //Set the second row of A
355  A.put(2*i+1, 0, 0.0);
356  A.put(2*i+1, 1, 0.0);
357  A.put(2*i+1, 2, 0.0);
358  A.put(2*i+1, 3, 0.0);
359 
360  A.put(2*i+1, 4, world_pts[i].x());
361  A.put(2*i+1, 5, world_pts[i].y());
362  A.put(2*i+1, 6, world_pts[i].z());
363  A.put(2*i+1, 7, 1.0);
364 
365  A.put(2*i+1, 8, -image_pts[i].y() * world_pts[i].x());
366  A.put(2*i+1, 9, -image_pts[i].y() * world_pts[i].y());
367  A.put(2*i+1, 10, -image_pts[i].y() * world_pts[i].z());
368 
369  //Set the current rows of the RHS vector
370  b[2 * i] = image_pts[i].x();
371  b[2 * i + 1] = image_pts[i].y();
372  }
373 
374  //Solve the system
375  vnl_svd<double> svd(A);
376  vnl_vector<double> x = svd.solve(b);
377 
378  //Transform the linearized version into the matrix form
380 
381  for (int row = 0; row < 3; row++) {
382  for (int col = 0; col < 4; col++) {
383  if (row*4 + col < 11) {
384  proj.put(row, col, x[row*4 + col]);
385  }
386  }
387  }
388 
389  proj.set(2, 3, 1.0);
390 
391  //-------------Find the error rate--------------------
392  err = 0;
393  for (unsigned int i = 0; i < image_pts.size(); ++i) {
395  world_pt[0] = world_pts[i].x();
396  world_pt[1] = world_pts[i].y();
397  world_pt[2] = world_pts[i].z();
398  world_pt[3] = 1.0;
399 
400  vnl_vector_fixed<double, 3> projed_pt = proj * world_pt;
401 
402  projed_pt[0] /= projed_pt[2];
403  projed_pt[1] /= projed_pt[2];
404 
405  double dx = projed_pt[0] - image_pts[i].x();
406  double dy = projed_pt[1] - image_pts[i].y();
407 
408  err += dx*dy;
409  }
410 
411  //-----Get the camera------------------------------
412  return vpgl_perspective_decomposition(proj, camera);
413  }
414 }
415 
416 //: Compute from two sets of corresponding 2D points (image and ground plane).
417 // \param ground_pts are 2D points representing world points with Z=0
418 // The calibration matrix of \a camera is enforced
419 // This computation is simpler than the general case above and only requires 4 points
420 // Put the resulting camera into \p camera, return true if successful.
422 compute( const std::vector< vgl_point_2d<double> >& image_pts,
423  const std::vector< vgl_point_2d<double> >& ground_pts,
425 {
426  auto num_pts = static_cast<unsigned int>(ground_pts.size());
427  if (image_pts.size()!=num_pts)
428  {
429  std::cout << "Unequal points sets in"
430  << " vpgl_perspective_camera_compute::compute()\n";
431  return false;
432  }
433  if (num_pts<4)
434  {
435  std::cout << "Need at least 4 points for"
436  << " vpgl_perspective_camera_compute::compute()\n";
437  return false;
438  }
439 
440  std::vector<vgl_homg_point_2d<double> > pi, pg;
441  for (unsigned i=0; i<num_pts; ++i) {
442 #ifdef CAMERA_DEBUG
443  std::cout << '('<<image_pts[i].x()<<", "<<image_pts[i].y()<<") -> "
444  << '('<<ground_pts[i].x()<<", "<<ground_pts[i].y()<<')'<<std::endl;
445 #endif
446  pi.emplace_back(image_pts[i].x(),image_pts[i].y());
447  pg.emplace_back(ground_pts[i].x(),ground_pts[i].y());
448  }
449 
450  // compute a homography from the ground plane to image plane
452  vnl_double_3x3 H = est_H.compute(pg,pi).get_matrix();
453  if (vnl_det(H) > 0)
454  H *= -1.0;
455 
456  // invert the effects of intrinsic parameters
458  vnl_double_3x3 A(Kinv*H);
459  // get the translation vector (up to a scale)
460  vnl_vector_fixed<double,3> t = A.get_column(2);
461  t.normalize();
462 
463  // compute the closest rotation matrix
464  A.set_column(2, vnl_cross_3d(A.get_column(0), A.get_column(1)));
465  vnl_svd<double> svdA(A.as_ref());
466  vnl_double_3x3 R = svdA.U()*svdA.V().conjugate_transpose();
467 
468  // find the point farthest from the origin
469  int max_idx = 0;
470  double max_dist = 0.0;
471  for (unsigned int i=0; i < ground_pts.size(); ++i) {
472  double d = (ground_pts[i]-vgl_point_2d<double>(0,0)).length();
473  if (d >= max_dist) {
474  max_dist = d;
475  max_idx = i;
476  }
477  }
478 
479  // compute the unknown scale
480  vnl_vector_fixed<double,3> i1 = Kinv*vnl_double_3(image_pts[max_idx].x(),image_pts[max_idx].y(),1.0);
482  vnl_vector_fixed<double,3> p1 = vnl_cross_3d(i1, R*vnl_double_3(ground_pts[max_idx].x(),ground_pts[max_idx].y(),1.0));
483  double s = p1.magnitude()/t1.magnitude();
484 
485  // compute the camera center
486  t *= s;
487  t = -R.transpose()*t;
488 
490  camera.set_camera_center(vgl_point_3d<double>(t[0],t[1],t[2]));
491 
492  //perform a final non-linear optimization
493  std::vector<vgl_homg_point_3d<double> > h_world_pts;
494  for (unsigned i = 0; i<num_pts; ++i) {
495  h_world_pts.emplace_back(ground_pts[i].x(),ground_pts[i].y(),0,1);
496  if (camera.is_behind_camera(h_world_pts.back())) {
497  std::cout << "behind camera" << std::endl;
498  return false;
499  }
500  }
501  camera = vpgl_optimize_camera::opt_orient_pos(camera, h_world_pts, image_pts);
502 
503  return true;
504 }
505 
506 #endif // vpgl_camera_compute_cxx_
bool vpgl_perspective_decomposition(const vnl_matrix_fixed< T, 3, 4 > &camera_matrix, vpgl_perspective_camera< T > &p_camera)
Decompose camera into parameter blocks.
abs_t magnitude() const
void set_rotation(const vgl_rotation_3d< T > &R)
vnl_vector< T > vnl_cross_3d(const vnl_vector< T > &v1, const vnl_vector< T > &v2)
A geographic coordinate system.
unsigned int rank() const
vnl_matrix_fixed< T, 3, 3 > as_matrix() const
vnl_vector_fixed< double, 3 > t()
the resulting translation vector.
static bool compute(const std::vector< vgl_homg_point_2d< double > > &image_pts, const std::vector< vgl_homg_point_3d< double > > &world_pts, vpgl_proj_camera< double > &camera)
Compute from two sets of corresponding points.
static bool compute_dlt(const std::vector< vgl_point_2d< double > > &image_pts, const std::vector< vgl_point_3d< double > > &world_pts, vpgl_perspective_camera< double > &camera, double &err)
Uses the direct linear transform algorithm described in "Multiple.
vnl_matrix< double > transpose() const
vnl_vector< T > nullvector() const
void set_camera_center(const vgl_point_3d< T > &camera_center)
vnl_matrix< T > inverse() const
void put(unsigned r, unsigned c, T const &v)
Type & z()
const vpgl_calibration_matrix< T > & get_calibration() const
static vpgl_perspective_camera< double > opt_orient_pos_cal(const vpgl_perspective_camera< double > &camera, const std::vector< vgl_homg_point_3d< double > > &world_points, const std::vector< vgl_point_2d< double > > &image_points, const double xtol=0.0001, const unsigned nevals=10000)
optimize orientation, position and internal calibration(no skew)for a perspective camera.
bool compute(std::vector< vgl_homg_point_2d< double > > const &points1, std::vector< vgl_homg_point_2d< double > > const &points2, vgl_h_matrix_2d< double > &H)
vnl_matrix< T > solve(vnl_matrix< T > const &B) const
vnl_matrix_fixed< T, 1, 1 > vnl_inverse(vnl_matrix_fixed< T, 1, 1 > const &m)
Several routines for computing different kinds of cameras from world-point correspondences.
void set_calibration(const vpgl_calibration_matrix< T > &K)
Setters and getters.
VNL_EXPORT T vnl_det(T const *row0, T const *row1)
Methods for projecting geometric structures onto the image.
Type & y()
vnl_matrix_fixed< T, num_cols, num_rows > transpose() const
vnl_matrix_fixed< T, 3, 3 > get_matrix() const
Get the calibration matrix.
vnl_matrix & fill(double const &)
static vpgl_perspective_camera< double > opt_orient_pos(const vpgl_perspective_camera< double > &camera, const std::vector< vgl_homg_point_3d< double > > &world_points, const std::vector< vgl_point_2d< double > > &image_points)
optimize orientation and position for a perspective camera.
Type & x()
This class implements the perspective camera class as described in Hartley & Zisserman as a finite ca...
bool compute_ok() const
successful computation.
double residual_mean_sq_error()
the residual error.
bool is_behind_camera(const vgl_homg_point_3d< T > &world_point) const
Determine whether the given point lies in front of the principal plane.
static bool compute(const std::vector< vgl_point_2d< double > > &image_pts, const std::vector< vgl_point_3d< double > > &world_pts, vpgl_affine_camera< double > &camera)
Compute from two sets of corresponding points.
unsigned int rows() const
void set_rows(const vnl_vector_fixed< T, 4 > &row1, const vnl_vector_fixed< T, 4 > &row2)
Set the top two rows.
vnl_matrix< T > & V()
vnl_vector_fixed< T, n > & normalize()
Solve orthogonal Procrustes problem.
static bool compute(const std::vector< vgl_point_2d< double > > &image_pts, const std::vector< vgl_point_3d< double > > &world_pts, const vpgl_calibration_matrix< double > &K, vpgl_perspective_camera< double > &camera)
Compute from two sets of corresponding points.
vnl_matrix_fixed< T, num_cols, num_rows > conjugate_transpose() const
vgl_rotation_3d< double > R()
the resulting rotation matrix.
double length(v const &a)
unsigned int columns() const
Solve min(R,s) ||X-s(RY+t)||, where R is a rotation matrix, X,Y are 3-d points, s is a scalar and t i...
vnl_matrix_fixed & set(unsigned r, unsigned c, T const &v)
Methods for back_projecting from cameras to 3-d geometric structures.
void put(unsigned r, unsigned c, double const &)
Type & y()
Type & x()
double s()
The scale factor, s.