core/vgl/algo/vgl_h_matrix_2d_optimize_lmq.cxx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_h_matrix_2d_optimize_lmq.cxx
00002 #include "vgl_h_matrix_2d_optimize_lmq.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include <vnl/vnl_inverse.h>
00010 #include <vnl/algo/vnl_levenberg_marquardt.h>
00011 #include <vgl/algo/vgl_norm_trans_2d.h>
00012 
00013 //: Construct a vgl_h_matrix_2d_optimize_lmq object.
00014 vgl_h_matrix_2d_optimize_lmq::
00015 vgl_h_matrix_2d_optimize_lmq(vgl_h_matrix_2d<double> const& initial_h)
00016   : vgl_h_matrix_2d_optimize(initial_h)
00017 {
00018 }
00019 
00020 //: optimize the normalized projection problem
00021 bool vgl_h_matrix_2d_optimize_lmq::
00022 optimize_h(vcl_vector<vgl_homg_point_2d<double> > const& points1,
00023            vcl_vector<vgl_homg_point_2d<double> > const& points2,
00024            vgl_h_matrix_2d<double> const& h_initial,
00025            vgl_h_matrix_2d<double>& h_optimized)
00026 {
00027   projection_lsqf lsq(points1, points2);
00028   vnl_vector<double> hv(9);
00029   vnl_matrix_fixed<double,3,3> m =  h_initial.get_matrix();
00030   unsigned i = 0;
00031   for (unsigned r=0; r<3; ++r)
00032     for (unsigned c=0; c<3; ++c, ++i)
00033       hv[i] = m[r][c];
00034   vnl_levenberg_marquardt lm(lsq);
00035   lm.set_verbose(verbose_);
00036   lm.set_trace(trace_);
00037   lm.set_x_tolerance(htol_);
00038   lm.set_f_tolerance(ftol_);
00039   lm.set_g_tolerance(gtol_);
00040   bool success = lm.minimize(hv);
00041   if (verbose_)
00042   {
00043     lm.diagnose_outcome(vcl_cout);
00044   }
00045 
00046   if (success)
00047     h_optimized.set(hv.data_block());
00048   else
00049     h_optimized = h_initial;
00050   return success;
00051 }
00052 
00053 bool vgl_h_matrix_2d_optimize_lmq::
00054 optimize_p(vcl_vector<vgl_homg_point_2d<double> > const& points1,
00055            vcl_vector<vgl_homg_point_2d<double> > const& points2,
00056            vgl_h_matrix_2d<double>& H)
00057 {
00058   //number of points must be the same
00059   assert(points1.size() == points2.size());
00060   int n = points1.size();
00061   assert(n>4);
00062 
00063   //compute the normalizing transforms
00064   vgl_norm_trans_2d<double> tr1, tr2;
00065   if (!tr1.compute_from_points(points1))
00066     return false;
00067   if (!tr2.compute_from_points(points2))
00068     return false;
00069   //normalize the input point sets
00070   vcl_vector<vgl_homg_point_2d<double> > tpoints1, tpoints2;
00071   for (int i=0; i<n; ++i)
00072   {
00073     tpoints1.push_back(tr1(points1[i]));
00074     tpoints2.push_back(tr2(points2[i]));
00075   }
00076   //Transform the initial homography into the normalized coordinate frame
00077   //  p1' = tr1 p1 , p2' = tr2 p2
00078   // p2 = initial_h_(p1)
00079   // (tr2^-1)p2' = initial_h_((tr1^-1)p1')
00080   // p2' = (tr2*initial_h_*(tr1^-1))p1'
00081   // thus initial_h_' = tr2*initial_h_*(tr1^-1)
00082 
00083   vgl_h_matrix_2d<double> tr1_inv = tr1.get_inverse();
00084   vgl_h_matrix_2d<double> initial_h_norm = tr2*initial_h_*tr1_inv;
00085 
00086   //The Levenberg-Marquardt algorithm can now be applied
00087   vgl_h_matrix_2d<double> hopt;
00088   if (!optimize_h(tpoints1, tpoints2, initial_h_norm, hopt))
00089     return false;
00090 
00091   // hopt has to be transformed back to the coordinate system of
00092   // the original point sets, i.e.,
00093   //  p1' = tr1 p1 , p2' = tr2 p2
00094   // hopt was determined from the transform relation
00095   //  p2' = hopt p1', thus
00096   // (tr2 p2) = hopt (tr1 p1)
00097   //  p2 = (tr2^-1 hopt tr1) p1 = H p1
00098   vgl_h_matrix_2d<double> tr2_inv = tr2.get_inverse();
00099   H = tr2_inv*hopt*tr1;
00100   return true;
00101 }
00102 
00103 bool vgl_h_matrix_2d_optimize_lmq::
00104 optimize_l(vcl_vector<vgl_homg_line_2d<double> > const& lines1,
00105            vcl_vector<vgl_homg_line_2d<double> > const& lines2,
00106            vgl_h_matrix_2d<double>& H)
00107 {
00108   //number of lines must be the same
00109   assert(lines1.size() == lines2.size());
00110   assert(lines1.size() > 4);
00111   //compute the normalizing transforms. By convention, these are point
00112   //transformations that act properly if the input is a line,
00113   // i.e., linei_norm = trx^-t(linei).
00114   vgl_norm_trans_2d<double> tr1, tr2;
00115   if (!tr1.compute_from_lines(lines1))
00116     return false;
00117   if (!tr2.compute_from_lines(lines2))
00118     return false;
00119   vcl_vector<vgl_homg_point_2d<double> > tlines1, tlines2;
00120   for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00121        lit = lines1.begin(); lit != lines1.end(); lit++)
00122   {
00123     // transform lines1 according to the normalizing transform
00124     vgl_homg_line_2d<double> l = tr1(*lit);
00125     // convert the line to a point to use the same linear code
00126     vgl_homg_point_2d<double> p(l.a(), l.b(), l.c());
00127     tlines1.push_back(p);
00128   }
00129   for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00130        lit = lines2.begin(); lit != lines2.end(); lit++)
00131   {
00132     // transform lines2 according to the normalizing transform
00133     vgl_homg_line_2d<double> l = tr2(*lit);
00134     // convert the line to a point to use the same linear code
00135     vgl_homg_point_2d<double> p(l.a(), l.b(), l.c());
00136     tlines2.push_back(p);
00137   }
00138   // At this step, we have two line sets normalized as a set of points.
00139   // The input to the point optimizer method must be a line transform,
00140   // so the initial homography, which is by convention a point transform,
00141   // must be converted as h_initial_line = h_initial_^-t
00142 
00143   // normalize the initial guess
00144   vgl_h_matrix_2d<double> h_initial_line, h_line_opt, initial_h_norm;
00145   vgl_h_matrix_2d<double> tr1_inv = tr1.get_inverse();
00146    initial_h_norm = tr2*initial_h_*tr1_inv;
00147   // convert to line form
00148   vnl_matrix_fixed<double, 3, 3> const &  Mp_init =
00149     initial_h_norm.get_matrix();
00150   vnl_matrix_fixed<double, 3, 3> Ml_init = vnl_inverse_transpose(Mp_init);
00151   h_initial_line.set(Ml_init);
00152 
00153   //run the optimization to refine the line transform
00154   if (!this->optimize_h(tlines1, tlines2, h_initial_line, h_line_opt))
00155     return false;
00156 
00157   // Convert the optimized line transform back to point form.
00158   vgl_h_matrix_2d<double> h_point_opt;
00159   vnl_matrix_fixed<double, 3, 3> const &  Ml_opt = h_line_opt.get_matrix();
00160   vnl_matrix_fixed<double, 3, 3> Mp_opt = vnl_inverse_transpose(Ml_opt);
00161   h_point_opt.set(Mp_opt);
00162 
00163   // Finally, h_point_opt has to be transformed back to the coordinate
00164   // system of the original lines, i.e.,
00165   //  l1' = tr1 l1 , l2' = tr2 l2
00166   // h_point_opt was determined from the transform relation
00167   //  l2' = h_point_opt l1', thus
00168   // (tr2 l2) = hh (tr1 l1)
00169   //  p2 = (tr2^-1 hh tr1) p1 = H p1
00170    vgl_h_matrix_2d<double> tr2inv = tr2.get_inverse();
00171   H = tr2inv*h_point_opt*tr1;
00172   return true;
00173 }
00174 
00175 bool vgl_h_matrix_2d_optimize_lmq::
00176 optimize_pl(vcl_vector<vgl_homg_point_2d<double> > const& points1,
00177             vcl_vector<vgl_homg_point_2d<double> > const& points2,
00178             vcl_vector<vgl_homg_line_2d<double> > const& lines1,
00179             vcl_vector<vgl_homg_line_2d<double> > const& lines2,
00180             vgl_h_matrix_2d<double>& H)
00181 {
00182   //number of points must be the same
00183   assert(points1.size() == points2.size());
00184   int np = points1.size();
00185   //number of lines must be the same
00186   assert(lines1.size() == lines2.size());
00187   int nl = lines1.size();
00188   // Must have enough equations
00189   assert((np+nl)>4);
00190   //compute the normalizing transforms
00191   vgl_norm_trans_2d<double> tr1, tr2;
00192   if (!tr1.compute_from_points_and_lines(points1,lines1))
00193     return false;
00194   if (!tr2.compute_from_points_and_lines(points2,lines2))
00195     return false;
00196   vcl_vector<vgl_homg_point_2d<double> > tpoints1, tpoints2;
00197   for (int i=0; i<np; ++i)
00198   {
00199     tpoints1.push_back(tr1(points1[i]));
00200     tpoints2.push_back(tr2(points2[i]));
00201   }
00202   for (int i=0; i<nl; ++i)
00203   {
00204     double a=lines1[i].a(), b=lines1[i].b(), c=lines1[i].c(), d=vcl_sqrt(a*a+b*b);
00205     tpoints1.push_back(tr1(vgl_homg_point_2d<double>(-a*c,-b*c,d)));
00206     a=lines2[i].a(), b=lines2[i].b(), c=lines2[i].c(), d = vcl_sqrt(a*a+b*b);
00207     tpoints2.push_back(tr2(vgl_homg_point_2d<double>(-a*c,-b*c,d)));
00208   }
00209 
00210   vgl_h_matrix_2d<double> tr1_inv = tr1.get_inverse();
00211   vgl_h_matrix_2d<double> initial_h_norm = tr2*initial_h_*tr1_inv;
00212 
00213   //The Levenberg-Marquardt algorithm can now be applied
00214   vgl_h_matrix_2d<double> hopt;
00215   if (!optimize_h(tpoints1, tpoints2, initial_h_norm, hopt))
00216     return false;
00217 
00218   // hopt has to be transformed back to the coordinate system of
00219   // the original point sets, i.e.,
00220   //  p1' = tr1 p1 , p2' = tr2 p2
00221   // hopt was determined from the transform relation
00222   //  p2' = hopt p1', thus
00223   // (tr2 p2) = hopt (tr1 p1)
00224   //  p2 = (tr2^-1 hopt tr1) p1 = H p1
00225 
00226   vgl_h_matrix_2d<double> tr2_inv = tr2.get_inverse();
00227   H = tr2_inv*hopt*tr1;
00228   return true;
00229 }