Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Conic2D.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "Conic2D.hh"
27 #include <Base/Geometry/HomgLine2D.hh>
28 #include <float.h>
29 #include <MathAlgo/PolynomialSolve.hh>
30 #include <MathAlgo/SVD.hh>
31 #include <Base/Math/Matrix2x2.hh>
32 #include <Base/Geometry/HomgPoint2D.hh>
33 #include <Base/Image/Image.hh>
34 #include <Geometry/Quadric3D.hh>
35 #include <Geometry/PMatrix.hh>
36 #include <Geometry/FMatrixEstimation.hh>
37 
38 #define SVD_ZERO_THRESH DBL_EPSILON * 16.0
39 
40 using namespace BIAS;
41 using namespace std;
42 
44 {
45  return ((*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[0][1]);
46 }
47 
48 bool Conic2D::IsDoubleLine() const {
49  // degenerate case ?
50  if (fabs(GetDeterminant())>DBL_EPSILON) {
51  // rank < 3
52  //cout << "rank<3, Det=" <<det()<<endl;
53  return false;
54  }
55  if (GetSignature() != 0) {
56  // Degenerated case
57  //cout << "Degenerated case" <<GetSignature()<<endl;
58  return false;
59  }
60  return true;
61 }
62 
63 bool Conic2D::IsSingleLine() const {
64  // degenerate case ?
65  if (fabs(GetDeterminant())>DBL_EPSILON) {
66  // rank < 3
67  //cout << "rank<3, Det=" <<det()<<endl;
68  return false;
69  }
70  if (GetSignature() != 1) {
71  // Degenerated case
72  //cout << "Degenerated case" <<GetSignature()<<endl;
73  return false;
74  }
75  return true;
76 }
77 
78 bool Conic2D::IsPoint() const {
79  // degenerate case ?
80  if (fabs(GetDeterminant())>DBL_EPSILON) {
81  // rank < 3
82  //cout << "rank<3, Det=" <<det()<<endl;
83  return false;
84  }
85  if (GetSignature() != 2) {
86  // Degenerated case
87  //cout << "Degenerated case" <<GetSignature()<<endl;
88  return false;
89  }
90  return true;
91 }
92 
93 bool Conic2D::IsEllipse() const {
94  // degenerate case ?
95  if (fabs(GetDeterminant())<=DBL_EPSILON) {
96  // rank < 3
97  //cout << "rank<3, Det=" <<det()<<endl;
98  return false;
99  }
100 
101  if (GetSignature() != 1) {
102  // Degenerated case
103  //cout << "Degenerated case" <<GetSignature()<<endl;
104  return false;
105  }
106 
107  // parabola or hyperbola ?
108  if (GetDiscriminant()<-DBL_EPSILON) {
109  //cerr <<"GetDiscriminant"<<endl;
110  return false;
111  }
112  if ((*this)[0][0]+(*this)[1][1]>0.0) {
113  // ok, should be ellipse
114  return true;
115  }
116  // must be empty set
117  //cerr <<(*this)[0][0] << "/" << (*this)[1][1]<<endl;
118  return false;
119 }
120 
121 bool Conic2D::IsParabola() const {
122  // degenerate case ?
123  if (fabs(GetDeterminant())<=DBL_EPSILON) {
124  // rank < 3
125  //cout << "rank<3, Det=" <<det()<<endl;
126  return false;
127  }
128 
129  if (GetSignature() != 1) {
130  // Degenerated case
131  //cout << "Degenerated case" <<GetSignature()<<endl;
132  return false;
133  }
134 
135  if (fabs(GetDiscriminant())<DBL_EPSILON) {
136  //cerr <<"GetDiscriminant"<<endl;
137  return true;
138  }
139  return false;
140 }
141 
142 bool Conic2D::IsHyperbola() const {
143  // degenerate case ?
144  if (fabs(GetDeterminant())<=DBL_EPSILON) {
145  // rank < 3
146  //cout << "rank<3, Det=" <<det()<<endl;
147  return false;
148  }
149 
150  if (GetSignature() != 1) {
151  // Degenerated case
152  //cout << "Degenerated case" <<GetSignature()<<endl;
153  return false;
154  }
155 
156  // parabola or hyperbola ?
157  if (GetDiscriminant()>=-DBL_EPSILON) {
158  //cerr <<"GetDiscriminant"<<endl;
159  return false;
160  }
161  return true;
162 }
163 
164 bool Conic2D::IsEmpty() const {
165  // degenerate case ?
166  if (fabs(GetDeterminant())<=DBL_EPSILON) {
167  // rank < 3
168  //cout << "rank<3, Det=" <<det()<<endl;
169  return false;
170  }
171  if (GetSignature() != 3) {
172  // Degenerated case
173  //cout << "Degenerated case" <<GetSignature()<<endl;
174  return false;
175  }
176  return true;
177 }
178 
179 bool Conic2D::IsProper() const {
180  double norm = this->NormFrobenius();
181  if (fabs(norm)<1e-9) return false;
182  //cout<<"det is "<<det()<<" norm is "<<norm<<endl;
183  return (fabs(GetDeterminant() / (norm*norm*norm))>1e-9);
184 }
185 
187  const unsigned int Signature = GetSignature();
188  if (!IsProper()) {
189  // degenerate case: cone center is on conic
190  switch (Signature) {
191  case 1: return Conic2D::SingleLine;
192  case 2: return Conic2D::Point;
193  }
194  // must be signature 0
195  if (NormL2()>DBL_EPSILON) return Conic2D::DoubleLine;
196  // we have a zero matrix
197  return Conic2D::WholePlane;
198  } else {
199  // cone center is not on conic
200  if (Signature==3) return Conic2D::Empty; // no real points
201  const double disc = GetDiscriminant();
202  if (disc>DBL_EPSILON) return Conic2D::Ellipse;
203  if (disc<-DBL_EPSILON) return Conic2D::Hyperbola;
204  return Conic2D::Parabola;
205  }
206  // can never happen but wont produce "no return value" warning
207  // no, unreachable! (jw)
208  //return Conic2D::Unknown;
209 }
210 
211 int Conic2D::GetPoint(HomgPoint2D& thepoint) const {
212  BIASASSERT(IsPoint());
213  SVD mysvd((Matrix<CONIC2D_TYPE>)*this);
214  thepoint = mysvd.GetNullvector();
215  thepoint.Normalize();
216  if (fabs(thepoint[2])>1e-10) thepoint.Homogenize();
217  return 0;
218 }
219 
220 
222 #ifdef BIAS_DEBUG
223  if (IsEllipse()) {
224  BIASERR("Better use ImageDraw::Ellipse for Conic drawing.");
225  }
226 #endif
227 
228  const unsigned int uiHeight = img.GetHeight();
229  const unsigned int uiWidth = img.GetWidth();
230  register unsigned char** ppI = img.GetImageDataArray();
231 
232  HomgPoint2D p(0,0);
233  p.Homogenize();
234  register int LastSign = 0;
235  double dist;
236  // dumb drawing algorithm (improve this using parameterized drawing)
237  // run over all pixels and check where the sign changes
238  // wont catch all ellipses with some radius<1
239  for (register unsigned int y=0;y<uiHeight; y++) {
240  p[0] = -1; p[1] = y;
241  dist = LocatePoint(p);
242  if (dist>0.0) LastSign = 1;
243  else if (dist<0.0) LastSign = -1;
244  else LastSign = 0 ;
245  for (register unsigned int x=0; x<uiWidth; x++) {
246  p[0] = x; p[1] = y;
247  dist = LocatePoint(p);
248  if (dist<0.0) {
249  if (LastSign>0) {
250  ppI[y][x] = (ppI[y][x]>127)?0:255;
251  cout << "D";
252  }
253  LastSign = -1;
254  } else if (dist>0.0) {
255  if (LastSign<0) {
256  ppI[y][x] = (ppI[y][x]>127)?0:255;
257  cout << "D";
258  }
259  LastSign = 1;
260  } else {
261  LastSign = 0;
262  ppI[y][x] = (ppI[y][x]>127)?0:255;
263  cout << "D";
264  }
265  }
266  }
267  // run into perpendicular direction to catch x-parallel lines
268  for (register unsigned int x=0;x<uiWidth; x++) {
269  p[0] = x; p[1] = -1;
270  dist = LocatePoint(p);
271  if (dist>0.0) LastSign = 1;
272  else if (dist<0.0) LastSign = -1;
273  else LastSign = 0 ;
274  for (register unsigned int y=0; y<uiHeight; y++) {
275  p[0] = x; p[1] = y;
276  dist = LocatePoint(p);
277  // cout << dist <<" ";
278  if (dist<0.0) {
279  if (LastSign>0) {
280  ppI[y][x] = (ppI[y][x]>127)?0:255;
281  cout << "D";
282  }
283  LastSign = -1;
284  } else if (dist>0.0) {
285  if (LastSign<0) {
286  ppI[y][x] = (ppI[y][x]>127)?0:255;
287  cout << "D";
288  }
289  LastSign = 1;
290  } else {
291  LastSign = 0;
292  ppI[y][x] = (ppI[y][x]>127)?0:255;
293  cout << "D";
294  }
295  }
296  }
297 }
298 
299 void Conic2D::SetEllipse(const HomgPoint2D& Center, const double& dAngle,
300  const double& radius_a, const double& radius_b) {
301 
302  SetZero();
303  (*this)[0][0] = 1.0 / (radius_a*radius_a);
304  (*this)[1][1] = 1.0 / (radius_b*radius_b);
305  (*this)[2][2] = -1;
306 
307  Matrix3x3<double> Transform, Rotation;
308 
309  // transfer ellipse center into origin
310  Transform.SetIdentity();
311  Transform[0][2] = -Center[0];
312  Transform[1][2] = -Center[1];
313  Transform[2][2] = Center[2];
314 
315  // rotate by dAngle around origin
316  Rotation.SetIdentity();
317  Rotation[1][1] = Rotation[0][0] = cos(dAngle);
318  Rotation[0][1] = -(Rotation[1][0] = sin(dAngle));
319 
320  // first transfer, than rotate
321  Transform = Rotation * Transform;
322 
323  (*this) = (Matrix<CONIC2D_TYPE>)(Transform.Transpose() * (*this) * Transform);
324  // Point * (*this) * Point now means:
325  // (R * (T * Point)) * (this_canonic) * (R * (T * Point))
326  // where this_canonic = diag(radius_a^2, radius_b^2, -1) is the unrotated
327  // ellipse around the origin
328 }
329 
330 void Conic2D::
332  const Matrix2x2<CONIC2D_TYPE>& cov,
333  const double& dScale)
334 {
335  BIASASSERT(!center.IsAtInfinity());
336 
337  // the Euclidean image coordinates
338  CONIC2D_TYPE cx=center[0]/center[2], cy=center[1]/center[2];
339 
340  // the upper left 2 by 2 matrix of the conic always consists of the inverse
341  // covariance matrix
343  if (cov.Invert(icov)!=0){
344  BIASASSERT(cov.Invert(icov)==0);
345  }
346  const double iscale=1.0/(dScale*dScale);
347  (*this)[0][0] = icov[0][0] * iscale;
348  (*this)[0][1] = icov[0][1] * iscale;
349  (*this)[1][0] = icov[1][0] * iscale;
350  (*this)[1][1] = icov[1][1] * iscale;
351 
352  // when center is at (0, 0, 1)^T, the conic c is simply given by the
353  // inverse covariance matrix:
354  // c = | cov^-1 0 |
355  // | 0 -1 |
356  // under a translation t = |0 -center|
357  // the conic c transforms to
358  // c' = t^T * c * t
359  // resulting in
360  (*this)[0][2]=(*this)[2][0]=-(cx*icov[0][0]+cy*icov[0][1]);
361  (*this)[1][2]=(*this)[2][1]=-(cx*icov[1][0]+cy*icov[1][1]);
362 
363  (*this)[2][2]=-cx*(*this)[0][2]-cy*(*this)[1][2]-1.0;
364 }
365 
366 
367 bool Conic2D::
369  Matrix2x2<CONIC2D_TYPE>& cov) const {
370  // the discriminant is the determinant of the upper left 2 by 2 matrix
371  const double dDisc = GetDiscriminant();
372  if (fabs(dDisc) <= DBL_EPSILON) {
373  // degenerate case
374  return false;
375  }
376 
377  const double a = (*this)[0][0];
378  const double b = 0.5*((*this)[1][0]+(*this)[0][1]);
379  const double c = (*this)[1][1];
380  const double d = 0.5*((*this)[2][0]+(*this)[0][2]);
381  const double e = 0.5*((*this)[2][1]+(*this)[1][2]);
382 
383  // find extremum of quadratic function
384  center[0] = (b * e - c * d) / dDisc;
385  center[1] = (b * d - a * e) / dDisc;
386  center[2] = 1;
387 
388  // invert the upper left 2 by 2 matrix
389  cov[0][0]=(*this)[1][1]/dDisc;
390  cov[1][0]=-(*this)[1][0]/dDisc;
391  cov[0][1]=-(*this)[0][1]/dDisc;
392  cov[1][1]=(*this)[0][0]/dDisc;
393 
394  return true;
395 }
396 
397 
398 
399 bool Conic2D::
400 GetEllipseParameters(double center[2], double a[2], double b[2]) const {
401  HomgPoint2D c;
403 
404  if (!GetPointAndCovariance(c, cov)){
405  return false;
406  }
407 
408  center[0]=c[0];
409  center[1]=c[1];
410 
411  double la, lb;
412  Vector2<double> va, vb;
413  cov.EigenvalueDecomposition(la, va, lb, vb);
414 
415  cout << "va "<<va[0]<<", "<<va[1]<<"\tla :"<<la
416  << "\nvb "<<vb[0]<<", "<<vb[1]<<"\tlb :"<<lb<<endl;
417 
418  la=sqrt(la);
419  lb=sqrt(lb);
420 
421  a[0]=la*va[0];
422  a[1]=la*va[1];
423 
424  b[0]=lb*vb[0];
425  b[1]=lb*vb[1];
426 
427  cout << "center "<<center[0]<<", "<<center[1]<<"\ta: "<<a[0]<<", "<<a[1]
428  <<"\tb: "<<b[0]<<", "<<b[1]<<endl;
429  return true;
430 }
431 
433  double& dAngle,
434  double& radius_a,
435  double& radius_b) const {
436  if (!IsEllipse()) {
437  // BIASERR("Conic is no ellipse! Make sure Det=-1");
438  return false;
439  }
440 
441  /* ellipse conic is symmetric matrix of form:
442 
443  a b d
444  b c e
445  d e f
446 
447  */
448 
449  const double& a = (*this)[0][0];
450  const double b = 0.5*((*this)[1][0]+(*this)[0][1]);
451  const double& c = (*this)[1][1];
452  const double d = 0.5*((*this)[2][0]+(*this)[0][2]);
453  const double e = 0.5*((*this)[2][1]+(*this)[1][2]);
454 
455  const double dDisc = GetDiscriminant();
456  if (fabs(dDisc) <= DBL_EPSILON) {
457  // degenerate case
458  return false;
459  }
460 
461  // find extremum of quadratic function
462  Center[0] = (b * e - c * d) / dDisc;
463  Center[1] = (b * d - a * e) / dDisc;
464  Center[2] = 1;
465 
466  const double q0 = LocatePoint(Center);
467 
468  double theta, lambda1, lambda2;
469  const double p = (a + c) / 2.0;
470  const double q = (a - c) / 2.0;
471  const double r = sqrt(q * q + b * b);
472  if ((fabs(b) <= DBL_EPSILON) && (fabs(q) <=DBL_EPSILON))
473  theta = 0.0;
474  else
475  theta = 0.5 * atan2(b, q);
476 
477  dAngle = -theta;
478 
479  lambda1 = p + r;
480  lambda2 = p - r;
481 
482 
483  if ((fabs(lambda1) <= DBL_EPSILON) ||
484  (fabs(lambda2) <= DBL_EPSILON) ||
485  (fabs(q0) <= DBL_EPSILON)) {
486  // degenerate
487  return false;
488  }
489 
490  lambda1 /= -q0;
491  lambda2 /= -q0;
492 
493  radius_a = 1.0 / sqrt(fabs(lambda1));
494  radius_b = 1.0 / sqrt(fabs(lambda2));
495  return true;
496 }
497 
498 
499 
500 bool Conic2D::EllipsoidSilhouetteToGauss(const double& ProbBorder,
501  HomgPoint2D& Center,
502  double& NormalizationFactor){
503 
504  const double b = 0.5*((*this)[1][0]+(*this)[0][1]);
505  const double d = 0.5*((*this)[2][0]+(*this)[0][2]);
506  const double e = 0.5*((*this)[2][1]+(*this)[1][2]);
507 
508  const double dDisc = GetDiscriminant();
509  if (fabs(dDisc) <= DBL_EPSILON) {
510  // degenerate case
511  return false;
512  }
513 
514  // find extremum of quadratic function
515  Center[0] = (b * e - (*this)[1][1] * d) / dDisc;
516  Center[1] = (b * d - (*this)[0][0] * e) / dDisc;
517  Center[2] = 1;
518 
519  const double q0 = -LocatePoint(Center);
520  (*this)[2][2] += q0;
521 
522  // if we want to evaluate exp( x^T * this * x) and get a probability
523  // we have to normalize by 1.0 / (2 M_PI * sqrt( discriminant((-2.0*A)^-1 )))
524  // where A is the upper left 2x2 part of this
525  // after simplification and exploiting det(A^-1)=1/det(A)
526  const double N = sqrt(GetDiscriminant()) / M_PI;
527 
528  const double scale = log(ProbBorder) / (-1.0*q0*(log(N)+1.0));
529  (*this) *= scale;
530  NormalizationFactor = sqrt(GetDiscriminant()) / M_PI;
531  return true;
532 }
533 
535  bool UseSVD) {
536  // get the dual quadric of Q since its projection is simple
537  Matrix4x4<double> DualQuadric(Q.GetDualQuadric(UseSVD));
538 
539  // "project" the dual quadric to the dual conic
540  Conic2D DualConic;
541  DualConic = P * DualQuadric * P.Transpose();
542 
543  // get the actual conic from the dual conic
544  (*this) = DualConic.GetDualConic(UseSVD);
545 
546  // set determinant to -1, so we can separate inside/outside in ellipses
547  Normalize();
548 }
549 
550 unsigned int Conic2D::GetSignature() const {
551  // do singular value decomposition of this
552  SVD svd((Matrix<CONIC2D_TYPE>)*this);
553  Vector3<double> S;
555  S = svd.GetS();
556  VT = svd.GetVT();
557  // now we need the eigenvalues (with sign !)
558  // compute this by projecting the (normalized) eigenvectors onto their images
559  Vector3<double> eigenvector, eigenimage;
560  int Signature = 0;
561  for (unsigned int i=0; i<3; i++) {
562  // get ith eigenvector and its image
563  VT.GetRow(i,eigenvector);
564  eigenimage = (*this) * eigenvector;
565  // compute scalar product, we are not "thinking" homogenized now
566  // this is simply an analysis of a 3x3 matrix !
567  S[i] = eigenimage * eigenvector;
568  if (S[i]<-SVD_ZERO_THRESH) Signature--;
569  else if (S[i]>SVD_ZERO_THRESH) Signature++;
570  }
571 
572  // return number of eigenvalues with one sign minus number of eigenvalues
573  // with opposite sign, choosing signs such that difference is not negative
574  if (Signature<0) return (unsigned int)(-Signature);
575  return (unsigned int)Signature;
576 }
577 
578 
579 
580 bool Conic2D::IntersectsCircle(const HomgPoint2D& C, double Radius) const {
581  // code has been copied from maple, see below
582 
583  vector<double> Coefficients;
584 
585  const double r = Radius;
586  const double u = C[0]/C[2];
587  const double v = C[1]/C[2];
588 
589  const double a = (*this)[0][0];
590  const double b = (*this)[1][1];
591  const double c = (*this)[0][1] + (*this)[1][0];
592  const double d = (*this)[0][2] + (*this)[2][0];
593  const double e = (*this)[1][2] + (*this)[2][1];
594  const double f = (*this)[2][2];
595 
596  // solve quartic equation
597  Coefficients.resize(5);
598 
599  // coefficients copied from maple, see below
600  Coefficients[4] = -2*a*b + b*b + a*a + c*c;
601 
602  Coefficients[3] = 2*u*c*a + 2*u*c*b - 4*a*a*v + 2*d*c + 2*e*b + 4*b*a*v
603  - 2*v*c*c - 2*a*e;
604 
605  Coefficients[2] = 2*f*b + 2*u*c*e - 2*a*a*r*r + 2*a*a*u*u + v*v*c*c
606  - r*r*c*c + u*u*c*c + e*e + 2*u*d*a + d*d + 2*b*a*u*u
607  + 4*e*a*v - 2*a*f - 4*v*c*d - 4*u*c*a*v
608  + 6*a*a*v*v + 2*u*d*b - 2*b*a*v*v + 2*b*a*r*r;
609 
610  Coefficients[1] = - 2*r*r*c*d - 4*a*a*u*u*v + 2*u*c*f - 2*e*a*v*v
611  + 2*e*a*r*r + 2*v*v*c*d + 2*f*e - 4*u*d*a*v + 4*f*a*v
612  - 2*v*d*d + 2*u*u*u*c*a + 2*u*c*a*v*v - 2*u*c*a*r*r
613  + 2*e*a*u*u + 2*u*d*e + 4*a*a*v*r*r - 4*a*a*v*v*v
614  + 2*u*u*c*d;
615 
616  Coefficients[0] = 2*u*d*f + 2*a*a*u*u*v*v - 2*a*a*u*u*r*r - 2*a*a*v*v*r*r
617  + 2*u*u*u*d*a + 2*f*a*u*u - 2*f*a*v*v + 2*f*a*r*r + f*f
618  + a*a*u*u*u*u + a*a*v*v*v*v + a*a*r*r*r*r + u*u*d*d
619  + v*v*d*d - r*r*d*d + 2*u*d*a*v*v - 2*u*d*a*r*r;
620 
621 
622  PolynomialSolve ps;
623  ps.CheckCoefficients(Coefficients);
624  return (ps.HasRealSolution(Coefficients));
625  // solution is y component of point
626 
627 /* maple code that has been used for IntersectsCircle:
628 
629 eqns := { a*x^2+b*y^2+c*x*y+d*x+e*y+f=0, (x-u)*(x-u)+(y-v)*(y-v)=r*r };
630 
631  2 2 2 2 2
632  %1 b - %1 a + %1 e + 2 %1 a v + f - a u - a v + a r
633  {y = %1, x = - --------------------------------------------------------}
634  %1 c + d + 2 a u
635 
636 
637 
638  2 2 2 4
639  %1 := RootOf((b + a + c - 2 a b) _Z +
640 
641  2 2
642  (- 2 v c + 2 d c - 4 a v + 2 u c b + 2 e b + 2 u c a + 4 b a v - 2 a e)
643 
644  3 2 2 2 2 2 2 2 2
645  _Z + (- 2 a r - 2 b a v + 2 d a u + 2 a u + 2 b a u + 6 a v
646 
647  2 2 2 2 2 2
648  + v c + 4 v a e + 2 u c e - 4 v d c + e - 4 u c a v + u c + 2 b a r
649 
650  2 2 2 2 2
651  - 2 a f + 2 u d b - r c + 2 b f + d ) _Z + (2 e a u + 4 f a v
652 
653  2 3 2 2 2 2
654  - 4 a v + 2 f e + 2 u c a v - 2 u c a r - 2 v d + 2 u d e + 2 v c d
655 
656  3 2 2 2
657  - 4 u d a v + 2 u c a + 2 u c f + 2 e a r - 2 r c d - 2 e a v
658 
659  2 2 2 2 2 3 2
660  + 2 u c d - 4 a u v + 4 a v r ) _Z + 2 u d f + 2 u d a - 2 f a v
661 
662  2 2 2 2 2 4 2 4 2 4 2 2 2 2 2 2
663  + f + 2 a u v + a u + a v + a r + u d + v d - r d
664 
665  2 2 2 2 2 2 2 2 2 2
666  + 2 u d a v - 2 u d a r - 2 a v r - 2 a u r + 2 f a u + 2 f a r )
667 
668 */
669 
670 }
671 
672 Conic2D Conic2D::GetDualConic(bool UseSVD) const {
673  // for degenerate conics we MUST go through SVD
674  if (!IsProper()) UseSVD = true;
675 
676  if (UseSVD) {
677  // SVD needs a Matrix, but Conic2D is a Matrix3x3, so a little conversion is
678  // needed here
679  Matrix<CONIC2D_TYPE> m(*this);
680 
681  // do it the safe way
682  SVD csvd(m, SVD_ZERO_THRESH, false);
683  unsigned int NullspaceDim = csvd.RelNullspaceDim();
684  //cout<<"nullspace dim is "<<NullspaceDim<<endl;
685  if (NullspaceDim==0) return (csvd.Invert());
686  // we have a zero singular value in the svd and therefore a degenerate conic
687  // return scaled adjugate matrix
689  for (unsigned int i=NullspaceDim; i>0; i--) {
690  SM[3-i][3-i] = 1.0;
691  }
692  //SM = csvd.GetV()*SM*csvd.GetU().Transpose();
693  Matrix3x3<double> temp(csvd.GetV());
694  temp *= SM;
695  temp *= csvd.GetU().Transpose();
696  SM = temp;
697 
698  const double thenorm = SM.NormFrobenius();
699  if (thenorm< SVD_ZERO_THRESH) return Conic2D(SM);
700  SM /= thenorm;
701  return Conic2D(SM);
702 
703 
704  }
705  // do it the fast way
706  const CONIC2D_TYPE& a = (*this)[0][0];
707  const CONIC2D_TYPE& b = (*this)[0][1];
708  const CONIC2D_TYPE& c = (*this)[0][2];
709  const CONIC2D_TYPE& e = (*this)[1][1];
710  const CONIC2D_TYPE& f = (*this)[1][2];
711  const CONIC2D_TYPE& g = (*this)[2][2];
712  // do it the fast way
713  Conic2D Dual;
714  Dual[0][0] = e*g - f*f;
715  Dual[0][1] = Dual[1][0] = c*f - b*g;
716  Dual[0][2] = Dual[2][0] = b*f - c*e;
717  Dual[1][1] = a*g - c*c;
718  Dual[1][2] = Dual[2][1] = b*c - a*f;
719  Dual[2][2] = a*e - b*b;
720 
721  return Dual;
722 }
723 
724 int Conic2D::
726 {
727  BIASCDOUT(D_CONIC2D_TAN, "conic: "<<*this<<endl);
728  BIASCDOUT(D_CONIC2D_TAN, "x: "<<x<<endl);
729  Conic2D polar_cross, dc;
730  HomgLine2D polar;
731 
732  // The polar of the pointy x with respect to the conic *this intersects the
733  // conic at the two points where the tangents to the conic through the point
734  // x touch the conic.
735  // See Hartley, Zisserman : "Multiple View Geometry", second edidtion
736  // chapter 2.8, page 58
737  //polar = (HomgLine2D)((*this)*x);
738  Mult(x, polar);
739  BIASCDOUT(D_CONIC2D_TAN, "polar: "<<polar<<endl);
740 
741  // dc is line (or dual) conic consisting of the two intersection points
742  // of the polar with the conic C
743  polar_cross.SetAsCrossProductMatrix(polar);
744  //dc = polar_cross * (*this) * polar_cross;
745  Mult(polar_cross, dc);
746  dc = (polar_cross * dc);
747  // dc.MultLeft(polar_cross);
748  BIASCDOUT(D_CONIC2D_TAN, "dc: "<<dc<<endl);
749 
750  // A dual conic dc consistig of the two points y=(y1, y2, 1)^T and
751  // x=(x1, x2, 1)^T is given by x*y^T+y*x^T
752  // (see Hartley, Zisserman : "Multiple View Geometry", second edidtion
753  // chapter 2.2.3 "Conics and dual conics", page 32, Example 2.8)
754  // resulting in the matrix A =
755  // +- -+
756  // | 2 x1 y1, x1 y2 + x2 y1, x1 + y1 |
757  // | |
758  // | x1 y2 + x2 y1, 2 x2 y2, x2 + y2 |
759  // | |
760  // | x1 + y1, x2 + y2, 2 |
761  // +- -+
762  // The system given by (this) = A can be solved analytically:
763 
764  // Norm lower right entry of conic to 2.0
765  // dc /= 0.5*dc[2][2];
766  //dc.MultiplyIP(2.0/dc[2][2]);
767  dc*=(2.0/dc[2][2]);
768  BIASCDOUT(D_CONIC2D_TAN, "normed dc: "<<dc<<endl);
769 
770  // Set (*this) = +- -+
771  // | a b d |
772  // | b c e |
773  // | d e 2 |
774  // +- -+
775  double a=dc[0][0], b=dc[0][1], c=dc[1][1], d=dc[0][2], e=dc[1][2];
776  // Setting (*this) = A results in the equations
777  // e = x2+y2 -> x2 = e-y2 (I)
778  // d = x1+y1 -> x1 = d-y1 (II)
779  // c = 2*x2*y2 (III)
780  // b = x1*y2 + x2*y1 (IV)
781  // a = 2*x1*y1 (V)
782  //
783  double y1a, y1b, y2a, y2b, y1, y2, min;
784  // Now use (I) in (III) and solve the quadratic equation
785  double tmp=e*e*0.25 - c*0.5, tmp2;
786  if (tmp>=0.0){
787  tmp = sqrt(tmp);
788  tmp2=e*0.5;
789  y2a = tmp2+tmp;
790  y2b = tmp2-tmp;
791  } else {
792  BIASERR("no solution for y2: tmp<0 "<<tmp);
793  return -1;
794  }
795  BIASCDOUT(D_CONIC2D_TAN, "y2a: "<<2.0*(e-y2a)*y2a-c
796  <<"\ny2b: "<<2.0*(e-y2b)*y2b-c<<endl);
797 
798  // Now use (II) in (V) and solve the quadratic equation
799  tmp=d*d*0.25 - a*0.5;
800  if (tmp>=0.0){
801  tmp = sqrt(tmp);
802  tmp2 = d*0.5;
803  y1a = tmp2+tmp;
804  y1b = tmp2-tmp;
805  } else {
806  BIASERR("no solution for y1: tmp<0 "<<tmp);
807  return -1;
808  }
809  BIASCDOUT(D_CONIC2D_TAN, "y1a: "<<2*d*y1a-2*y1a*y1a-a
810  << "\ny1b: "<<2*d*y1b-2*y1b*y1b-a<<endl);
811 
812  // 4 different solutions exist. Test for the best solution by using
813  // the equation (IV) and minimize the error
814 
815  // test y1a, y2a
816  BIASCDOUT(D_CONIC2D_TAN, "y1a, y2a ("<<y1a<<", "<<y2a<<")"<<endl);
817  y1=y1a, y2=y2a;
818  min = fabs((d-y1)*y2+(e-y2)*y1 - b);
819  BIASCDOUT(D_CONIC2D_TAN, "y1a, y2a = "<<min<<endl);
820  // test y1a y2b
821  BIASCDOUT(D_CONIC2D_TAN, "y1a, y2b ("<<y1a<<", "<<y2b<<")"<<endl);
822  tmp = fabs((d-y1a)*y2b+(e-y2b)*y1a - b);
823  if (tmp<min){
824  min = tmp;
825  y1=y1a;
826  y2=y2b;
827  BIASCDOUT(D_CONIC2D_TAN, "y1a, y2b = "<<min<<endl);
828  } else {
829  BIASCDOUT(D_CONIC2D_TAN, "not taking y1a, y2b = "<<tmp<<endl);
830  }
831  // test y1b, y2a
832  BIASCDOUT(D_CONIC2D_TAN, "y1b, y2a ("<<y1b<<", "<<y2a<<")"<<endl);
833  tmp = fabs((d-y1b)*y2a+(e-y2a)*y1b - b);
834  if (tmp<min){
835  min = tmp;
836  y1=y1b;
837  y2=y2a;
838  BIASCDOUT(D_CONIC2D_TAN, "y1b, y2a = "<<min<<endl);
839  } else {
840  BIASCDOUT(D_CONIC2D_TAN, "not taking y1b, y2a = "<<tmp<<endl);
841  }
842 
843  // test y1b, y2b
844  BIASCDOUT(D_CONIC2D_TAN, "y1b, y2b ("<<y1b<<", "<<y2b<<")"<<endl);
845  tmp = fabs((d-y1b)*y2b+(e-y2b)*y1b - b);
846  if (tmp<min){
847  min = tmp;
848  y1=y1b;
849  y2=y2b;
850  BIASCDOUT(D_CONIC2D_TAN, "y1b, y2b = "<<min<<endl);
851  } else {
852  BIASCDOUT(D_CONIC2D_TAN, "not taking y1b, y2b = "<<tmp<<endl);
853  }
854 
855  p1.Set(y1, y2, 1.0);
856  p2.Set(d-y1, e-y2, 1.0);
857 
858  BIASCDOUT(D_CONIC2D_TAN, "tangent points: "<<p1<<"\t"<<p2<<endl);
859 
860 
861  return 2;
862 }
863 
864 int Conic2D::
865 GetLines(std::vector<HomgLine2D>& lines) const {
866  lines.clear();
867  Conic2D A(*this);
868  A /= A.NormFrobenius();
869  ConicType thetype = A.GetConicType();
870  if (thetype==DoubleLine) {
871  // in principal we can use getdualconic, however, we get an unknown
872  // scale, therefore we here compute the adjugate directly:
873  // adjugate matrix (NOT to be confused with
874  // adjoint or with moore-penrose-pseudo-inverse)
875  // first compute cofactor matrix
876  Matrix3x3<double> cofactors;
877  for (unsigned int i=0; i<3; i++) {
878  for (unsigned int j=0; j<3; j++) {
879  Matrix2x2<double> submatrix((*this)[(i+1)%3][(j+1)%3],
880  (*this)[(i+1)%3][(j+2)%3],
881  (*this)[(i+2)%3][(j+1)%3],
882  (*this)[(i+2)%3][(j+2)%3]);
883  cofactors[i][j] = submatrix.det();
884  }
885  }
886  Conic2D Dual(cofactors.Transpose());
887 
888  //SVD testsvd(Dual);
889  //cout<<"dual has singular values "<<testsvd.GetS()<<endl;
890 
891  double themax = 0;
892  int index = -1;
893  for (unsigned int i=0; i<3; i++) {
894  if (fabs(Dual[i][i])>themax) {
895  themax = fabs(Dual[i][i]);
896  index = i;
897  }
898  }
899  if (index<0) {
900  BIASERR("didnt find positive diagonal element");
901  return -1;
902  }
903  if (Dual[index][index]<0.0) {
904  A *= -1.0;
905  Dual *= -1.0;
906  }
907  double beta = sqrt(themax);
908  //cout<<"Dual is "<<Dual<<" while beta is "<<beta<<endl;
909  Vector3<double> p(Dual[index][0]/beta,
910  Dual[index][1]/beta,
911  Dual[index][2]/beta);
912 
913  //cout<<"p is "<<p<<endl;
914 
915  // this results in error: no match for 'operator+' (rwulff)
916  //Matrix3x3<double> C((*this) + p.GetSkewSymmetricMatrix());
917  Matrix3x3<double> C(*this);
918  C += p.GetSkewSymmetricMatrix();
919 
920 
921  //SVD mysvd(C);
922  //cout<<"singular values of C are "<< mysvd.GetS()<<endl;
923  //cout<<"C is "<<C<<endl;
924  HomgLine2D g(0,0,0),h(0,0,0);
925  for (unsigned int i=0; i<3; i++) {
926  for (unsigned int j=0; j<3; j++) {
927  if (fabs(C[i][j])>1e-10) {
928  // found nonzero element:
929  g[0] = C[i][0];
930  g[1] = C[i][1];
931  g[2] = C[i][2];
932  h[0] = C[0][j];
933  h[1] = C[1][j];
934  h[2] = C[2][j];
935  break;
936  }
937  }
938  }
939  g /= g.NormL2();
940  lines.push_back(g);
941  h /= h.NormL2();
942  lines.push_back(h);
943  } else if (thetype==SingleLine) {
944  HomgLine2D g(0,0,0);
945  if ((A[0][0]<=0.0) && (A[1][1]<=0.0) && (A[1][1]<=0.0)) {
946  A *= -1.0;
947  }
948  for (unsigned int i=0; i<3; i++) {
949  if (A[i][i]>=0.0) g[i] = sqrt(A[i][i]);
950  else if (A[i][i]>-1e-5) g[i] = 0;
951  else {
952  //g[i] = 0;
953  BIASERR("line has complex coefficients, need sqrt from "<<A[i][i]);
954  return -1;
955  }
956  }
957  //cout<<"g absolute values are "<<g<<endl;
958  // the absolute values of g are correct, however, we must check the signs
959 
960  Matrix<double> Aabsolute(g.OuterProduct(g)-A);
961  //cout<<"Aabsolute is "<< Aabsolute <<endl;
962 
963 
964  // it seems more reasonable to check for positivity here than for <1e-10!!!
965 
966  // bool signabequal = (Aabsolute[0][1]<1e-10);
967  //bool signbcequal = (Aabsolute[1][2]<1e-10);
968  //bool signacequal = (Aabsolute[0][2]<1e-10);
969 
970  bool signabequal = (Aabsolute[0][1]>0.0);
971  bool signbcequal = (Aabsolute[1][2]>0.0);
972  bool signacequal = (Aabsolute[0][2]>0.0);
973 
974  if (signabequal) {
975  if (signbcequal) {
976  if (signacequal) {
977  // fine, all positive or all negative!
978  } else {
979  BIASERR("inconsistent data: "<<Aabsolute[0][1]<<" "
980  <<Aabsolute[1][2]<<" "<<Aabsolute[0][2]);
981  }
982  } else {
983  if (signacequal) {
984  BIASERR("inconsistent data: "<<Aabsolute[0][1]<<" "
985  <<Aabsolute[1][2]<<" "<<Aabsolute[0][2]);
986  } else {
987  g[2] *= -1.0;
988  }
989  }
990  } else {
991  if (signbcequal) {
992  if (signacequal) {
993  BIASERR("inconsistent data: "<<Aabsolute[0][1]<<" "
994  <<Aabsolute[1][2]<<" "<<Aabsolute[0][2]);
995  } else {
996  g[0] *= -1.0;
997  }
998  } else {
999  if (signacequal) {
1000  g[1] *= -1.0;
1001  } else {
1002  BIASERR("inconsistent data: "<<Aabsolute[0][1]<<" "
1003  <<Aabsolute[1][2]<<" "<<Aabsolute[0][2]);
1004  }
1005  }
1006  }
1007  //cout<<"g final is "<<g<<endl;
1008 
1009  lines.push_back(g);
1010  } else {
1011  BIASERR("GetLines called for Conic which does not consist of one or two lines! Type is "<<thetype);
1012  BIASABORT;
1013  return -1;
1014  }
1015  return 0;
1016 }
1017 
1018 int Conic2D::
1019 IntersectConic(const Conic2D& otherconic,
1020  std::vector<HomgPoint2D>& intersectionPoints) const {
1021  intersectionPoints.clear();
1022  if (!IsProper()) {
1023  //cout<<"improper conic has type "<<GetConicType()<<endl;
1024  if (otherconic.IsEmpty()) return 0; // no solution at all
1025  switch (GetConicType()) {
1026  case WholePlane: {
1027  if (otherconic.IsPoint()) {
1028  HomgPoint2D solution;
1029  if (otherconic.GetPoint(solution)!=0) return 1;
1030  intersectionPoints.push_back(solution);
1031  return 0;
1032  } // no solution
1033  return 1; // degenerate case with multiple solutions
1034  }
1035  case SingleLine:
1036  case DoubleLine: {
1037  vector<HomgLine2D> thelines;
1038  GetLines(thelines);
1039  if (otherconic.IsProper()) {
1040  vector<HomgPoint2D> thepoints;
1041  for (unsigned int i=0; i<thelines.size(); i++) {
1042  otherconic.IntersectLine(thelines[i], thepoints);
1043  for (unsigned int j=0; j<thepoints.size(); j++) {
1044  thepoints[j].Normalize();
1045  bool isNewPoint = true;
1046  for (unsigned int k=0; k<intersectionPoints.size(); k++)
1047  if (Equal(thepoints[j][0], intersectionPoints[k][0]) &&
1048  Equal(thepoints[j][1], intersectionPoints[k][1]) &&
1049  Equal(thepoints[j][2], intersectionPoints[k][2]))
1050  isNewPoint = false;
1051  if (isNewPoint) intersectionPoints.push_back(thepoints[j]);
1052  }
1053  }
1054  return 0;
1055  } else {
1056  // both conics are degenerate !
1057  switch (otherconic.GetConicType()) {
1058  case SingleLine:
1059  case DoubleLine: {
1060  vector<HomgLine2D> otherlines;
1061  otherconic.GetLines(otherlines);
1062  // now intersect each line with each other
1063  for (unsigned int i=0; i<thelines.size(); i++) {
1064  for (unsigned int j=0; j<otherlines.size(); j++) {
1065  HomgPoint2D intersection =
1066  thelines[i].CrossProduct(otherlines[j]);
1067  const double norm = intersection.NormL2();
1068  if (norm<1e-10) continue; // identical lines
1069  intersection /= norm;
1070  bool isNewPoint = true;
1071  for (unsigned int k=0; k<intersectionPoints.size(); k++)
1072  if (Equal(intersection[0], intersectionPoints[k][0]) &&
1073  Equal(intersection[1], intersectionPoints[k][1]) &&
1074  Equal(intersection[2], intersectionPoints[k][2]))
1075  isNewPoint = false;
1076  if (isNewPoint) intersectionPoints.push_back(intersection);
1077  }
1078  }
1079  return 0;
1080  }
1081  case Point: {
1082  HomgPoint2D point;
1083  if (otherconic.GetPoint(point)!=0) return -1;
1084  if (fabs(LocatePoint(point))>1e-9) return 0;
1085  intersectionPoints.push_back(point);
1086  return 0;
1087  }
1088  default: return -1; // degenerate case with multi-solutions
1089  }
1090  }
1091  }
1092  case Point: {
1093  HomgPoint2D point;
1094  if (GetPoint(point)!=0) return -1;
1095  if (fabs(otherconic.LocatePoint(point))>1e-9) return 0;
1096  intersectionPoints.push_back(point);
1097  return 0;
1098  }
1099  case Empty: return 0; // no solution, everything fine
1100  default: return -1;
1101  }
1102  } else if (!otherconic.IsProper()) {
1103  // switch roles of conics and use upper part in other conic object ...
1104  return otherconic.IntersectConic(*this, intersectionPoints);
1105  }
1106  // intersection of two proper conics:
1107  return IntersectConicProper(otherconic, intersectionPoints);
1108 }
1109 
1110 
1111 int Conic2D::
1112 IntersectConicProper(const Conic2D& otherconic,
1113  std::vector<HomgPoint2D>& intersectionPoints) const {
1114 
1115  BIASASSERT(IsProper()); // read below
1116  BIASASSERT(otherconic.IsProper()); // read below
1117  // this implementation handles the difficult case of intersecting
1118  // ellipses/parabolas/hyberbolas with poissibly 4 solutions
1119  // if one or both of the conics are actually lines or single points
1120  // this is handled by the intersectconic method
1121  intersectionPoints.clear();
1122 
1123 
1124  // the intersection points must lie on both conics:
1125  // x C1 X = 0 x C2 x = 0
1126  // therefore they must also fulfill
1127  // x (l C1 + m C2) x = 0
1128  // for ANY l and m
1129  // particularly, if a and b are chosen in a way that the conic degenerates
1130  // det(l C1 + m C2) = 0
1131  // this happens when the characteristic polynomial vanishes.
1132 
1133 
1134  // actually this is the same as in the 7point algorithm for f-estimation
1135  FMatrixEstimation FEst;
1136 
1137  BIAS::Vector<double> f1(9), f2(9);
1138  for (unsigned int i=0; i<9; i++) {
1139  f1[i] = (*this)[i/3][i%3];
1140  f2[i] = otherconic[i/3][i%3];
1141  }
1142  vector<double> polynomial;
1143  FEst.GetDetPolynomial(f1,f2,polynomial);
1144  PolynomialSolve PS;
1145  std::vector<double > solutions;
1146  //cout<<"Polynomial is ";
1147  //for (unsigned int i=0; i<polynomial.size(); i++)
1148  // cout<<polynomial[i]<<" ";
1149  //cout<<endl;
1150  if (PS.Solve(polynomial, solutions)<1) {
1151  BIASERR("PS failed.");
1152  return -1;
1153  }
1154  if (solutions.empty()) {
1155  //cout<<"Polynomial has no real root!!!"<<endl;
1156  return -1;
1157  }
1158 
1159 
1160  // should we consider the other solutions here as well or maybe select a
1161  // "better" solution
1162  Conic2D degenerated(solutions[0]*(*this) + (1.0-solutions[0])*otherconic);
1163  const double degeneratednorm = degenerated.NormFrobenius();
1164  if (degeneratednorm<1e-10) return 1;
1165  degenerated /= degeneratednorm;
1166 
1167  // SVD mysvd(degenerated);
1168 // Vector<double> S(mysvd.GetS());
1169 // Matrix<double> SS(3,3,MatrixZero);
1170 // SS[0][0] = S[0];
1171 // SS[1][1] = S[1];
1172 // cout<<"det is "<<degenerated.det()<<endl;
1173 // degenerated = mysvd.GetU() * SS * mysvd.GetVT();
1174 // cout<<"det is now "<<degenerated.det()<<endl;
1175 // Matrix<double> mymat(degenerated);
1176 // cout<<"general det is "<<mymat.DetSquare()<<endl;
1177 // SVD mysvd2(degenerated);
1178 // cout<<"degenerated conic has singular values "<<mysvd2.GetS()<<endl;
1179 
1180  vector<HomgLine2D> lines;
1181  degenerated.GetLines(lines);
1182  for (unsigned int i=0; i<lines.size(); i++) {
1183  vector<HomgPoint2D> points;
1184  this->IntersectLine(lines[i],points);
1185  //cout<<"this line intersects the conic in "<<points.size()<<" points: "<<endl;
1186 
1187 
1188 
1189 
1190  for (unsigned int j=0 ;j<points.size(); j++) {
1191  //cout<<points[j]<<endl;
1192  points[j].Normalize();
1193  bool isNewPoint = true;
1194  for (unsigned int k=0; k<intersectionPoints.size(); k++)
1195  if (Equal(points[j][0], intersectionPoints[k][0]) &&
1196  Equal(points[j][1], intersectionPoints[k][1]) &&
1197  Equal(points[j][2], intersectionPoints[k][2])) isNewPoint = false;
1198  if (isNewPoint) intersectionPoints.push_back(points[j]);
1199  }
1200  }
1201 
1202  return 0;
1203 }
1204 
1205 int Conic2D::
1206 IntersectLine(const HomgLine2D& theline,
1207  std::vector<HomgPoint2D>& intersectionPoints) const {
1208  intersectionPoints.clear();
1209  if (theline.NormL2()<1e-10) return -1;
1210 
1211  HomgLine2D myline(theline);
1212  myline /= myline.NormL2();
1213  //cout<<"using normalized line "<<myline<<endl;
1214  Matrix3x3<double> A(*this);
1215 
1216  double themax = 0;
1217  int theindex = -1;
1218  for (unsigned int i=0; i<3; i++) {
1219  if (fabs(myline[i])>themax) {
1220  themax = fabs(myline[i]);
1221  theindex = i;
1222  }
1223  }
1224  // cout<<"largest line element is "<<theindex<<endl;
1225 
1226  if (theindex<0) {
1227  BIASERR("Supplied invalid line 000");
1228  return -1;
1229  }
1231  //cout<<"M is "<<M<<endl;
1232  Matrix3x3<double> B(M.Transpose() * A * M);
1233  //cout<<"B is "<<B<<endl;
1234  Matrix2x2<double> submatrix(B[(theindex+1)%3][(theindex+1)%3],
1235  B[(theindex+1)%3][(theindex+2)%3],
1236  B[(theindex+2)%3][(theindex+1)%3],
1237  B[(theindex+2)%3][(theindex+2)%3]);
1238  //cout<<"submatrix is "<<submatrix<<endl;
1239  double det = submatrix.det();
1240  if (det<0.0) {
1241  //cout<<"negative det., changing signs "<<endl;
1242  A *= -1.0;
1243  B *= -1.0;
1244  det *= -1.0;
1245  }
1246  double alpha = sqrt(det)/myline[theindex];
1247  //cout<<"alpha is "<<alpha<<endl;
1248 
1249  Matrix3x3<double> C(B - alpha*M);
1250  //cout<<"C is "<<C<<endl;
1251  HomgPoint2D p,q;
1252  bool foundit = false;
1253  for (unsigned int i=0; i<3; i++) {
1254  for (unsigned int j=0; j<3; j++) {
1255  if (fabs(C[i][j])>1e-10) {
1256  // found nonzero element:
1257  p[0] = C[i][0];
1258  p[1] = C[i][1];
1259  p[2] = C[i][2];
1260  q[0] = C[0][j];
1261  q[1] = C[1][j];
1262  q[2] = C[2][j];
1263  foundit = true;
1264  break;
1265  }
1266  }
1267  }
1268  if (!foundit) return -2;
1269  //cout<<"p is "<<p<<endl;
1270  //cout<<"q is "<<q<<endl;
1271 
1272  p.Homogenize();
1273  intersectionPoints.push_back(p);
1274  q.Homogenize();
1275  intersectionPoints.push_back(q);
1276  return 0;
1277 }
1278 
1279 
1280 void Conic2D::
1282  theline /= theline.NormL2();
1283  (*this) = theline.OuterProduct(theline);
1284 }
1285 
1286 
1287 void Conic2D::
1289  HomgLine2D theline2) {
1290  theline1 /= theline1.NormL2();
1291  theline2 /= theline2.NormL2();
1292  (*this) = theline1.OuterProduct(theline2) + theline2.OuterProduct(theline1);
1293 }
1294 
1295 
1296 int Conic2D::
1298  HomgPoint2D& distance,
1299  const HomgPoint2DCov& pointcov) const {
1300  BIASERR("untested");
1301  BIASABORT;
1302  HomgPoint2D p(point);
1303  HomgPoint2D n(*this * p);
1304  const double norm = n.NormL2();
1305  if (norm<1e-9) return -1;
1306  n *= 1.0 / norm;
1307 
1308  pointcov.Mult(n, distance);
1309  distance *= n.ScalarProduct(point) / (2.0 * n.ScalarProduct(distance));
1310 
1311  return 0;
1312 }
1313 
1314 
1315 double Conic2D::
1317  HomgPoint2D& distance,
1318  const HomgPoint2DCov& pointcov) const {
1319  BIASERR("untested");
1320  BIASABORT;
1321  if (GetLinearizedOffset(point, distance, pointcov)!=0){
1322  BIASERR("could not estimate distance");
1323  return DBL_MAX;
1324  }
1325  double l = LocatePoint(point);
1326  return (l*l / (4.0 *
1327  point.ScalarProduct((*this) * pointcov * (*this) * point)));
1328 
1329 
1330 }
void SetTwoLines(HomgLine2D theline1, HomgLine2D theline2)
create a degenerate point conic consisting of two lines
Definition: Conic2D.cpp:1288
Vector< double > GetNullvector(const int last_offset=0)
return one of the nullvectors.
Definition: SVD.hh:404
void GetRow(const unsigned int row, Vector3< T > &r) const
extract one row (&#39;Zeile&#39;) from ths matrix (for convenience)
Definition: Matrix3x3.cpp:287
unsigned int GetSignature() const
computes signature of matrix, (no.
Definition: Conic2D.cpp:550
int Invert(Matrix2x2< T > &result) const
analyticaly inverts matrix
Definition: Matrix2x2.cpp:115
Conic2D GetDualConic(bool UseSVD=false) const
returns the dual of this conic, which is the inverse
Definition: Conic2D.cpp:672
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
class representing the covariance matrix of a homogenous point 2D
T det() const
calculate the determinante
Definition: Matrix2x2.hh:266
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
void CheckCoefficients(std::vector< POLYNOMIALSOLVE_TYPE > &coeff, double eps=DBL_EPSILON)
removes leading zeros in coefficients
int IntersectConicProper(const Conic2D &otherconic, std::vector< HomgPoint2D > &intersectionPoints) const
compute intersection of 2 non-degenerate (full-rank) conics
Definition: Conic2D.cpp:1112
bool GetEllipseParameters(HomgPoint2D &Center, double &dAngle, double &radius_a, double &radius_b) const
computes explicit ellipse representation
Definition: Conic2D.cpp:432
bool IsEllipse() const
check whether this conic is an ellipse
Definition: Conic2D.cpp:93
is a &#39;fixed size&#39; quadratic matrix of dim.
Definition: Matrix2x2.hh:48
Matrix< T > Transpose() const
transpose function, storing data destination matrix
Definition: Matrix.hh:823
bool IsDoubleLine() const
check whether this conic is a double line
Definition: Conic2D.cpp:48
void ScalarProduct(const Vector3< T > &argvec, T &result) const
scalar product (=inner product) of two vectors, storing the result in result
Definition: Vector3.hh:603
HomgPoint2D & Homogenize()
homogenize class data member elements to W==1 by divison by W
Definition: HomgPoint2D.hh:215
void OuterProduct(const Vector3< T > &v, Matrix3x3< T > &res) const
outer product, constructs a matrix.
Definition: Vector3.cpp:151
bool IsEmpty() const
check whether this conic contains no points
Definition: Conic2D.cpp:164
double GetDiscriminant() const
Definition: Conic2D.cpp:43
void SetEllipse(const HomgPoint2D &Center, const double &dAngle, const double &radius_a, const double &radius_b)
construct an ellipse with explicit parameters
Definition: Conic2D.cpp:299
bool IsParabola() const
check whether this conic is a parabola
Definition: Conic2D.cpp:121
unsigned int GetWidth() const
Definition: ImageBase.hh:312
base class for solving polynomial equations
int GetLines(std::vector< HomgLine2D > &lines) const
retrieve one or two lines from a degenerate point conic
Definition: Conic2D.cpp:865
Matrix< T > GetSkewSymmetricMatrix() const
constructs a skew symmetric 3x3 matrix from (*this), which can be used instead of the cross product ...
Definition: Vector3.cpp:257
A quadric as a 4x4 matrix describing a surface in 3d projective space defined by a quadratic equation...
Definition: Quadric3D.hh:106
double GetPointDistance(const HomgPoint2D &point, HomgPoint2D &distance, const HomgPoint2DCov &pointcov=HomgPoint2DCov(MatrixIdentity)) const
return the squared mahalanobis distance of the point to the conic
Definition: Conic2D.cpp:1316
const int RelNullspaceDim() const
compare singular values against greatest, not absolute
Definition: SVD.cpp:433
double NormFrobenius() const
Definition: Matrix3x3.hh:446
void Mult(const Vector3< T > &argvec, Vector3< T > &destvec) const
matrix - vector multiplicate this matrix with Vector3, storing the result in destvec calculates: dest...
Definition: Matrix3x3.hh:302
double LocatePoint(const HomgPoint2D &point2D) const
determines if the point is inside/on/outside the conic
Definition: Conic2D.hh:144
int IntersectConic(const Conic2D &otherconic, std::vector< HomgPoint2D > &intersectionPoints) const
compute intersection of 2 conics
Definition: Conic2D.cpp:1019
bool IsAtInfinity() const
Definition: HomgPoint2D.hh:165
bool IsHyperbola() const
check whether this conic is a hyperbola
Definition: Conic2D.cpp:142
bool HasRealSolution(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff)
determine whether the polynomial has a solution in IR
int IntersectLine(const HomgLine2D &theline, std::vector< HomgPoint2D > &intersectionPoints) const
compute intersection of a conic with a line
Definition: Conic2D.cpp:1206
Matrix< double > GetV() const
return V
Definition: SVD.hh:396
const Matrix< double > & GetVT() const
return VT (=transposed(V))
Definition: SVD.hh:177
functions for estimating a fundamental matrix (FMatrix) given a set of 2d-2d correspondences (no outl...
unsigned int GetHeight() const
Definition: ImageBase.hh:319
const Vector< double > & GetS() const
return S which is a vector of the singular values of A in descending order.
Definition: SVD.hh:167
a line l = (a b c)^T is a form of the implicit straight line equation 0 = a*x + b*y + c if homogenize...
Definition: HomgLine2D.hh:48
void SetQuadricProjection(const Quadric3D &Q, const PMatrix &P, bool UseSVD=false)
constructs a conic that is a projection of the quadric Q using camera matrix P
Definition: Conic2D.cpp:534
bool IsProper() const
is this a proper conic (parabola/hyperbola/ellipse) with rank3 or some of the degenerate cases ...
Definition: Conic2D.cpp:179
bool GetPointAndCovariance(HomgPoint2D &center, Matrix2x2< CONIC2D_TYPE > &cov) const
reconstructs center and covariance matrix from conic
Definition: Conic2D.cpp:368
int GetTangentPoints(const HomgPoint2D &x, HomgPoint2D &p1, HomgPoint2D &p2) const
Returns the two points p1 and p2 on the conic subject to the constraint that the two tangents at the ...
Definition: Conic2D.cpp:725
void SetPointAndCovariance(const HomgPoint2D &center, const Matrix2x2< CONIC2D_TYPE > &cov, const double &dScale=GAUSS2D_CONFIDENCE_39_PERCENT)
constructs a conic from a point and a covariance matrix
Definition: Conic2D.cpp:331
void GetDetPolynomial(const BIAS::Vector< double > &f1, const BIAS::Vector< double > &f2, std::vector< POLYNOMIALSOLVE_TYPE > &v)
set up a polynomial in alpha given Det(alpha*F1+(1-alpha)*F2)=0, where the f vectors are interpreted ...
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
int EigenvalueDecomposition(T &value1, Vector2< T > &vector1, T &value2, Vector2< T > &vector2) const
Eigenvalue decomposition.
Definition: Matrix2x2.cpp:131
bool IntersectsCircle(const HomgPoint2D &C, double Radius) const
returns true if the given Conic intersects with the circle of radius Radius around point C...
Definition: Conic2D.cpp:580
matrix class with arbitrary size, indexing is row major.
ConicType GetConicType() const
return the type of point conic of (*this)
Definition: Conic2D.cpp:186
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
bool IsSingleLine() const
check whether this conic is a single line
Definition: Conic2D.cpp:63
double NormL2() const
Definition: Matrix3x3.hh:255
int Solve(const std::vector< POLYNOMIALSOLVE_TYPE > &coeff, std::vector< POLYNOMIALSOLVE_TYPE > &sol)
solve polynomial of arbitrary order n coeff[n]x^n+...+coeff[2]x^2+coeff[1]x+coeff[0]=0 coeff[n]!=0...
const Matrix< double > & GetU() const
return U U is a m x m orthogonal matrix
Definition: SVD.hh:187
Matrix< double > Invert()
returns pseudoinverse of A = U * S * V^T A^+ = V * S^+ * U^T
Definition: SVD.cpp:214
void Draw(Image< unsigned char > &img) const
draws conic into an image using a brute force method
Definition: Conic2D.cpp:221
bool EllipsoidSilhouetteToGauss(const double &ProbBorder, HomgPoint2D &Center, double &NormalizationFactor)
assign a probability of a gaussian distribution to a conic to measure probabilities in the image plan...
Definition: Conic2D.cpp:500
void SetSingleLine(HomgLine2D theline)
create a degenerate point conic consisting only of one line
Definition: Conic2D.cpp:1281
describes a projective 3D -&gt; 2D mapping in homogenous coordinates
Definition: PMatrix.hh:88
void SetAsCrossProductMatrix(const Vector3< T > &vec)
Sets matrix from vector as cross product matrix of this vector.
Definition: Matrix3x3.cpp:275
Quadric3D GetDualQuadric(bool UseSVD=false) const
computes the dual quadric (points &lt;-&gt; planes)
Definition: Quadric3D.cpp:121
int GetLinearizedOffset(const HomgPoint2D &point, HomgPoint2D &distance, const HomgPoint2DCov &pointcov=HomgPoint2DCov(MatrixIdentity)) const
compute approximate offset of a measured point to a known conic
Definition: Conic2D.cpp:1297
void Set(const HOMGPOINT2D_TYPE &x, const HOMGPOINT2D_TYPE &y)
set elementwise with given 2 euclidean scalar values.
Definition: HomgPoint2D.hh:174
A 3x3 matrix representing a conic (cone/plane intersection)
Definition: Conic2D.hh:71
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
bool IsPoint() const
check whether this conic is a point
Definition: Conic2D.cpp:78
void SetIdentity()
set the elements of this matrix to the identity matrix (possibly overriding the inherited method) ...
Definition: Matrix3x3.hh:429
int GetPoint(HomgPoint2D &thepoint) const
if the conic consists of a single point (degenerate case, rank=2) retrieve this point ...
Definition: Conic2D.cpp:211
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153