00001
00002 #include "vpgl_bundle_adjust.h"
00003
00004
00005
00006 #include <vnl/vnl_vector_ref.h>
00007 #include <vnl/vnl_double_3.h>
00008 #include <vnl/algo/vnl_sparse_lm.h>
00009 #include <vgl/algo/vgl_rotation_3d.h>
00010 #include <vgl/vgl_point_2d.h>
00011 #include <vgl/vgl_point_3d.h>
00012
00013 #include <vcl_iostream.h>
00014 #include <vcl_fstream.h>
00015 #include <vcl_algorithm.h>
00016 #include <vcl_cassert.h>
00017
00018
00019
00020 vpgl_bundle_adj_lsqr::
00021 vpgl_bundle_adj_lsqr(const vcl_vector<vpgl_calibration_matrix<double> >& K,
00022 const vcl_vector<vgl_point_2d<double> >& image_points,
00023 const vcl_vector<vcl_vector<bool> >& mask,
00024 bool use_confidence_weights)
00025 : vnl_sparse_lst_sqr_function(K.size(),6,mask[0].size(),3,mask,2,use_gradient),
00026 K_(K),
00027 image_points_(image_points),
00028 use_covars_(false),
00029 use_weights_(use_confidence_weights),
00030 weights_(image_points.size(),1.0),
00031 iteration_count_(0)
00032 {
00033 for (unsigned int i=0; i<K_.size(); ++i)
00034 Km_.push_back(K_[i].get_matrix());
00035 }
00036
00037
00038
00039
00040
00041 vpgl_bundle_adj_lsqr::
00042 vpgl_bundle_adj_lsqr(const vcl_vector<vpgl_calibration_matrix<double> >& K,
00043 const vcl_vector<vgl_point_2d<double> >& image_points,
00044 const vcl_vector<vnl_matrix<double> >& inv_covars,
00045 const vcl_vector<vcl_vector<bool> >& mask,
00046 bool use_confidence_weights)
00047 : vnl_sparse_lst_sqr_function(K.size(),6,mask[0].size(),3,mask,2,use_gradient),
00048 K_(K),
00049 image_points_(image_points),
00050 use_covars_(true),
00051 use_weights_(use_confidence_weights),
00052 weights_(image_points.size(),1.0),
00053 iteration_count_(0)
00054 {
00055 for (unsigned int i=0; i<K_.size(); ++i)
00056 Km_.push_back(K_[i].get_matrix());
00057
00058 assert(image_points.size() == inv_covars.size());
00059 vnl_matrix<double> U(2,2,0.0);
00060 for (unsigned i=0; i<inv_covars.size(); ++i)
00061 {
00062 const vnl_matrix<double>& S = inv_covars[i];
00063 if (S(0,0) > 0.0) {
00064 U(0,0) = vcl_sqrt(S(0,0));
00065 U(0,1) = S(0,1)/U(0,0);
00066 double U11 = S(1,1)-S(0,1)*S(0,1)/S(0,0);
00067 U(1,1) = (U11>0.0)?vcl_sqrt(U11):0.0;
00068 }
00069 else if (S(1,1) > 0.0) {
00070 assert(S(0,1) == 0.0);
00071 U(0,0) = 0.0;
00072 U(0,1) = 0.0;
00073 U(1,1) = vcl_sqrt(S(1,1));
00074 }
00075 else {
00076 vcl_cout << "warning: not positive definite"<<vcl_endl;
00077 U.fill(0.0);
00078 }
00079 factored_inv_covars_.push_back(U);
00080 }
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 void
00092 vpgl_bundle_adj_lsqr::f(vnl_vector<double> const& a,
00093 vnl_vector<double> const& b,
00094 vnl_vector<double>& e)
00095 {
00096 typedef vnl_crs_index::sparse_vector::iterator sv_itr;
00097 for (unsigned int i=0; i<number_of_a(); ++i)
00098 {
00099
00100 vnl_double_3x4 Pi = param_to_cam_matrix(i,a);
00101
00102 vnl_crs_index::sparse_vector row = residual_indices_.sparse_row(i);
00103 for (sv_itr r_itr=row.begin(); r_itr!=row.end(); ++r_itr)
00104 {
00105 unsigned int j = r_itr->second;
00106 unsigned int k = r_itr->first;
00107
00108
00109 const double * bj = b.data_block()+index_b(j);
00110 vnl_vector_fixed<double,4> Xj(bj[0], bj[1], bj[2], 1.0);
00111
00112
00113 vnl_vector_fixed<double,3> xij = Pi*Xj;
00114
00115 double* eij = e.data_block()+index_e(k);
00116 eij[0] = xij[0]/xij[2] - image_points_[k].x();
00117 eij[1] = xij[1]/xij[2] - image_points_[k].y();
00118 if (use_covars_){
00119
00120 vnl_matrix<double>& Sij = factored_inv_covars_[k];
00121 eij[0] *= Sij(0,0);
00122 eij[0] += eij[1]*Sij(0,1);
00123 eij[1] *= Sij(1,1);
00124 }
00125 }
00126 }
00127
00128 if (use_weights_){
00129 vnl_vector<double> unweighted(e);
00130 for (unsigned int k=0; k<weights_.size(); ++k){
00131 e[2*k] *= weights_[k];
00132 e[2*k+1] *= weights_[k];
00133 }
00134
00135 double avg_error = e.rms();
00136 for (unsigned int k=0; k<weights_.size(); ++k){
00137 vnl_vector_ref<double> uw(2,unweighted.data_block()+2*k);
00138 double update = 2.0*avg_error/uw.rms();
00139 if (update < 1.0)
00140 weights_[k] = vcl_min(weights_[k], update);
00141 else
00142 weights_[k] = 1.0;
00143
00144 e[2*k] = unweighted[2*k] * weights_[k];
00145 e[2*k+1] = unweighted[2*k+1] * weights_[k];
00146 }
00147 vcl_cout << vcl_endl;
00148 }
00149 }
00150
00151
00152
00153
00154
00155 void
00156 vpgl_bundle_adj_lsqr::fij(int i, int j, vnl_vector<double> const& ai,
00157 vnl_vector<double> const& bj, vnl_vector<double>& fij)
00158 {
00159
00160 vnl_double_3x4 Pi = param_to_cam_matrix(i,ai.data_block());
00161
00162
00163 vnl_vector_fixed<double,4> Xj(bj[0], bj[1], bj[2], 1.0);
00164
00165
00166 vnl_vector_fixed<double,3> xij = Pi*Xj;
00167
00168 int k = residual_indices_(i,j);
00169 fij[0] = xij[0]/xij[2] - image_points_[k].x();
00170 fij[1] = xij[1]/xij[2] - image_points_[k].y();
00171 if (use_covars_){
00172
00173 vnl_matrix<double>& Sij = factored_inv_covars_[k];
00174 fij[0] *= Sij(0,0);
00175 fij[0] += fij[1]*Sij(0,1);
00176 fij[1] *= Sij(1,1);
00177 }
00178 if (use_weights_){
00179 fij[0] *= weights_[k];
00180 fij[1] *= weights_[k];
00181 }
00182 }
00183
00184
00185
00186 void
00187 vpgl_bundle_adj_lsqr::jac_blocks(vnl_vector<double> const& a, vnl_vector<double> const& b,
00188 vcl_vector<vnl_matrix<double> >& A,
00189 vcl_vector<vnl_matrix<double> >& B)
00190 {
00191 typedef vnl_crs_index::sparse_vector::iterator sv_itr;
00192 for (unsigned int i=0; i<number_of_a(); ++i)
00193 {
00194
00195 vnl_double_3x4 Pi = param_to_cam_matrix(i,a);
00196
00197
00198 const vnl_vector_ref<double> ai(number_of_params_a(i),
00199 const_cast<double*>(a.data_block())+index_a(i));
00200
00201 vnl_crs_index::sparse_vector row = residual_indices_.sparse_row(i);
00202 for (sv_itr r_itr=row.begin(); r_itr!=row.end(); ++r_itr)
00203 {
00204 unsigned int j = r_itr->second;
00205 unsigned int k = r_itr->first;
00206
00207 const vnl_vector_ref<double> bj(number_of_params_b(j),
00208 const_cast<double*>(b.data_block())+index_b(j));
00209
00210 jac_Bij(Pi,bj,B[k]);
00211 jac_Aij(Pi,Km_[i],ai,bj,A[k]);
00212 if (use_covars_){
00213 const vnl_matrix<double>& Sij = factored_inv_covars_[k];
00214 A[k] = Sij*A[k];
00215 B[k] = Sij*B[k];
00216 }
00217 if (use_weights_){
00218 A[k] *= weights_[k];
00219 B[k] *= weights_[k];
00220 }
00221 }
00222 }
00223 }
00224
00225
00226
00227 void
00228 vpgl_bundle_adj_lsqr::jac_Aij(vnl_double_3x4 const& Pi,
00229 vnl_double_3x3 const& K,
00230 vnl_vector<double> const& ai,
00231 vnl_vector<double> const& bj,
00232 vnl_matrix<double>& Aij)
00233 {
00234
00235
00236
00237
00238 {
00239 vnl_double_3x4 sPi(Pi);
00240 vnl_double_3x3 M = sPi.extract(3,3);
00241 sPi.set_column(3,-(M*bj));
00242
00243 const vnl_vector_ref<double> t(3,const_cast<double*>(ai.data_block())+3);
00244
00245 vnl_matrix<double> Aij_sub(2,3);
00246 jac_Bij(sPi,t,Aij_sub);
00247 Aij.update(Aij_sub,0,3);
00248 }
00249
00250
00251
00252
00253 {
00254 vnl_double_3 t(bj[0]-ai[3], bj[1]-ai[4], bj[2]-ai[5]);
00255
00256 const double& x = ai[0];
00257 const double& y = ai[1];
00258 const double& z = ai[2];
00259 double x2 = x*x, y2 = y*y, z2 = z*z;
00260 double m2 = x2 + y2 + z2;
00261
00262 if (m2 == 0.0)
00263 {
00264 Aij(0,0) = 0;
00265 Aij(1,0) = -1;
00266 Aij(0,1) = 1;
00267 Aij(1,1) = 0;
00268 Aij(0,2) = 0;
00269 Aij(1,2) = 0;
00270 }
00271 else
00272 {
00273 double m = vcl_sqrt(m2);
00274 double c = vcl_cos(m);
00275 double s = vcl_sin(m);
00276
00277
00278 double ct = (1-c)/m2;
00279 double st = s/m;
00280
00281
00282
00283
00284 double dct = s/m/m2;
00285 double dst = c/m2 - dct;
00286 dct -= 2*(1-c)/(m2*m2);
00287
00288 double utc = t[2]*x*z + t[1]*x*y - t[0]*(y2+z2);
00289 double uts = t[2]*y - t[1]*z;
00290 double vtc = t[0]*x*y + t[2]*y*z - t[1]*(x2+z2);
00291 double vts = t[0]*z - t[2]*x;
00292 double wtc = t[0]*x*z + t[1]*y*z - t[2]*(x2+y2);
00293 double wts = t[1]*x - t[0]*y;
00294
00295
00296
00297 double u = ct*utc + st*uts + t[0];
00298 double v = ct*vtc + st*vts + t[1];
00299 double w = ct*wtc + st*wts + t[2];
00300
00301 double w2 = w*w;
00302
00303 double dw = dct*x*wtc + ct*(t[0]*z - 2*t[2]*x)
00304 + dst*x*wts + st*t[1];
00305 Aij(0,0) = (w*(dct*x*utc + ct*(t[2]*z + t[1]*y)
00306 + dst*x*uts) - u*dw)/w2;
00307 Aij(1,0) = (w*(dct*x*vtc + ct*(t[0]*y - 2*t[1]*x)
00308 + dst*x*vts - st*t[2]) - v*dw)/w2;
00309
00310 dw = dct*y*wtc + ct*(t[1]*z - 2*t[2]*y)
00311 + dst*y*wts - st*t[0];
00312 Aij(0,1) = (w*(dct*y*utc + ct*(t[1]*x - 2*t[0]*y)
00313 + dst*y*uts + st*t[2]) - u*dw)/w2;
00314 Aij(1,1) = (w*(dct*y*vtc + ct*(t[0]*x + t[2]*z)
00315 + dst*y*vts) - v*dw)/w2;
00316
00317 dw = dct*z*wtc + ct*(t[0]*x + t[1]*y)
00318 + dst*z*wts;
00319 Aij(0,2) = (w*(dct*z*utc + ct*(t[2]*x - 2*t[0]*z)
00320 + dst*z*uts - st*t[1]) - u*dw)/w2;
00321 Aij(1,2) = (w*(dct*z*vtc + ct*(t[2]*y - 2*t[1]*z)
00322 + dst*z*vts + st*t[0]) - v*dw)/w2;
00323 }
00324
00325 Aij(0,0) *= K(0,0);
00326 Aij(0,0) += Aij(1,0)*K(0,1);
00327 Aij(1,0) *= K(1,1);
00328 Aij(0,1) *= K(0,0);
00329 Aij(0,1) += Aij(1,1)*K(0,1);
00330 Aij(1,1) *= K(1,1);
00331 Aij(0,2) *= K(0,0);
00332 Aij(0,2) += Aij(1,2)*K(0,1);
00333 Aij(1,2) *= K(1,1);
00334 }
00335 }
00336
00337
00338
00339 void
00340 vpgl_bundle_adj_lsqr::jac_Bij(vnl_double_3x4 const& Pi, vnl_vector<double> const& bj,
00341 vnl_matrix<double>& Bij)
00342 {
00343 double denom = Pi(2,0)*bj[0] + Pi(2,1)*bj[1] + Pi(2,2)*bj[2] + Pi(2,3);
00344 denom *= denom;
00345
00346 double txy = Pi(0,0)*Pi(2,1) - Pi(0,1)*Pi(2,0);
00347 double txz = Pi(0,0)*Pi(2,2) - Pi(0,2)*Pi(2,0);
00348 double tyz = Pi(0,1)*Pi(2,2) - Pi(0,2)*Pi(2,1);
00349 double tx = Pi(0,0)*Pi(2,3) - Pi(0,3)*Pi(2,0);
00350 double ty = Pi(0,1)*Pi(2,3) - Pi(0,3)*Pi(2,1);
00351 double tz = Pi(0,2)*Pi(2,3) - Pi(0,3)*Pi(2,2);
00352
00353 Bij(0,0) = ( txy*bj[1] + txz*bj[2] + tx) / denom;
00354 Bij(0,1) = (-txy*bj[0] + tyz*bj[2] + ty) / denom;
00355 Bij(0,2) = (-txz*bj[0] - tyz*bj[1] + tz) / denom;
00356
00357 txy = Pi(1,0)*Pi(2,1) - Pi(1,1)*Pi(2,0);
00358 txz = Pi(1,0)*Pi(2,2) - Pi(1,2)*Pi(2,0);
00359 tyz = Pi(1,1)*Pi(2,2) - Pi(1,2)*Pi(2,1);
00360 tx = Pi(1,0)*Pi(2,3) - Pi(1,3)*Pi(2,0);
00361 ty = Pi(1,1)*Pi(2,3) - Pi(1,3)*Pi(2,1);
00362 tz = Pi(1,2)*Pi(2,3) - Pi(1,3)*Pi(2,2);
00363
00364 Bij(1,0) = ( txy*bj[1] + txz*bj[2] + tx) / denom;
00365 Bij(1,1) = (-txy*bj[0] + tyz*bj[2] + ty) / denom;
00366 Bij(1,2) = (-txz*bj[0] - tyz*bj[1] + tz) / denom;
00367 }
00368
00369
00370
00371 vnl_matrix_fixed<double,3,3>
00372 vpgl_bundle_adj_lsqr::rod_to_matrix(const double* r) const
00373 {
00374 double x2 = r[0]*r[0], y2 = r[1]*r[1], z2 = r[2]*r[2];
00375 double m = x2 + y2 + z2;
00376 double theta = vcl_sqrt(m);
00377 double s = vcl_sin(theta) / theta;
00378 double c = (1 - vcl_cos(theta)) / m;
00379
00380 vnl_matrix_fixed<double,3,3> R(0.0);
00381 R(0,0) = R(1,1) = R(2,2) = 1.0;
00382 if (m == 0.0)
00383 return R;
00384
00385 R(0,0) -= (y2 + z2) * c;
00386 R(1,1) -= (x2 + z2) * c;
00387 R(2,2) -= (x2 + y2) * c;
00388 R(0,1) = R(1,0) = r[0]*r[1]*c;
00389 R(0,2) = R(2,0) = r[0]*r[2]*c;
00390 R(1,2) = R(2,1) = r[1]*r[2]*c;
00391
00392 double t = r[0]*s;
00393 R(1,2) -= t;
00394 R(2,1) += t;
00395 t = r[1]*s;
00396 R(0,2) += t;
00397 R(2,0) -= t;
00398 t = r[2]*s;
00399 R(0,1) -= t;
00400 R(1,0) += t;
00401
00402 return R;
00403 }
00404
00405
00406
00407 vnl_vector<double>
00408 vpgl_bundle_adj_lsqr::create_param_vector(const vcl_vector<vpgl_perspective_camera<double> >& cameras)
00409 {
00410 vnl_vector<double> a(6*cameras.size(),0.0);
00411 for (unsigned int i=0; i<cameras.size(); ++i)
00412 {
00413 const vpgl_perspective_camera<double>& cam = cameras[i];
00414 const vgl_point_3d<double>& c = cam.get_camera_center();
00415 const vgl_rotation_3d<double>& R = cam.get_rotation();
00416
00417
00418 vnl_vector<double> w = R.as_rodrigues();
00419
00420 double* ai = a.data_block() + i*6;
00421 ai[0]=w[0]; ai[1]=w[1]; ai[2]=w[2];
00422 ai[3]=c.x(); ai[4]=c.y(); ai[5]=c.z();
00423 }
00424 return a;
00425 }
00426
00427
00428
00429 vnl_vector<double>
00430 vpgl_bundle_adj_lsqr::create_param_vector(const vcl_vector<vgl_point_3d<double> >& world_points)
00431 {
00432 vnl_vector<double> b(3*world_points.size(),0.0);
00433 for (unsigned int j=0; j<world_points.size(); ++j){
00434 const vgl_point_3d<double>& point = world_points[j];
00435 double* bj = b.data_block() + j*3;
00436 bj[0]=point.x(); bj[1]=point.y(); bj[2]=point.z();
00437 }
00438 return b;
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 vpgl_bundle_adjust::vpgl_bundle_adjust()
00448 : ba_func_(NULL),
00449 use_weights_(false),
00450 use_gradient_(true),
00451 start_error_(0.0),
00452 end_error_(0.0)
00453 {
00454 }
00455
00456 vpgl_bundle_adjust::~vpgl_bundle_adjust()
00457 {
00458 delete ba_func_;
00459 }
00460
00461
00462 bool
00463 vpgl_bundle_adjust::optimize(vcl_vector<vpgl_perspective_camera<double> >& cameras,
00464 vcl_vector<vgl_point_3d<double> >& world_points,
00465 const vcl_vector<vgl_point_2d<double> >& image_points,
00466 const vcl_vector<vcl_vector<bool> >& mask)
00467 {
00468
00469 vcl_vector<vpgl_calibration_matrix<double> > K;
00470 a_ = vpgl_bundle_adj_lsqr::create_param_vector(cameras);
00471 b_ = vpgl_bundle_adj_lsqr::create_param_vector(world_points);
00472 for (unsigned int i=0; i<cameras.size(); ++i){
00473 K.push_back(cameras[i].get_calibration());
00474 }
00475
00476
00477 delete ba_func_;
00478 ba_func_ = new vpgl_bundle_adj_lsqr(K,image_points,mask,use_weights_);
00479 vnl_sparse_lm lm(*ba_func_);
00480 lm.set_trace(true);
00481 lm.set_verbose(true);
00482 if (!lm.minimize(a_,b_,use_gradient_))
00483 return false;
00484
00485 start_error_ = lm.get_start_error();
00486 end_error_ = lm.get_end_error();
00487 num_iterations_ = lm.get_num_iterations();
00488
00489
00490 for (unsigned int i=0; i<cameras.size(); ++i)
00491 cameras[i] = ba_func_->param_to_cam(i,a_);
00492
00493 for (unsigned int j=0; j<world_points.size(); ++j)
00494 world_points[j] = ba_func_->param_to_point(j,b_);
00495
00496 return true;
00497 }
00498
00499
00500
00501 void
00502 vpgl_bundle_adjust::write_vrml(const vcl_string& filename,
00503 vcl_vector<vpgl_perspective_camera<double> >& cameras,
00504 vcl_vector<vgl_point_3d<double> >& world_points)
00505 {
00506 vcl_ofstream os(filename.c_str());
00507 os << "#VRML V2.0 utf8\n\n";
00508
00509 for (unsigned int i=0; i<cameras.size(); ++i){
00510 vnl_double_3x3 K = cameras[i].get_calibration().get_matrix();
00511
00512 const vgl_rotation_3d<double>& R = cameras[i].get_rotation();
00513
00514
00515 vgl_point_3d<double> ctr = cameras[i].get_camera_center();
00516 double fov = 2.0*vcl_max(vcl_atan(K[1][2]/K[1][1]), vcl_atan(K[0][2]/K[0][0]));
00517 os << "Viewpoint {\n"
00518 << " position "<< ctr.x() << ' ' << ctr.y() << ' ' << ctr.z() << '\n'
00519 << " orientation "<< R.axis() << ' '<< R.angle() << '\n'
00520 << " fieldOfView "<< fov << '\n'
00521 << " description \"Camera" << i << "\"\n}\n";
00522 }
00523
00524 os << "Shape {\n appearance NULL\n geometry PointSet {\n"
00525 << " color Color { color [1 0 0] }\n coord Coordinate{\n"
00526 << " point[\n";
00527
00528 for (unsigned int j=0; j<world_points.size(); ++j){
00529 os << world_points[j].x() << ' '
00530 << world_points[j].y() << ' '
00531 << world_points[j].z() << '\n';
00532 }
00533 os << " ]\n }\n }\n}\n";
00534
00535 os.close();
00536 }
00537