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