core/vgl/algo/vgl_conic_2d_regression.h
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_conic_2d_regression.h
00002 #ifndef vgl_conic_2d_regression_h_
00003 #define vgl_conic_2d_regression_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Fits a conic to a set of points using linear regression
00010 // \author J.L. Mundy
00011 // \date June 17, 2005
00012 //
00013 //  Since conic fitting is rather ill-conditioned it is necessary to
00014 //  normalize the point coordinates so that they have equal standard
00015 //  deviations with respect to the center (mean) of the pointset.
00016 //  The points are transformed to have zero mean. The resulting conic
00017 //  is transformed back to the original frame for computing
00018 //  the Sampson approximation to fitting error.
00019 //
00020 //  The regression uses the Bookstein algorithm which constrains the
00021 //  conic norm, $ |ax^2 + bxy + cy^2 + dx + ey +f|^2 $, so that
00022 //   $ a^2 + 0.5*b^2 + c^2 = 2 $
00023 //  With this normalization, the resulting fit is invariant up to a similarity
00024 //  transform of the pointset.  The solution is formulated as an eigenvalue
00025 //  problem as follows:
00026 //
00027 //      The scatter matrix S is decomposed as
00028 //
00029 //      $ S   =  \begin{array}{cc}     S_{11} & S_{12}
00030 //                              \\     S_{21} & S_{22}     \end{array}$
00031 //      note $S_{21} = S_{12}^t$
00032 //
00033 //      The conic coefficients are $v_1 = \{a,b,c\}^t$ and $v_2 = \{d,e,f\}^t$
00034 //      The Bookstein constraint is expressed by the diagonal matrix
00035 //               D = Diag{1, 0.5, 1, 0, 0, 0}
00036 //      The Lagrangian to be minimized is
00037 //      $ L =  v_1^t S_{11} v_1  + 2 v_2^t S_{21} v_1  + v_2^t S_{22} v_2
00038 //             - \lambda(v_1^t D v_1 -2) $.
00039 //
00040 //      Minimizing with respect to v2 gives
00041 //      $ dL/dv_2 = 2 S_{21} v_1 + 2 S_{22} v_2 = 0 $
00042 //
00043 //      So,  $ v_2 = -S_{22}^-1 S_{21} v_1 $.
00044 //
00045 //      Substituting for v2 in L,
00046 //
00047 // $ L = v_1^t ( S_{11} - S_{12} * S_{22}^-1 * S_{21}) v_1 - \lambda(v_1^t D v_1 -2)
00048 //     = v_1^t ( (S_{11} - S_{12} * S_{22}^-1 * S_{21}) - \lambda D ) v_1 - 2 \lambda $,
00049 //
00050 // $ dL/dv_1 =  ( (S_{11} - S_{12} * S_{22}^-1 * S_{21}) - \lambda D ) v_1 = 0 $.
00051 //
00052 //   So, $ \lambda v_1 = D^-1 (S_{11} - S_{12} * S_{22}^-1 * S_{21}) v_1 $.
00053 //
00054 //   This eigenvalue problem is solved using singular value decomposition.
00055 //
00056 // \verbatim
00057 //  Modifications
00058 //   none
00059 // \endverbatim
00060 
00061 #include <vcl_vector.h>
00062 #include <vcl_iostream.h>
00063 #include <vnl/vnl_matrix_fixed.h>
00064 #include <vgl/vgl_point_2d.h>
00065 #include <vgl/vgl_homg_point_2d.h>
00066 #include <vgl/vgl_conic.h>
00067 #include <vgl/algo/vgl_norm_trans_2d.h>
00068 
00069 template <class T>
00070 class vgl_conic_2d_regression
00071 {
00072  public:
00073 
00074   // Constructors/Initializers/Destructors-------------------------------------
00075 
00076   vgl_conic_2d_regression();
00077 
00078   ~vgl_conic_2d_regression(){}
00079 
00080   // Operations----------------------------------------------------------------
00081 
00082 
00083   //: Number of regression points
00084   unsigned get_n_pts() const {return npts_;}
00085 
00086   //: clear the regression data
00087   void clear_points();
00088 
00089   void add_point(vgl_point_2d<T> const& p);
00090 
00091   void remove_point(vgl_point_2d<T> const& p);
00092 
00093   //: get the estimated Euclidean error with respect to the fitted conic segment in the original frame
00094   T get_rms_error_est(vgl_point_2d<T> const& p) const;
00095 
00096   //: get the current Euclidean fitting error in the original frame
00097   T get_rms_sampson_error() const { return sampson_error_; } //temporarily
00098 
00099   //: get the current algebraic fitting error in the normalized frame
00100   T get_rms_algebraic_error() const;
00101 
00102   //: the fitting method
00103   bool fit();
00104 
00105   // Data Access---------------------------------------------------------------
00106 
00107   vgl_conic<T> conic() const { return conic_; }
00108 
00109   // Debug support
00110   void print_pointset(vcl_ostream& str = vcl_cout );
00111  protected:
00112   // Internals
00113   void init();
00114   void compute_partial_sums();
00115   void fill_scatter_matrix();
00116   void set_sampson_error(T a, T b, T c, T d, T e, T f);
00117 
00118   // Data Members--------------------------------------------------------------
00119 
00120   //: The current set of points
00121   vcl_vector<vgl_point_2d<T> > points_;
00122 
00123   //: Size of point set
00124   unsigned npts_;
00125 
00126   //: The normalizing transformation
00127   vgl_norm_trans_2d<T> trans_;
00128 
00129   //: The partial scatter term sums, updated with each ::add_point
00130   vcl_vector<T> partial_sums_;
00131 
00132   //: The fitting matrices
00133   vnl_matrix_fixed<T,3,3> S11_, S12_, S22_;
00134   vnl_matrix_fixed<T,3,3> Dinv_;
00135 
00136   //: The fitted conic in the un-normalized frame
00137   vgl_conic<T> conic_;
00138 
00139   //: The algebraic fitting cost in the normalized frame
00140   T cost_;
00141 
00142   //: The Sampson approximation to Euclidean distance in the normalized frame
00143   T sampson_error_;
00144 
00145   //: Normalized points
00146   vcl_vector<vgl_homg_point_2d<T> > hnorm_points_;
00147 };
00148 
00149 #define VGL_CONIC_2D_REGRESSION_INSTANTIATE(T) extern "please include vgl/algo/vgl_conic_2d_regression.txx first"
00150 
00151 #endif // vgl_conic_2d_regression_h_