vgl_conic_2d_regression.hxx
Go to the documentation of this file.
1 // This is core/vgl/algo/vgl_conic_2d_regression.hxx
2 #ifndef vgl_conic_2d_regression_hxx_
3 #define vgl_conic_2d_regression_hxx_
4 //:
5 // \file
6 
7 #include <iostream>
8 #include <algorithm>
10 #ifdef _MSC_VER
11 # include <vcl_msvc_warnings.h>
12 #endif
13 #include <vnl/vnl_vector_fixed.h>
14 #include <vnl/vnl_inverse.h>
15 #include <vnl/vnl_numeric_traits.h>
16 #include <vnl/algo/vnl_svd.h>
17 #include <vgl/vgl_distance.h>
19 
20 template <class T>
22 {
23  partial_sums_.resize(14, 0.0);
24  npts_ = 0;
25  Dinv_.fill(0.0);
26  Dinv_.put(0,0,0.5); Dinv_.put(1,1,1.0); Dinv_.put(2,2,0.5);
27  cost_ = 0;
28  sampson_error_ = 0;
29 }
30 
31 
32 //--------------------------------------------------------------
33 //: Constructors
34 template <class T>
36 {
37  this->init();
38 }
39 
40 // == OPERATIONS ==
41 
42 template <class T>
44 {
45  points_.clear();
46  npts_ = 0;
47 }
48 
49 // get the estimated error with respect to the fitted conic segment
50 template <class T>
52 {
55  // make sure point is not ideal - if it is, return a very large number
56  if (hp.w() == 0 || hc.w() == 0) {
57  return vnl_numeric_traits<T>::maxval;
58  }
59  return static_cast<T>(vgl_distance(hp, hc));
60 }
61 
62 // The Sampson approximation to mean Euclidean distance
63 // The conic coefficients are for the original frame
64 template <class T>
65 void vgl_conic_2d_regression<T>::set_sampson_error(T a, T b, T c, T d, T e, T f)
66 {
67  T sum = 0;
68  //remove warnings on implicit typename
69  typename std::vector<vgl_point_2d<T> >::iterator pit;
70  for (pit = points_.begin(); pit != points_.end(); ++pit)
71  {
72  T x = pit->x(), y = pit->y();
73  T alg_dist = (a*x + b*y + d)*x + (c*y + e)*y + f;
74  T two = static_cast<T>(2);//eliminate warning
75  T dx = two*a*x + b*y + d;
76  T dy = two*c*y + b*x + e;
77  T grad_mag_sqrd = dx*dx+dy*dy;
78  sum += (alg_dist*alg_dist)/grad_mag_sqrd;
79  }
80  if (npts_)
81  {
82  sampson_error_ = static_cast<T>(std::sqrt(sum/npts_));
83  return;
84  }
85  sampson_error_ = vnl_numeric_traits<T>::maxval;
86 }
87 
88 template <class T>
90 {
91  points_.push_back(p);
92  ++npts_;
93 }
94 
95 template <class T>
97 {
98  //remove warnings on implicit typename
99  typename std::vector<vgl_point_2d<T> >::iterator result;
100  result = std::find(points_.begin(), points_.end(), p);
101  if (result != points_.end())
102  points_.erase(result);
103  if (npts_>0)
104  --npts_;
105 }
106 
107 // get the current rms algebraic fitting error
108 template <class T>
110 {
111  return cost_;
112 }
113 
114 template <class T>
116 {
117  hnorm_points_.clear();
118  //Compute the normalizing transformation
119  std::vector<vgl_homg_point_2d<T> > hpoints;
120  //remove warnings on implicit typename
121  typename std::vector<vgl_point_2d<T> >::iterator pit;
122  for (pit = points_.begin(); pit != points_.end(); ++pit)
123  {
124  hpoints.push_back(vgl_homg_point_2d<T>(*pit));
125  }
126  trans_.compute_from_points(hpoints, false);
127 
128  //Transform the input pointset
129  for (typename std::vector<vgl_homg_point_2d<T> >::iterator pit = hpoints.begin();
130  pit != hpoints.end(); ++pit)
131  hnorm_points_.push_back(trans_(*pit));
132 
133  for (typename std::vector<T>::iterator dit = partial_sums_.begin();
134  dit != partial_sums_.end(); ++dit)
135  (*dit)=0;
136 
137  T x2,y2,x3,y3;
138  for (typename std::vector<vgl_homg_point_2d<T> >::iterator pit = hnorm_points_.begin();
139  pit != hnorm_points_.end(); ++pit)
140  {
141  T x = pit->x()/pit->w(),
142  y = pit->y()/pit->w();
143 
144  x2 = x*x; x3 = x2*x; y2 = y*y; y3 = y2*y;
145  partial_sums_[0] += x3*x; partial_sums_[1] += x3*y;
146  partial_sums_[2] += x2*y2; partial_sums_[3] += x*y3;
147  partial_sums_[4] += y3*y; partial_sums_[5] += x3;
148  partial_sums_[6] += x2*y; partial_sums_[7] += x*y2;
149  partial_sums_[8] += y3; partial_sums_[9] += x2;
150  partial_sums_[10] += x*y; partial_sums_[11] += y2;
151  partial_sums_[12] += x; partial_sums_[13] += y;
152  }
153 }
154 
155 template <class T>
157 {
158  S11_.put(0,0,partial_sums_[0]); // x3*x
159  S11_.put(0,1,partial_sums_[1]); // x3*y
160  S11_.put(0,2,partial_sums_[2]); // x2*y2
161  S11_.put(1,0,partial_sums_[1]); // x3*y
162  S11_.put(1,1,partial_sums_[2]); // x2*y2
163  S11_.put(1,2,partial_sums_[3]); // x*y3
164  S11_.put(2,0,partial_sums_[2]); // x2*y2
165  S11_.put(2,1,partial_sums_[3]); // x*y3
166  S11_.put(2,2,partial_sums_[4]); // y3*y
167 
168  S12_.put(0,0,partial_sums_[5]); // x3
169  S12_.put(0,1,partial_sums_[6]); // x2*y
170  S12_.put(0,2,partial_sums_[9]); // x2
171  S12_.put(1,0,partial_sums_[6]); // x2*y
172  S12_.put(1,1,partial_sums_[7]); // x*y2
173  S12_.put(1,2,partial_sums_[10]);// x*y
174  S12_.put(2,0,partial_sums_[7]); // x*y2
175  S12_.put(2,1,partial_sums_[8]); // y3
176  S12_.put(2,2,partial_sums_[11]);// y2
177 
178  S22_.put(0,0,partial_sums_[9]); // x2
179  S22_.put(0,1,partial_sums_[10]); // x*y
180  S22_.put(0,2,partial_sums_[12]); // x
181  S22_.put(1,0,partial_sums_[10]); // x*y
182  S22_.put(1,1,partial_sums_[11]); // y2
183  S22_.put(1,2,partial_sums_[13]); // y
184  S22_.put(2,0,partial_sums_[12]); // x
185  S22_.put(2,1,partial_sums_[13]); // y
186  T npts = static_cast<T>(npts_);//warnings
187  S22_.put(2,2,npts); // 1
188 }
189 
190 template <class T>
192 {
193  //Can't fit a conic with fewer than 5 points
194  if (this->get_n_pts()<5)
195  return false;
196 
197  //Compute the elements of the scatter matrix from the points
198  this->compute_partial_sums();
199 
200  //Fill the scatter matrices
201  this->fill_scatter_matrix();
202 
203  //Check the condition of S22
204  T det = vnl_det(S22_);
205  if (det == static_cast<T>(0))
206  {
207  std::cout << "Singular S22 Matrix in vgl_conic_2d_regression::fit()\n";
208  return false;
209  }
210  //The Bookstein solution.
211  vnl_matrix_fixed<T,3,3> S12_T = S12_.transpose();
212  vnl_matrix_fixed<T,3,3> S_lambda =
213  Dinv_*(S11_- S12_*(vnl_inverse(S22_)*S12_T));
214 
215  vnl_svd<T> svd(S_lambda.as_ref()); // size 3x3
216  cost_ = svd.sigma_min();
217  vnl_vector_fixed<T,3> v1 = svd.nullvector();
218  vnl_vector_fixed<T,3> v2 = - vnl_inverse(S22_)*S12_T*v1;
219  vgl_conic<T> nc(v1[0], v1[1], v1[2], v2[0], v2[1], v2[2]);
220 
221  //Transform back to original frame
222  // We have xn^t nc xn = 0 in the normalized frame
223  // But xn = trans_ x;
224  // So (trans_ x )^t nc (trans_ x) = 0
225  // Thus x^t ( (trans_)^t nc trans_ ) x = 0;
226  // so c = trans_(nc);
227 
228  conic_ = trans_(nc);
229 
230  //Set the Sampson approximation to fitting error
231  this->set_sampson_error(conic_.a(), conic_.b(), conic_.c(),
232  conic_.d(), conic_.e(), conic_.f());
233 
234  return true;
235 }
236 
237 template <class T>
239 {
240  str << "Current Pointset has " << npts_ << " points\n";
241  //remove warnings on implicit typename
242  typename std::vector<vgl_point_2d<T> >::iterator pit;
243  for (pit = points_.begin(); pit != points_.end(); ++pit)
244  str << *pit << '\n';
245 }
246 
247 //--------------------------------------------------------------------------
248 #undef VGL_CONIC_2D_REGRESSION_INSTANTIATE
249 #define VGL_CONIC_2D_REGRESSION_INSTANTIATE(T) \
250 template class vgl_conic_2d_regression<T >
251 
252 #endif // vgl_conic_2d_regression_hxx_
void remove_point(vgl_point_2d< T > const &p)
2D homogeneous operations
void add_point(vgl_point_2d< T > const &p)
static vgl_homg_point_2d< T > closest_point(vgl_homg_line_2d< T > const &l, vgl_homg_point_2d< T > const &p)
Return the point on the line closest to the given point.
T get_rms_error_est(vgl_point_2d< T > const &p) const
get the estimated Euclidean error with respect to the fitted conic segment in the original frame.
void clear_points()
clear the regression data.
bool fit()
the fitting method.
void set_sampson_error(T a, T b, T c, T d, T e, T f)
Fits a conic to a set of points using linear regression.
A quadratic plane curve.
Definition: vgl_conic.h:70
double vgl_distance(vgl_point_2d< T >const &p1, vgl_point_2d< T >const &p2)
return the distance between two points.
Definition: vgl_distance.h:104
void print_pointset(std::ostream &str=std::cout)
Set of distance functions.
Represents a homogeneous 2D point.
Definition: vgl_fwd.h:8
T get_rms_algebraic_error() const
get the current algebraic fitting error in the normalized frame.