blob: 781f528ebfd8b2ab4551ae4f0dce7d9c59782014 [file] [log] [blame]
Sarah Parker4dc0f1b2016-08-09 17:40:53 -07001/*
Yaowu Xubde4ac82016-11-28 15:26:06 -08002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Sarah Parker4dc0f1b2016-08-09 17:40:53 -07003 *
Yaowu Xubde4ac82016-11-28 15:26:06 -08004 * 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.
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070010 */
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070011#include <memory.h>
12#include <math.h>
13#include <time.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <assert.h>
17
Yaowu Xuf883b422016-08-30 14:01:10 -070018#include "av1/encoder/ransac.h"
Debargha Mukherjee7ae7aea2017-05-04 15:17:17 -070019#include "av1/encoder/mathutils.h"
Alex Converse9d068c12017-08-03 11:48:19 -070020#include "av1/encoder/random.h"
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070021
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070022#define MAX_MINPTS 4
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070023#define MAX_DEGENERATE_ITER 10
24#define MINPTS_MULTIPLIER 5
25
Debargha Mukherjee5dfa9302017-02-10 05:00:08 -080026#define INLIER_THRESHOLD 1.0
27#define MIN_TRIALS 20
28
Sarah Parker4dc0f1b2016-08-09 17:40:53 -070029////////////////////////////////////////////////////////////////////////////////
30// ransac
Sarah Parkerf9a961c2016-09-06 11:25:04 -070031typedef int (*IsDegenerateFunc)(double *p);
32typedef void (*NormalizeFunc)(double *p, int np, double *T);
33typedef void (*DenormalizeFunc)(double *params, double *T1, double *T2);
34typedef int (*FindTransformationFunc)(int points, double *points1,
35 double *points2, double *params);
Sarah Parker97fa6da2016-09-23 11:17:27 -070036typedef void (*ProjectPointsDoubleFunc)(double *mat, double *points,
37 double *proj, const int n,
38 const int stride_points,
39 const int stride_proj);
40
41static void project_points_double_translation(double *mat, double *points,
42 double *proj, const int n,
43 const int stride_points,
44 const int stride_proj) {
45 int i;
46 for (i = 0; i < n; ++i) {
47 const double x = *(points++), y = *(points++);
Debargha Mukherjee8db4c772016-11-07 12:54:21 -080048 *(proj++) = x + mat[0];
49 *(proj++) = y + mat[1];
Sarah Parker97fa6da2016-09-23 11:17:27 -070050 points += stride_points - 2;
51 proj += stride_proj - 2;
52 }
53}
54
55static void project_points_double_rotzoom(double *mat, double *points,
56 double *proj, const int n,
57 const int stride_points,
58 const int stride_proj) {
59 int i;
60 for (i = 0; i < n; ++i) {
61 const double x = *(points++), y = *(points++);
Debargha Mukherjee8db4c772016-11-07 12:54:21 -080062 *(proj++) = mat[2] * x + mat[3] * y + mat[0];
63 *(proj++) = -mat[3] * x + mat[2] * y + mat[1];
Sarah Parker97fa6da2016-09-23 11:17:27 -070064 points += stride_points - 2;
65 proj += stride_proj - 2;
66 }
67}
68
69static void project_points_double_affine(double *mat, double *points,
70 double *proj, const int n,
71 const int stride_points,
72 const int stride_proj) {
73 int i;
74 for (i = 0; i < n; ++i) {
75 const double x = *(points++), y = *(points++);
Debargha Mukherjee8db4c772016-11-07 12:54:21 -080076 *(proj++) = mat[2] * x + mat[3] * y + mat[0];
77 *(proj++) = mat[4] * x + mat[5] * y + mat[1];
Sarah Parker97fa6da2016-09-23 11:17:27 -070078 points += stride_points - 2;
79 proj += stride_proj - 2;
80 }
81}
82
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -080083static void normalize_homography(double *pts, int n, double *T) {
84 double *p = pts;
85 double mean[2] = { 0, 0 };
86 double msqe = 0;
87 double scale;
88 int i;
Debargha Mukherjeeafe7c5f2017-06-22 13:47:23 -070089
90 assert(n > 0);
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -080091 for (i = 0; i < n; ++i, p += 2) {
92 mean[0] += p[0];
93 mean[1] += p[1];
94 }
95 mean[0] /= n;
96 mean[1] /= n;
97 for (p = pts, i = 0; i < n; ++i, p += 2) {
98 p[0] -= mean[0];
99 p[1] -= mean[1];
100 msqe += sqrt(p[0] * p[0] + p[1] * p[1]);
101 }
102 msqe /= n;
Debargha Mukherjee11f0e402017-03-29 07:42:40 -0700103 scale = (msqe == 0 ? 1.0 : sqrt(2) / msqe);
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800104 T[0] = scale;
105 T[1] = 0;
106 T[2] = -scale * mean[0];
107 T[3] = 0;
108 T[4] = scale;
109 T[5] = -scale * mean[1];
110 T[6] = 0;
111 T[7] = 0;
112 T[8] = 1;
113 for (p = pts, i = 0; i < n; ++i, p += 2) {
114 p[0] *= scale;
115 p[1] *= scale;
116 }
117}
118
119static void invnormalize_mat(double *T, double *iT) {
120 double is = 1.0 / T[0];
121 double m0 = -T[2] * is;
122 double m1 = -T[5] * is;
123 iT[0] = is;
124 iT[1] = 0;
125 iT[2] = m0;
126 iT[3] = 0;
127 iT[4] = is;
128 iT[5] = m1;
129 iT[6] = 0;
130 iT[7] = 0;
131 iT[8] = 1;
132}
133
134static void denormalize_homography(double *params, double *T1, double *T2) {
135 double iT2[9];
136 double params2[9];
137 invnormalize_mat(T2, iT2);
138 multiply_mat(params, T1, params2, 3, 3, 3);
139 multiply_mat(iT2, params2, params, 3, 3, 3);
140}
141
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800142static void denormalize_affine_reorder(double *params, double *T1, double *T2) {
143 double params_denorm[MAX_PARAMDIM];
144 params_denorm[0] = params[0];
145 params_denorm[1] = params[1];
146 params_denorm[2] = params[4];
147 params_denorm[3] = params[2];
148 params_denorm[4] = params[3];
149 params_denorm[5] = params[5];
150 params_denorm[6] = params_denorm[7] = 0;
151 params_denorm[8] = 1;
152 denormalize_homography(params_denorm, T1, T2);
153 params[0] = params_denorm[2];
154 params[1] = params_denorm[5];
155 params[2] = params_denorm[0];
156 params[3] = params_denorm[1];
157 params[4] = params_denorm[3];
158 params[5] = params_denorm[4];
159 params[6] = params[7] = 0;
160}
161
162static void denormalize_rotzoom_reorder(double *params, double *T1,
163 double *T2) {
164 double params_denorm[MAX_PARAMDIM];
165 params_denorm[0] = params[0];
166 params_denorm[1] = params[1];
167 params_denorm[2] = params[2];
168 params_denorm[3] = -params[1];
169 params_denorm[4] = params[0];
170 params_denorm[5] = params[3];
171 params_denorm[6] = params_denorm[7] = 0;
172 params_denorm[8] = 1;
173 denormalize_homography(params_denorm, T1, T2);
174 params[0] = params_denorm[2];
175 params[1] = params_denorm[5];
176 params[2] = params_denorm[0];
177 params[3] = params_denorm[1];
178 params[4] = -params[3];
179 params[5] = params[2];
180 params[6] = params[7] = 0;
181}
182
183static void denormalize_translation_reorder(double *params, double *T1,
184 double *T2) {
185 double params_denorm[MAX_PARAMDIM];
186 params_denorm[0] = 1;
187 params_denorm[1] = 0;
188 params_denorm[2] = params[0];
189 params_denorm[3] = 0;
190 params_denorm[4] = 1;
191 params_denorm[5] = params[1];
192 params_denorm[6] = params_denorm[7] = 0;
193 params_denorm[8] = 1;
194 denormalize_homography(params_denorm, T1, T2);
195 params[0] = params_denorm[2];
196 params[1] = params_denorm[5];
197 params[2] = params[5] = 1;
198 params[3] = params[4] = 0;
199 params[6] = params[7] = 0;
200}
201
Yaowu Xu4ff59b52017-04-24 12:41:56 -0700202static int find_translation(int np, double *pts1, double *pts2, double *mat) {
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800203 int i;
204 double sx, sy, dx, dy;
205 double sumx, sumy;
206
207 double T1[9], T2[9];
208 normalize_homography(pts1, np, T1);
209 normalize_homography(pts2, np, T2);
210
211 sumx = 0;
212 sumy = 0;
213 for (i = 0; i < np; ++i) {
214 dx = *(pts2++);
215 dy = *(pts2++);
216 sx = *(pts1++);
217 sy = *(pts1++);
218
219 sumx += dx - sx;
220 sumy += dy - sy;
221 }
222 mat[0] = sumx / np;
223 mat[1] = sumy / np;
224 denormalize_translation_reorder(mat, T1, T2);
225 return 0;
226}
227
Yaowu Xu4ff59b52017-04-24 12:41:56 -0700228static int find_rotzoom(int np, double *pts1, double *pts2, double *mat) {
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800229 const int np2 = np * 2;
Debargha Mukherjee0a981102017-05-14 11:45:39 -0700230 double *a = (double *)aom_malloc(sizeof(*a) * (np2 * 5 + 20));
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800231 double *b = a + np2 * 4;
232 double *temp = b + np2;
233 int i;
234 double sx, sy, dx, dy;
235
236 double T1[9], T2[9];
237 normalize_homography(pts1, np, T1);
238 normalize_homography(pts2, np, T2);
239
240 for (i = 0; i < np; ++i) {
241 dx = *(pts2++);
242 dy = *(pts2++);
243 sx = *(pts1++);
244 sy = *(pts1++);
245
246 a[i * 2 * 4 + 0] = sx;
247 a[i * 2 * 4 + 1] = sy;
248 a[i * 2 * 4 + 2] = 1;
249 a[i * 2 * 4 + 3] = 0;
250 a[(i * 2 + 1) * 4 + 0] = sy;
251 a[(i * 2 + 1) * 4 + 1] = -sx;
252 a[(i * 2 + 1) * 4 + 2] = 0;
253 a[(i * 2 + 1) * 4 + 3] = 1;
254
255 b[2 * i] = dx;
256 b[2 * i + 1] = dy;
257 }
Debargha Mukherjee7ae7aea2017-05-04 15:17:17 -0700258 if (!least_squares(4, a, np2, 4, b, temp, mat)) {
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800259 aom_free(a);
260 return 1;
261 }
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800262 denormalize_rotzoom_reorder(mat, T1, T2);
263 aom_free(a);
264 return 0;
265}
266
Yaowu Xu4ff59b52017-04-24 12:41:56 -0700267static int find_affine(int np, double *pts1, double *pts2, double *mat) {
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800268 const int np2 = np * 2;
Debargha Mukherjee0a981102017-05-14 11:45:39 -0700269 double *a = (double *)aom_malloc(sizeof(*a) * (np2 * 7 + 42));
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800270 double *b = a + np2 * 6;
271 double *temp = b + np2;
272 int i;
273 double sx, sy, dx, dy;
274
275 double T1[9], T2[9];
276 normalize_homography(pts1, np, T1);
277 normalize_homography(pts2, np, T2);
278
279 for (i = 0; i < np; ++i) {
280 dx = *(pts2++);
281 dy = *(pts2++);
282 sx = *(pts1++);
283 sy = *(pts1++);
284
285 a[i * 2 * 6 + 0] = sx;
286 a[i * 2 * 6 + 1] = sy;
287 a[i * 2 * 6 + 2] = 0;
288 a[i * 2 * 6 + 3] = 0;
289 a[i * 2 * 6 + 4] = 1;
290 a[i * 2 * 6 + 5] = 0;
291 a[(i * 2 + 1) * 6 + 0] = 0;
292 a[(i * 2 + 1) * 6 + 1] = 0;
293 a[(i * 2 + 1) * 6 + 2] = sx;
294 a[(i * 2 + 1) * 6 + 3] = sy;
295 a[(i * 2 + 1) * 6 + 4] = 0;
296 a[(i * 2 + 1) * 6 + 5] = 1;
297
298 b[2 * i] = dx;
299 b[2 * i + 1] = dy;
300 }
Debargha Mukherjee7ae7aea2017-05-04 15:17:17 -0700301 if (!least_squares(6, a, np2, 6, b, temp, mat)) {
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800302 aom_free(a);
303 return 1;
304 }
Debargha Mukherjeee6eb3b52017-02-26 08:50:56 -0800305 denormalize_affine_reorder(mat, T1, T2);
306 aom_free(a);
307 return 0;
308}
309
Sarah Parkerefa65822016-10-11 12:29:07 -0700310static int get_rand_indices(int npoints, int minpts, int *indices,
311 unsigned int *seed) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700312 int i, j;
Yaowu Xu9fa02482017-05-03 09:14:57 -0700313 int ptr = lcg_rand16(seed) % npoints;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700314 if (minpts > npoints) return 0;
315 indices[0] = ptr;
316 ptr = (ptr == npoints - 1 ? 0 : ptr + 1);
317 i = 1;
318 while (i < minpts) {
Yaowu Xu9fa02482017-05-03 09:14:57 -0700319 int index = lcg_rand16(seed) % npoints;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700320 while (index) {
321 ptr = (ptr == npoints - 1 ? 0 : ptr + 1);
322 for (j = 0; j < i; ++j) {
323 if (indices[j] == ptr) break;
324 }
325 if (j == i) index--;
326 }
327 indices[i++] = ptr;
328 }
329 return 1;
330}
331
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500332typedef struct {
333 int num_inliers;
334 double variance;
335 int *inlier_indices;
336} RANSAC_MOTION;
337
338// Return -1 if 'a' is a better motion, 1 if 'b' is better, 0 otherwise.
339static int compare_motions(const void *arg_a, const void *arg_b) {
340 const RANSAC_MOTION *motion_a = (RANSAC_MOTION *)arg_a;
341 const RANSAC_MOTION *motion_b = (RANSAC_MOTION *)arg_b;
342
343 if (motion_a->num_inliers > motion_b->num_inliers) return -1;
344 if (motion_a->num_inliers < motion_b->num_inliers) return 1;
345 if (motion_a->variance < motion_b->variance) return -1;
346 if (motion_a->variance > motion_b->variance) return 1;
347 return 0;
348}
349
350static int is_better_motion(const RANSAC_MOTION *motion_a,
351 const RANSAC_MOTION *motion_b) {
352 return compare_motions(motion_a, motion_b) < 0;
353}
354
355static void copy_points_at_indices(double *dest, const double *src,
356 const int *indices, int num_points) {
357 for (int i = 0; i < num_points; ++i) {
358 const int index = indices[i];
359 dest[i * 2] = src[index * 2];
360 dest[i * 2 + 1] = src[index * 2 + 1];
361 }
362}
363
364static const double kInfiniteVariance = 1e12;
365
366static void clear_motion(RANSAC_MOTION *motion, int num_points) {
367 motion->num_inliers = 0;
368 motion->variance = kInfiniteVariance;
369 memset(motion->inlier_indices, 0,
370 sizeof(*motion->inlier_indices * num_points));
371}
372
373static int ransac(const int *matched_points, int npoints,
374 int *num_inliers_by_motion, double *params_by_motion,
375 int num_desired_motions, const int minpts,
David Barker94b876f2016-11-16 13:47:12 +0000376 IsDegenerateFunc is_degenerate,
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700377 FindTransformationFunc find_transformation,
Sarah Parker97fa6da2016-09-23 11:17:27 -0700378 ProjectPointsDoubleFunc projectpoints) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700379 static const double PROBABILITY_REQUIRED = 0.9;
380 static const double EPS = 1e-12;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700381
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700382 int N = 10000, trial_count = 0;
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500383 int i = 0;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700384 int ret_val = 0;
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500385
Sarah Parkerefa65822016-10-11 12:29:07 -0700386 unsigned int seed = (unsigned int)npoints;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700387
Sarah Parkerefa65822016-10-11 12:29:07 -0700388 int indices[MAX_MINPTS] = { 0 };
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700389
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500390 double *points1, *points2;
391 double *corners1, *corners2;
Sarah Parker97fa6da2016-09-23 11:17:27 -0700392 double *image1_coord;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700393
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500394 // Store information for the num_desired_motions best transformations found
395 // and the worst motion among them, as well as the motion currently under
396 // consideration.
397 RANSAC_MOTION *motions, *worst_kept_motion = NULL;
398 RANSAC_MOTION current_motion;
399
400 // Store the parameters and the indices of the inlier points for the motion
401 // currently under consideration.
402 double params_this_motion[MAX_PARAMDIM];
403
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700404 double *cnp1, *cnp2;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700405
Debargha Mukherjee187a02e2017-05-03 17:35:52 -0700406 for (i = 0; i < num_desired_motions; ++i) {
407 num_inliers_by_motion[i] = 0;
408 }
Sarah Parkerfa75ae02016-10-26 12:48:01 -0700409 if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700410 return 1;
411 }
412
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500413 points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2);
414 points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700415 corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700416 corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2);
Sarah Parker97fa6da2016-09-23 11:17:27 -0700417 image1_coord = (double *)aom_malloc(sizeof(*image1_coord) * npoints * 2);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700418
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500419 motions =
420 (RANSAC_MOTION *)aom_malloc(sizeof(RANSAC_MOTION) * num_desired_motions);
421 for (i = 0; i < num_desired_motions; ++i) {
422 motions[i].inlier_indices =
423 (int *)aom_malloc(sizeof(*motions->inlier_indices) * npoints);
424 clear_motion(motions + i, npoints);
425 }
426 current_motion.inlier_indices =
427 (int *)aom_malloc(sizeof(*current_motion.inlier_indices) * npoints);
428 clear_motion(&current_motion, npoints);
429
430 worst_kept_motion = motions;
431
432 if (!(points1 && points2 && corners1 && corners2 && image1_coord && motions &&
433 current_motion.inlier_indices)) {
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700434 ret_val = 1;
435 goto finish_ransac;
436 }
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700437
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500438 cnp1 = corners1;
439 cnp2 = corners2;
440 for (i = 0; i < npoints; ++i) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700441 *(cnp1++) = *(matched_points++);
442 *(cnp1++) = *(matched_points++);
443 *(cnp2++) = *(matched_points++);
444 *(cnp2++) = *(matched_points++);
445 }
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700446
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700447 while (N > trial_count) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700448 double sum_distance = 0.0;
449 double sum_distance_squared = 0.0;
450
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500451 clear_motion(&current_motion, npoints);
452
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700453 int degenerate = 1;
454 int num_degenerate_iter = 0;
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500455
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700456 while (degenerate) {
457 num_degenerate_iter++;
Sarah Parkerefa65822016-10-11 12:29:07 -0700458 if (!get_rand_indices(npoints, minpts, indices, &seed)) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700459 ret_val = 1;
460 goto finish_ransac;
461 }
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500462
463 copy_points_at_indices(points1, corners1, indices, minpts);
464 copy_points_at_indices(points2, corners2, indices, minpts);
465
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700466 degenerate = is_degenerate(points1);
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700467 if (num_degenerate_iter > MAX_DEGENERATE_ITER) {
468 ret_val = 1;
469 goto finish_ransac;
470 }
471 }
472
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500473 if (find_transformation(minpts, points1, points2, params_this_motion)) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700474 trial_count++;
475 continue;
476 }
477
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500478 projectpoints(params_this_motion, corners1, image1_coord, npoints, 2, 2);
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700479
480 for (i = 0; i < npoints; ++i) {
Sarah Parker97fa6da2016-09-23 11:17:27 -0700481 double dx = image1_coord[i * 2] - corners2[i * 2];
482 double dy = image1_coord[i * 2 + 1] - corners2[i * 2 + 1];
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700483 double distance = sqrt(dx * dx + dy * dy);
484
emilkeyder@google.comd8941da2017-02-16 15:33:02 -0500485 if (distance < INLIER_THRESHOLD) {
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500486 current_motion.inlier_indices[current_motion.num_inliers++] = i;
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700487 sum_distance += distance;
488 sum_distance_squared += distance * distance;
489 }
490 }
491
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500492 if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
493 current_motion.num_inliers > 1) {
Sarah Parkerfa75ae02016-10-26 12:48:01 -0700494 int temp;
Debargha Mukherjee1ae93c12017-05-05 15:39:51 -0700495 double fracinliers, pNoOutliers, mean_distance, dtemp;
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500496 mean_distance = sum_distance / ((double)current_motion.num_inliers);
497 current_motion.variance =
498 sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
499 mean_distance * mean_distance * ((double)current_motion.num_inliers) /
500 ((double)current_motion.num_inliers - 1.0);
501 if (is_better_motion(&current_motion, worst_kept_motion)) {
502 // This motion is better than the worst currently kept motion. Remember
503 // the inlier points and variance. The parameters for each kept motion
504 // will be recomputed later using only the inliers.
505 worst_kept_motion->num_inliers = current_motion.num_inliers;
506 worst_kept_motion->variance = current_motion.variance;
507 memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
508 sizeof(*current_motion.inlier_indices) * npoints);
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700509
Sarah Parkerfa75ae02016-10-26 12:48:01 -0700510 assert(npoints > 0);
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500511 fracinliers = (double)current_motion.num_inliers / (double)npoints;
Sarah Parkerfa75ae02016-10-26 12:48:01 -0700512 pNoOutliers = 1 - pow(fracinliers, minpts);
513 pNoOutliers = fmax(EPS, pNoOutliers);
514 pNoOutliers = fmin(1 - EPS, pNoOutliers);
Debargha Mukherjee1ae93c12017-05-05 15:39:51 -0700515 dtemp = log(1.0 - PROBABILITY_REQUIRED) / log(pNoOutliers);
516 temp = (dtemp > (double)INT32_MAX)
517 ? INT32_MAX
518 : dtemp < (double)INT32_MIN ? INT32_MIN : (int)dtemp;
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500519
Sarah Parkerfa75ae02016-10-26 12:48:01 -0700520 if (temp > 0 && temp < N) {
521 N = AOMMAX(temp, MIN_TRIALS);
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700522 }
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500523
524 // Determine the new worst kept motion and its num_inliers and variance.
525 for (i = 0; i < num_desired_motions; ++i) {
526 if (is_better_motion(worst_kept_motion, &motions[i])) {
527 worst_kept_motion = &motions[i];
528 }
529 }
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700530 }
531 }
532 trial_count++;
533 }
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500534
535 // Sort the motions, best first.
536 qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions);
537
538 // Recompute the motions using only the inliers.
539 for (i = 0; i < num_desired_motions; ++i) {
Debargha Mukherjeeafe7c5f2017-06-22 13:47:23 -0700540 if (motions[i].num_inliers >= minpts) {
541 copy_points_at_indices(points1, corners1, motions[i].inlier_indices,
542 motions[i].num_inliers);
543 copy_points_at_indices(points2, corners2, motions[i].inlier_indices,
544 motions[i].num_inliers);
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500545
Debargha Mukherjeeafe7c5f2017-06-22 13:47:23 -0700546 find_transformation(motions[i].num_inliers, points1, points2,
547 params_by_motion + (MAX_PARAMDIM - 1) * i);
548 }
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500549 num_inliers_by_motion[i] = motions[i].num_inliers;
550 }
551
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700552finish_ransac:
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500553 aom_free(points1);
554 aom_free(points2);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700555 aom_free(corners1);
556 aom_free(corners2);
557 aom_free(image1_coord);
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500558 aom_free(current_motion.inlier_indices);
559 for (i = 0; i < num_desired_motions; ++i) {
560 aom_free(motions[i].inlier_indices);
561 }
562 aom_free(motions);
563
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700564 return ret_val;
565}
566
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700567static int is_collinear3(double *p1, double *p2, double *p3) {
568 static const double collinear_eps = 1e-3;
569 const double v =
570 (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]);
571 return fabs(v) < collinear_eps;
572}
573
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700574static int is_degenerate_translation(double *p) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700575 return (p[0] - p[2]) * (p[0] - p[2]) + (p[1] - p[3]) * (p[1] - p[3]) <= 2;
576}
577
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700578static int is_degenerate_affine(double *p) {
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700579 return is_collinear3(p, p + 2, p + 4);
580}
581
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500582int ransac_translation(int *matched_points, int npoints,
583 int *num_inliers_by_motion, double *params_by_motion,
584 int num_desired_motions) {
585 return ransac(matched_points, npoints, num_inliers_by_motion,
586 params_by_motion, num_desired_motions, 3,
emilkeyder@google.comd8941da2017-02-16 15:33:02 -0500587 is_degenerate_translation, find_translation,
Debargha Mukherjee487a3882016-11-10 12:48:13 -0800588 project_points_double_translation);
Sarah Parker4dc0f1b2016-08-09 17:40:53 -0700589}
590
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500591int ransac_rotzoom(int *matched_points, int npoints, int *num_inliers_by_motion,
592 double *params_by_motion, int num_desired_motions) {
593 return ransac(matched_points, npoints, num_inliers_by_motion,
594 params_by_motion, num_desired_motions, 3, is_degenerate_affine,
595 find_rotzoom, project_points_double_rotzoom);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700596}
597
emilkeyder@google.comf3477632017-03-01 16:29:14 -0500598int ransac_affine(int *matched_points, int npoints, int *num_inliers_by_motion,
599 double *params_by_motion, int num_desired_motions) {
600 return ransac(matched_points, npoints, num_inliers_by_motion,
601 params_by_motion, num_desired_motions, 3, is_degenerate_affine,
602 find_affine, project_points_double_affine);
Sarah Parkerf9a961c2016-09-06 11:25:04 -0700603}