core/vgl/algo/vgl_conic_2d_regression.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_conic_2d_regression.txx
00002 #ifndef vgl_conic_2d_regression_txx_
00003 #define vgl_conic_2d_regression_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_conic_2d_regression.h"
00008 #include <vcl_iostream.h>
00009 #include <vcl_algorithm.h>
00010 #include <vnl/vnl_vector_fixed.h>
00011 #include <vnl/vnl_inverse.h>
00012 #include <vnl/vnl_numeric_traits.h>
00013 #include <vnl/algo/vnl_svd.h>
00014 #include <vgl/vgl_distance.h>
00015 #include <vgl/algo/vgl_homg_operators_2d.h>
00016 
00017 template <class T>
00018 void vgl_conic_2d_regression<T>::init()
00019 {
00020   partial_sums_.resize(14, 0.0);
00021   npts_ = 0;
00022   Dinv_.fill(0.0);
00023   Dinv_.put(0,0,0.5);  Dinv_.put(1,1,1.0);  Dinv_.put(2,2,0.5);
00024   cost_ = 0;
00025   sampson_error_ = 0;
00026 }
00027 
00028 
00029 //--------------------------------------------------------------
00030 //: Constructors
00031 template <class T>
00032 vgl_conic_2d_regression<T>::vgl_conic_2d_regression()
00033 {
00034   this->init();
00035 }
00036 
00037 // == OPERATIONS ==
00038 
00039 template <class T>
00040 void vgl_conic_2d_regression<T>::clear_points()
00041 {
00042   points_.clear();
00043   npts_ = 0;
00044 }
00045 
00046 // get the estimated error with respect to the fitted conic segment
00047 template <class T>
00048 T vgl_conic_2d_regression<T>::get_rms_error_est(vgl_point_2d<T> const& p) const
00049 {
00050   vgl_homg_point_2d<T> hp(p);
00051   vgl_homg_point_2d<T> hc = vgl_homg_operators_2d<T>::closest_point(conic_, p);
00052   return static_cast<T>(vgl_distance(hp, hc));
00053 }
00054 
00055 // The Sampson approximation to mean Euclidean distance
00056 // The conic coefficients are for the original frame
00057 template <class T>
00058 void vgl_conic_2d_regression<T>::set_sampson_error(T a, T b, T c, T d, T e, T f)
00059 {
00060   T sum = 0;
00061   //remove warnings on implicit typename
00062   typename vcl_vector<vgl_point_2d<T> >::iterator pit;
00063   for (pit = points_.begin(); pit != points_.end(); ++pit)
00064   {
00065     T x = pit->x(), y = pit->y();
00066     T alg_dist = (a*x + b*y + d)*x + (c*y + e)*y + f;
00067     T two = static_cast<T>(2);//eliminate warning
00068     T dx = two*a*x + b*y + d;
00069     T dy = two*c*y + b*x + e;
00070     T grad_mag_sqrd = dx*dx+dy*dy;
00071     sum += (alg_dist*alg_dist)/grad_mag_sqrd;
00072   }
00073   if (npts_)
00074   {
00075     sampson_error_ = static_cast<T>(vcl_sqrt(sum/npts_));
00076     return;
00077   }
00078   sampson_error_ = vnl_numeric_traits<T>::maxval;
00079 }
00080 
00081 template <class T>
00082 void vgl_conic_2d_regression<T>::add_point(vgl_point_2d<T> const& p)
00083 {
00084   points_.push_back(p);
00085   ++npts_;
00086 }
00087 
00088 template <class T>
00089 void vgl_conic_2d_regression<T>::remove_point(vgl_point_2d<T> const& p)
00090 {
00091   //remove warnings on implicit typename
00092   typename vcl_vector<vgl_point_2d<T> >::iterator result;
00093   result = vcl_find(points_.begin(), points_.end(), p);
00094   if (result != points_.end())
00095     points_.erase(result);
00096   if (npts_>0)
00097     --npts_;
00098 }
00099 
00100 // get the current rms algebraic fitting error
00101 template <class T>
00102 T vgl_conic_2d_regression<T>::get_rms_algebraic_error() const
00103 {
00104   return cost_;
00105 }
00106 
00107 template <class T>
00108 void vgl_conic_2d_regression<T>::compute_partial_sums()
00109 {
00110   hnorm_points_.clear();
00111   //Compute the normalizing transformation
00112   vcl_vector<vgl_homg_point_2d<T> > hpoints;
00113   //remove warnings on implicit typename
00114   typename vcl_vector<vgl_point_2d<T> >::iterator pit;
00115   for (pit = points_.begin(); pit != points_.end(); ++pit)
00116   {
00117     hpoints.push_back(vgl_homg_point_2d<T>(*pit));
00118   }
00119   trans_.compute_from_points(hpoints, false);
00120 
00121   //Transform the input pointset
00122   for (typename vcl_vector<vgl_homg_point_2d<T> >::iterator pit = hpoints.begin();
00123        pit != hpoints.end(); ++pit)
00124     hnorm_points_.push_back(trans_(*pit));
00125 
00126   for (typename vcl_vector<T>::iterator dit = partial_sums_.begin();
00127        dit != partial_sums_.end(); ++dit)
00128     (*dit)=0;
00129 
00130   T x2,y2,x3,y3;
00131   for (typename vcl_vector<vgl_homg_point_2d<T> >::iterator pit = hnorm_points_.begin();
00132        pit != hnorm_points_.end(); ++pit)
00133   {
00134     T x = pit->x()/pit->w(),
00135       y = pit->y()/pit->w();
00136 
00137     x2 = x*x;  x3 = x2*x;  y2 = y*y;  y3 = y2*y;
00138     partial_sums_[0] += x3*x;   partial_sums_[1] += x3*y;
00139     partial_sums_[2] += x2*y2;  partial_sums_[3] += x*y3;
00140     partial_sums_[4] += y3*y;   partial_sums_[5] += x3;
00141     partial_sums_[6] += x2*y;   partial_sums_[7] += x*y2;
00142     partial_sums_[8] += y3;     partial_sums_[9] += x2;
00143     partial_sums_[10] += x*y;   partial_sums_[11] += y2;
00144     partial_sums_[12] += x;     partial_sums_[13] += y;
00145   }
00146 }
00147 
00148 template <class T>
00149 void vgl_conic_2d_regression<T>::fill_scatter_matrix()
00150 {
00151   S11_.put(0,0,partial_sums_[0]); // x3*x
00152   S11_.put(0,1,partial_sums_[1]); // x3*y
00153   S11_.put(0,2,partial_sums_[2]); // x2*y2
00154   S11_.put(1,0,partial_sums_[1]); // x3*y
00155   S11_.put(1,1,partial_sums_[2]); // x2*y2
00156   S11_.put(1,2,partial_sums_[3]); // x*y3
00157   S11_.put(2,0,partial_sums_[2]); // x2*y2
00158   S11_.put(2,1,partial_sums_[3]); // x*y3
00159   S11_.put(2,2,partial_sums_[4]); // y3*y
00160 
00161   S12_.put(0,0,partial_sums_[5]); // x3
00162   S12_.put(0,1,partial_sums_[6]); // x2*y
00163   S12_.put(0,2,partial_sums_[9]); // x2
00164   S12_.put(1,0,partial_sums_[6]); // x2*y
00165   S12_.put(1,1,partial_sums_[7]); // x*y2
00166   S12_.put(1,2,partial_sums_[10]);// x*y
00167   S12_.put(2,0,partial_sums_[7]); // x*y2
00168   S12_.put(2,1,partial_sums_[8]); // y3
00169   S12_.put(2,2,partial_sums_[11]);// y2
00170 
00171   S22_.put(0,0,partial_sums_[9]);  // x2
00172   S22_.put(0,1,partial_sums_[10]); // x*y
00173   S22_.put(0,2,partial_sums_[12]); // x
00174   S22_.put(1,0,partial_sums_[10]); // x*y
00175   S22_.put(1,1,partial_sums_[11]); // y2
00176   S22_.put(1,2,partial_sums_[13]); // y
00177   S22_.put(2,0,partial_sums_[12]); // x
00178   S22_.put(2,1,partial_sums_[13]); // y
00179   T npts = static_cast<T>(npts_);//warnings
00180   S22_.put(2,2,npts); // 1
00181 }
00182 
00183 template <class T>
00184 bool vgl_conic_2d_regression<T>::fit()
00185 {
00186   //Can't fit a conic with fewer than 5 points
00187   if (this->get_n_pts()<5)
00188     return false;
00189 
00190   //Compute the elements of the scatter matrix from the points
00191   this->compute_partial_sums();
00192 
00193   //Fill the scatter matrices
00194   this->fill_scatter_matrix();
00195 
00196   //Check the condition of S22
00197   T det = vnl_det(S22_);
00198   if (det == static_cast<T>(0))
00199   {
00200     vcl_cout << "Singular S22 Matrix in vgl_conic_2d_regression::fit()\n";
00201     return false;
00202   }
00203   //The Bookstein solution.
00204   vnl_matrix_fixed<T,3,3> S12_T = S12_.transpose();
00205   vnl_matrix_fixed<T,3,3> S_lambda =
00206     Dinv_*(S11_- S12_*(vnl_inverse(S22_)*S12_T));
00207 
00208   vnl_svd<T> svd(S_lambda.as_ref()); // size 3x3
00209   cost_ = svd.sigma_min();
00210   vnl_vector_fixed<T,3> v1 = svd.nullvector();
00211   vnl_vector_fixed<T,3> v2 = - vnl_inverse(S22_)*S12_T*v1;
00212   vgl_conic<T> nc(v1[0], v1[1], v1[2], v2[0], v2[1], v2[2]);
00213 
00214   //Transform back to original frame
00215   // We have xn^t nc xn = 0 in the normalized frame
00216   // But xn = trans_  x;
00217   // So (trans_ x )^t  nc  (trans_ x) = 0
00218   // Thus x^t ( (trans_)^t nc trans_ ) x = 0;
00219   // so c = trans_(nc);
00220 
00221   conic_ = trans_(nc);
00222 
00223   //Set the Sampson approximation to fitting error
00224   this->set_sampson_error(conic_.a(), conic_.b(), conic_.c(),
00225                           conic_.d(), conic_.e(), conic_.f());
00226 
00227   return true;
00228 }
00229 
00230 template <class T>
00231 void vgl_conic_2d_regression<T>::print_pointset(vcl_ostream& str)
00232 {
00233   str << "Current Pointset has " << npts_ << " points\n";
00234   //remove warnings on implicit typename
00235   typename vcl_vector<vgl_point_2d<T> >::iterator pit;
00236   for (pit = points_.begin(); pit != points_.end(); ++pit)
00237     str << *pit << '\n';
00238 }
00239 
00240 //--------------------------------------------------------------------------
00241 #undef VGL_CONIC_2D_REGRESSION_INSTANTIATE
00242 #define VGL_CONIC_2D_REGRESSION_INSTANTIATE(T) \
00243 template class vgl_conic_2d_regression<T >
00244 
00245 #endif // vgl_conic_2d_regression_txx_