00001
00002 #include "vpgl_bundle_adjust.h"
00003
00004
00005
00006
00007 #include <vnl/algo/vnl_sparse_lm.h>
00008 #include <vnl/vnl_double_3.h>
00009
00010 #include <vgl/vgl_plane_3d.h>
00011 #include <vpgl/algo/vpgl_ba_fixed_k_lsqr.h>
00012 #include <vpgl/algo/vpgl_ba_shared_k_lsqr.h>
00013 #include <vgl/algo/vgl_rotation_3d.h>
00014
00015 #include <vcl_fstream.h>
00016 #include <vcl_algorithm.h>
00017
00018
00019 vpgl_bundle_adjust::vpgl_bundle_adjust()
00020 : ba_func_(NULL),
00021 use_m_estimator_(false),
00022 m_estimator_scale_(1.0),
00023 use_gradient_(true),
00024 self_calibrate_(false),
00025 normalize_data_(true),
00026 verbose_(false),
00027 max_iterations_(1000),
00028 x_tol_(1e-8),
00029 g_tol_(1e-8),
00030 epsilon_(1e-3),
00031 start_error_(0.0),
00032 end_error_(0.0)
00033 {
00034 }
00035
00036 vpgl_bundle_adjust::~vpgl_bundle_adjust()
00037 {
00038 delete ba_func_;
00039 }
00040
00041
00042
00043 void
00044 vpgl_bundle_adjust::normalize_points(vcl_vector<vgl_point_2d<double> >& image_points,
00045 double& nx, double& ny, double& ns)
00046 {
00047 nx = ny = ns = 0.0;
00048 for (unsigned int i=0; i<image_points.size(); ++i)
00049 {
00050 double x = image_points[i].x();
00051 double y = image_points[i].y();
00052 nx += x;
00053 ny += y;
00054 ns += x*x + y*y;
00055 }
00056 nx /= image_points.size();
00057 ny /= image_points.size();
00058 ns /= image_points.size();
00059 ns -= nx*nx + ny*ny;
00060 ns /= 2;
00061 ns = vcl_sqrt(ns);
00062 for (unsigned int i=0; i<image_points.size(); ++i)
00063 {
00064 image_points[i].x() -= nx;
00065 image_points[i].y() -= ny;
00066 image_points[i].x() /= ns;
00067 image_points[i].y() /= ns;
00068 }
00069 }
00070
00071
00072
00073 void
00074 vpgl_bundle_adjust::
00075 reflect_points(const vgl_plane_3d<double>& plane,
00076 vcl_vector<vgl_point_3d<double> >& points)
00077 {
00078 vgl_h_matrix_3d<double> H;
00079 H.set_reflection_plane(plane);
00080 for (unsigned int i=0; i<points.size(); ++i)
00081 {
00082 points[i] = H * vgl_homg_point_3d<double>(points[i]);
00083 }
00084 }
00085
00086
00087
00088 void
00089 vpgl_bundle_adjust::
00090 rotate_cameras(const vgl_vector_3d<double>& axis,
00091 vcl_vector<vpgl_perspective_camera<double> >& cameras)
00092 {
00093 vnl_double_3 r(axis.x(), axis.y(), axis.z());
00094 r.normalize();
00095 r *= vnl_math::pi;
00096 vgl_rotation_3d<double> R(r);
00097 vgl_rotation_3d<double> R2(0.0, 0.0, vnl_math::pi);
00098 for (unsigned int j=0; j<cameras.size(); ++j)
00099 {
00100 vpgl_perspective_camera<double>& c = cameras[j];
00101 c.set_camera_center(R*c.get_camera_center());
00102 c.set_rotation(R2*c.get_rotation()*R);
00103 }
00104 }
00105
00106
00107
00108
00109
00110
00111
00112 void
00113 vpgl_bundle_adjust::
00114 depth_reverse(vcl_vector<vpgl_perspective_camera<double> >& cameras,
00115 vcl_vector<vgl_point_3d<double> >& points)
00116 {
00117 vnl_double_3 pc(0.0,0.0,0.0), cc(0.0,0.0,0.0);
00118
00119 for (unsigned int i=0; i<points.size(); ++i)
00120 {
00121 pc += vnl_double_3(points[i].x(), points[i].y(), points[i].z());
00122 }
00123 pc /= points.size();
00124 vgl_point_3d<double> point_center(pc[0],pc[1],pc[2]);
00125
00126
00127 for (unsigned int j=0; j<cameras.size(); ++j)
00128 {
00129 vgl_point_3d<double> c = cameras[j].get_camera_center();
00130 cc += vnl_double_3(c.x(), c.y(), c.z());
00131 }
00132 cc /= cameras.size();
00133 vgl_point_3d<double> camera_center(cc[0],cc[1],cc[2]);
00134
00135
00136 vgl_vector_3d<double> axis(camera_center-point_center);
00137 normalize(axis);
00138 vgl_plane_3d<double> reflect_plane(axis, point_center);
00139
00140 reflect_points(reflect_plane,points);
00141 rotate_cameras(axis, cameras);
00142 }
00143
00144
00145
00146 bool
00147 vpgl_bundle_adjust::optimize(vcl_vector<vpgl_perspective_camera<double> >& cameras,
00148 vcl_vector<vgl_point_3d<double> >& world_points,
00149 const vcl_vector<vgl_point_2d<double> >& image_points,
00150 const vcl_vector<vcl_vector<bool> >& mask)
00151 {
00152 delete ba_func_;
00153
00154 double nx=0.0, ny=0.0, ns=1.0;
00155 vcl_vector<vgl_point_2d<double> > norm_image_points(image_points);
00156 if (normalize_data_)
00157 normalize_points(norm_image_points,nx,ny,ns);
00158
00159
00160 if (self_calibrate_)
00161 {
00162
00163 vpgl_ba_shared_k_lsqr::create_param_vector(cameras,a_,c_);
00164 c_[0] /= ns;
00165 b_ = vpgl_ba_shared_k_lsqr::create_param_vector(world_points);
00166
00167 vnl_vector<double> K_vals(5,0.0);
00168 for (unsigned int i=0; i<cameras.size(); ++i){
00169 const vpgl_calibration_matrix<double>& Ki = cameras[i].get_calibration();
00170 K_vals[0] += Ki.focal_length()*Ki.x_scale();
00171 K_vals[1] += Ki.y_scale() / Ki.x_scale();
00172 K_vals[2] += Ki.principal_point().x();
00173 K_vals[3] += Ki.principal_point().y();
00174 K_vals[4] += Ki.skew();
00175 }
00176 K_vals /= cameras.size();
00177 vpgl_calibration_matrix<double> K(K_vals[0]/ns,
00178 vgl_point_2d<double>((K_vals[2]-nx)/ns,(K_vals[3]-ny)/ns),
00179 1.0,
00180 K_vals[1],
00181 K_vals[4]);
00182 ba_func_ = new vpgl_ba_shared_k_lsqr(K,norm_image_points,mask);
00183 }
00184 else
00185 {
00186
00187 vcl_vector<vpgl_calibration_matrix<double> > K;
00188 a_ = vpgl_ba_fixed_k_lsqr::create_param_vector(cameras);
00189 b_ = vpgl_ba_fixed_k_lsqr::create_param_vector(world_points);
00190 for (unsigned int i=0; i<cameras.size(); ++i){
00191 vpgl_calibration_matrix<double> Ktmp = cameras[i].get_calibration();
00192 if (normalize_data_)
00193 {
00194 Ktmp.set_focal_length(Ktmp.focal_length()/ns);
00195 vgl_point_2d<double> pp = Ktmp.principal_point();
00196 pp.x() = (pp.x()-nx)/ns;
00197 pp.y() = (pp.y()-ny)/ns;
00198 Ktmp.set_principal_point(pp);
00199 }
00200 K.push_back(Ktmp);
00201 }
00202 ba_func_ = new vpgl_ba_fixed_k_lsqr(K,norm_image_points,mask);
00203 }
00204
00205
00206 ba_func_->set_residual_scale(m_estimator_scale_/ns);
00207
00208
00209 vnl_sparse_lm lm(*ba_func_);
00210 lm.set_trace(true);
00211 lm.set_verbose(verbose_);
00212
00213 lm.set_max_function_evals(max_iterations_);
00214 lm.set_x_tolerance(x_tol_);
00215 lm.set_g_tolerance(g_tol_);
00216 lm.set_epsilon_function(epsilon_);
00217 if (!lm.minimize(a_,b_,c_,use_gradient_,use_m_estimator_) &&
00218 lm.get_num_iterations() < int(max_iterations_))
00219 {
00220 return false;
00221 }
00222
00223 if (use_m_estimator_)
00224 {
00225 weights_ = vcl_vector<double>(lm.get_weights().begin(), lm.get_weights().end());
00226 }
00227 else
00228 {
00229 weights_.clear();
00230 weights_.resize(image_points.size(),1.0);
00231 }
00232
00233 if (self_calibrate_ && verbose_)
00234 vcl_cout << "final focal length = "<<c_[0]*ns<<vcl_endl;
00235
00236 start_error_ = lm.get_start_error()*ns;
00237 end_error_ = lm.get_end_error()*ns;
00238 num_iterations_ = lm.get_num_iterations();
00239
00240
00241 for (unsigned int i=0; i<cameras.size(); ++i)
00242 {
00243 cameras[i] = ba_func_->param_to_cam(i,a_,c_);
00244 if (normalize_data_)
00245 {
00246
00247 vpgl_calibration_matrix<double> K = cameras[i].get_calibration();
00248 K.set_focal_length(K.focal_length()*ns);
00249 vgl_point_2d<double> pp = K.principal_point();
00250 pp.x() = ns*pp.x() + nx;
00251 pp.y() = ns*pp.y() + ny;
00252 K.set_principal_point(pp);
00253 cameras[i].set_calibration(K);
00254 }
00255 }
00256
00257 for (unsigned int j=0; j<world_points.size(); ++j)
00258 world_points[j] = ba_func_->param_to_point(j,b_,c_);
00259
00260 return true;
00261 }
00262
00263
00264
00265 void
00266 vpgl_bundle_adjust::write_vrml(const vcl_string& filename,
00267 const vcl_vector<vpgl_perspective_camera<double> >& cameras,
00268 const vcl_vector<vgl_point_3d<double> >& world_points)
00269 {
00270 vcl_ofstream os(filename.c_str());
00271 os << "#VRML V2.0 utf8\n\n";
00272
00273
00274 vgl_rotation_3d<double> rot180x(vnl_math::pi, 0.0, 0.0);
00275
00276 for (unsigned int i=0; i<cameras.size(); ++i){
00277 vnl_double_3x3 K = cameras[i].get_calibration().get_matrix();
00278
00279 vgl_rotation_3d<double> R = (rot180x*cameras[i].get_rotation()).inverse();
00280 vgl_point_3d<double> ctr = cameras[i].get_camera_center();
00281 double fov = 2.0*vcl_max(vcl_atan(K[1][2]/K[1][1]), vcl_atan(K[0][2]/K[0][0]));
00282 os << "Viewpoint {\n"
00283 << " position "<< ctr.x() << ' ' << ctr.y() << ' ' << ctr.z() << '\n'
00284 << " orientation "<< R.axis() << ' '<< R.angle() << '\n'
00285 << " fieldOfView "<< fov << '\n'
00286 << " description \"Camera" << i << "\"\n}\n";
00287 }
00288
00289 os << "Shape {\n appearance NULL\n geometry PointSet {\n"
00290 << " color Color { color [1 0 0] }\n coord Coordinate{\n"
00291 << " point[\n";
00292
00293 for (unsigned int j=0; j<world_points.size(); ++j){
00294 os << world_points[j].x() << ' '
00295 << world_points[j].y() << ' '
00296 << world_points[j].z() << '\n';
00297 }
00298 os << " ]\n }\n }\n}\n";
00299
00300 os.close();
00301 }
00302