core/vgl/algo/vgl_norm_trans_2d.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_norm_trans_2d.txx
00002 #ifndef vgl_norm_trans_2d_txx_
00003 #define vgl_norm_trans_2d_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_norm_trans_2d.h"
00008 #include <vgl/vgl_point_2d.h>
00009 #include <vcl_iostream.h>
00010 #include <vnl/vnl_math.h>
00011 
00012 //--------------------------------------------------------------
00013 //
00014 
00015 // Default constructor
00016 template <class T>
00017 vgl_norm_trans_2d<T>::vgl_norm_trans_2d() : vgl_h_matrix_2d<T>()
00018 {
00019 }
00020 
00021 // Copy constructor
00022 template <class T>
00023 vgl_norm_trans_2d<T>::vgl_norm_trans_2d(const vgl_norm_trans_2d<T>& M)
00024 : vgl_h_matrix_2d<T>(M)
00025 {
00026 }
00027 
00028 
00029 // Constructor from vcl_istream
00030 template <class T>
00031 vgl_norm_trans_2d<T>::vgl_norm_trans_2d(vcl_istream& s)
00032 : vgl_h_matrix_2d<T>(s)
00033 {
00034 }
00035 
00036 // Constructor from file
00037 template <class T>
00038 vgl_norm_trans_2d<T>::vgl_norm_trans_2d(char const* filename)
00039 : vgl_h_matrix_2d<T>(filename)
00040 {
00041 }
00042 
00043 //--------------------------------------------------------------
00044 // Constructor
00045 template <class T>
00046 vgl_norm_trans_2d<T>::vgl_norm_trans_2d(vnl_matrix_fixed<T,3,3> const& M)
00047 : vgl_h_matrix_2d<T>(M)
00048 {
00049 }
00050 
00051 //--------------------------------------------------------------
00052 // Constructor
00053 template <class T>
00054 vgl_norm_trans_2d<T>::vgl_norm_trans_2d(const T* H)
00055 : vgl_h_matrix_2d<T>(H)
00056 {
00057 }
00058 
00059 // Destructor
00060 template <class T>
00061 vgl_norm_trans_2d<T>::~vgl_norm_trans_2d()
00062 {
00063 }
00064 
00065 // == OPERATIONS ==
00066 //----------------------------------------------------------------
00067 //: Get the normalizing transform for a set of points
00068 // - Compute the center of gravity & form the normalizing transformation matrix
00069 // - Transform the point set to a temporary collection
00070 // - Compute the average point radius
00071 // - Complete the normalizing transform
00072 template <class T>
00073 bool vgl_norm_trans_2d<T>::
00074 compute_from_points(vcl_vector<vgl_homg_point_2d<T> > const& points,
00075                     bool isotropic)
00076 {
00077   T cx, cy;
00078   this->center_of_mass(points, cx, cy);
00079   vgl_h_matrix_2d<T>::set_identity().set_translation(-cx,-cy);
00080   vcl_vector<vgl_homg_point_2d<T> > temp;
00081   for (typename vcl_vector<vgl_homg_point_2d<T> >::const_iterator
00082        pit = points.begin(); pit != points.end(); pit++)
00083   {
00084     vgl_homg_point_2d<T> p((*this)(*pit));
00085     temp.push_back(p);
00086   }
00087 
00088   if (isotropic) {
00089     T radius = T(1);
00090     //Points might be coincident
00091     if (!this->scale_xyroot2(temp, radius))
00092       return false;
00093     vgl_h_matrix_2d<T>::set_scale(T(1)/radius);
00094     return true;
00095   }
00096   T sdx = 1, sdy = 1, c = 1, s = 0;
00097   if (!this->scale_aniostropic(temp, sdx, sdy, c, s))
00098     return false;
00099   T scx = 1/sdx, scy = 1/sdy;
00100   T data[] = { c*scx, -s*scx, -c*scx*cx +s*scx*cy,
00101                s*scy,  c*scy, -s*scy*cx -c*scy*cy };
00102   vgl_h_matrix_2d<T>::set_affine(vnl_matrix_fixed<T,2,3>(data));
00103   return true;
00104 }
00105 
00106 //-----------------------------------------------------------------
00107 //:
00108 //  The normalizing transform for lines is computed from the
00109 //  set of points defined by the intersection of the perpendicular from
00110 //  the origin with the line.  Each such point is given by:
00111 //    $p = [-a*c, -b*c, \sqrt(a^2+b^2)]^T$
00112 //  If we assume the line is normalized then:
00113 //    $p = [-a*c, -b*c, 1]^T$
00114 //
00115 template <class T>
00116 bool vgl_norm_trans_2d<T>::
00117 compute_from_lines(vcl_vector<vgl_homg_line_2d<T> > const& lines,
00118                    bool isotropic)
00119 {
00120   vcl_vector<vgl_homg_point_2d<T> > points;
00121   for (typename vcl_vector<vgl_homg_line_2d<T> >::const_iterator lit=lines.begin();
00122        lit != lines.end(); lit++)
00123   {
00124     vgl_homg_line_2d<T> l = (*lit);
00125     vgl_homg_point_2d<T> p(-l.a()*l.c(), -l.b()*l.c(), l.a()*l.a()+l.b()*l.b());
00126     points.push_back(p);
00127   }
00128   return this->compute_from_points(points, isotropic);
00129 }
00130 
00131 //-----------------------------------------------------------------
00132 //:
00133 // The normalizing transform for points and lines is computed from the set of
00134 // points used by compute_from_points() & the one used by compute_from_lines().
00135 //
00136 template <class T>
00137 bool vgl_norm_trans_2d<T>::
00138 compute_from_points_and_lines(vcl_vector<vgl_homg_point_2d<T> > const& pts,
00139                               vcl_vector<vgl_homg_line_2d< T> > const& lines,
00140                               bool isotropic)
00141 {
00142   vcl_vector<vgl_homg_point_2d<T> > points = pts;
00143   for (typename vcl_vector<vgl_homg_line_2d<T> >::const_iterator lit=lines.begin();
00144        lit != lines.end(); lit++)
00145   {
00146     vgl_homg_line_2d<T> l = (*lit);
00147     vgl_homg_point_2d<T> p(-l.a()*l.c(), -l.b()*l.c(), l.a()*l.a()+l.b()*l.b());
00148     points.push_back(p);
00149   }
00150   return this->compute_from_points(points, isotropic);
00151 }
00152 
00153 //-------------------------------------------------------------------
00154 // Find the center of a point cloud
00155 //
00156 template <class T>
00157 void vgl_norm_trans_2d<T>::
00158 center_of_mass(vcl_vector<vgl_homg_point_2d<T> > const& in, T& cx, T& cy)
00159 {
00160   T cog_x = 0;
00161   T cog_y = 0;
00162   T cog_count = 0.0;
00163   T tol = static_cast<T>(1e-06);
00164   unsigned n = in.size();
00165   for (unsigned i = 0; i < n; ++i)
00166   {
00167     if (in[i].ideal(tol))
00168       continue;
00169     vgl_point_2d<T> p(in[i]);
00170     T x = p.x();
00171     T y = p.y();
00172     cog_x += x;
00173     cog_y += y;
00174     ++cog_count;
00175   }
00176   if (cog_count > 0)
00177   {
00178     cog_x /= cog_count;
00179     cog_y /= cog_count;
00180   }
00181   //output result
00182   cx = cog_x;
00183   cy = cog_y;
00184 }
00185 
00186 //-------------------------------------------------------------------
00187 // Find the mean distance of the input pointset. Assumed to have zero mean
00188 //
00189 template <class T>
00190 bool vgl_norm_trans_2d<T>::
00191 scale_xyroot2(vcl_vector<vgl_homg_point_2d<T> > const& in, T& radius)
00192 {
00193   T magnitude = T(0);
00194   int numfinite = 0;
00195   T tol = T(1e-06);
00196   radius = T(0);
00197   for (unsigned i = 0; i < in.size(); ++i)
00198   {
00199     if (in[i].ideal(tol))
00200       continue;
00201     vgl_point_2d<T> p(in[i]);
00202     magnitude += vnl_math_hypot(p.x(),p.y());
00203     ++numfinite;
00204   }
00205 
00206   if (numfinite > 0)
00207   {
00208     radius = T(magnitude / (numfinite*vnl_math::sqrt2));
00209     return radius>=tol;
00210   }
00211   return false;
00212 }
00213 
00214 //------------------------------------------------------------
00215 // Anisotropic scaling of the point set around the center of gravity.
00216 // Determines the principal axes and standard deviations along the principal
00217 // axes.  Assumes that the pointset has zero mean, so ::center_of_mass should
00218 // be removed before calling this function.
00219 template <class T>
00220 bool vgl_norm_trans_2d<T>::
00221 scale_aniostropic(vcl_vector<vgl_homg_point_2d<T> > const& in,
00222                   T& sdx, T& sdy, T& c, T& s)
00223 {
00224   T tol = T(1e-06);
00225   unsigned count = 0;
00226   unsigned n = in.size();
00227   //The point scatter matrix coefficients
00228   double Sx2=0, Sxy=0, Sy2=0;
00229   for (unsigned i = 0; i < n; ++i)
00230   {
00231     if (in[i].ideal(tol))
00232       continue;
00233     ++count;
00234     vgl_point_2d<T> p(in[i]);
00235     T x = p.x();
00236     T y = p.y();
00237     Sx2 += (double)x*x;
00238     Sxy += (double)x*y;
00239     Sy2 += (double)y*y;
00240   }
00241   if (!count)
00242     return false;
00243 
00244   double t =0.0;
00245   // Compute the rotation that makes Sxy zero
00246   if ( Sx2 != Sy2 )
00247     t = 0.5*vcl_atan( -2.0*Sxy/(Sx2-Sy2) );
00248 
00249   double dc = vcl_cos(t),  ds = vcl_sin(t);
00250 
00251   /* determine the standard deviations in the rotated frame */
00252   double sddx = vcl_sqrt( (dc*dc*Sx2-2.0*dc*ds*Sxy+ds*ds*Sy2)/count );
00253   double sddy = vcl_sqrt( (ds*ds*Sx2+2.0*dc*ds*Sxy+dc*dc*Sy2)/count );
00254 
00255   //cast back to T
00256   sdx = static_cast<T>(sddx);
00257   sdy = static_cast<T>(sddy);
00258   c = static_cast<T>(dc);
00259   s = static_cast<T>(ds);
00260   return sdx>tol && sdy >tol;
00261 }
00262 
00263 //----------------------------------------------------------------------------
00264 #undef VGL_NORM_TRANS_2D_INSTANTIATE
00265 #define VGL_NORM_TRANS_2D_INSTANTIATE(T) \
00266 template class vgl_norm_trans_2d<T >
00267 
00268 #endif // vgl_norm_trans_2d_txx_