vpgl_bundle_adjust.cxx
Go to the documentation of this file.
1 // This is vpgl/algo/vpgl_bundle_adjust.cxx
2 #include <fstream>
3 #include <algorithm>
4 #include "vpgl_bundle_adjust.h"
5 //:
6 // \file
7 
8 
10 #include <vnl/vnl_double_3.h>
11 
12 #include <vgl/vgl_plane_3d.h>
16 
17 #ifdef _MSC_VER
18 # include <vcl_msvc_warnings.h>
19 #endif
20 
21 
23  : ba_func_(nullptr),
24  use_m_estimator_(false),
25  m_estimator_scale_(1.0),
26  use_gradient_(true),
27  self_calibrate_(false),
28  normalize_data_(true),
29  verbose_(false),
30  max_iterations_(1000),
31  x_tol_(1e-8),
32  g_tol_(1e-8),
33  epsilon_(1e-3),
34  start_error_(0.0),
35  end_error_(0.0)
36 {
37 }
38 
40 {
41  delete ba_func_;
42 }
43 
44 //: normalize image points to be mean centered with scale sqrt(2)
45 // \return parameters such that original point are recovered as (ns*x+nx, ns*y+ny)
46 void
48  double& nx, double& ny, double& ns)
49 {
50  nx = ny = ns = 0.0;
51  for (auto & image_point : image_points)
52  {
53  double x = image_point.x();
54  double y = image_point.y();
55  nx += x;
56  ny += y;
57  ns += x*x + y*y;
58  }
59  nx /= image_points.size();
60  ny /= image_points.size();
61  ns /= image_points.size();
62  ns -= nx*nx + ny*ny;
63  ns /= 2;
64  ns = std::sqrt(ns);
65  for (auto & image_point : image_points)
66  {
67  image_point.x() -= nx;
68  image_point.y() -= ny;
69  image_point.x() /= ns;
70  image_point.y() /= ns;
71  }
72 }
73 
74 
75 // reflect the points about a plane
76 void
79  std::vector<vgl_point_3d<double> >& points)
80 {
82  H.set_reflection_plane(plane);
83  for (auto & point : points)
84  {
85  point = H * vgl_homg_point_3d<double>(point);
86  }
87 }
88 
89 
90 // rotate the cameras 180 degrees around an axis
91 void
94  std::vector<vpgl_perspective_camera<double> >& cameras)
95 {
96  vnl_double_3 r(axis.x(), axis.y(), axis.z());
97  r.normalize();
98  r *= vnl_math::pi;
100  vgl_rotation_3d<double> R2(0.0, 0.0, vnl_math::pi);
101  for (auto & c : cameras)
102  {
103  c.set_camera_center(R*c.get_camera_center());
104  c.set_rotation(R2*c.get_rotation()*R);
105  }
106 }
107 
108 
109 //: Approximately depth invert the scene.
110 // Apply this and re-optimize to get out of a common local minimum.
111 // Find the mean axis between cameras and points, mirror the points about
112 // a plane perpendicular to this axis, and rotate the cameras 180 degrees
113 // around this axis
114 void
117  std::vector<vgl_point_3d<double> >& points)
118 {
119  vnl_double_3 pc(0.0,0.0,0.0), cc(0.0,0.0,0.0);
120  // compute the mean of the points
121  for (auto & point : points)
122  {
123  pc += vnl_double_3(point.x(), point.y(), point.z());
124  }
125  pc /= points.size();
126  vgl_point_3d<double> point_center(pc[0],pc[1],pc[2]);
127 
128  // compute the mean of the camera centers
129  for (auto & camera : cameras)
130  {
131  vgl_point_3d<double> c = camera.get_camera_center();
132  cc += vnl_double_3(c.x(), c.y(), c.z());
133  }
134  cc /= cameras.size();
135  vgl_point_3d<double> camera_center(cc[0],cc[1],cc[2]);
136 
137  // define the plane of reflection
138  vgl_vector_3d<double> axis(camera_center-point_center);
139  normalize(axis);
140  vgl_plane_3d<double> reflect_plane(axis, point_center);
141 
142  reflect_points(reflect_plane,points);
143  rotate_cameras(axis, cameras);
144 }
145 
146 
147 //: Bundle Adjust
148 bool
150  std::vector<vgl_point_3d<double> >& world_points,
151  const std::vector<vgl_point_2d<double> >& image_points,
152  const std::vector<std::vector<bool> >& mask)
153 {
154  delete ba_func_;
155 
156  double nx=0.0, ny=0.0, ns=1.0;
157  std::vector<vgl_point_2d<double> > norm_image_points(image_points);
158  if (normalize_data_)
159  normalize_points(norm_image_points,nx,ny,ns);
160 
161  // construct the bundle adjustment function
162  if (self_calibrate_)
163  {
164  // Extract the camera and point parameters
165  vpgl_ba_shared_k_lsqr::create_param_vector(cameras,a_,c_);
166  c_[0] /= ns;
167  b_ = vpgl_ba_shared_k_lsqr::create_param_vector(world_points);
168  // Compute the average calibration matrix
169  vnl_vector<double> K_vals(5,0.0);
170  for (auto & camera : cameras){
171  const vpgl_calibration_matrix<double>& Ki = camera.get_calibration();
172  K_vals[0] += Ki.focal_length()*Ki.x_scale();
173  K_vals[1] += Ki.y_scale() / Ki.x_scale();
174  K_vals[2] += Ki.principal_point().x();
175  K_vals[3] += Ki.principal_point().y();
176  K_vals[4] += Ki.skew();
177  }
178  K_vals /= cameras.size();
179  vpgl_calibration_matrix<double> K(K_vals[0]/ns,
180  vgl_point_2d<double>((K_vals[2]-nx)/ns,(K_vals[3]-ny)/ns),
181  1.0,
182  K_vals[1],
183  K_vals[4]);
184  ba_func_ = new vpgl_ba_shared_k_lsqr(K,norm_image_points,mask);
185  }
186  else
187  {
188  // Extract the camera and point parameters
189  std::vector<vpgl_calibration_matrix<double> > K;
192  for (auto & camera : cameras){
193  vpgl_calibration_matrix<double> Ktmp = camera.get_calibration();
194  if (normalize_data_)
195  {
196  Ktmp.set_focal_length(Ktmp.focal_length()/ns);
198  pp.x() = (pp.x()-nx)/ns;
199  pp.y() = (pp.y()-ny)/ns;
200  Ktmp.set_principal_point(pp);
201  }
202  K.push_back(Ktmp);
203  }
204  ba_func_ = new vpgl_ba_fixed_k_lsqr(K,norm_image_points,mask);
205  }
206 
207  // apply normalization to the scale of residuals
209 
210  // do the bundle adjustment
211  vnl_sparse_lm lm(*ba_func_);
212  lm.set_trace(true);
213  lm.set_verbose(verbose_);
214 
221  {
222  return false;
223  }
224 
225  if (use_m_estimator_)
226  {
227  weights_ = std::vector<double>(lm.get_weights().begin(), lm.get_weights().end());
228  }
229  else
230  {
231  weights_.clear();
232  weights_.resize(image_points.size(),1.0);
233  }
234 
235  if (self_calibrate_ && verbose_)
236  std::cout << "final focal length = "<<c_[0]*ns<<std::endl;
237 
238  start_error_ = lm.get_start_error()*ns;
239  end_error_ = lm.get_end_error()*ns;
241 
242  // Update the camera parameters
243  for (unsigned int i=0; i<cameras.size(); ++i)
244  {
245  cameras[i] = ba_func_->param_to_cam(i,a_,c_);
246  if (normalize_data_)
247  {
248  // undo the normalization in the camera calibration
249  vpgl_calibration_matrix<double> K = cameras[i].get_calibration();
250  K.set_focal_length(K.focal_length()*ns);
252  pp.x() = ns*pp.x() + nx;
253  pp.y() = ns*pp.y() + ny;
254  K.set_principal_point(pp);
255  cameras[i].set_calibration(K);
256  }
257  }
258  // Update the point locations
259  for (unsigned int j=0; j<world_points.size(); ++j)
260  world_points[j] = ba_func_->param_to_point(j,b_,c_);
261 
262  return true;
263 }
264 
265 
266 //: Write cameras and points to a file in VRML 2.0 for debugging
267 void
268 vpgl_bundle_adjust::write_vrml(const std::string& filename,
269  const std::vector<vpgl_perspective_camera<double> >& cameras,
270  const std::vector<vgl_point_3d<double> >& world_points)
271 {
272  std::ofstream os(filename.c_str());
273  os << "#VRML V2.0 utf8\n\n";
274 
275  // vrml views are rotated 180 degrees around the X axis
276  vgl_rotation_3d<double> rot180x(vnl_math::pi, 0.0, 0.0);
277 
278  for (unsigned int i=0; i<cameras.size(); ++i){
279  vnl_double_3x3 K = cameras[i].get_calibration().get_matrix();
280 
281  vgl_rotation_3d<double> R = (rot180x*cameras[i].get_rotation()).inverse();
282  vgl_point_3d<double> ctr = cameras[i].get_camera_center();
283  double fov = 2.0*std::max(std::atan(K[1][2]/K[1][1]), std::atan(K[0][2]/K[0][0]));
284  os << "Viewpoint {\n"
285  << " position "<< ctr.x() << ' ' << ctr.y() << ' ' << ctr.z() << '\n'
286  << " orientation "<< R.axis() << ' '<< R.angle() << '\n'
287  << " fieldOfView "<< fov << '\n'
288  << " description \"Camera" << i << "\"\n}\n";
289  }
290 
291  os << "Shape {\n appearance NULL\n geometry PointSet {\n"
292  << " color Color { color [1 0 0] }\n coord Coordinate{\n"
293  << " point[\n";
294 
295  for (const auto & world_point : world_points){
296  os << world_point.x() << ' '
297  << world_point.y() << ' '
298  << world_point.z() << '\n';
299  }
300  os << " ]\n }\n }\n}\n";
301 
302  os.close();
303 }
void reflect_points(const vgl_plane_3d< double > &plane, std::vector< vgl_point_3d< double > > &points)
vgl_point_2d< T > principal_point() const
int get_num_iterations() const
double get_end_error() const
size_t size() const
void normalize_points(std::vector< vgl_point_2d< double > > &image_points, double &nx, double &ny, double &ns)
normalize image points to be mean centered with scale sqrt(2).
double angle() const
vpgl_bundle_adjust()
Constructor.
void set_verbose(bool verb)
bool optimize(std::vector< vpgl_perspective_camera< double > > &cameras, std::vector< vgl_point_3d< double > > &world_points, const std::vector< vgl_point_2d< double > > &image_points, const std::vector< std::vector< bool > > &mask)
Bundle Adjust.
vnl_vector< double > a_
The last camera parameters.
static void write_vrml(const std::string &filename, const std::vector< vpgl_perspective_camera< double > > &cameras, const std::vector< vgl_point_3d< double > > &world_points)
Write cameras and points to a file in VRML 2.0 for debugging.
Type & z()
void depth_reverse(std::vector< vpgl_perspective_camera< double > > &cameras, std::vector< vgl_point_3d< double > > &world_points)
Approximately depth invert the scene.
Bundle adjustment sparse least squares class for fixed intrinsics.
void set_g_tolerance(double v)
void set_principal_point(const vgl_point_2d< T > &new_principal_point)
std::vector< double > weights_
The last estimated weights.
vgl_homg_point_3d< double > param_to_point(int j, const vnl_vector< double > &b, const vnl_vector< double > &c) const
construct the
T y() const
Type & y()
vnl_vector< double > b_
The last point parameters.
a class for bundle adjustment with fixed intrinsic parameters.
void set_max_function_evals(int v)
~vpgl_bundle_adjust()
Destructor.
T x() const
T z() const
Type & x()
This class implements the perspective camera class as described in Hartley & Zisserman as a finite ca...
void rotate_cameras(const vgl_vector_3d< double > &axis, std::vector< vpgl_perspective_camera< double > > &cameras)
void set_epsilon_function(double v)
static vnl_vector< double > create_param_vector(const std::vector< vpgl_perspective_camera< double > > &cameras)
Create the parameter vector a from a vector of cameras.
unsigned int max_iterations_
vnl_vector< double > c_
The last global parameters.
double get_start_error() const
Bundle adjustment sparse least squares functions.
vpgl_bundle_adjust_lsqr * ba_func_
The bundle adjustment error function.
const vnl_vector< double > & get_weights() const
void set_reflection_plane(vgl_plane_3d< double > const &p)
v & normalize(v &a)
void set_focal_length(T new_focal_length)
Getters and setters for all of the parameters.
vnl_vector_fixed< T, 3 > axis() const
Type & y()
Type & x()
void set_residual_scale(double scale)
set the residual scale for the robust estimation.
bool minimize(vnl_vector< double > &a, vnl_vector< double > &b, vnl_vector< double > &c, bool use_gradient=true, bool use_weights=true)
vpgl_perspective_camera< double > param_to_cam(int i, const vnl_vector< double > &a, const vnl_vector< double > &c) const
construct the
void set_x_tolerance(double v)
void set_trace(bool on)