Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
HMatrix.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 #include "HMatrix.hh"
26 
27 #include <MathAlgo/SVD.hh>
28 #include <MathAlgo/Lapack.hh>
29 #include <Geometry/RMatrix.hh>
30 
31 
32 
33 using namespace BIAS;
34 using namespace std;
35 
37  HMatrixBase() {
38 }
39 
41  HMatrixBase(Mat) {
42 }
43 
45 
46 {
48  return *this;
49 }
50 
52 }
53 
54 
56  HMatrix HTaylor(MatrixZero);
57  Matrix<double> Jac(2,2,MatrixZero);
58  GetJacobian(x,Jac);
59  for (unsigned int i=0; i<2; i++) {
60  for (unsigned int j=0; j<2; j++) {
61  HTaylor[i][j] = Jac[i][j];
62  }
63  }
64  HomgPoint2D y = (*this) * x;
65  if (fabs(y[2])<1e-9) {
66  // linearization point is at infinity, this doesnt give much information on
67  // finite points
68  BIASERR("Cannot linearize homography near infinity");
69  // return zero matrix here ???
70  HTaylor[2][2] = 0.0;
71  } else {
72  y.Homogenize();
73  HTaylor[2][2] = 1.0;
74  }
75  y = y - HTaylor * x;
76  for (unsigned int i=0; i<2; i++) HTaylor[i][2] = y[i];
77  return HTaylor;
78 }
79 
80 void HMatrix::
81 MapAcrossPlane(const PMatrix& P1o, const PMatrix& P2o,
82  const HomgPlane3D& scenePlane) {
83  // (0 0 0 0) is no valid plane:
84  BIASASSERT(scenePlane.NormL2()>1e-5);
85 
86  PMatrix P1(P1o);
87  PMatrix P2(P2o);
88  Vector3<double> C1,C2;
89  KMatrix K1, K2;
90  RMatrix R1, R2;
91  P1.GetK(K1);
92  P1.GetR(R1);
93  P1.GetC(C1);
94  P2.GetK(K2);
95  P2.GetR(R2);
96  P2.GetC(C2);
97  // cout<<"R1="<<R1<<" C1 "<<C1<<endl;
98  Vector3<double> normal(scenePlane[0], scenePlane[1], scenePlane[2]);
99  double norm = normal.NormL2();
100  if (norm/scenePlane.NormL2()<1e-9) {
101  //BIASWARN("using infinite homography");
102  // plane at infinity => infinity homography
103 // (*this) = K1.Invert()*R1.Transpose()*R2*K2;
104  (*this) = K2*R2*R1.Transpose()*K1.Invert();
105  return;
106  }
107  normal /= norm;
108  Vector3<double> point((-scenePlane[3]/norm)*normal);
109 
110  //cout<<"point on plane is "<<point<<", normal is "<<normal<<endl;
111 #ifdef BIAS_DEBUG
112  // make sure point is on plane
113  double tester = 0;
114  HomgPoint3D(point).ScalarProduct(scenePlane, tester);
115  BIASASSERT(fabs(tester)<1e-3);
116 #endif
117 
118  // now we change the coordinate system such that P1 is canonic
119  R2 = R1.Transpose()*R2;
120  C2 = R1.Transpose()*(C2-C1);
121  normal = R1.Transpose()*normal;
122  point = R1.Transpose()*(point-C1);
123 
124  //cout<<"R2="<<R2<<" C2="<<C2<<" normal="<<normal<<" point="<<point<<endl;
125  // and use the planar mapping ...
126  (*this) = point.ScalarProduct(normal)*R2.Transpose() -
127  R2.Transpose()*(C2.OuterProduct(normal));
128  // finally, add calibrations
129  (*this) = K2*(*this)*K1.Invert();
130 }
131 
132 
133 
134 
135 void HMatrix::GetMappedRange(const unsigned int OrigWidth,
136  const unsigned int OrigHeight,
137  BIAS::Vector2<double> & corner,
138  double & sizeWidth, double & sizeHeight) const {
139 
140  double minX, maxX, minY, maxY; // extrema
141 
142  // rect. coordinates of the 4 src. corners.
143  BIAS::HomgPoint2D mapped[4];
144 
145  // 0 3
146  // 1 2
147  mapped[0]= (*this) * BIAS::HomgPoint2D(0, 0, 1);
148  // H * '0' left, upper
149 
150  mapped[1]= (*this) * BIAS::HomgPoint2D(0, OrigHeight, 1);
151  // H * '1' left, lower
152 
153  mapped[2]= (*this) * BIAS::HomgPoint2D(OrigWidth, OrigHeight, 1);
154  // H * '2' right, lower
155 
156  mapped[3]= (*this) * BIAS::HomgPoint2D(OrigWidth, 0, 1);
157  // H * '3' right, upper
158 
159  // calc. extrema(xmy) of mapped corners
160  // init with first point:
161  mapped[0].Homogenize(); // let w==1
162  minX=maxX=mapped[0][0]; // x euclid
163  minY=maxY=mapped[0][1]; // y suclid
164  // homogenize and calc extrema
165  for (unsigned int i=1; i<4; i++) {
166  mapped[i].Homogenize();
167  // find new extrema
168  minX = (mapped[i][0]<minX) ? mapped[i][0] : minX; // x
169  maxX = (mapped[i][0]>maxX) ? mapped[i][0] : maxX;
170  minY = (mapped[i][1]<minY) ? mapped[i][1] : minY; // y
171  maxY = (mapped[i][1]>maxY) ? mapped[i][1] : maxY;
172  };
173 
174  corner=BIAS::Vector2<double>(minX, minY);
175  sizeWidth=maxX-minX;
176  sizeHeight=maxY-minY;
177 }
178 
179 double HMatrix::GetMappedError(const HomgPoint2D &PointPicOne, const HomgPoint2D &PointPicTwo) const {
180 
181  HomgPoint2D x1 = PointPicOne;
182  HomgPoint2D x2 = PointPicTwo;
183  x1.Homogenize();
184  x2.Homogenize();
185  HomgPoint2D mapped((*this) * x1);
186  mapped.Homogenize();
187  return (mapped[0]-x2[0])*(mapped[0]-x2[0]) + (mapped[1]-x2[1])*(mapped[1]-x2[1]);
188 }
189 
190 void HMatrix::GetJacobian(const HomgPoint2D& x, Matrix<double>& Jac) const {
191 #ifdef BIAS_DEBUG
192  if (!x.IsHomogenized()) {
193  BIASERR("supplied unhomogenized point !");
194  BIASABORT;
195  }
196  if ((Jac.GetRows()!=2) ||(Jac.GetCols()!=2)) {
197  BIASERR("Jacobian has wrong size !");
198  BIASABORT;
199  }
200 #endif
201 
202  // determine denominator w of mapped point
203  const double factor = ((*this)[2][0]*x[0]+(*this)[2][1]*x[1]+(*this)[2][2]);
204  // Is the point mapped to the line at infinity?
205  if (fabs(factor)<1e-10) {
206  // Jac will be complicated to obtain with lots of special cases.
207  Jac.SetZero();
208  // This catches finite points mapped to infinity in a very rough sense:
209  // there may be cases where lim(dH/dx) is not simply infinity but does
210  // not exist or where one might even obtain a finite value using l'Hospital
211  // Running along the line at infinity will typically have a different
212  // derivative than runnig orthogonally.
213  // Such cases cannot be handled well in 2D euclidean space and someone
214  // should think of a correct implementation here.
215  // For now, we simply set a huge value to avoid division by zero.
216  BIASWARN("Trying to obtain Jacobian of point mapped to infinity");
217  if ((*this)[0][0] * (*this)[2][1]*x[1] + (*this)[0][0]*(*this)[2][2] - (*this)[0][1]*x[1]*(*this)[2][0] - (*this)[0][2]*(*this)[2][0]<0.0)
218  Jac[0][0] = -HUGE_VAL;
219  else
220  Jac[0][0] = HUGE_VAL;
221 
222  if ((*this)[1][0]*x[0]*(*this)[2][1] - (*this)[1][1]*(*this)[2][0]*x[0] - (*this)[1][1]*(*this)[2][2] + (*this)[1][2]*(*this)[2][1] < 0.0)
223  Jac[1][1] = HUGE_VAL;
224  else
225  Jac[1][1] = -HUGE_VAL;
226  return;
227  }
228 
229  // make scaled version to improve conditioning
230  HMatrix scaled((*this)/factor);
231 
232  // ( x' y' )^T = H( (x y)^T), assume w==w'==1
233  const double enumx = (scaled[0][0]*x[0]+scaled[0][1]*x[1]+scaled[0][2]);
234  const double enumy = (scaled[1][0]*x[0]+scaled[1][1]*x[1]+scaled[1][2]);
235 
236  // x'/dx
237  Jac[0][0] = (scaled[0][0] - scaled[2][0]*enumx);
238  // x'/dy
239  Jac[0][1] = (scaled[0][1] - scaled[2][1]*enumx);
240  // y'/dx
241  Jac[1][0] = (scaled[1][0] - scaled[2][0]*enumy);
242  // y'/dy
243  Jac[1][1] = (scaled[1][1] - scaled[2][1]*enumy);
244 
245 
246 }
247 
249  Matrix2x2<double>& theta, double& d1, double& d2) {
250  // TODO: use svd2x2 here !
251  SVD mysvd;
252  if (mysvd.Compute(A)!=0)
253  return -1;
254  d1 = mysvd.GetS()[0];
255  d2 = mysvd.GetS()[1];
256  phi = mysvd.GetVT();
257  theta = mysvd.GetU() * phi;
258  // theta[0][0] = theta[1][1] = 0.5 * theta[0][0] + 0.5 * theta[1][1];
259  return 0;
260 }
261 
263  Matrix2x2<double>& theta, double& d1, double& d2) {
264  // TODO: use svd2x2 here !
265  SVD mysvd;
266 
267  int res = mysvd.Compute(A);
268  if (res!=0) {
269  BIASERR("Factorization of affine matrix failed ..."<<res<<flush);
270  return -1;
271  }
272  d1 = mysvd.GetS()[0];
273  d2 = mysvd.GetS()[1];
274  phi = mysvd.GetU().Transpose();
275  theta = mysvd.GetU() * mysvd.GetVT();
276  // theta[0][0] = theta[1][1] = 0.5 * theta[0][0] + 0.5 * theta[1][1];
277  return res;
278 }
279 
281  const Matrix2x2<double>& theta, const double& d1,
282  const double& d2) {
283  int res = 0;
285  d[0][0] = d1;
286  d[1][1] = d2;
287 
288  A = theta * phi.Invert() * d * phi;
289  return res;
290 }
291 
293  const Matrix2x2<double>& theta, const double& d1,
294  const double& d2) {
295  int res = 0;
297  d[0][0] = d1;
298  d[1][1] = d2;
299  A = phi.Invert() * d * phi * theta;
300  return res;
301 }
302 
303 double HMatrix::GetReprojectionError(std::vector<BIAS::HomgPoint2D>& p1,
304  std::vector<BIAS::HomgPoint2D>& p2) {
305 
306  HomgPoint2D x1,x2, mapped1, mapped2;
307 
308  if(p1.size() != p2.size()) BIASWARN("HMatrix::GetReprojectionError HomgPoint2D vectors have different sizes!");
309  int size = (p1.size()<p2.size())? p1.size():p2.size();
310 
311  double error = 0;
312  Matrix3x3<double> invH = (*this);
313  invH.InvertIP();
314  for(int i=0; i < size; i++){
315  x1 = p1[i];
316  x2 = p2[i];
317  x1.Homogenize();
318  x2.Homogenize();
319  mapped1 = ((*this) * x1);
320  mapped1.Homogenize();
321  mapped2 = invH * x2;
322  mapped2.Homogenize();
323  error += mapped1.DistanceSquared(x2);
324  error += mapped2.DistanceSquared(x1);
325  }
326  error /= size;
327  return error;
328 }
329 
330 
331 double HMatrix::
333  const HomgPoint2D& y) const {
334 
335  HomgPoint2D truePoint = (*this)*y;
336  truePoint.Homogenize();
337  HMatrix HLin = this->GetLinearized(x0);
338  HomgPoint2D approxPoint = HLin * y;
339  approxPoint.Homogenize();
340 
341  return (truePoint-approxPoint).NormL2();
342 }
int Invert(Matrix2x2< T > &result) const
analyticaly inverts matrix
Definition: Matrix2x2.cpp:115
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
a 3x3 Matrix describing projective transformations between planes
Definition: HMatrix.hh:39
Matrix< T > Transpose() const
transpose function, storing data destination matrix
Definition: Matrix.hh:823
HMatrixBase & operator=(const HMatrixBase &mat)
assignment operators calls corresponding operator from parent
Definition: HMatrixBase.hh:87
void GetMappedRange(const unsigned int OrigWidth, const unsigned int OrigHeight, BIAS::Vector2< double > &corner, double &sizeWidth, double &sizeHeight) const
maps the rectangle (0,0),(OrigWidth,OrigHeight) with this H and computes mapped range as corner + siz...
Definition: HMatrix.cpp:135
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
static int FactorizeAffineMatrixRRight(const Matrix2x2< double > &A, Matrix2x2< double > &phi, Matrix2x2< double > &theta, double &d1, double &d2)
decompose affine matrix into rotations and nonisotropic scalings
Definition: HMatrix.cpp:262
void OuterProduct(const Vector3< T > &v, Matrix3x3< T > &res) const
outer product, constructs a matrix.
Definition: Vector3.cpp:151
void GetJacobian(const HomgPoint2D &x, Matrix< double > &Jac) const
returns jacobian of H: R^2 –&gt; R^2
Definition: HMatrix.cpp:190
int GetR(Matrix3x3< double > &R)
Definition: PMatrix.cpp:204
int Compute(const Matrix< double > &M, double ZeroThreshold=DEFAULT_DOUBLE_ZERO_THRESHOLD)
set a new matrix and compute its decomposition.
Definition: SVD.cpp:102
static int FactorizeAffineMatrixRLeft(const Matrix2x2< double > &A, Matrix2x2< double > &phi, Matrix2x2< double > &theta, double &d1, double &d2)
decompose affine matrix into rotations and nonisotropic scalings
Definition: HMatrix.cpp:248
static int ComposeAffineMatrixRLeft(Matrix2x2< double > &A, const Matrix2x2< double > &phi, const Matrix2x2< double > &theta, const double &d1, const double &d2)
compose affine matrix from rotations and nonisotropic scalings
Definition: HMatrix.cpp:280
double NormL2() const
Return the L2 norm: sqrt(a^2 + b^2 + c^2 + d^2)
Definition: Vector4.hh:510
3D rotation matrix
Definition: RMatrix.hh:49
void SetZero()
Sets all values to zero.
Definition: Matrix.hh:856
unsigned int GetRows() const
Definition: Matrix.hh:202
const Matrix< double > & GetVT() const
return VT (=transposed(V))
Definition: SVD.hh:177
void MapAcrossPlane(const PMatrix &P1, const PMatrix &P2, const HomgPlane3D &scenePlane=HomgPlane3D(0, 0, 0, 1))
Set (*this) to map coordinates from camera p1 to p2 using the given scene plane.
Definition: HMatrix.cpp:81
describes a homography
Definition: HMatrixBase.hh:58
HMatrix GetLinearized(const HomgPoint2D &x) const
returns 1st order Taylor expansion of homography at x
Definition: HMatrix.cpp:55
double GetReprojectionError(std::vector< BIAS::HomgPoint2D > &p1, std::vector< BIAS::HomgPoint2D > &p2)
compute reprojection error for both vectors of HomgPoint2D
Definition: HMatrix.cpp:303
const Vector< double > & GetS() const
return S which is a vector of the singular values of A in descending order.
Definition: SVD.hh:167
unsigned int GetCols() const
Definition: Matrix.hh:204
int GetC(Vector3< double > &C)
computes translation vector origin world coo -&gt; origin camera coo (center), uses decomposition, which is cached
Definition: PMatrix.cpp:165
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
const Matrix< double > & GetU() const
return U U is a m x m orthogonal matrix
Definition: SVD.hh:187
double GetMappedError(const BIAS::HomgPoint2D &PointPicOne, const BIAS::HomgPoint2D &PointPicTwo) const
Definition: HMatrix.cpp:179
K describes the mapping from world coordinates (wcs) to pixel coordinates (pcs).
Definition: KMatrix.hh:48
double ComputeLinearizationError(const HomgPoint2D &x0, const HomgPoint2D &y) const
compute distance between y mapped with homography or first order taylor approximation at development ...
Definition: HMatrix.cpp:332
HMatrix & operator=(const HMatrix &mat)
Definition: HMatrix.cpp:44
int InvertIP()
In place matrix conversion.
Definition: Matrix3x3.cpp:420
describes a projective 3D -&gt; 2D mapping in homogenous coordinates
Definition: PMatrix.hh:88
static int ComposeAffineMatrixRRight(Matrix2x2< double > &A, const Matrix2x2< double > &phi, const Matrix2x2< double > &theta, const double &d1, const double &d2)
compose affine matrix from rotations and nonisotropic scalings
Definition: HMatrix.cpp:292
KMatrix Invert() const
returns analyticaly inverted matrix
Definition: KMatrix.cpp:31
bool IsHomogenized() const
Definition: HomgPoint2D.hh:202
HOMGPOINT2D_TYPE DistanceSquared(const HomgPoint2D &point) const
Definition: HomgPoint2D.hh:377
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
class BIASGeometryBase_EXPORT HomgPoint2D
class BIASGeometryBase_EXPORT HomgPoint3D
int GetK(KMatrix &K)
calibration matrix
Definition: PMatrix.cpp:220
A homogeneous plane (in P^3) All points X on the plane p fulfill p &#39; * X = 0.
Definition: HomgPlane3D.hh:46