Hugin trunk 0.1
Loading...
Searching...
No Matches
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
28namespace lfeat
29{
30
31const int Homography::kNCols = 8;
32
33inline int fsign(double x)
34{
35 return (x > 0 ? 1 : (x < 0) ? -1 : 0);
36}
37
38bool Givens(double** C, double* d, double* x, double* r, int N, int n, int want_r);
39
40Homography::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
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
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 {
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
130std::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
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
172void 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 {
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
241Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
242(QR-decomposition). Direct implementation of the algorithm
243presented in H.R.Schwarz: Numerische Mathematik, 'equation'
244number (7.33)
245
246If 'd == NULL', d is not accesed: the routine just computes the QR
247decomposition of C and exits.
248
249If 'want_r == 0', r is not rotated back (\hat{r} is returned
250instead).
251
252*****************************************************************/
253
254bool 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}
void allocMemory(int iNPoints)
static const int kNCols
Definition Homography.h:52
void initMatchesNormalization(PointMatchVector_t &iMatches)
double ** _Amat
Definition Homography.h:59
void transformPoint(double iX, double iY, double &oX, double &oY)
bool estimate(PointMatchVector_t &iMatches)
double _H[3][3]
Definition Homography.h:65
void addMatch(size_t iIndex, PointMatch &iMatch)
static double sigma
int fsign(double x)
bool Givens(double **C, double *d, double *x, double *r, int N, int n, int want_r)
std::ostream & operator<<(std::ostream &o, const Homography &H)
std::shared_ptr< PointMatch > PointMatchPtr
Definition PointMatch.h:52
std::vector< PointMatchPtr > PointMatchVector_t
Definition PointMatch.h:53
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41