blob: 23243dd9e60b37c08489207d2f1cc2a8d3892b0a [file] [log] [blame]
Debargha Mukherjee7ae7aea2017-05-04 15:17:17 -07001/*
2 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12#include <memory.h>
13#include <math.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <assert.h>
17
18static const double TINY_NEAR_ZERO = 1.0E-16;
19
20// Solves Ax = b, where x and b are column vectors of size nx1 and A is nxn
21static INLINE int linsolve(int n, double *A, int stride, double *b, double *x) {
22 int i, j, k;
23 double c;
24 // Forward elimination
25 for (k = 0; k < n - 1; k++) {
26 // Bring the largest magitude to the diagonal position
27 for (i = n - 1; i > k; i--) {
28 if (fabs(A[(i - 1) * stride + k]) < fabs(A[i * stride + k])) {
29 for (j = 0; j < n; j++) {
30 c = A[i * stride + j];
31 A[i * stride + j] = A[(i - 1) * stride + j];
32 A[(i - 1) * stride + j] = c;
33 }
34 c = b[i];
35 b[i] = b[i - 1];
36 b[i - 1] = c;
37 }
38 }
39 for (i = k; i < n - 1; i++) {
40 if (fabs(A[k * stride + k]) < TINY_NEAR_ZERO) return 0;
41 c = A[(i + 1) * stride + k] / A[k * stride + k];
42 for (j = 0; j < n; j++) A[(i + 1) * stride + j] -= c * A[k * stride + j];
43 b[i + 1] -= c * b[k];
44 }
45 }
46 // Backward substitution
47 for (i = n - 1; i >= 0; i--) {
48 if (fabs(A[i * stride + i]) < TINY_NEAR_ZERO) return 0;
49 c = 0;
50 for (j = i + 1; j <= n - 1; j++) c += A[i * stride + j] * x[j];
51 x[i] = (b[i] - c) / A[i * stride + i];
52 }
53
54 return 1;
55}
56
57////////////////////////////////////////////////////////////////////////////////
58// Least-squares
59// Solves for n-dim x in a least squares sense to minimize |Ax - b|^2
60// The solution is simply x = (A'A)^-1 A'b or simply the solution for
61// the system: A'A x = A'b
62static INLINE int least_squares(int n, double *A, int rows, int stride,
63 double *b, double *scratch, double *x) {
64 int i, j, k;
65 double *scratch_ = NULL;
66 double *AtA, *Atb;
67 if (!scratch) {
68 scratch_ = (double *)aom_malloc(sizeof(*scratch) * n * (n + 1));
69 scratch = scratch_;
70 }
71 AtA = scratch;
72 Atb = scratch + n * n;
73
74 for (i = 0; i < n; ++i) {
75 for (j = i; j < n; ++j) {
76 AtA[i * n + j] = 0.0;
77 for (k = 0; k < rows; ++k)
78 AtA[i * n + j] += A[k * stride + i] * A[k * stride + j];
79 AtA[j * n + i] = AtA[i * n + j];
80 }
81 Atb[i] = 0;
82 for (k = 0; k < rows; ++k) Atb[i] += A[k * stride + i] * b[k];
83 }
84 int ret = linsolve(n, AtA, n, Atb, x);
85 if (scratch_) aom_free(scratch_);
86 return ret;
87}
88
89// Matrix multiply
90static INLINE void multiply_mat(const double *m1, const double *m2, double *res,
91 const int m1_rows, const int inner_dim,
92 const int m2_cols) {
93 double sum;
94
95 int row, col, inner;
96 for (row = 0; row < m1_rows; ++row) {
97 for (col = 0; col < m2_cols; ++col) {
98 sum = 0;
99 for (inner = 0; inner < inner_dim; ++inner)
100 sum += m1[row * inner_dim + inner] * m2[inner * m2_cols + col];
101 *(res++) = sum;
102 }
103 }
104}
105
106//
107// The functions below are needed only for homography computation
108// Remove if the homography models are not used.
109//
110///////////////////////////////////////////////////////////////////////////////
111// svdcmp
112// Adopted from Numerical Recipes in C
113
114static INLINE double sign(double a, double b) {
115 return ((b) >= 0 ? fabs(a) : -fabs(a));
116}
117
118static INLINE double pythag(double a, double b) {
119 double ct;
120 const double absa = fabs(a);
121 const double absb = fabs(b);
122
123 if (absa > absb) {
124 ct = absb / absa;
125 return absa * sqrt(1.0 + ct * ct);
126 } else {
127 ct = absa / absb;
128 return (absb == 0) ? 0 : absb * sqrt(1.0 + ct * ct);
129 }
130}
131
132static INLINE int svdcmp(double **u, int m, int n, double w[], double **v) {
133 const int max_its = 30;
134 int flag, i, its, j, jj, k, l, nm;
135 double anorm, c, f, g, h, s, scale, x, y, z;
136 double *rv1 = (double *)aom_malloc(sizeof(*rv1) * (n + 1));
137 g = scale = anorm = 0.0;
138 for (i = 0; i < n; i++) {
139 l = i + 1;
140 rv1[i] = scale * g;
141 g = s = scale = 0.0;
142 if (i < m) {
143 for (k = i; k < m; k++) scale += fabs(u[k][i]);
144 if (scale != 0.) {
145 for (k = i; k < m; k++) {
146 u[k][i] /= scale;
147 s += u[k][i] * u[k][i];
148 }
149 f = u[i][i];
150 g = -sign(sqrt(s), f);
151 h = f * g - s;
152 u[i][i] = f - g;
153 for (j = l; j < n; j++) {
154 for (s = 0.0, k = i; k < m; k++) s += u[k][i] * u[k][j];
155 f = s / h;
156 for (k = i; k < m; k++) u[k][j] += f * u[k][i];
157 }
158 for (k = i; k < m; k++) u[k][i] *= scale;
159 }
160 }
161 w[i] = scale * g;
162 g = s = scale = 0.0;
163 if (i < m && i != n - 1) {
164 for (k = l; k < n; k++) scale += fabs(u[i][k]);
165 if (scale != 0.) {
166 for (k = l; k < n; k++) {
167 u[i][k] /= scale;
168 s += u[i][k] * u[i][k];
169 }
170 f = u[i][l];
171 g = -sign(sqrt(s), f);
172 h = f * g - s;
173 u[i][l] = f - g;
174 for (k = l; k < n; k++) rv1[k] = u[i][k] / h;
175 for (j = l; j < m; j++) {
176 for (s = 0.0, k = l; k < n; k++) s += u[j][k] * u[i][k];
177 for (k = l; k < n; k++) u[j][k] += s * rv1[k];
178 }
179 for (k = l; k < n; k++) u[i][k] *= scale;
180 }
181 }
182 anorm = fmax(anorm, (fabs(w[i]) + fabs(rv1[i])));
183 }
184
185 for (i = n - 1; i >= 0; i--) {
186 if (i < n - 1) {
187 if (g != 0.) {
188 for (j = l; j < n; j++) v[j][i] = (u[i][j] / u[i][l]) / g;
189 for (j = l; j < n; j++) {
190 for (s = 0.0, k = l; k < n; k++) s += u[i][k] * v[k][j];
191 for (k = l; k < n; k++) v[k][j] += s * v[k][i];
192 }
193 }
194 for (j = l; j < n; j++) v[i][j] = v[j][i] = 0.0;
195 }
196 v[i][i] = 1.0;
197 g = rv1[i];
198 l = i;
199 }
200 for (i = AOMMIN(m, n) - 1; i >= 0; i--) {
201 l = i + 1;
202 g = w[i];
203 for (j = l; j < n; j++) u[i][j] = 0.0;
204 if (g != 0.) {
205 g = 1.0 / g;
206 for (j = l; j < n; j++) {
207 for (s = 0.0, k = l; k < m; k++) s += u[k][i] * u[k][j];
208 f = (s / u[i][i]) * g;
209 for (k = i; k < m; k++) u[k][j] += f * u[k][i];
210 }
211 for (j = i; j < m; j++) u[j][i] *= g;
212 } else {
213 for (j = i; j < m; j++) u[j][i] = 0.0;
214 }
215 ++u[i][i];
216 }
217 for (k = n - 1; k >= 0; k--) {
218 for (its = 0; its < max_its; its++) {
219 flag = 1;
220 for (l = k; l >= 0; l--) {
221 nm = l - 1;
222 if ((double)(fabs(rv1[l]) + anorm) == anorm || nm < 0) {
223 flag = 0;
224 break;
225 }
226 if ((double)(fabs(w[nm]) + anorm) == anorm) break;
227 }
228 if (flag) {
229 c = 0.0;
230 s = 1.0;
231 for (i = l; i <= k; i++) {
232 f = s * rv1[i];
233 rv1[i] = c * rv1[i];
234 if ((double)(fabs(f) + anorm) == anorm) break;
235 g = w[i];
236 h = pythag(f, g);
237 w[i] = h;
238 h = 1.0 / h;
239 c = g * h;
240 s = -f * h;
241 for (j = 0; j < m; j++) {
242 y = u[j][nm];
243 z = u[j][i];
244 u[j][nm] = y * c + z * s;
245 u[j][i] = z * c - y * s;
246 }
247 }
248 }
249 z = w[k];
250 if (l == k) {
251 if (z < 0.0) {
252 w[k] = -z;
253 for (j = 0; j < n; j++) v[j][k] = -v[j][k];
254 }
255 break;
256 }
257 if (its == max_its - 1) {
258 aom_free(rv1);
259 return 1;
260 }
261 assert(k > 0);
262 x = w[l];
263 nm = k - 1;
264 y = w[nm];
265 g = rv1[nm];
266 h = rv1[k];
267 f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
268 g = pythag(f, 1.0);
269 f = ((x - z) * (x + z) + h * ((y / (f + sign(g, f))) - h)) / x;
270 c = s = 1.0;
271 for (j = l; j <= nm; j++) {
272 i = j + 1;
273 g = rv1[i];
274 y = w[i];
275 h = s * g;
276 g = c * g;
277 z = pythag(f, h);
278 rv1[j] = z;
279 c = f / z;
280 s = h / z;
281 f = x * c + g * s;
282 g = g * c - x * s;
283 h = y * s;
284 y *= c;
285 for (jj = 0; jj < n; jj++) {
286 x = v[jj][j];
287 z = v[jj][i];
288 v[jj][j] = x * c + z * s;
289 v[jj][i] = z * c - x * s;
290 }
291 z = pythag(f, h);
292 w[j] = z;
293 if (z != 0.) {
294 z = 1.0 / z;
295 c = f * z;
296 s = h * z;
297 }
298 f = c * g + s * y;
299 x = c * y - s * g;
300 for (jj = 0; jj < m; jj++) {
301 y = u[jj][j];
302 z = u[jj][i];
303 u[jj][j] = y * c + z * s;
304 u[jj][i] = z * c - y * s;
305 }
306 }
307 rv1[l] = 0.0;
308 rv1[k] = f;
309 w[k] = x;
310 }
311 }
312 aom_free(rv1);
313 return 0;
314}
315
316static INLINE int SVD(double *U, double *W, double *V, double *matx, int M,
317 int N) {
318 // Assumes allocation for U is MxN
319 double **nrU = (double **)aom_malloc((M) * sizeof(*nrU));
320 double **nrV = (double **)aom_malloc((N) * sizeof(*nrV));
321 int problem, i;
322
323 problem = !(nrU && nrV);
324 if (!problem) {
325 for (i = 0; i < M; i++) {
326 nrU[i] = &U[i * N];
327 }
328 for (i = 0; i < N; i++) {
329 nrV[i] = &V[i * N];
330 }
331 } else {
332 if (nrU) aom_free(nrU);
333 if (nrV) aom_free(nrV);
334 return 1;
335 }
336
337 /* copy from given matx into nrU */
338 for (i = 0; i < M; i++) {
339 memcpy(&(nrU[i][0]), matx + N * i, N * sizeof(*matx));
340 }
341
342 /* HERE IT IS: do SVD */
343 if (svdcmp(nrU, M, N, W, nrV)) {
344 aom_free(nrU);
345 aom_free(nrV);
346 return 1;
347 }
348
349 /* aom_free Numerical Recipes arrays */
350 aom_free(nrU);
351 aom_free(nrV);
352
353 return 0;
354}