vpgl_rational_adjust.cxx
Go to the documentation of this file.
1 #include <cmath>
2 #include <utility>
3 #include "vpgl_rational_adjust.h"
4 //:
5 // \file
6 
7 #ifdef _MSC_VER
8 # include <vcl_msvc_warnings.h>
9 #endif
10 #include <vgl/vgl_plane_3d.h>
11 #include <vgl/vgl_distance.h>
12 #include <vgl/vgl_point_2d.h>
16 #define ADJUST_DEBUG
17 
20  std::vector<vgl_point_2d<double> > const& img_pts,
21  std::vector<vgl_point_3d<double> > geo_pts,
22  unsigned num_unknowns, unsigned num_residuals)
23  : vnl_least_squares_function(num_unknowns, num_residuals,
24  vnl_least_squares_function::no_gradient),
25  rcam_(rcam), img_pts_(img_pts), geo_pts_(std::move(geo_pts))
26 {
27  num_corrs_ = static_cast<unsigned>(img_pts.size());
28 }
29 // The virtual least-squares cost function.
30 // The unknowns are [xscale, xoff, yscale, yoff, zscale, zoff]
31 // The error residual vector elements are image errors for each point
33  vnl_vector<double> & projection_error)
34 {
35  // set the scales and offsets for the rational camera
36 #if 0
43 
44  std::cout << "x(" << unknowns[0] << ' ' << unknowns[1] << ")\n"
45  << "y(" << unknowns[2] << ' ' << unknowns[3] << ")\n"
46  << "z(" << unknowns[4] << ' ' << unknowns[5] << ")\n";
47 #endif
51 
52  // project the geo points using the camera
53  unsigned ir = 0;
54  for (unsigned i = 0; i<num_corrs_; ++i)
55  {
58  projection_error[ir++] = (pp.x()-c.x())*(pp.x()-c.x());
59  projection_error[ir++] = (pp.y()-c.y())*(pp.y()-c.y());
60 
61 #if 0
62  projection_error[ir++] = std::fabs(pp.x()-c.x());
63  projection_error[ir++] = std::fabs(pp.y()-c.y());
64 
65  std::cout << "perror[" << i << "](" << projection_error[ir-2] << ' '
66  << projection_error[ir-1] << ")\n";
67 #endif
68  }
69 }
70 
71 //This method works by projecting the image points onto a plane that is
72 //at the average elevation of the 3-d points. zoff is set to this value.
73 //xoff and yoff are adjusted to remove the average translation between
74 //The backprojected image points and their actual 3-d locations.
75 //
76 static bool initial_offsets(vpgl_rational_camera<double> const& initial_rcam,
77  std::vector<vgl_point_2d<double> > const& img_pts,
78  std::vector<vgl_point_3d<double> > const& geo_pts,
79  double& xoff,
80  double& yoff,
81  double& zoff)
82 {
83  auto npts = static_cast<unsigned>( img_pts.size() );
84  // get the average elevation
85  zoff = 0;
86  for (unsigned i = 0; i<npts; ++i)
87  zoff += geo_pts[i].z();
88  zoff /= npts;
89  // construct a x-y plane with this elevation
90  vgl_plane_3d<double> pl(0, 0, 1, -zoff);
91 
92  // an initial point for the backprojection
93  double xo = initial_rcam.offset(vpgl_rational_camera<double>::X_INDX);
94  double yo = initial_rcam.offset(vpgl_rational_camera<double>::Y_INDX);
95  vgl_point_3d<double> initial_pt(xo, yo, zoff);
96 
97  double xshift = 0, yshift = 0;
98  // backproject the image points onto this plane
99  for (unsigned i = 0; i<npts; ++i)
100  {
101  vgl_point_3d<double> bp_pt;
102  if (!vpgl_backproject::bproj_plane(initial_rcam,
103  img_pts[i], pl,
104  initial_pt, bp_pt))
105  return false;
106  xshift += geo_pts[i].x()- bp_pt.x();
107  yshift += geo_pts[i].y()- bp_pt.y();
108  }
109  xoff = xo + xshift/npts;
110  yoff = yo + yshift/npts;
111  return true;
112 }
113 
114 //: A function adjust the rational camera 3-d scales and offsets
115 // Returns true if successful, else false
118  std::vector<vgl_point_2d<double> > img_pts,
119  std::vector<vgl_point_3d<double> > geo_pts,
120  vpgl_rational_camera<double> & adj_rcam)
121 {
122  // Get initial offsets by backprojection
123  double xoff=0, yoff=0, zoff=0;
124  if (!initial_offsets(initial_rcam, img_pts, geo_pts, xoff, yoff, zoff))
125  return false;
126  auto num_corrs = static_cast<unsigned>( img_pts.size() );
127  unsigned num_unknowns = 3;
128  unsigned num_residuals = num_corrs*2;
129  // Initialize the least squares function
130  vpgl_adjust_lsqr lsf(initial_rcam, img_pts, geo_pts,
131  num_unknowns, num_residuals);
132 
133  // Create the Levenberg Marquardt minimizer
134  vnl_levenberg_marquardt levmarq(lsf);
135 #ifdef ADJUST_DEBUG
136  levmarq.set_verbose(true);
137  levmarq.set_trace(true);
138 #endif
139 #if 0
140  // Set the x-tolerance. When the length of the steps taken in X (variables)
141  // are no longer than this, the minimization terminates.
142  levmarq.set_x_tolerance(1e-5);
143 
144  // Set the epsilon-function. This is the step length for FD Jacobian.
145  levmarq.set_epsilon_function(1.0);
146 
147  // Set the f-tolerance. When the successive RMS errors are less than this,
148  // minimization terminates.
149  levmarq.set_f_tolerance(1e-10);
150 #endif
151  // Set the maximum number of iterations
152  levmarq.set_max_function_evals(10000);
153 
154  // Create an initial values of parameters with which to start
155  vnl_vector<double> unknowns(num_unknowns);
156 
157 #if 0
158  unknowns[0] = initial_rcam.scale(vpgl_rational_camera<double>::X_INDX);
159  unknowns[1] = xoff;
160  unknowns[2] = initial_rcam.scale(vpgl_rational_camera<double>::Y_INDX);
161  unknowns[3] = yoff;
162  unknowns[4] = initial_rcam.scale(vpgl_rational_camera<double>::Z_INDX);
163  unknowns[5] = zoff;
164 #endif
165  unknowns[0] = xoff;
166  unknowns[1] = yoff;
167  unknowns[2] = zoff;
168 
169  // Minimize the error and get best correspondence vertices and translations
170  levmarq.minimize(unknowns);
171 
172  // Summarize the results
173  levmarq.diagnose_outcome();
174 #ifdef ADJUST_DEBUG
175  std::cout << "Min error of " << levmarq.get_end_error() << " at the following local minima : " << '\n';
176 #endif
177  // set up the camera for return
178  adj_rcam = initial_rcam;
179  // set the scales and offsets for the rational camera
180 
181  adj_rcam.set_offset(vpgl_rational_camera<double>::X_INDX, unknowns[0]);
182  adj_rcam.set_offset(vpgl_rational_camera<double>::Y_INDX, unknowns[1]);
183  adj_rcam.set_offset(vpgl_rational_camera<double>::Z_INDX, unknowns[2]);
184 
185 #ifdef ADJUST_DEBUG
186  for (unsigned i = 0; i<num_corrs; ++i)
187  {
188  vgl_point_2d<double> pp = adj_rcam.project(geo_pts[i]);
189  vgl_point_2d<double> c = img_pts[i];
190  double d = vgl_distance<double>(c, pp);
191  std::cout << "p[" << i << "]->(" << pp.x() << ' ' << pp.y() << ")\n"
192  << "c(" << c.x() << ' ' << c.y() << "): " << d << '\n';
193  }
194 #endif
195  // Return success
196  return true;
197 }
void set_f_tolerance(double v)
std::vector< vgl_point_2d< double > > img_pts_
vpgl_rational_camera< double > rcam_
vpgl_adjust_lsqr(vpgl_rational_camera< double > const &rcam, std::vector< vgl_point_2d< double > > const &img_pts, std::vector< vgl_point_3d< double > > geo_pts, unsigned num_unknowns, unsigned num_residuals)
Constructor.
The 3-d offset and scale parameters of rational cameras typically must be adjusted to compensate for ...
static bool adjust(vpgl_rational_camera< double > const &initial_rcam, std::vector< vgl_point_2d< double > > img_pts, std::vector< vgl_point_3d< double > > geo_pts, vpgl_rational_camera< double > &adj_rcam)
A function adjust the rational camera 3-d scales and offsets.
double get_end_error() const
void set_verbose(bool verb)
void set_scale(const coor_index coor_index, const T scale)
set a specific scale value.
Type & y()
void set_offset(const coor_index coor_index, const T offset)
set a specific scale value.
Adjust 3-d offset and scale to align rational cameras to geolocations.
void set_max_function_evals(int v)
void f(vnl_vector< double > const &x, vnl_vector< double > &fx) override
The main function.
Find the 3-d point closest to the intersection of rays from >= 2 cameras.
Type & x()
void set_epsilon_function(double v)
T scale(const coor_index coor_index) const
get a specific scale value.
void diagnose_outcome() const
T offset(const coor_index coor_index) const
get a specific offset value.
bool minimize(vnl_vector< double > &x)
static bool bproj_plane(const vpgl_camera< double > *cam, vnl_double_2 const &image_point, vnl_double_4 const &plane, vnl_double_3 const &initial_guess, vnl_double_3 &world_point, double error_tol=0.05, double relative_diameter=1.0)
Generic camera interfaces (pointer for abstract class).
Methods for back_projecting from cameras to 3-d geometric structures.
Type & y()
std::vector< vgl_point_3d< double > > geo_pts_
Type & x()
void project(const T x, const T y, const T z, T &u, T &v) const override
The generic camera interface. u represents image column, v image row.
void set_x_tolerance(double v)
void set_trace(bool on)