vgl_fit_conics_2d.hxx
Go to the documentation of this file.
1 // This is core/vgl/algo/vgl_fit_conics_2d.hxx
2 #ifndef vgl_fit_conics_2d_hxx_
3 #define vgl_fit_conics_2d_hxx_
4 //:
5 // \file
6 
7 #include <iostream>
8 #include "vgl_fit_conics_2d.h"
9 #include <vgl/vgl_vector_2d.h>
11 #ifdef _MSC_VER
12 # include <vcl_msvc_warnings.h>
13 #endif
14 #include <cassert>
15 
16 //--------------------------------------------------------------
17 //: Constructor
18 template <class T>
19 vgl_fit_conics_2d<T>::vgl_fit_conics_2d(const unsigned min_length,
20  const T tol)
21  : min_length_(min_length), tol_(tol)
22 {
23 }
24 
25 // == OPERATIONS ==
26 
27 //: add point
28 template <class T>
30 {
31  curve_.push_back(p);
32 #ifdef DEBUG
33  std::cout << p << '\n';
34 #endif
35 }
36 
37 //: add point
38 template <class T>
40 {
41  curve_.push_back(vgl_point_2d<T>(x, y));
42 }
43 
44 //: clear
45 template <class T>
47 {
48  curve_.clear();
49  segs_.clear();
50 }
51 
52 template <class T>
53 void vgl_fit_conics_2d<T>::output(const unsigned start_index,
54  const unsigned end_index,
55  vgl_conic<T> const& conic)
56 {
57  assert(start_index < curve_.size() && end_index <= curve_.size());
58 
59  vgl_homg_point_2d<T> center = conic.centre();
60  if (center.ideal(static_cast<T>(1e-06)))
61  {
62  std::cout << "Can't output a conic at infinity in vgl_fit_conics<T>\n";
63  return;
64  }
65 
66  //Need to establish the sense of the fitted curve
67  //The curve should proceed in a counter-clockwise direction from p1 to p2.
68  // 1) choose a point in the middle of the curve
69  int middle_index = (end_index-1-start_index)/2 + start_index;
70  if (middle_index == static_cast<int>(start_index))
71  middle_index = end_index-1;
72  vgl_point_2d<T> pm = curve_[middle_index];
73  // 2) construct a vector from the middle to ps
74  vgl_point_2d<T> ps = curve_[start_index], pe = curve_[end_index-1];
75  vgl_vector_2d<T> vms(ps.x()-pm.x(), ps.y()-pm.y());
76  // 3) construct a vector from the middle to pe
77  vgl_vector_2d<T> vme(pe.x()-pm.x(), pe.y()-pm.y());
78  //The cross product should be negative and significant
79  T cp = cross_product(vms, vme);
80 
81  //If not, exchange p1 and p2
82  unsigned i1=start_index, i2 = end_index-1;
83  if (cp > 1e-04)
84  {
85  i1 = end_index-1;
86  i2 = start_index;
87  }
88 
89 
90  // unsigned i1=start_index, i2 = end_index-1;
91  vgl_conic_segment_2d<T> e_seg(curve_[i1], curve_[i2], conic);
92 #ifdef DEBUG
93  std::cout << "output " << e_seg << '\n';
94 #endif
95  segs_.push_back(e_seg);
96 }
97 
98 template <class T>
100 {
101  if (curve_.size()<min_length_)
102  {
103  std::cout << "In vgl_fit_conics_2d<T>::fit() - number of points < min_length "
104  << min_length_ << '\n';
105  return false;
106  }
107  //A helper to hold points and do the linear regression
109 
110  // Start at the beginning of the curve with
111  // a segment with minimum number of points
112  unsigned int ns = 0, nf = min_length_, cur_len = curve_.size();
113  for (unsigned int i = ns; i<nf; ++i)
114  reg.add_point(curve_[i]);
115  //The main loop
116  while (nf<=cur_len)
117  {
118  if (reg.fit()&&reg.get_rms_sampson_error()<tol_)
119  {
120  if (nf==cur_len)
121  {
122  output(ns, nf, reg.conic());
123  return true;
124  }
125 #ifdef DEBUG
126  std::cout << "Initial fit error " << reg.get_rms_sampson_error()
127  << " for\n" << reg.conic() << '\n';
128 #endif
129  bool below_error_tol = true;
130  bool data_added = false;
131  while (nf<cur_len&&below_error_tol)
132  {
133  vgl_point_2d<T>& p = curve_[nf];
134  //if the point can be added without exeeding the threshold, do so
135  T error = reg.get_rms_error_est(p);
136  below_error_tol = error<tol_;
137  if (below_error_tol)
138  {
139  reg.add_point(p);
140  data_added = true;
141  nf++;
142 #ifdef DEBUG
143  std::cout << "Adding point " << p << "with estimated error "
144  << error << '\n';
145 #endif
146  }
147  }
148  //if no points were added output the conic
149  //and initialize a new fit
150  if (!data_added)
151  {
152  output(ns, nf, reg.conic());
153  ns = nf-1; nf=ns+min_length_;
154  if (nf<=cur_len)
155  {
156  reg.clear_points();
157  for (unsigned int i = ns; i<nf; i++)
158  reg.add_point(curve_[i]);
159  }
160  }
161  }
162  // Else the fit is not good enough. We therefore remove the first
163  // point and add or delete points from the end of the current line
164  // segment until the resulting segment length is _min_fit_length
165  else
166  {
167  reg.remove_point(curve_[ns]);
168  ns++;
169  if (reg.get_n_pts()>min_length_)
170  while (reg.get_n_pts()>min_length_+1)
171  {
172  nf--;
173  reg.remove_point(curve_[nf]);
174  }
175  else if (nf<cur_len)
176  {
177  reg.add_point(curve_[nf]);
178  nf++;
179  }
180  else
181  nf++;
182  }
183  }
184  return true;
185 }
186 
187 //--------------------------------------------------------------------------
188 #undef VGL_FIT_CONICS_2D_INSTANTIATE
189 #define VGL_FIT_CONICS_2D_INSTANTIATE(T) \
190 template class vgl_fit_conics_2d<T >
191 
192 #endif // vgl_fit_conics_2d_hxx_
void remove_point(vgl_point_2d< T > const &p)
void output(const unsigned start_index, const unsigned end_index, vgl_conic< T > const &conic)
output a conic that fits from start to end.
vgl_fit_conics_2d(const unsigned min_length=10, const T tol=0.01)
Constructor.
Direction vector in Euclidean 2D space, templated by type of element.
Definition: vgl_fwd.h:12
void add_point(vgl_point_2d< T > const &p)
T get_rms_sampson_error() const
get the current Euclidean fitting error in the original frame.
unsigned get_n_pts() const
Number of regression points.
vgl_conic< T > conic() const
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.
vgl_homg_point_2d< T > centre() const
Returns the centre of the conic, or its point at infinity if a parabola.
Definition: vgl_conic.h:245
Represents a 2D conic segment using two points.
Fits a conic to a set of points using linear regression.
T cross_product(v const &a, v const &b)
cross product of two vectors (area of enclosed parallellogram).
void add_point(vgl_point_2d< T > const &p)
add a point to the curve.
Fits a contiguous set of conic segments to a sampled curve.
Type & y()
Definition: vgl_point_2d.h:72
A quadratic plane curve.
Definition: vgl_conic.h:70
direction vector in Euclidean 2D space
bool fit()
the fitting method.
void clear()
clear internal data.
Represents a homogeneous 2D point.
Definition: vgl_fwd.h:8
Type & x()
Definition: vgl_point_2d.h:71