core/vgl/algo/vgl_fit_conics_2d.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_fit_conics_2d.txx
00002 #ifndef vgl_fit_conics_2d_txx_
00003 #define vgl_fit_conics_2d_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_fit_conics_2d.h"
00008 #include <vgl/vgl_vector_2d.h>
00009 #include <vgl/algo/vgl_conic_2d_regression.h>
00010 #include <vcl_iostream.h>
00011 #include <vcl_cassert.h>
00012 
00013 //--------------------------------------------------------------
00014 //: Constructor
00015 template <class T>
00016 vgl_fit_conics_2d<T>::vgl_fit_conics_2d(const unsigned min_length,
00017                                         const T tol)
00018   :  min_length_(min_length), tol_(tol)
00019 {
00020 }
00021 
00022 // == OPERATIONS ==
00023 
00024 //: add point
00025 template <class T>
00026 void vgl_fit_conics_2d<T>::add_point(vgl_point_2d<T> const& p)
00027 {
00028   curve_.push_back(p);
00029 #ifdef DEBUG
00030   vcl_cout << p << '\n';
00031 #endif
00032 }
00033 
00034 //: add point
00035 template <class T>
00036 void vgl_fit_conics_2d<T>::add_point(T x, T y)
00037 {
00038   curve_.push_back(vgl_point_2d<T>(x, y));
00039 }
00040 
00041 //: clear
00042 template <class T>
00043 void vgl_fit_conics_2d<T>::clear()
00044 {
00045   curve_.clear();
00046   segs_.clear();
00047 }
00048 
00049 template <class T>
00050 void vgl_fit_conics_2d<T>::output(const unsigned start_index,
00051                                   const unsigned end_index,
00052                                   vgl_conic<T> const& conic)
00053 {
00054   assert(start_index < curve_.size() && end_index <= curve_.size());
00055 
00056   vgl_homg_point_2d<T> center = conic.centre();
00057   if (center.ideal(static_cast<T>(1e-06)))
00058   {
00059     vcl_cout << "Can't output a conic at infinity in vgl_fit_conics<T>\n";
00060     return;
00061   }
00062 
00063   //Need to establish the sense of the fitted curve
00064   //The curve should proceed in a counter-clockwise direction from p1 to p2.
00065   // 1) choose a point in the middle of the curve
00066   int middle_index = (end_index-1-start_index)/2 + start_index;
00067   if (middle_index == static_cast<int>(start_index))
00068     middle_index = end_index-1;
00069   vgl_point_2d<T> pm = curve_[middle_index];
00070   // 2) construct a vector from the middle to ps
00071   vgl_point_2d<T> ps = curve_[start_index], pe = curve_[end_index-1];
00072   vgl_vector_2d<T> vms(ps.x()-pm.x(), ps.y()-pm.y());
00073   // 3) construct a vector from the middle to pe
00074   vgl_vector_2d<T> vme(pe.x()-pm.x(), pe.y()-pm.y());
00075   //The cross product should be negative and significant
00076   T cp = cross_product(vms, vme);
00077 
00078   //If not, exchange p1 and p2
00079   unsigned i1=start_index, i2 = end_index-1;
00080   if (cp > 1e-04)
00081   {
00082     i1 = end_index-1;
00083     i2 = start_index;
00084   }
00085 
00086 
00087   //   unsigned i1=start_index, i2 = end_index-1;
00088   vgl_conic_segment_2d<T> e_seg(curve_[i1], curve_[i2], conic);
00089 #ifdef DEBUG
00090   vcl_cout << "output " << e_seg << '\n';
00091 #endif
00092   segs_.push_back(e_seg);
00093 }
00094 
00095 template <class T>
00096 bool vgl_fit_conics_2d<T>::fit()
00097 {
00098   if (curve_.size()<min_length_)
00099   {
00100     vcl_cout << "In vgl_fit_conics_2d<T>::fit() - number of points < min_length "
00101              << min_length_ << '\n';
00102     return false;
00103   }
00104   //A helper to hold points and do the linear regression
00105   vgl_conic_2d_regression<T> reg;
00106 
00107   // Start at the beginning of the curve with
00108   // a segment with minimum number of points
00109   unsigned int ns = 0, nf = min_length_, cur_len = curve_.size();
00110   for (unsigned int i = ns; i<nf; ++i)
00111     reg.add_point(curve_[i]);
00112   //The main loop
00113   while (nf<=cur_len)
00114   {
00115     if (reg.fit()&&reg.get_rms_sampson_error()<tol_)
00116     {
00117       if (nf==cur_len)
00118       {
00119         output(ns, nf, reg.conic());
00120         return true;
00121       }
00122 #ifdef DEBUG
00123       vcl_cout << "Initial fit error " << reg.get_rms_sampson_error()
00124                << " for\n" << reg.conic() << '\n';
00125 #endif
00126       bool below_error_tol = true;
00127       bool data_added = false;
00128       while (nf<cur_len&&below_error_tol)
00129       {
00130         vgl_point_2d<T>& p = curve_[nf];
00131         //if the point can be added without exeeding the threshold, do so
00132         T error = reg.get_rms_error_est(p);
00133         below_error_tol = error<tol_;
00134         if (below_error_tol)
00135         {
00136           reg.add_point(p);
00137           data_added = true;
00138           nf++;
00139 #ifdef DEBUG
00140           vcl_cout << "Adding point " << p << "with estimated error "
00141                    << error << '\n';
00142 #endif
00143         }
00144       }
00145        //if no points were added output the conic
00146        //and initialize a new fit
00147       if (!data_added)
00148       {
00149         output(ns, nf, reg.conic());
00150         ns = nf-1; nf=ns+min_length_;
00151         if (nf<=cur_len)
00152         {
00153           reg.clear_points();
00154           for (unsigned int i = ns; i<nf; i++)
00155             reg.add_point(curve_[i]);
00156         }
00157       }
00158     }
00159         // Else the fit is not good enough. We therefore remove the first
00160     // point and add or delete points from the end of the current line
00161     // segment until the resulting segment length is _min_fit_length
00162     else
00163     {
00164       reg.remove_point(curve_[ns]);
00165       ns++;
00166       if (reg.get_n_pts()>min_length_)
00167         while (reg.get_n_pts()>min_length_+1)
00168         {
00169           nf--;
00170           reg.remove_point(curve_[nf]);
00171         }
00172       else if (nf<cur_len)
00173       {
00174         reg.add_point(curve_[nf]);
00175         nf++;
00176       }
00177       else
00178         nf++;
00179     }
00180   }
00181   return true;
00182 }
00183 
00184 //--------------------------------------------------------------------------
00185 #undef VGL_FIT_CONICS_2D_INSTANTIATE
00186 #define VGL_FIT_CONICS_2D_INSTANTIATE(T) \
00187 template class vgl_fit_conics_2d<T >
00188 
00189 #endif // vgl_fit_conics_2d_txx_