Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Homography.cpp
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007-2008 Anael Orlinski
3 *
4 * This file is part of Panomatic.
5 *
6 * Panomatic is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Panomatic is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Panomatic; if not, write to the Free Software
18 * <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <iostream>
22 #include <float.h>
23 #include <math.h>
24 //#include "Tracer.h"
25 
26 #include "Homography.h"
27 
28 namespace lfeat
29 {
30 
31 const int Homography::kNCols = 8;
32 
33 inline int fsign(double x)
34 {
35  return (x > 0 ? 1 : (x < 0) ? -1 : 0);
36 }
37 
38 bool Givens(double** C, double* d, double* x, double* r, int N, int n, int want_r);
39 
40 Homography::Homography(void) : _nMatches(0)
41 {
42  _Amat = NULL;
43  _Bvec = NULL;
44  _Rvec = NULL;
45  _Xvec = NULL;
46  _v1x = 0;
47  _v2x = 0;
48  _v1y = 0;
49  _v2y = 0;
50  for (size_t i = 0; i < 3; ++i)
51  {
52  for (size_t j = 0; j < 3; ++j)
53  {
54  _H[i][j] = 0;
55  };
56  };
57 }
58 
59 void Homography::allocMemory(int iNMatches)
60 {
61  int aNRows = iNMatches * 2;
62  _Amat = new double*[aNRows];
63  for(int aRowIter = 0; aRowIter < aNRows; ++aRowIter)
64  {
65  _Amat[aRowIter] = new double[kNCols];
66  }
67 
68  _Bvec = new double[aNRows];
69  _Rvec = new double[aNRows];
70  _Xvec = new double[kNCols];
71 
72  _nMatches = iNMatches;
73 }
74 
76 {
77  // free memory
78  delete[] _Bvec;
79  delete[] _Rvec;
80  delete[] _Xvec;
81  for(int aRowIter = 0; aRowIter < 2 * _nMatches; ++aRowIter)
82  {
83  delete[] _Amat[aRowIter];
84  }
85  delete[] _Amat;
86 
87  // reset number of matches
88  _nMatches = 0;
89 
90 }
91 
93 {
94  if (_nMatches)
95  {
96  freeMemory();
97  }
98 }
99 
101 {
102  // for each set of points (img1, img2), find the vector
103  // to apply to all points to have coordinates centered
104  // on the barycenter.
105 
106  _v1x = 0;
107  _v2x = 0;
108  _v1y = 0;
109  _v2y = 0;
110 
111  //estimate the center of gravity
112  for (size_t i = 0; i < iMatches.size(); ++i)
113  {
114  PointMatchPtr& aMatchIt = iMatches[i];
115  //aMatchIt->print();
116 
117  _v1x += aMatchIt->_img1_x;
118  _v1y += aMatchIt->_img1_y;
119  _v2x += aMatchIt->_img2_x;
120  _v2y += aMatchIt->_img2_y;
121  }
122 
123  _v1x /= (double)iMatches.size();
124  _v1y /= (double)iMatches.size();
125  _v2x /= (double)iMatches.size();
126  _v2y /= (double)iMatches.size();
127 }
128 
129 
130 std::ostream& operator<< (std::ostream& o, const Homography& H)
131 {
132  o << H._H[0][0] << "\t" << H._H[0][1] << "\t" << H._H[0][2] << std::endl
133  << H._H[1][0] << "\t" << H._H[1][1] << "\t" << H._H[1][2] << std::endl
134  << H._H[2][0] << "\t" << H._H[2][1] << "\t" << H._H[2][2] << std::endl;
135 
136  return o;
137 }
138 
139 void Homography::addMatch(size_t iIndex, PointMatch& iMatch)
140 {
141  size_t aRow = iIndex * 2;
142  double aI1x = iMatch._img1_x - _v1x;
143  double aI1y = iMatch._img1_y - _v1y;
144  double aI2x = iMatch._img2_x - _v2x;
145  double aI2y = iMatch._img2_y - _v2y;
146 
147  _Amat[aRow][0] = 0;
148  _Amat[aRow][1] = 0;
149  _Amat[aRow][2] = 0;
150  _Amat[aRow][3] = - aI1x;
151  _Amat[aRow][4] = - aI1y;
152  _Amat[aRow][5] = -1;
153  _Amat[aRow][6] = aI1x * aI2y;
154  _Amat[aRow][7] = aI1y * aI2y;
155 
156  _Bvec[aRow] = aI2y;
157 
158  aRow++;
159 
160  _Amat[aRow][0] = aI1x;
161  _Amat[aRow][1] = aI1y;
162  _Amat[aRow][2] = 1;
163  _Amat[aRow][3] = 0;
164  _Amat[aRow][4] = 0;
165  _Amat[aRow][5] = 0;
166  _Amat[aRow][6] = - aI1x * aI2x;
167  _Amat[aRow][7] = - aI1y * aI2x;
168 
169  _Bvec[aRow] = - aI2x;
170 }
171 
172 void Homography::transformPoint(double iX, double iY, double& oX, double& oY)
173 {
174  double aX = iX - _v1x;
175  double aY = iY - _v1y;
176  double aK = double(1. / (_H[2][0] * aX + _H[2][1] * aY + _H[2][2]));
177 
178  oX = aK * (_H[0][0] * aX + _H[0][1] * aY + _H[0][2]) + _v2x;
179  oY = aK * (_H[1][0] * aX + _H[1][1] * aY + _H[1][2]) + _v2y;
180 }
181 
183 {
184  // check the number of matches we need at least 4.
185  if (iMatches.size() < 4)
186  {
187  //TRACE_ERROR("At least 4 matches are needed for homography");
188  return false;
189  }
190 
191  // create matrices for least-squares solving
192 
193  // if there is a different size of matrices set, delete them
194  if (_nMatches != (int)iMatches.size() && _nMatches != 0)
195  {
196  freeMemory();
197  }
198 
199  // if there is no memory allocated, alloc memory
200  if (_nMatches == 0)
201  {
202  allocMemory((int)iMatches.size());
203  }
204 
205  // fill the matrices and vectors with points
206  for (size_t aFillRow = 0; aFillRow < iMatches.size(); ++aFillRow)
207  {
208  addMatch(aFillRow, *(iMatches[aFillRow]));
209  }
210 
211  // solve the system
212  if (!Givens(_Amat, _Bvec, _Xvec, _Rvec, _nMatches*2, kNCols, 0))
213  {
214  //TRACE_ERROR("Failed to solve the linear system");
215  return false;
216  }
217 
218  // fill the homography matrix with the values.
219 
220  _H[0][0] = _Xvec[0];
221  _H[0][1] = _Xvec[1];
222  _H[0][2] = _Xvec[2];
223 
224  _H[1][0] = _Xvec[3];
225  _H[1][1] = _Xvec[4];
226  _H[1][2] = _Xvec[5];
227 
228  _H[2][0] = _Xvec[6];
229  _H[2][1] = _Xvec[7];
230  _H[2][2] = 1.0;
231 
232  return true;
233 
234 }
235 
236 
237 
238 
239 /*****************************************************************
240 
241 Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
242 (QR-decomposition). Direct implementation of the algorithm
243 presented in H.R.Schwarz: Numerische Mathematik, 'equation'
244 number (7.33)
245 
246 If 'd == NULL', d is not accesed: the routine just computes the QR
247 decomposition of C and exits.
248 
249 If 'want_r == 0', r is not rotated back (\hat{r} is returned
250 instead).
251 
252 *****************************************************************/
253 
254 bool Givens(double** C, double* d, double* x, double* r, int N, int n, int want_r)
255 {
256  int i, j, k;
257  double w, gamma, sigma, rho, temp;
258  double epsilon = DBL_EPSILON; /* FIXME (?) */
259 
260  /*
261  * First, construct QR decomposition of C, by 'rotating away'
262  * all elements of C below the diagonal. The rotations are
263  * stored in place as Givens coefficients rho.
264  * Vector d is also rotated in this same turn, if it exists
265  */
266  for (j = 0; j < n; j++)
267  {
268  for (i = j + 1; i < N; i++)
269  {
270  if (C[i][j])
271  {
272  if (fabs(C[j][j]) < epsilon * fabs(C[i][j]))
273  {
274  /* find the rotation parameters */
275  w = -C[i][j];
276  gamma = 0;
277  sigma = 1;
278  rho = 1;
279  }
280  else
281  {
282  w = fsign(C[j][j]) * sqrt(C[j][j] * C[j][j] + C[i][j] * C[i][j]);
283  if (w == 0)
284  {
285  return false;
286  }
287  gamma = C[j][j] / w;
288  sigma = -C[i][j] / w;
289  rho = (fabs(sigma) < gamma) ? sigma : fsign(sigma) / gamma;
290  }
291  C[j][j] = w;
292  C[i][j] = rho; /* store rho in place, for later use */
293  for (k = j + 1; k < n; k++)
294  {
295  /* rotation on index pair (i,j) */
296  temp = gamma * C[j][k] - sigma * C[i][k];
297  C[i][k] = sigma * C[j][k] + gamma * C[i][k];
298  C[j][k] = temp;
299 
300  }
301  if (d) /* if no d vector given, don't use it */
302  {
303  temp = gamma * d[j] - sigma * d[i]; /* rotate d */
304  d[i] = sigma * d[j] + gamma * d[i];
305  d[j] = temp;
306  }
307  }
308  }
309  }
310 
311  if (!d) /* stop here if no d was specified */
312  {
313  return true;
314  }
315 
316  /* solve R*x+d = 0, by backsubstitution */
317  for (i = n - 1; i >= 0; i--)
318  {
319  double s = d[i];
320 
321  r[i] = 0; /* ... and also set r[i] = 0 for i<n */
322  for (k = i + 1; k < n; k++)
323  {
324  s += C[i][k] * x[k];
325  }
326  if (C[i][i] == 0)
327  {
328  return false;
329  }
330  x[i] = -s / C[i][i];
331  }
332 
333  for (i = n; i < N; i++)
334  {
335  r[i] = d[i]; /* set the other r[i] to d[i] */
336  }
337 
338  if (!want_r) /* if r isn't needed, stop here */
339  {
340  return true;
341  }
342 
343  /* rotate back the r vector */
344  for (j = n - 1; j >= 0; j--)
345  {
346  for (i = N - 1; i >= 0; i--)
347  {
348  if ((rho = C[i][j]) == 1) /* reconstruct gamma, sigma from stored rho */
349  {
350  gamma = 0;
351  sigma = 1;
352  }
353  else if (fabs(rho) < 1)
354  {
355  sigma = rho;
356  gamma = sqrt(1 - sigma * sigma);
357  }
358  else
359  {
360  gamma = 1 / fabs(rho);
361  sigma = fsign(rho) * sqrt(1 - gamma * gamma);
362  }
363  temp = gamma * r[j] + sigma * r[i]; /* rotate back indices (i,j) */
364  r[i] = -sigma * r[j] + gamma * r[i];
365  r[j] = temp;
366  }
367  }
368  return true;
369 }
370 
371 }
double * _Rvec
Definition: Homography.h:61
std::vector< PointMatchPtr > PointMatchVector_t
Definition: PointMatch.h:53
double * _Bvec
Definition: Homography.h:60
double * _Xvec
Definition: Homography.h:62
void initMatchesNormalization(PointMatchVector_t &iMatches)
Definition: Homography.cpp:100
void transformPoint(double iX, double iY, double &oX, double &oY)
Definition: Homography.cpp:172
void addMatch(size_t iIndex, PointMatch &iMatch)
Definition: Homography.cpp:139
static double sigma
double ** _Amat
Definition: Homography.h:59
bool Givens(double **C, double *d, double *x, double *r, int N, int n, int want_r)
Definition: Homography.cpp:254
int fsign(double x)
Definition: Homography.cpp:33
void allocMemory(int iNPoints)
Definition: Homography.cpp:59
std::ostream & operator<<(std::ostream &o, const Homography &H)
Definition: Homography.cpp:130
bool estimate(PointMatchVector_t &iMatches)
Definition: Homography.cpp:182
static const int kNCols
Definition: Homography.h:52
std::shared_ptr< PointMatch > PointMatchPtr
Definition: PointMatch.h:52
double _H[3][3]
Definition: Homography.h:65