vpgl_optimize_camera.cxx
Go to the documentation of this file.
1 // This is core/vpgl/algo/vpgl_optimize_camera.cxx
2 #include <utility>
3 #include "vpgl_optimize_camera.h"
4 //:
5 // \file
7 #include <vnl/vnl_double_3.h>
8 #include <vnl/vnl_double_3x3.h>
10 #include <vgl/vgl_homg_point_2d.h>
11 #if 0
13 #endif
15 #include <cassert>
16 #ifdef _MSC_VER
17 # include <vcl_msvc_warnings.h>
18 #endif
19 
20 
21 //: Constructor
24  const vgl_point_3d<double>& c,
25  const std::vector<vgl_homg_point_3d<double> >& world_points,
26  std::vector<vgl_point_2d<double> > image_points )
27  : vnl_least_squares_function(3,static_cast<unsigned int>(2*world_points.size()),no_gradient),
28  K_(K),
29  c_(c),
30  world_points_(world_points),
31  image_points_(std::move(image_points))
32 {
33  assert(world_points_.size() == image_points_.size());
34 }
35 
36 
37 //: The main function.
38 // Given the parameter vector x, compute the vector of residuals fx.
39 // Fx has been sized appropriately before the call.
40 // The parameters in x are the {wx, wy, wz}
41 // where w is the Rodrigues vector of the rotation.
42 void
44 {
46  for (unsigned int i=0; i<world_points_.size(); ++i)
47  {
49  fx[2*i] = image_points_[i].x() - proj.x()/proj.w();
50  fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
51  }
52 }
53 
54 //==============================================================================
55 
56 //: Constructor
59  const std::vector<vgl_homg_point_3d<double> >& world_points,
60  std::vector<vgl_point_2d<double> > image_points )
61  : vnl_least_squares_function(6, static_cast<unsigned int>(2 * world_points.size()), no_gradient),
62  K_(K),
63  world_points_(world_points),
64  image_points_(std::move(image_points))
65 {
66  assert(world_points_.size() == image_points_.size());
67 }
68 
69 
70 //: The main function.
71 // Given the parameter vector x, compute the vector of residuals fx.
72 // Fx has been sized appropriately before the call.
73 // The parameters in x are really two three component vectors {wx, wy, wz, tx, ty, tz}
74 // where w is the Rodrigues vector of the rotation and t is the translation.
75 void
77 {
78  assert(x.size() == 6);
79  vnl_double_3 w(x[0], x[1], x[2]);
80  vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
82  for (unsigned int i=0; i<world_points_.size(); ++i)
83  {
85  fx[2*i] = image_points_[i].x() - proj.x()/proj.w();
86  fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
87  }
88 }
89 
90 #if 0
91 //: Called after each LM iteration to print debugging etc.
92 void
94  vnl_vector<double> const& x,
95  vnl_vector<double> const& fx)
96 {
97  assert(x.size() == 6);
98  vnl_double_3 w(x[0], x[1], x[2]);
99  vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
100  vgl_h_matrix_3d<double> R(vnl_rotation_matrix(w), vnl_double_3(0.0,0.0,0.0));
102 #ifdef DEBUG
103  std::cout << "camera =\n" << cam.get_matrix() << std::endl;
104 #endif
105 }
106 #endif
107 
108 //==============================================================================
109 
110 //: Constructor
113  std::vector<vgl_point_2d<double> > image_points )
114  : vnl_least_squares_function(10,2*world_points.size(),no_gradient),
115  world_points_(world_points),
116  image_points_(std::move(image_points))
117 {
118  assert(world_points_.size() == image_points_.size());
119 }
120 
121 
122 //: The main function.
123 // Given the parameter vector x, compute the vector of residuals fx.
124 // Fx has been sized appropriately before the call.
125 // The parameters in x are really two three component vectors {wx, wy, wz, tx, ty, tz}
126 // where w is the Rodrigues vector of the rotation and t is the translation.
127 void
129 {
130  assert(x.size() == 10);
131  vnl_double_3 w(x[0], x[1], x[2]);
133  vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
134  vnl_double_3x3 kk;
135  kk.fill(0);
136  kk[0][0]=x[6]; kk[0][2]=x[7];
137  kk[1][1]=x[8]; kk[1][2]=x[9]; kk[2][2]=1.0;
138 
139  // Check that it is a valid calibration matrix.
140  if ( !(kk[0][0]>0) || !(kk[1][1]>0) ) {
141  for (unsigned int i=0; i<world_points_.size(); ++i) {
142  fx[2*i] = 100000000;
143  fx[2*i+1] = 100000000;
144  }
145  return;
146  }
147 
149  vpgl_perspective_camera<double> cam(K, t, R);
150  for (unsigned int i=0; i<world_points_.size(); ++i)
151  {
153  fx[2*i] = image_points_[i].x() - proj.x()/proj.w();
154  fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
155  }
156 }
157 
158 //: Constructor
161  const std::vector<vgl_homg_point_3d<double> >& world_points,
162  std::vector<vgl_point_2d<double> > image_points )
163  : vnl_least_squares_function(8,2*world_points.size(),use_gradient),
164  K_init_(K_init),
165  world_points_(world_points),
166  image_points_(std::move(image_points))
167 {
168  assert(world_points_.size() == image_points_.size());
169 }
170 
171 
172 //: The main function.
173 // Given the parameter vector x, compute the vector of residuals fx.
174 // Fx has been sized appropriately before the call.
175 // The parameters in x are quaternion, translation, focal length {q: x, y, z, r | t: t1, t2, t3 | f}
176 void
178 {
179  assert(x.size() == 8);
180  vnl_quaternion<double> q(x[0], x[1], x[2], x[3]);
182  vgl_vector_3d<double> t(x[4], x[5], x[6]);
183 
184  // Check that it is a valid focal length
185  if (x[7]<=0) {
186  for (unsigned int i=0; i<world_points_.size(); ++i) {
187  fx[2*i] = 100000000;
188  fx[2*i+1] = 100000000;
189  }
190  return;
191  }
192 
194  K.set_focal_length(x[7]);
195  vpgl_perspective_camera<double> cam(K, R, t);
196  for (unsigned int i=0; i<world_points_.size(); ++i)
197  {
199  fx[2*i] = image_points_[i].x() - proj.x()/proj.w();
200  fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
201  }
202 }
203 
204 //: Gradients of the cost-function w.r.t. to the 8 free parameters of x
205 // The eight parameters are quaternions(wx, wy, wz), translation(tx, ty, tz) and focal length (Fx)
206 void
208 {
209  // norm of unnormalized quaternion
210  double norm = sqrt(xvec[0]*xvec[0] + xvec[1]*xvec[1] + xvec[2]*xvec[2] + xvec[3]*xvec[3]);
211  vnl_quaternion<double> q(xvec[0], xvec[1], xvec[2], xvec[3]);
214  // Quaternion gets normalized after getting passed to R
215  q = R.as_quaternion();
216  double x, y, z, r;
217  x = q.x(); y = q.y(); z = q.z(); r = q.r();
218 
219  vgl_vector_3d<double> t(xvec[4], xvec[5], xvec[6]);
220 
222  K.set_focal_length(xvec[7]);
223  vpgl_perspective_camera<double> cam(K, R, t);
224 
225  // The 3 rows of [R | t] matrix
226  double A, B, C;
227  // camera translation
228  double t1, t2, t3;
229  t1 = t.x(); t2 = t.y(); t3 = t.z();
230  // 3D point coordinates
231  double X, Y, Z, W;
232  // Focal length
233  double F = xvec[7];
234 
235  for (unsigned int idx=0; idx < world_points_.size(); ++idx)
236  {
237  X = world_points_[idx].x(); Y = world_points_[idx].y(); Z = world_points_[idx].z(); W = world_points_[idx].w();
238 
239  A = Rmat[0][0]*X + Rmat[0][1]*Y + Rmat[0][2]*Z + t1*W;
240  B = Rmat[1][0]*X + Rmat[1][1]*Y + Rmat[1][2]*Z + t2*W;
241  C = Rmat[2][0]*X + Rmat[2][1]*Y + Rmat[2][2]*Z + t3*W;
242 
243  double dex_dr1, dex_dr2, dex_dr3, dex_dr4, dey_dr1, dey_dr2, dey_dr3, dey_dr4;
244  double dex_dt1, dey_dt1, dex_dt2, dey_dt2, dex_dt3, dey_dt3, dex_df, dey_df;
245 
246  dex_dr1 = 2*((W*t1*x + X*x + Y*y + Z*z)*C - (W*t3*x + X*z + Y*r - Z*x)*A)/(C*C);
247  dex_dr2 = 2*((W*t1*y - X*y + Y*x + Z*r)*C - (W*t3*y - X*r + Y*z - Z*y)*A)/(C*C);
248  dex_dr3 = 2*((W*t1*z - X*z - Y*r + Z*x)*C - (W*t3*z + X*x + Y*y + Z*z)*A)/(C*C);
249  dex_dr4 = 2*((W*t1*r + X*r - Y*z + Z*y)*C - (W*t3*r - X*y + Y*x + Z*r)*A)/(C*C);
250 
251  dey_dr1 = 2*((W*t2*x + X*y - Y*x - Z*r)*C - (W*t3*x + X*z + Y*r - Z*x)*B)/(C*C);
252  dey_dr2 = 2*((W*t2*y + X*x + Y*y + Z*z)*C - (W*t3*y - X*r + Y*z - Z*y)*B)/(C*C);
253  dey_dr3 = 2*((W*t2*z + X*r - Y*z + Z*y)*C - (W*t3*z + X*x + Y*y + Z*z)*B)/(C*C);
254  dey_dr4 = 2*((W*t2*r + X*z + Y*r - Z*x)*C - (W*t3*r - X*y + Y*x + Z*r)*B)/(C*C);
255 
256  dex_dr1 *= -F/norm; dex_dr2 *= -F/norm; dex_dr3 *= -F/norm; dex_dr4 *= -F/norm;
257  dey_dr1 *= -F/norm; dey_dr2 *= -F/norm; dey_dr3 *= -F/norm; dey_dr4 *= -F/norm;
258 
259  dey_dt2 = dex_dt1 = -F/C;
260  dex_dt2 = dey_dt1 = 0;
261  dex_dt3 = F*A / (C*C);
262  dey_dt3 = F*B / (C*C);
263  dex_df = -A/C;
264  dey_df = -B/C;
265 
266  jacobian(2*idx,0) = dex_dr1;
267  jacobian(2*idx,1) = dex_dr2;
268  jacobian(2*idx,2) = dex_dr3;
269  jacobian(2*idx,3) = dex_dr4;
270 
271  jacobian(2*idx,4) = dex_dt1;
272  jacobian(2*idx,5) = dex_dt2;
273  jacobian(2*idx,6) = dex_dt3;
274  jacobian(2*idx,7) = dex_df;
275 
276  jacobian(2*idx+1,0) = dey_dr1;
277  jacobian(2*idx+1,1) = dey_dr2;
278  jacobian(2*idx+1,2) = dey_dr3;
279  jacobian(2*idx+1,3) = dey_dr4;
280 
281  jacobian(2*idx+1,4) = dey_dt1;
282  jacobian(2*idx+1,5) = dey_dt2;
283  jacobian(2*idx+1,6) = dey_dt3;
284  jacobian(2*idx+1,7) = dey_df;
285  }
286 }
287 
288 //===============================================================
289 // Static functions for vpgl_optimize_camera
290 //===============================================================
291 
292 
293 //: optimize orientation for a perspective camera
296  const std::vector<vgl_homg_point_3d<double> >& world_points,
297  const std::vector<vgl_point_2d<double> >& image_points )
298 {
300  const vgl_point_3d<double>& c = camera.get_camera_center();
301  const vgl_rotation_3d<double>& R = camera.get_rotation();
302 
303  // compute the Rodrigues vector from the rotation
304  vnl_double_3 w = R.as_rodrigues();
305 
306  vpgl_orientation_lsqr lsqr_func(K,c,world_points,image_points);
307  vnl_levenberg_marquardt lm(lsqr_func);
308  //lm.set_trace(true);
309  lm.minimize(w);
310 
312 }
313 
314 
315 //: optimize orientation and position for a perspective camera
318  const std::vector<vgl_homg_point_3d<double> >& world_points,
319  const std::vector<vgl_point_2d<double> >& image_points )
320 {
323  const vgl_rotation_3d<double>& R = camera.get_rotation();
324 
325  // compute the Rodrigues vector from the rotation
326  vnl_double_3 w = R.as_rodrigues();
327 
328  vpgl_orientation_position_lsqr lsqr_func(K,world_points,image_points);
329  vnl_levenberg_marquardt lm(lsqr_func);
330  vnl_vector<double> params(6);
331  params[0]=w[0]; params[1]=w[1]; params[2]=w[2];
332  params[3]=c.x(); params[4]=c.y(); params[5]=c.z();
333  //lm.set_trace(true);
334  lm.minimize(params);
335  vnl_double_3 w_min(params[0],params[1],params[2]);
336  vgl_homg_point_3d<double> c_min(params[3], params[4], params[5]);
337 
339 }
340 
341 // optimize orientation, position, and focal length
344  const std::vector<vgl_homg_point_3d<double> >& world_points,
345  const std::vector<vgl_point_2d<double> >& image_points,
346  const double xtol, const unsigned nevals)
347 {
350  const vgl_rotation_3d<double>& R = camera.get_rotation();
352 
353  vpgl_orientation_position_focal_lsqr lsqr_func(K, world_points,image_points);
354  vnl_levenberg_marquardt lm(lsqr_func);
355 
356  vnl_vector<double> params(8);
357  params[0] = q.x(); params[1] = q.y(); params[2] = q.z(); params[3] = q.r();
358  params[4]=t.x(); params[5]=t.y(); params[6]=t.z();
359  params[7]=K.focal_length();
360 
361  // lm.set_trace(true);
362  lm.set_x_tolerance(xtol);
363  lm.set_f_tolerance(1e-2);
364  lm.set_max_function_evals(nevals);
365  lm.minimize(params);
366 
367  vnl_quaternion<double> q_min(params[0], params[1], params[2], params[3]);
368  vgl_vector_3d<double> t_min(params[4], params[5], params[6]);
369  double f_min = params[7];
371  K_min.set_focal_length(f_min);
372  return vpgl_perspective_camera<double>(K_min, vgl_rotation_3d<double>(q_min), t_min);
373 }
374 
375 // optimize all the parameters except internal skew
378  const std::vector<vgl_homg_point_3d<double> >& world_points,
379  const std::vector<vgl_point_2d<double> >& image_points,
380  const double xtol, const unsigned nevals)
381 {
384  const vgl_rotation_3d<double>& R = camera.get_rotation();
385  vnl_double_3 w = R.as_rodrigues();
386 
387  vnl_double_3x3 kk = K.get_matrix();
388  vpgl_orientation_position_calibration_lsqr lsqr_func(world_points,image_points);
389  vnl_levenberg_marquardt lm(lsqr_func);
390  vnl_vector<double> params(10);
391  params[0]=w[0]; params[1]=w[1]; params[2]=w[2];
392  params[3]=c.x(); params[4]=c.y(); params[5]=c.z();
393  params[6]=kk[0][0]; params[7]=kk[0][2];
394  params[8]=kk[1][1]; params[9]=kk[1][2];
395  // lm.set_trace(true);
396  lm.set_x_tolerance(xtol);
397  lm.set_max_function_evals(nevals);
398  lm.minimize(params);
399  vnl_double_3 w_min(params[0],params[1],params[2]);
400  vgl_homg_point_3d<double> c_min(params[3], params[4], params[5]);
401  vnl_double_3x3 kk_min;
402  kk_min.fill(0); kk_min[2][2]=1.0;
403  kk_min[0][0]=params[6]; kk_min[0][2]=params[7];
404  kk_min[1][1]=params[8]; kk_min[1][2]=params[9];
405  vpgl_calibration_matrix<double> K_min(kk_min);
406  return vpgl_perspective_camera<double>(K_min, c_min, vgl_rotation_3d<double>(w_min));
407 }
void set_f_tolerance(double v)
vnl_matrix_fixed< T, 3, 3 > as_matrix() const
void f(vnl_vector< double > const &x, vnl_vector< double > &fx) override
The main function.
std::vector< vgl_point_2d< double > > image_points_
The corresponding points in the image.
std::vector< vgl_point_2d< double > > image_points_
The corresponding points in the image.
vpgl_calibration_matrix< double > K_
The fixed internal camera calibration.
void gradf(vnl_vector< double > const &x, vnl_matrix< double > &jacobian) override
Gradients of the cost-function w.r.t. to the 7 free parameters of x.
std::vector< vgl_point_2d< double > > image_points_
The corresponding points in the image.
static vpgl_perspective_camera< double > opt_orient_pos_f(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 focal length for a perspective camera.
this class optimizes the rotation/translation of a perspective camera given an initial estimate and a...
vpgl_orientation_lsqr(const vpgl_calibration_matrix< double > &K, const vgl_point_3d< double > &c, const std::vector< vgl_homg_point_3d< double > > &world_points, std::vector< vgl_point_2d< double > > image_points)
Constructor.
size_t size() const
vnl_vector_fixed< T, 3 > as_rodrigues() const
std::vector< vgl_point_2d< double > > image_points_
The corresponding points in the image.
vgl_point_3d< double > c_
The fixed camera center.
static vpgl_perspective_camera< double > opt_orient(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 for a perspective camera.
vpgl_calibration_matrix< double > K_init_
The initial calibration matrix.
this class optimizes the rotation of a perspective camera given an initial estimate and a known inter...
std::vector< vgl_homg_point_3d< double > > world_points_
The known points in the world.
vnl_quaternion< T > as_quaternion() const
std::vector< vgl_homg_point_3d< double > > world_points_
The known points in the world.
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.
const vgl_rotation_3d< T > & get_rotation() const
vpgl_calibration_matrix< double > K_
The fixed internal camera calibration.
virtual void trace(int iteration, vnl_vector< double > const &x, vnl_vector< double > const &fx)
T y() const
Methods for projecting geometric structures onto the image.
std::vector< vgl_homg_point_3d< double > > world_points_
The known points in the world.
vnl_matrix_fixed< T, 3, 3 > get_matrix() const
Get the calibration matrix.
void set_max_function_evals(int v)
const vgl_point_3d< T > & get_camera_center() const
vnl_matrix_fixed & fill(T)
bool vnl_rotation_matrix(double const x[3], double **R)
void f(vnl_vector< double > const &x, vnl_vector< double > &fx) override
The main function.
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.
T x() const
T z() const
void f(vnl_vector< double > const &x, vnl_vector< double > &fx) override
The main function.
Type & x()
This class implements the perspective camera class as described in Hartley & Zisserman as a finite ca...
std::vector< vgl_homg_point_3d< double > > world_points_
The known points in the world.
void f(vnl_vector< double > const &x, vnl_vector< double > &fx) override
The main function.
this class optimizes the rotation/translation/focal length of a perspective camera given an initial e...
vpgl_orientation_position_focal_lsqr(const vpgl_calibration_matrix< double > &K_init, const std::vector< vgl_homg_point_3d< double > > &world_points, std::vector< vgl_point_2d< double > > image_points)
Constructor.
vpgl_orientation_position_lsqr(const vpgl_calibration_matrix< double > &K, const std::vector< vgl_homg_point_3d< double > > &world_points, std::vector< vgl_point_2d< double > > image_points)
Constructor.
void set_focal_length(T new_focal_length)
Getters and setters for all of the parameters.
bool minimize(vnl_vector< double > &x)
vgl_vector_3d< T > get_translation() const
this class optimizes the rotation/translation/calibration of a perspective camera given an initial es...
Type & y()
void set_x_tolerance(double v)
vpgl_orientation_position_calibration_lsqr(const std::vector< vgl_homg_point_3d< double > > &world_points, std::vector< vgl_point_2d< double > > image_points)
Constructor.