00001 #include "vpgl_rational_adjust.h"
00002
00003
00004
00005 #include <vcl_cmath.h>
00006 #include <vgl/vgl_plane_3d.h>
00007 #include <vgl/vgl_distance.h>
00008 #include <vgl/vgl_point_2d.h>
00009 #include <vnl/algo/vnl_levenberg_marquardt.h>
00010 #include <vpgl/algo/vpgl_backproject.h>
00011 #include <vpgl/algo/vpgl_ray_intersect.h>
00012 #define ADJUST_DEBUG
00013
00014 vpgl_adjust_lsqr::
00015 vpgl_adjust_lsqr(vpgl_rational_camera<double> const& rcam,
00016 vcl_vector<vgl_point_2d<double> > const& img_pts,
00017 vcl_vector<vgl_point_3d<double> > const& geo_pts,
00018 unsigned num_unknowns, unsigned num_residuals)
00019 : vnl_least_squares_function(num_unknowns, num_residuals,
00020 vnl_least_squares_function::no_gradient),
00021 rcam_(rcam), img_pts_(img_pts), geo_pts_(geo_pts)
00022 {
00023 num_corrs_ = img_pts.size();
00024 }
00025
00026
00027
00028 void vpgl_adjust_lsqr::f( const vnl_vector<double>& unknowns,
00029 vnl_vector<double> & projection_error)
00030 {
00031
00032 #if 0
00033 rcam_.set_scale(vpgl_rational_camera<double>::X_INDX, unknowns[0]);
00034 rcam_.set_offset(vpgl_rational_camera<double>::X_INDX, unknowns[1]);
00035 rcam_.set_scale(vpgl_rational_camera<double>::Y_INDX, unknowns[2]);
00036 rcam_.set_offset(vpgl_rational_camera<double>::Y_INDX, unknowns[3]);
00037 rcam_.set_scale(vpgl_rational_camera<double>::Z_INDX, unknowns[4]);
00038 rcam_.set_offset(vpgl_rational_camera<double>::Z_INDX, unknowns[5]);
00039
00040 vcl_cout << "x(" << unknowns[0] << ' ' << unknowns[1] << ")\n"
00041 << "y(" << unknowns[2] << ' ' << unknowns[3] << ")\n"
00042 << "z(" << unknowns[4] << ' ' << unknowns[5] << ")\n";
00043 #endif
00044 rcam_.set_offset(vpgl_rational_camera<double>::X_INDX, unknowns[0]);
00045 rcam_.set_offset(vpgl_rational_camera<double>::Y_INDX, unknowns[1]);
00046 rcam_.set_offset(vpgl_rational_camera<double>::Z_INDX, unknowns[2]);
00047
00048
00049 unsigned ir = 0;
00050 for (unsigned i = 0; i<num_corrs_; ++i)
00051 {
00052 vgl_point_2d<double> pp = rcam_.project(geo_pts_[i]);
00053 vgl_point_2d<double> c = img_pts_[i];
00054 projection_error[ir++] = (pp.x()-c.x())*(pp.x()-c.x());
00055 projection_error[ir++] = (pp.y()-c.y())*(pp.y()-c.y());
00056
00057 #if 0
00058 projection_error[ir++] = vcl_fabs(pp.x()-c.x());
00059 projection_error[ir++] = vcl_fabs(pp.y()-c.y());
00060
00061 vcl_cout << "perror[" << i << "](" << projection_error[ir-2] << ' '
00062 << projection_error[ir-1] << ")\n";
00063 #endif
00064 }
00065 }
00066
00067
00068
00069
00070
00071
00072 static bool initial_offsets(vpgl_rational_camera<double> const& initial_rcam,
00073 vcl_vector<vgl_point_2d<double> > const& img_pts,
00074 vcl_vector<vgl_point_3d<double> > const& geo_pts,
00075 double& xoff,
00076 double& yoff,
00077 double& zoff)
00078 {
00079 unsigned npts = img_pts.size();
00080
00081 zoff = 0;
00082 for (unsigned i = 0; i<npts; ++i)
00083 zoff += geo_pts[i].z();
00084 zoff /= npts;
00085
00086 vgl_plane_3d<double> pl(0, 0, 1, -zoff);
00087
00088
00089 double xo = initial_rcam.offset(vpgl_rational_camera<double>::X_INDX);
00090 double yo = initial_rcam.offset(vpgl_rational_camera<double>::Y_INDX);
00091 vgl_point_3d<double> initial_pt(xo, yo, zoff);
00092
00093 double xshift = 0, yshift = 0;
00094
00095 for (unsigned i = 0; i<npts; ++i)
00096 {
00097 vgl_point_3d<double> bp_pt;
00098 if (!vpgl_backproject::bproj_plane(initial_rcam,
00099 img_pts[i], pl,
00100 initial_pt, bp_pt))
00101 return false;
00102 xshift += geo_pts[i].x()- bp_pt.x();
00103 yshift += geo_pts[i].y()- bp_pt.y();
00104 }
00105 xoff = xo + xshift/npts;
00106 yoff = yo + yshift/npts;
00107 return true;
00108 }
00109
00110
00111
00112 bool vpgl_rational_adjust::
00113 adjust(vpgl_rational_camera<double> const& initial_rcam,
00114 vcl_vector<vgl_point_2d<double> > img_pts,
00115 vcl_vector<vgl_point_3d<double> > geo_pts,
00116 vpgl_rational_camera<double> & adj_rcam)
00117 {
00118
00119 double xoff=0, yoff=0, zoff=0;
00120 if (!initial_offsets(initial_rcam, img_pts, geo_pts, xoff, yoff, zoff))
00121 return false;
00122 unsigned num_corrs = img_pts.size();
00123 unsigned num_unknowns = 3;
00124 unsigned num_residuals = num_corrs*2;
00125
00126 vpgl_adjust_lsqr lsf(initial_rcam, img_pts, geo_pts,
00127 num_unknowns, num_residuals);
00128
00129
00130 vnl_levenberg_marquardt levmarq(lsf);
00131 #ifdef ADJUST_DEBUG
00132 levmarq.set_verbose(true);
00133 levmarq.set_trace(true);
00134 #endif
00135 #if 0
00136
00137
00138 levmarq.set_x_tolerance(1e-5);
00139
00140
00141 levmarq.set_epsilon_function(1.0);
00142
00143
00144
00145 levmarq.set_f_tolerance(1e-10);
00146 #endif
00147
00148 levmarq.set_max_function_evals(10000);
00149
00150
00151 vnl_vector<double> unknowns(num_unknowns);
00152
00153 #if 0
00154 unknowns[0] = initial_rcam.scale(vpgl_rational_camera<double>::X_INDX);
00155 unknowns[1] = xoff;
00156 unknowns[2] = initial_rcam.scale(vpgl_rational_camera<double>::Y_INDX);
00157 unknowns[3] = yoff;
00158 unknowns[4] = initial_rcam.scale(vpgl_rational_camera<double>::Z_INDX);
00159 unknowns[5] = zoff;
00160 #endif
00161 unknowns[0] = xoff;
00162 unknowns[1] = yoff;
00163 unknowns[2] = zoff;
00164
00165
00166 levmarq.minimize(unknowns);
00167
00168
00169 levmarq.diagnose_outcome();
00170 #ifdef ADJUST_DEBUG
00171 vcl_cout << "Min error of " << levmarq.get_end_error() << " at the following local minima : " << '\n';
00172 #endif
00173
00174 adj_rcam = initial_rcam;
00175
00176
00177 adj_rcam.set_offset(vpgl_rational_camera<double>::X_INDX, unknowns[0]);
00178 adj_rcam.set_offset(vpgl_rational_camera<double>::Y_INDX, unknowns[1]);
00179 adj_rcam.set_offset(vpgl_rational_camera<double>::Z_INDX, unknowns[2]);
00180
00181 #ifdef ADJUST_DEBUG
00182 for (unsigned i = 0; i<num_corrs; ++i)
00183 {
00184 vgl_point_2d<double> pp = adj_rcam.project(geo_pts[i]);
00185 vgl_point_2d<double> c = img_pts[i];
00186 double d = vgl_distance<double>(c, pp);
00187 vcl_cout << "p[" << i << "]->(" << pp.x() << ' ' << pp.y() << ")\n"
00188 << "c(" << c.x() << ' ' << c.y() << "): " << d << '\n';
00189 }
00190 #endif
00191
00192 return true;
00193 }