core/vpgl/algo/vpgl_ray_intersect.cxx
Go to the documentation of this file.
00001 #include "vpgl_ray_intersect.h"
00002 //:
00003 // \file
00004 #include <vnl/algo/vnl_levenberg_marquardt.h>
00005 #include <vnl/vnl_numeric_traits.h>
00006 #include <vnl/vnl_vector.h>
00007 #include <vnl/vnl_double_3.h>
00008 #include <vcl_iostream.h>
00009 #include <vpgl/vpgl_camera.h>
00010 
00011 //#define RAY_INT_DEBUG
00012 vpgl_ray_intersect_lsqr::
00013 vpgl_ray_intersect_lsqr(vcl_vector<vpgl_camera<double>* > const& cams,
00014                         vcl_vector<vgl_point_2d<double> > const& image_pts,
00015                         unsigned num_residuals) :
00016   vnl_least_squares_function(3, num_residuals,
00017                              vnl_least_squares_function::no_gradient ),
00018   f_cameras_(cams),
00019   f_image_pts_(image_pts)
00020 {}
00021 
00022 // Define virtual function for the LeastSquaresFunction class.  Given
00023 // a conjectured point (intersection_vert) in space, this determines the
00024 // error vector formed by appending all <u - conjecture_u, v - conjecture_v>
00025 // error tuples for each image.  Here <u, v> is the actual image point, and
00026 // <conjecture_u, conjecture_v> is the point corresponding to intersection_vert.
00027 void vpgl_ray_intersect_lsqr::f(vnl_vector<double> const& intersection_point,
00028                                 vnl_vector<double>& image_errors)
00029 {
00030   // Get the size of the error vector
00031   unsigned dim = image_errors.size()/2;
00032 
00033   // Initialize huge error
00034   double huge = vnl_numeric_traits<double>::maxval;
00035   for (unsigned i=0; i<image_errors.size(); i++)
00036     image_errors.put(i, huge);
00037 
00038   // Compute the error in each image
00039   double intersection_point_x =  intersection_point[0];
00040   double intersection_point_y =  intersection_point[1];
00041   double intersection_point_z =  intersection_point[2];
00042 #ifdef RAY_INT_DEBUG
00043   vcl_cout << "Error Vector (" << intersection_point_x << ", "
00044            << intersection_point_y << ", " << intersection_point_z << ") = ";
00045 #endif
00046 
00047   for (unsigned image_no = 0; image_no < dim; image_no++)
00048   {
00049     // Get this camera and corresponding image point
00050     vpgl_camera<double>* cam = f_cameras_[image_no];
00051     double image_u = f_image_pts_[image_no].x(),
00052       image_v = f_image_pts_[image_no].y();
00053     // Compute the image of the intersection vert through this camera
00054     double cur_image_u, cur_image_v;
00055     cam->project(intersection_point_x, intersection_point_y,
00056                  intersection_point_z, cur_image_u, cur_image_v);
00057     // Compute and store the error with respect to actual image
00058     image_errors.put(2*image_no,
00059                      (cur_image_u - image_u));
00060     image_errors.put(2*image_no+1,
00061                      (cur_image_v - image_v));
00062 #ifdef RAY_INT_DEBUG
00063     vcl_cout << " x_err = " << cur_image_u << '-' << image_u << '='
00064              << image_errors[2*image_no]
00065              << " y_err = " << cur_image_v << '-' << image_v << '='
00066              << image_errors[2*image_no+1];
00067 #endif
00068 
00069 
00070 #ifdef RAY_INT_DEBUG
00071     vcl_cout << '\n';
00072 #endif
00073   }
00074 }
00075 
00076 // Constructor.
00077 vpgl_ray_intersect::vpgl_ray_intersect(unsigned dim): dim_(dim)
00078 {}
00079 
00080 // A function to get the point closest to the rays coming out of image_pts
00081 // in images, whose cameras (cams) are known.  Point is stored in intersection.
00082 // Returns true if successful, else false
00083 bool vpgl_ray_intersect::
00084 intersect(vcl_vector<vpgl_camera<double>* > const& cams,
00085           vcl_vector<vgl_point_2d<double> > const& image_pts,
00086           vgl_point_3d<double> const& initial_intersection,
00087           vgl_point_3d<double>& intersection)
00088 {
00089   // Make sure the dimension is at least 2
00090   if (dim_ < 2)
00091   {
00092     vcl_cerr << "The dimension is too small.  There must be at least 2 images"
00093              << '\n';
00094     return false;
00095   }
00096 
00097   // Make sure there are correct number of cameras
00098   if (cams.size() != dim_)
00099   {
00100     vcl_cerr << "Please provide correct number of cameras" << '\n';
00101     return false;
00102   }
00103 
00104   // Make sure there are correct number of image points
00105   if (image_pts.size() != dim_)
00106   {
00107     vcl_cerr << "Please provide correct number of image points" << '\n';
00108     return false;
00109   }
00110 
00111   // cache the image points and camera points
00112   f_cameras_ = cams;
00113   f_image_pts_ = image_pts;
00114 
00115   // Create the Levenberg Marquardt minimizer
00116   vpgl_ray_intersect_lsqr lqf(cams, image_pts, 2*dim_);
00117   vnl_levenberg_marquardt levmarq(lqf);
00118 #ifdef RAY_INT_DEBUG
00119   vcl_cout << "Created LevenbergMarquardt minimizer ... setting tolerances\n";
00120   levmarq.set_verbose(true);
00121 #endif
00122   // Set the x-tolerance.  When the length of the steps taken in X (variables)
00123   // are no longer than this, the minimization terminates.
00124   levmarq.set_x_tolerance(1e-10);
00125 
00126   // Set the epsilon-function.  This is the step length for FD Jacobian.
00127   levmarq.set_epsilon_function(1.0);
00128 
00129   // Set the f-tolerance.  When the successive RMS errors are less than this,
00130   // minimization terminates.
00131   levmarq.set_f_tolerance(1e-10);
00132 
00133   // Set the maximum number of iterations
00134   levmarq.set_max_function_evals(10000);
00135   vnl_double_3 intersection_pt;
00136   intersection_pt[0]=initial_intersection.x();
00137   intersection_pt[1]=initial_intersection.y();
00138   intersection_pt[2]=initial_intersection.z();
00139 
00140 #ifdef RAY_INT_DEBUG
00141   vcl_cout << "Initialized the intersection point " << intersection_pt
00142            << " ... minimizing\n";
00143 #endif
00144 
00145   // Minimize the error and get the best intersection point
00146   levmarq.minimize(intersection_pt);
00147 
00148   // Summarize the results
00149 #ifdef RAY_INT_DEBUG
00150   vcl_cout << "Min error of " << levmarq.get_end_error() << " at "
00151            << '(' << intersection_pt[0] << ", " << intersection_pt[1]
00152            << ", " << intersection_pt[2] << ")\n"
00153            << "Iterations: " << levmarq.get_num_iterations() << "    "
00154            << "Evaluations: " << levmarq.get_num_evaluations() << '\n';
00155   levmarq.diagnose_outcome();
00156 #endif
00157   // Assign the intersection
00158   intersection.set(intersection_pt[0],
00159                    intersection_pt[1],
00160                    intersection_pt[2]);
00161   // Return success
00162   return true;
00163 }