core/vpgl/algo/vpgl_rational_adjust_onept.cxx
Go to the documentation of this file.
00001 #include "vpgl_rational_adjust_onept.h"
00002 //:
00003 // \file
00004 #include <vcl_cmath.h>
00005 #include <vcl_cassert.h>
00006 #include <vgl/vgl_plane_3d.h>
00007 #include <vgl/vgl_point_3d.h>
00008 #include <vnl/vnl_numeric_traits.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 
00013 #include <vcl_limits.h>
00014 
00015 //#define TRANS_ONE_DEBUG
00016 
00017 static const double vpgl_trans_z_step = 30.0;//meters
00018 static double
00019 scatter_var(vcl_vector<vpgl_rational_camera<double> > const& cams,
00020             vcl_vector<vgl_point_2d<double> > const& image_pts,
00021             vgl_point_3d<double> const& initial_pt,
00022             double elevation, double& xm, double& ym)
00023 {
00024   unsigned int n = cams.size();
00025   vgl_plane_3d<double> pl(0, 0, 1, -elevation);
00026   double xsq = 0, ysq = 0;
00027   xm = 0; ym = 0;
00028   for (unsigned int i = 0; i<n; ++i)
00029   {
00030     vgl_point_3d<double> pb_pt;
00031     if (!vpgl_backproject::bproj_plane(cams[i],
00032                                        image_pts[i], pl,
00033                                        initial_pt, pb_pt))
00034       return false;
00035     double x = pb_pt.x(), y = pb_pt.y();
00036     xm+=x; ym +=y;
00037     xsq+=x*x; ysq+=y*y;
00038   }
00039   xm/=n; ym/=n;
00040   double xvar = xsq-(n*xm*xm);
00041   double yvar = ysq-(n*ym*ym);
00042   xvar/=n; yvar/=n;
00043   double var = vcl_sqrt(xvar*xvar + yvar*yvar);
00044   return var;
00045 }
00046 
00047 vpgl_z_search_lsqr::
00048 vpgl_z_search_lsqr(vcl_vector<vpgl_rational_camera<double> > const& cams,
00049                    vcl_vector<vgl_point_2d<double> > const& image_pts,
00050                    vgl_point_3d<double> const& initial_pt)
00051   :  vnl_least_squares_function(1, 1,
00052                                 vnl_least_squares_function::no_gradient ),
00053      initial_pt_(initial_pt),
00054      cameras_(cams),
00055      image_pts_(image_pts),
00056      xm_(0), ym_(0)
00057 {}
00058 
00059 void vpgl_z_search_lsqr::f(vnl_vector<double> const& elevation,
00060                            vnl_vector<double>& variance)
00061 {
00062   variance[0] = scatter_var(cameras_, image_pts_,initial_pt_, elevation[0], xm_, ym_);
00063 }
00064 
00065 bool vpgl_rational_adjust_onept::
00066 find_intersection_point(vcl_vector<vpgl_rational_camera<double> > const& cams,
00067                         vcl_vector<vgl_point_2d<double> > const& corrs,
00068                         vgl_point_3d<double>& p_3d)
00069 {
00070   unsigned int n = cams.size();
00071   if (!n || n!=corrs.size())
00072     return false;
00073   //the average view volume center
00074   double x0=0, y0=0;
00075   // Get the lower bound on elevation range from the cameras
00076   double zmax = vnl_numeric_traits<double>::maxval, zmin = -zmax;
00077   for (vcl_vector<vpgl_rational_camera<double> >::const_iterator cit = cams.begin(); cit != cams.end(); ++cit)
00078   {
00079     x0+=(*cit).offset(vpgl_rational_camera<double>::X_INDX);
00080     y0+=(*cit).offset(vpgl_rational_camera<double>::Y_INDX);
00081 
00082     double zoff = (*cit).offset(vpgl_rational_camera<double>::Z_INDX);
00083     double zscale = (*cit).scale(vpgl_rational_camera<double>::Z_INDX);
00084     double zplus = zoff+zscale;
00085     double zminus = zoff-zscale;
00086     if (zminus>zmin) zmin = zminus;
00087     if (zplus<zmax) zmax = zplus;
00088   }
00089   assert(zmin<=zmax);
00090   x0/=n; y0/=n;
00091 
00092   double error = vnl_numeric_traits<double>::maxval;
00093   vgl_point_3d<double> initial_point(x0, y0, zmin);
00094   double xopt=0, yopt=0, zopt = 0;
00095   for (double z = zmin; z<=zmax; z+=vpgl_trans_z_step)
00096   {
00097     double xm = 0, ym = 0;
00098     double var = scatter_var(cams, corrs,initial_point, z, xm, ym);
00099     if (var<error)
00100     {
00101       error = var;
00102       xopt = xm;
00103       yopt = ym;
00104       zopt = z;
00105     }
00106     initial_point.set(xm, ym, z);
00107 #ifdef TRANS_ONE_DEBUG
00108     vcl_cout << z << '\t' << var << '\n';
00109 #endif
00110   }
00111   // at this point the best common intersection point is known.
00112   // do some sanity checks
00113   if (zopt == zmin||zopt == zmax)
00114     return false;
00115   p_3d.set(xopt, yopt, zopt);
00116   return true;
00117 }
00118 
00119 bool vpgl_rational_adjust_onept::
00120 refine_intersection_pt(vcl_vector<vpgl_rational_camera<double> > const& cams,
00121                        vcl_vector<vgl_point_2d<double> > const& image_pts,
00122                        vgl_point_3d<double> const& initial_pt,
00123                        vgl_point_3d<double>& final_pt)
00124 {
00125   vpgl_z_search_lsqr zsf(cams, image_pts, initial_pt);
00126   vnl_levenberg_marquardt levmarq(zsf);
00127 #ifdef TRANS_ONE_DEBUG
00128   levmarq.set_verbose(true);
00129 #endif
00130   // Set the x-tolerance.  When the length of the steps taken in X (variables)
00131   // are no longer than this, the minimization terminates.
00132   levmarq.set_x_tolerance(1e-10);
00133 
00134   // Set the epsilon-function.  This is the step length for FD Jacobian.
00135   levmarq.set_epsilon_function(1);
00136 
00137   // Set the f-tolerance.  When the successive RMS errors are less than this,
00138   // minimization terminates.
00139   levmarq.set_f_tolerance(1e-15);
00140 
00141   // Set the maximum number of iterations
00142   levmarq.set_max_function_evals(10000);
00143 
00144   vnl_vector<double> elevation(1);
00145   elevation[0]=initial_pt.z();
00146 
00147   // Minimize the error and get the best intersection point
00148   levmarq.minimize(elevation);
00149 #ifdef TRANS_ONE_DEBUG
00150   levmarq.diagnose_outcome();
00151 #endif
00152   final_pt.set(zsf.xm(), zsf.ym(), elevation[0]);
00153   return true;
00154 }
00155 
00156 bool vpgl_rational_adjust_onept::
00157 adjust(vcl_vector<vpgl_rational_camera<double> > const& cams,
00158        vcl_vector<vgl_point_2d<double> > const& corrs,
00159        vcl_vector<vgl_vector_2d<double> >& cam_translations,
00160        vgl_point_3d<double>& final)
00161 {
00162   cam_translations.clear();
00163   vgl_point_3d<double> intersection;
00164   if (!find_intersection_point(cams, corrs,intersection))
00165     return false;
00166 
00167   if (!refine_intersection_pt(cams, corrs,intersection, final))
00168     return false;
00169   vcl_vector<vpgl_rational_camera<double> >::const_iterator cit = cams.begin();
00170   vcl_vector<vgl_point_2d<double> >::const_iterator rit = corrs.begin();
00171   for (; cit!=cams.end() && rit!=corrs.end(); ++cit, ++rit)
00172   {
00173     vgl_point_2d<double> uvp = (*cit).project(final);
00174     vgl_point_2d<double> uv = *rit;
00175     vgl_vector_2d<double> t(uv.x()-uvp.x(), uv.y()-uvp.y());
00176     cam_translations.push_back(t);
00177   }
00178   return true;
00179 }