core/vpgl/algo/vpgl_optimize_camera.cxx
Go to the documentation of this file.
00001 // This is core/vpgl/algo/vpgl_optimize_camera.cxx
00002 #include "vpgl_optimize_camera.h"
00003 //:
00004 // \file
00005 #include <vnl/vnl_rotation_matrix.h>
00006 #include <vnl/vnl_double_3.h>
00007 #include <vnl/vnl_double_3x3.h>
00008 #include <vnl/algo/vnl_levenberg_marquardt.h>
00009 #include <vgl/vgl_homg_point_2d.h>
00010 #if 0
00011 #include <vgl/algo/vgl_h_matrix_3d.h>
00012 #endif
00013 #include <vgl/algo/vgl_rotation_3d.h>
00014 #include <vcl_cassert.h>
00015 
00016 //: Constructor
00017 vpgl_orientation_lsqr::
00018   vpgl_orientation_lsqr(const vpgl_calibration_matrix<double>& K,
00019                         const vgl_point_3d<double>& c,
00020                         const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00021                         const vcl_vector<vgl_point_2d<double> >& image_points )
00022  : vnl_least_squares_function(3,2*world_points.size(),no_gradient),
00023    K_(K),
00024    c_(c),
00025    world_points_(world_points),
00026    image_points_(image_points)
00027 {
00028   assert(world_points_.size() == image_points_.size());
00029 }
00030 
00031 
00032 //: The main function.
00033 //  Given the parameter vector x, compute the vector of residuals fx.
00034 //  Fx has been sized appropriately before the call.
00035 //  The parameters in x are the {wx, wy, wz}
00036 //  where w is the Rodrigues vector of the rotation.
00037 void
00038 vpgl_orientation_lsqr::f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00039 {
00040   vpgl_perspective_camera<double> cam(K_,c_,vgl_rotation_3d<double>(x));
00041   for (unsigned int i=0; i<world_points_.size(); ++i)
00042   {
00043     vgl_homg_point_2d<double> proj = cam(world_points_[i]);
00044     fx[2*i]   = image_points_[i].x() - proj.x()/proj.w();
00045     fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
00046   }
00047 }
00048 
00049 //==============================================================================
00050 
00051 //: Constructor
00052 vpgl_orientation_position_lsqr::
00053   vpgl_orientation_position_lsqr(const vpgl_calibration_matrix<double>& K,
00054                                  const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00055                                  const vcl_vector<vgl_point_2d<double> >& image_points )
00056  : vnl_least_squares_function(6,2*world_points.size(),no_gradient),
00057    K_(K),
00058    world_points_(world_points),
00059    image_points_(image_points)
00060 {
00061   assert(world_points_.size() == image_points_.size());
00062 }
00063 
00064 
00065 //: The main function.
00066 //  Given the parameter vector x, compute the vector of residuals fx.
00067 //  Fx has been sized appropriately before the call.
00068 //  The parameters in x are really two three component vectors {wx, wy, wz, tx, ty, tz}
00069 //  where w is the Rodrigues vector of the rotation and t is the translation.
00070 void
00071 vpgl_orientation_position_lsqr::f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00072 {
00073   assert(x.size() == 6);
00074   vnl_double_3 w(x[0], x[1], x[2]);
00075   vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
00076   vpgl_perspective_camera<double> cam(K_,t,vgl_rotation_3d<double>(w));
00077   for (unsigned int i=0; i<world_points_.size(); ++i)
00078   {
00079     vgl_homg_point_2d<double> proj = cam(world_points_[i]);
00080     fx[2*i]   = image_points_[i].x() - proj.x()/proj.w();
00081     fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
00082   }
00083 }
00084 
00085 #if 0
00086 //: Called after each LM iteration to print debugging etc.
00087 void
00088 vpgl_orientation_position_lsqr::trace(int iteration,
00089                                       vnl_vector<double> const& x,
00090                                       vnl_vector<double> const& fx)
00091 {
00092   assert(x.size() == 6);
00093   vnl_double_3 w(x[0], x[1], x[2]);
00094   vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
00095   vgl_h_matrix_3d<double> R(vnl_rotation_matrix(w), vnl_double_3(0.0,0.0,0.0));
00096   vpgl_perspective_camera<double> cam(K_,t,R);
00097 #ifdef DEBUG
00098   vcl_cout << "camera =\n" << cam.get_matrix() << vcl_endl;
00099 #endif
00100 }
00101 #endif
00102 
00103 //==============================================================================
00104 
00105 //: Constructor
00106 vpgl_orientation_position_calibration_lsqr::
00107 vpgl_orientation_position_calibration_lsqr(const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00108                                            const vcl_vector<vgl_point_2d<double> >& image_points )
00109  : vnl_least_squares_function(10,2*world_points.size(),no_gradient),
00110    world_points_(world_points),
00111    image_points_(image_points)
00112 {
00113   assert(world_points_.size() == image_points_.size());
00114 }
00115 
00116 
00117 //: The main function.
00118 //  Given the parameter vector x, compute the vector of residuals fx.
00119 //  Fx has been sized appropriately before the call.
00120 //  The parameters in x are really two three component vectors {wx, wy, wz, tx, ty, tz}
00121 //  where w is the Rodrigues vector of the rotation and t is the translation.
00122 void
00123 vpgl_orientation_position_calibration_lsqr::f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00124 {
00125   assert(x.size() == 10);
00126   vnl_double_3 w(x[0], x[1], x[2]);
00127   vgl_rotation_3d<double> R(w);
00128   vgl_homg_point_3d<double> t(x[3], x[4], x[5]);
00129   vnl_double_3x3 kk;
00130   kk.fill(0);
00131   kk[0][0]=x[6]; kk[0][2]=x[7];
00132   kk[1][1]=x[8]; kk[1][2]=x[9]; kk[2][2]=1.0;
00133 
00134   // Check that it is a valid calibration matrix.
00135   if ( !(kk[0][0]>0) || !(kk[1][1]>0) ) {
00136     for (unsigned int i=0; i<world_points_.size(); ++i) {
00137       fx[2*i]   = 100000000;
00138       fx[2*i+1] = 100000000;
00139     }
00140     return;
00141   }
00142 
00143   vpgl_calibration_matrix<double> K(kk);
00144   vpgl_perspective_camera<double> cam(K, t, R);
00145   for (unsigned int i=0; i<world_points_.size(); ++i)
00146   {
00147     vgl_homg_point_2d<double> proj = cam(world_points_[i]);
00148     fx[2*i]   = image_points_[i].x() - proj.x()/proj.w();
00149     fx[2*i+1] = image_points_[i].y() - proj.y()/proj.w();
00150   }
00151 }
00152 
00153 //===============================================================
00154 // Static functions for vpgl_optimize_camera
00155 //===============================================================
00156 
00157 
00158 //: optimize orientation for a perspective camera
00159 vpgl_perspective_camera<double>
00160 vpgl_optimize_camera::opt_orient(const vpgl_perspective_camera<double>& camera,
00161                                  const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00162                                  const vcl_vector<vgl_point_2d<double> >& image_points )
00163 {
00164   const vpgl_calibration_matrix<double>& K = camera.get_calibration();
00165   const vgl_point_3d<double>& c = camera.get_camera_center();
00166   const vgl_rotation_3d<double>& R = camera.get_rotation();
00167 
00168   // compute the Rodrigues vector from the rotation
00169   vnl_double_3 w = R.as_rodrigues();
00170 
00171   vpgl_orientation_lsqr lsqr_func(K,c,world_points,image_points);
00172   vnl_levenberg_marquardt lm(lsqr_func);
00173   lm.set_trace(true);
00174   lm.minimize(w);
00175 
00176   return vpgl_perspective_camera<double>(K, c, vgl_rotation_3d<double>(w) );
00177 }
00178 
00179 
00180 //: optimize orientation and position for a perspective camera
00181 vpgl_perspective_camera<double>
00182 vpgl_optimize_camera::opt_orient_pos(const vpgl_perspective_camera<double>& camera,
00183                                      const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00184                                      const vcl_vector<vgl_point_2d<double> >& image_points )
00185 {
00186   const vpgl_calibration_matrix<double>& K = camera.get_calibration();
00187   vgl_point_3d<double> c = camera.get_camera_center();
00188   const vgl_rotation_3d<double>& R = camera.get_rotation();
00189 
00190   // compute the Rodrigues vector from the rotation
00191   vnl_double_3 w = R.as_rodrigues();
00192 
00193   vpgl_orientation_position_lsqr lsqr_func(K,world_points,image_points);
00194   vnl_levenberg_marquardt lm(lsqr_func);
00195   vnl_vector<double> params(6);
00196   params[0]=w[0];  params[1]=w[1];  params[2]=w[2];
00197   params[3]=c.x();  params[4]=c.y();  params[5]=c.z();
00198   lm.set_trace(true);
00199   lm.minimize(params);
00200   vnl_double_3 w_min(params[0],params[1],params[2]);
00201   vgl_homg_point_3d<double> c_min(params[3], params[4], params[5]);
00202 
00203   return vpgl_perspective_camera<double>(K, c_min, vgl_rotation_3d<double>(w_min) );
00204 }
00205 // optimize all the parameters except internal skew
00206 vpgl_perspective_camera<double>
00207 vpgl_optimize_camera::opt_orient_pos_cal(const vpgl_perspective_camera<double>& camera,
00208                                          const vcl_vector<vgl_homg_point_3d<double> >& world_points,
00209                                          const vcl_vector<vgl_point_2d<double> >& image_points,
00210                                          const double xtol, const unsigned nevals)
00211 {
00212   const vpgl_calibration_matrix<double>& K = camera.get_calibration();
00213   vgl_point_3d<double> c = camera.get_camera_center();
00214   const vgl_rotation_3d<double>& R = camera.get_rotation();
00215   vnl_double_3 w = R.as_rodrigues();
00216 
00217   vnl_double_3x3 kk = K.get_matrix();
00218   vpgl_orientation_position_calibration_lsqr lsqr_func(world_points,image_points);
00219   vnl_levenberg_marquardt lm(lsqr_func);
00220   vnl_vector<double> params(10);
00221   params[0]=w[0];  params[1]=w[1];  params[2]=w[2];
00222   params[3]=c.x();  params[4]=c.y();  params[5]=c.z();
00223   params[6]=kk[0][0]; params[7]=kk[0][2];
00224   params[8]=kk[1][1]; params[9]=kk[1][2];
00225   //  lm.set_trace(true);
00226   lm.set_x_tolerance(xtol);
00227   lm.set_max_function_evals(nevals);
00228   lm.minimize(params);
00229   vnl_double_3 w_min(params[0],params[1],params[2]);
00230   vgl_homg_point_3d<double> c_min(params[3], params[4], params[5]);
00231   vnl_double_3x3 kk_min;
00232   kk_min.fill(0); kk_min[2][2]=1.0;
00233    kk_min[0][0]=params[6];  kk_min[0][2]=params[7];
00234    kk_min[1][1]=params[8]; kk_min[1][2]=params[9];
00235    vpgl_calibration_matrix<double> K_min(kk_min);
00236   return vpgl_perspective_camera<double>(K_min, c_min, vgl_rotation_3d<double>(w_min));
00237 }