core/vgl/algo/vgl_line_2d_regression.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_line_2d_regression.txx
00002 #ifndef vgl_line_2d_regression_txx_
00003 #define vgl_line_2d_regression_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_line_2d_regression.h"
00008 #include <vcl_cmath.h>
00009 #include <vgl/vgl_distance.h>
00010 #include <vnl/vnl_matrix_fixed.h>
00011 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00012 #include <vcl_iostream.h>
00013 #include <vcl_cassert.h>
00014 
00015 //: Constructor
00016 template <class T>
00017 vgl_line_2d_regression<T>::vgl_line_2d_regression()
00018 {
00019   this->clear();
00020 }
00021 
00022 //: Add a point to the current regression sums
00023 template <class T>
00024 void vgl_line_2d_regression<T>::increment_partial_sums(const T x, const T y)
00025 {
00026   Sx_ += x;
00027   Sy_ += y;
00028   Sxx_ += x*x;
00029   Sxy_ += x*y;
00030   Syy_ += y*y;
00031   ++npts_;
00032 }
00033 
00034 //: Remove a point from the current regression sums
00035 template <class T>
00036 void vgl_line_2d_regression<T>::decrement_partial_sums(const T x, const T y)
00037 {
00038   assert(npts_!=0);
00039   Sx_ -= x;
00040   Sy_ -= y;
00041   Sxx_ -= x*x;
00042   Sxy_ -= x*y;
00043   Syy_ -= y*y;
00044   --npts_;
00045 }
00046 
00047 //: Clear the regression sums
00048 template <class T>
00049 void vgl_line_2d_regression<T>::clear()
00050 {
00051   Sx_ = 0;
00052   Sy_ = 0;
00053   Sxx_ = 0;
00054   Sxy_ = 0;
00055   Syy_ = 0;
00056   npts_=0;
00057   squared_error_=0;
00058 }
00059 
00060 //: Fit a line to the current regression data
00061 template <class T>
00062 bool vgl_line_2d_regression<T>::fit()
00063 {
00064   if (npts_<2)
00065     return false;
00066 
00067   vnl_matrix_fixed<T, 2, 2> M;
00068   M(0, 0) = Sxx_-Sx_*Sx_/npts_;
00069   M(0, 1) = M(1, 0) = Sxy_-Sx_*Sy_/npts_;
00070   M(1, 1) = Syy_-Sy_*Sy_/npts_;
00071 
00072   vnl_symmetric_eigensystem<T> sym(M.as_ref()); // size 2x2
00073   T a = sym.V(0,0);
00074   T b = sym.V(1,0);
00075   T c = -(a*Sx_/npts_ + b*Sy_/npts_);
00076   line_= vgl_line_2d<T>(a,b,c);
00077 
00078   return true;
00079 }
00080 
00081 template <class T>
00082 bool vgl_line_2d_regression<T>::fit_constrained(T x, T y)
00083 {
00084   if (npts_<1)
00085   {
00086     vcl_cout << "In vgl_line_2d_regression<T>::fit_constrained() - less than 1 point\n";
00087     return false;
00088   }
00089   vnl_matrix_fixed<T, 2, 2> M;
00090   M(0, 0) = Sxx_-2*Sx_*x +npts_*x*x;
00091   M(0, 1) = M(1, 0) = Sxy_-Sx_*y-x*Sy_+npts_*x*y;
00092   M(1, 1) = Syy_-2*Sy_*y+npts_*y*y;
00093   vnl_symmetric_eigensystem<T> sym(M.as_ref()); // size 2x2
00094   T a = sym.V(0,0);
00095   T b = sym.V(1,0);
00096   T c = -(a*x + b*y);
00097   line_= vgl_line_2d<T>(a,b,c);
00098   return true;
00099 }
00100 
00101 template <class T>
00102 double vgl_line_2d_regression<T>::get_rms_error(const T a, const T b, const T c)
00103 {
00104   if (npts_==0)
00105     return 0;
00106   double t0 = Sxx_*a*a + 2*Sxy_*a*b + Syy_*b*b;
00107   double t1 = 2*Sx_*a*c + 2*Sy_*b*c + npts_*c*c;
00108   double rms = vcl_sqrt(vcl_fabs(t0+t1)/((a*a+b*b)*npts_));
00109   return rms;
00110 }
00111 
00112 template <class T>
00113 double vgl_line_2d_regression<T>::get_rms_error()
00114 {
00115   return this->get_rms_error(line_.a(), line_.b(), line_.c());
00116 }
00117 
00118 //==================================================================
00119 //:
00120 // We want to add points to the regression until it is likely that
00121 // the fitting error has been exceeded.
00122 //
00123 // \verbatim
00124 //  squared_error_  = squared_error_ + d^2
00125 //                   ---------------------
00126 //                         npts_+1
00127 // \endverbatim
00128 //===================================================================
00129 // Initialize the recursive estimation of fitting error
00130 template <class T>
00131 void vgl_line_2d_regression<T>::init_rms_error_est()
00132 {
00133   squared_error_ = this->get_rms_error();
00134   squared_error_ *=squared_error_;
00135   squared_error_ *= npts_;
00136 }
00137 
00138 //: estimate of the fitting error if a new point is added.
00139 // Worst case is distance from the point, (x, y) to the current line.
00140 // Add the error to the accumulating estimation sum.
00141 template <class T>
00142 double vgl_line_2d_regression<T>::get_rms_error_est(vgl_point_2d<T> const&  p,
00143                                                     bool increment)
00144 {
00145   if (npts_==0)
00146     return 0;
00147   double d = vgl_distance(p, line_);
00148   double ds = d*d;
00149   if (increment)
00150     squared_error_ = squared_error_ + ds;
00151   return vcl_sqrt(squared_error_/(npts_+1));
00152 }
00153 
00154 //----------------------------------------------------------------------------
00155 #undef VGL_LINE_2D_REGRESSION_INSTANTIATE
00156 #define VGL_LINE_2D_REGRESSION_INSTANTIATE(T) \
00157 template class vgl_line_2d_regression<T >
00158 
00159 #endif // vgl_line_2d_regression_txx_