Coverage Report

Created: 2022-08-24 06:11

/src/aom/av1/encoder/ransac.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2016, 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
#include <memory.h>
12
#include <math.h>
13
#include <time.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <assert.h>
17
18
#include "aom_dsp/mathutils.h"
19
#include "av1/encoder/ransac.h"
20
#include "av1/encoder/random.h"
21
22
#define MAX_MINPTS 4
23
0
#define MAX_DEGENERATE_ITER 10
24
0
#define MINPTS_MULTIPLIER 5
25
26
0
#define INLIER_THRESHOLD 1.25
27
0
#define MIN_TRIALS 20
28
29
////////////////////////////////////////////////////////////////////////////////
30
// ransac
31
typedef int (*IsDegenerateFunc)(double *p);
32
typedef void (*NormalizeFunc)(double *p, int np, double *T);
33
typedef void (*DenormalizeFunc)(double *params, double *T1, double *T2);
34
typedef int (*FindTransformationFunc)(int points, double *points1,
35
                                      double *points2, double *params);
36
typedef void (*ProjectPointsDoubleFunc)(double *mat, double *points,
37
                                        double *proj, int n, int stride_points,
38
                                        int stride_proj);
39
40
static void project_points_double_translation(double *mat, double *points,
41
                                              double *proj, int n,
42
                                              int stride_points,
43
0
                                              int stride_proj) {
44
0
  int i;
45
0
  for (i = 0; i < n; ++i) {
46
0
    const double x = *(points++), y = *(points++);
47
0
    *(proj++) = x + mat[0];
48
0
    *(proj++) = y + mat[1];
49
0
    points += stride_points - 2;
50
0
    proj += stride_proj - 2;
51
0
  }
52
0
}
53
54
static void project_points_double_rotzoom(double *mat, double *points,
55
                                          double *proj, int n,
56
0
                                          int stride_points, int stride_proj) {
57
0
  int i;
58
0
  for (i = 0; i < n; ++i) {
59
0
    const double x = *(points++), y = *(points++);
60
0
    *(proj++) = mat[2] * x + mat[3] * y + mat[0];
61
0
    *(proj++) = -mat[3] * x + mat[2] * y + mat[1];
62
0
    points += stride_points - 2;
63
0
    proj += stride_proj - 2;
64
0
  }
65
0
}
66
67
static void project_points_double_affine(double *mat, double *points,
68
                                         double *proj, int n, int stride_points,
69
0
                                         int stride_proj) {
70
0
  int i;
71
0
  for (i = 0; i < n; ++i) {
72
0
    const double x = *(points++), y = *(points++);
73
0
    *(proj++) = mat[2] * x + mat[3] * y + mat[0];
74
0
    *(proj++) = mat[4] * x + mat[5] * y + mat[1];
75
0
    points += stride_points - 2;
76
0
    proj += stride_proj - 2;
77
0
  }
78
0
}
79
80
0
static void normalize_homography(double *pts, int n, double *T) {
81
0
  double *p = pts;
82
0
  double mean[2] = { 0, 0 };
83
0
  double msqe = 0;
84
0
  double scale;
85
0
  int i;
86
87
0
  assert(n > 0);
88
0
  for (i = 0; i < n; ++i, p += 2) {
89
0
    mean[0] += p[0];
90
0
    mean[1] += p[1];
91
0
  }
92
0
  mean[0] /= n;
93
0
  mean[1] /= n;
94
0
  for (p = pts, i = 0; i < n; ++i, p += 2) {
95
0
    p[0] -= mean[0];
96
0
    p[1] -= mean[1];
97
0
    msqe += sqrt(p[0] * p[0] + p[1] * p[1]);
98
0
  }
99
0
  msqe /= n;
100
0
  scale = (msqe == 0 ? 1.0 : sqrt(2) / msqe);
101
0
  T[0] = scale;
102
0
  T[1] = 0;
103
0
  T[2] = -scale * mean[0];
104
0
  T[3] = 0;
105
0
  T[4] = scale;
106
0
  T[5] = -scale * mean[1];
107
0
  T[6] = 0;
108
0
  T[7] = 0;
109
0
  T[8] = 1;
110
0
  for (p = pts, i = 0; i < n; ++i, p += 2) {
111
0
    p[0] *= scale;
112
0
    p[1] *= scale;
113
0
  }
114
0
}
115
116
0
static void invnormalize_mat(double *T, double *iT) {
117
0
  double is = 1.0 / T[0];
118
0
  double m0 = -T[2] * is;
119
0
  double m1 = -T[5] * is;
120
0
  iT[0] = is;
121
0
  iT[1] = 0;
122
0
  iT[2] = m0;
123
0
  iT[3] = 0;
124
0
  iT[4] = is;
125
0
  iT[5] = m1;
126
0
  iT[6] = 0;
127
0
  iT[7] = 0;
128
0
  iT[8] = 1;
129
0
}
130
131
0
static void denormalize_homography(double *params, double *T1, double *T2) {
132
0
  double iT2[9];
133
0
  double params2[9];
134
0
  invnormalize_mat(T2, iT2);
135
0
  multiply_mat(params, T1, params2, 3, 3, 3);
136
0
  multiply_mat(iT2, params2, params, 3, 3, 3);
137
0
}
138
139
0
static void denormalize_affine_reorder(double *params, double *T1, double *T2) {
140
0
  double params_denorm[MAX_PARAMDIM];
141
0
  params_denorm[0] = params[0];
142
0
  params_denorm[1] = params[1];
143
0
  params_denorm[2] = params[4];
144
0
  params_denorm[3] = params[2];
145
0
  params_denorm[4] = params[3];
146
0
  params_denorm[5] = params[5];
147
0
  params_denorm[6] = params_denorm[7] = 0;
148
0
  params_denorm[8] = 1;
149
0
  denormalize_homography(params_denorm, T1, T2);
150
0
  params[0] = params_denorm[2];
151
0
  params[1] = params_denorm[5];
152
0
  params[2] = params_denorm[0];
153
0
  params[3] = params_denorm[1];
154
0
  params[4] = params_denorm[3];
155
0
  params[5] = params_denorm[4];
156
0
  params[6] = params[7] = 0;
157
0
}
158
159
static void denormalize_rotzoom_reorder(double *params, double *T1,
160
0
                                        double *T2) {
161
0
  double params_denorm[MAX_PARAMDIM];
162
0
  params_denorm[0] = params[0];
163
0
  params_denorm[1] = params[1];
164
0
  params_denorm[2] = params[2];
165
0
  params_denorm[3] = -params[1];
166
0
  params_denorm[4] = params[0];
167
0
  params_denorm[5] = params[3];
168
0
  params_denorm[6] = params_denorm[7] = 0;
169
0
  params_denorm[8] = 1;
170
0
  denormalize_homography(params_denorm, T1, T2);
171
0
  params[0] = params_denorm[2];
172
0
  params[1] = params_denorm[5];
173
0
  params[2] = params_denorm[0];
174
0
  params[3] = params_denorm[1];
175
0
  params[4] = -params[3];
176
0
  params[5] = params[2];
177
0
  params[6] = params[7] = 0;
178
0
}
179
180
static void denormalize_translation_reorder(double *params, double *T1,
181
0
                                            double *T2) {
182
0
  double params_denorm[MAX_PARAMDIM];
183
0
  params_denorm[0] = 1;
184
0
  params_denorm[1] = 0;
185
0
  params_denorm[2] = params[0];
186
0
  params_denorm[3] = 0;
187
0
  params_denorm[4] = 1;
188
0
  params_denorm[5] = params[1];
189
0
  params_denorm[6] = params_denorm[7] = 0;
190
0
  params_denorm[8] = 1;
191
0
  denormalize_homography(params_denorm, T1, T2);
192
0
  params[0] = params_denorm[2];
193
0
  params[1] = params_denorm[5];
194
0
  params[2] = params[5] = 1;
195
0
  params[3] = params[4] = 0;
196
0
  params[6] = params[7] = 0;
197
0
}
198
199
0
static int find_translation(int np, double *pts1, double *pts2, double *mat) {
200
0
  int i;
201
0
  double sx, sy, dx, dy;
202
0
  double sumx, sumy;
203
204
0
  double T1[9], T2[9];
205
0
  normalize_homography(pts1, np, T1);
206
0
  normalize_homography(pts2, np, T2);
207
208
0
  sumx = 0;
209
0
  sumy = 0;
210
0
  for (i = 0; i < np; ++i) {
211
0
    dx = *(pts2++);
212
0
    dy = *(pts2++);
213
0
    sx = *(pts1++);
214
0
    sy = *(pts1++);
215
216
0
    sumx += dx - sx;
217
0
    sumy += dy - sy;
218
0
  }
219
0
  mat[0] = sumx / np;
220
0
  mat[1] = sumy / np;
221
0
  denormalize_translation_reorder(mat, T1, T2);
222
0
  return 0;
223
0
}
224
225
0
static int find_rotzoom(int np, double *pts1, double *pts2, double *mat) {
226
0
  const int np2 = np * 2;
227
0
  double *a = (double *)aom_malloc(sizeof(*a) * (np2 * 5 + 20));
228
0
  double *b = a + np2 * 4;
229
0
  double *temp = b + np2;
230
0
  int i;
231
0
  double sx, sy, dx, dy;
232
233
0
  double T1[9], T2[9];
234
0
  normalize_homography(pts1, np, T1);
235
0
  normalize_homography(pts2, np, T2);
236
237
0
  for (i = 0; i < np; ++i) {
238
0
    dx = *(pts2++);
239
0
    dy = *(pts2++);
240
0
    sx = *(pts1++);
241
0
    sy = *(pts1++);
242
243
0
    a[i * 2 * 4 + 0] = sx;
244
0
    a[i * 2 * 4 + 1] = sy;
245
0
    a[i * 2 * 4 + 2] = 1;
246
0
    a[i * 2 * 4 + 3] = 0;
247
0
    a[(i * 2 + 1) * 4 + 0] = sy;
248
0
    a[(i * 2 + 1) * 4 + 1] = -sx;
249
0
    a[(i * 2 + 1) * 4 + 2] = 0;
250
0
    a[(i * 2 + 1) * 4 + 3] = 1;
251
252
0
    b[2 * i] = dx;
253
0
    b[2 * i + 1] = dy;
254
0
  }
255
0
  if (!least_squares(4, a, np2, 4, b, temp, mat)) {
256
0
    aom_free(a);
257
0
    return 1;
258
0
  }
259
0
  denormalize_rotzoom_reorder(mat, T1, T2);
260
0
  aom_free(a);
261
0
  return 0;
262
0
}
263
264
0
static int find_affine(int np, double *pts1, double *pts2, double *mat) {
265
0
  assert(np > 0);
266
0
  const int np2 = np * 2;
267
0
  double *a = (double *)aom_malloc(sizeof(*a) * (np2 * 7 + 42));
268
0
  if (a == NULL) return 1;
269
0
  double *b = a + np2 * 6;
270
0
  double *temp = b + np2;
271
0
  int i;
272
0
  double sx, sy, dx, dy;
273
274
0
  double T1[9], T2[9];
275
0
  normalize_homography(pts1, np, T1);
276
0
  normalize_homography(pts2, np, T2);
277
278
0
  for (i = 0; i < np; ++i) {
279
0
    dx = *(pts2++);
280
0
    dy = *(pts2++);
281
0
    sx = *(pts1++);
282
0
    sy = *(pts1++);
283
284
0
    a[i * 2 * 6 + 0] = sx;
285
0
    a[i * 2 * 6 + 1] = sy;
286
0
    a[i * 2 * 6 + 2] = 0;
287
0
    a[i * 2 * 6 + 3] = 0;
288
0
    a[i * 2 * 6 + 4] = 1;
289
0
    a[i * 2 * 6 + 5] = 0;
290
0
    a[(i * 2 + 1) * 6 + 0] = 0;
291
0
    a[(i * 2 + 1) * 6 + 1] = 0;
292
0
    a[(i * 2 + 1) * 6 + 2] = sx;
293
0
    a[(i * 2 + 1) * 6 + 3] = sy;
294
0
    a[(i * 2 + 1) * 6 + 4] = 0;
295
0
    a[(i * 2 + 1) * 6 + 5] = 1;
296
297
0
    b[2 * i] = dx;
298
0
    b[2 * i + 1] = dy;
299
0
  }
300
0
  if (!least_squares(6, a, np2, 6, b, temp, mat)) {
301
0
    aom_free(a);
302
0
    return 1;
303
0
  }
304
0
  denormalize_affine_reorder(mat, T1, T2);
305
0
  aom_free(a);
306
0
  return 0;
307
0
}
308
309
static int get_rand_indices(int npoints, int minpts, int *indices,
310
0
                            unsigned int *seed) {
311
0
  int i, j;
312
0
  int ptr = lcg_rand16(seed) % npoints;
313
0
  if (minpts > npoints) return 0;
314
0
  indices[0] = ptr;
315
0
  ptr = (ptr == npoints - 1 ? 0 : ptr + 1);
316
0
  i = 1;
317
0
  while (i < minpts) {
318
0
    int index = lcg_rand16(seed) % npoints;
319
0
    while (index) {
320
0
      ptr = (ptr == npoints - 1 ? 0 : ptr + 1);
321
0
      for (j = 0; j < i; ++j) {
322
0
        if (indices[j] == ptr) break;
323
0
      }
324
0
      if (j == i) index--;
325
0
    }
326
0
    indices[i++] = ptr;
327
0
  }
328
0
  return 1;
329
0
}
330
331
typedef struct {
332
  int num_inliers;
333
  double variance;
334
  int *inlier_indices;
335
} RANSAC_MOTION;
336
337
// Return -1 if 'a' is a better motion, 1 if 'b' is better, 0 otherwise.
338
0
static int compare_motions(const void *arg_a, const void *arg_b) {
339
0
  const RANSAC_MOTION *motion_a = (RANSAC_MOTION *)arg_a;
340
0
  const RANSAC_MOTION *motion_b = (RANSAC_MOTION *)arg_b;
341
342
0
  if (motion_a->num_inliers > motion_b->num_inliers) return -1;
343
0
  if (motion_a->num_inliers < motion_b->num_inliers) return 1;
344
0
  if (motion_a->variance < motion_b->variance) return -1;
345
0
  if (motion_a->variance > motion_b->variance) return 1;
346
0
  return 0;
347
0
}
348
349
static int is_better_motion(const RANSAC_MOTION *motion_a,
350
0
                            const RANSAC_MOTION *motion_b) {
351
0
  return compare_motions(motion_a, motion_b) < 0;
352
0
}
353
354
static void copy_points_at_indices(double *dest, const double *src,
355
0
                                   const int *indices, int num_points) {
356
0
  for (int i = 0; i < num_points; ++i) {
357
0
    const int index = indices[i];
358
0
    dest[i * 2] = src[index * 2];
359
0
    dest[i * 2 + 1] = src[index * 2 + 1];
360
0
  }
361
0
}
362
363
static const double kInfiniteVariance = 1e12;
364
365
0
static void clear_motion(RANSAC_MOTION *motion, int num_points) {
366
0
  motion->num_inliers = 0;
367
0
  motion->variance = kInfiniteVariance;
368
0
  memset(motion->inlier_indices, 0,
369
0
         sizeof(*motion->inlier_indices) * num_points);
370
0
}
371
372
static int ransac(const int *matched_points, int npoints,
373
                  int *num_inliers_by_motion, MotionModel *params_by_motion,
374
                  int num_desired_motions, int minpts,
375
                  IsDegenerateFunc is_degenerate,
376
                  FindTransformationFunc find_transformation,
377
0
                  ProjectPointsDoubleFunc projectpoints) {
378
0
  int trial_count = 0;
379
0
  int i = 0;
380
0
  int ret_val = 0;
381
382
0
  unsigned int seed = (unsigned int)npoints;
383
384
0
  int indices[MAX_MINPTS] = { 0 };
385
386
0
  double *points1, *points2;
387
0
  double *corners1, *corners2;
388
0
  double *image1_coord;
389
390
  // Store information for the num_desired_motions best transformations found
391
  // and the worst motion among them, as well as the motion currently under
392
  // consideration.
393
0
  RANSAC_MOTION *motions, *worst_kept_motion = NULL;
394
0
  RANSAC_MOTION current_motion;
395
396
  // Store the parameters and the indices of the inlier points for the motion
397
  // currently under consideration.
398
0
  double params_this_motion[MAX_PARAMDIM];
399
400
0
  double *cnp1, *cnp2;
401
402
0
  for (i = 0; i < num_desired_motions; ++i) {
403
0
    num_inliers_by_motion[i] = 0;
404
0
  }
405
0
  if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) {
406
0
    return 1;
407
0
  }
408
409
0
  points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2);
410
0
  points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2);
411
0
  corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2);
412
0
  corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2);
413
0
  image1_coord = (double *)aom_malloc(sizeof(*image1_coord) * npoints * 2);
414
415
0
  motions =
416
0
      (RANSAC_MOTION *)aom_malloc(sizeof(RANSAC_MOTION) * num_desired_motions);
417
0
  for (i = 0; i < num_desired_motions; ++i) {
418
0
    motions[i].inlier_indices =
419
0
        (int *)aom_malloc(sizeof(*motions->inlier_indices) * npoints);
420
0
    clear_motion(motions + i, npoints);
421
0
  }
422
0
  current_motion.inlier_indices =
423
0
      (int *)aom_malloc(sizeof(*current_motion.inlier_indices) * npoints);
424
0
  clear_motion(&current_motion, npoints);
425
426
0
  worst_kept_motion = motions;
427
428
0
  if (!(points1 && points2 && corners1 && corners2 && image1_coord && motions &&
429
0
        current_motion.inlier_indices)) {
430
0
    ret_val = 1;
431
0
    goto finish_ransac;
432
0
  }
433
434
0
  cnp1 = corners1;
435
0
  cnp2 = corners2;
436
0
  for (i = 0; i < npoints; ++i) {
437
0
    *(cnp1++) = *(matched_points++);
438
0
    *(cnp1++) = *(matched_points++);
439
0
    *(cnp2++) = *(matched_points++);
440
0
    *(cnp2++) = *(matched_points++);
441
0
  }
442
443
0
  while (MIN_TRIALS > trial_count) {
444
0
    double sum_distance = 0.0;
445
0
    double sum_distance_squared = 0.0;
446
447
0
    clear_motion(&current_motion, npoints);
448
449
0
    int degenerate = 1;
450
0
    int num_degenerate_iter = 0;
451
452
0
    while (degenerate) {
453
0
      num_degenerate_iter++;
454
0
      if (!get_rand_indices(npoints, minpts, indices, &seed)) {
455
0
        ret_val = 1;
456
0
        goto finish_ransac;
457
0
      }
458
459
0
      copy_points_at_indices(points1, corners1, indices, minpts);
460
0
      copy_points_at_indices(points2, corners2, indices, minpts);
461
462
0
      degenerate = is_degenerate(points1);
463
0
      if (num_degenerate_iter > MAX_DEGENERATE_ITER) {
464
0
        ret_val = 1;
465
0
        goto finish_ransac;
466
0
      }
467
0
    }
468
469
0
    if (find_transformation(minpts, points1, points2, params_this_motion)) {
470
0
      trial_count++;
471
0
      continue;
472
0
    }
473
474
0
    projectpoints(params_this_motion, corners1, image1_coord, npoints, 2, 2);
475
476
0
    for (i = 0; i < npoints; ++i) {
477
0
      double dx = image1_coord[i * 2] - corners2[i * 2];
478
0
      double dy = image1_coord[i * 2 + 1] - corners2[i * 2 + 1];
479
0
      double distance = sqrt(dx * dx + dy * dy);
480
481
0
      if (distance < INLIER_THRESHOLD) {
482
0
        current_motion.inlier_indices[current_motion.num_inliers++] = i;
483
0
        sum_distance += distance;
484
0
        sum_distance_squared += distance * distance;
485
0
      }
486
0
    }
487
488
0
    if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
489
0
        current_motion.num_inliers > 1) {
490
0
      double mean_distance;
491
0
      mean_distance = sum_distance / ((double)current_motion.num_inliers);
492
0
      current_motion.variance =
493
0
          sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
494
0
          mean_distance * mean_distance * ((double)current_motion.num_inliers) /
495
0
              ((double)current_motion.num_inliers - 1.0);
496
0
      if (is_better_motion(&current_motion, worst_kept_motion)) {
497
        // This motion is better than the worst currently kept motion. Remember
498
        // the inlier points and variance. The parameters for each kept motion
499
        // will be recomputed later using only the inliers.
500
0
        worst_kept_motion->num_inliers = current_motion.num_inliers;
501
0
        worst_kept_motion->variance = current_motion.variance;
502
0
        memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
503
0
               sizeof(*current_motion.inlier_indices) * npoints);
504
0
        assert(npoints > 0);
505
        // Determine the new worst kept motion and its num_inliers and variance.
506
0
        for (i = 0; i < num_desired_motions; ++i) {
507
0
          if (is_better_motion(worst_kept_motion, &motions[i])) {
508
0
            worst_kept_motion = &motions[i];
509
0
          }
510
0
        }
511
0
      }
512
0
    }
513
0
    trial_count++;
514
0
  }
515
516
  // Sort the motions, best first.
517
0
  qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions);
518
519
  // Recompute the motions using only the inliers.
520
0
  for (i = 0; i < num_desired_motions; ++i) {
521
0
    if (motions[i].num_inliers >= minpts) {
522
0
      copy_points_at_indices(points1, corners1, motions[i].inlier_indices,
523
0
                             motions[i].num_inliers);
524
0
      copy_points_at_indices(points2, corners2, motions[i].inlier_indices,
525
0
                             motions[i].num_inliers);
526
527
0
      find_transformation(motions[i].num_inliers, points1, points2,
528
0
                          params_by_motion[i].params);
529
530
0
      params_by_motion[i].num_inliers = motions[i].num_inliers;
531
0
      memcpy(params_by_motion[i].inliers, motions[i].inlier_indices,
532
0
             sizeof(*motions[i].inlier_indices) * npoints);
533
0
      num_inliers_by_motion[i] = motions[i].num_inliers;
534
0
    }
535
0
  }
536
537
0
finish_ransac:
538
0
  aom_free(points1);
539
0
  aom_free(points2);
540
0
  aom_free(corners1);
541
0
  aom_free(corners2);
542
0
  aom_free(image1_coord);
543
0
  aom_free(current_motion.inlier_indices);
544
0
  for (i = 0; i < num_desired_motions; ++i) {
545
0
    aom_free(motions[i].inlier_indices);
546
0
  }
547
0
  aom_free(motions);
548
549
0
  return ret_val;
550
0
}
551
552
static int ransac_double_prec(const double *matched_points, int npoints,
553
                              int *num_inliers_by_motion,
554
                              MotionModel *params_by_motion,
555
                              int num_desired_motions, int minpts,
556
                              IsDegenerateFunc is_degenerate,
557
                              FindTransformationFunc find_transformation,
558
0
                              ProjectPointsDoubleFunc projectpoints) {
559
0
  int trial_count = 0;
560
0
  int i = 0;
561
0
  int ret_val = 0;
562
563
0
  unsigned int seed = (unsigned int)npoints;
564
565
0
  int indices[MAX_MINPTS] = { 0 };
566
567
0
  double *points1, *points2;
568
0
  double *corners1, *corners2;
569
0
  double *image1_coord;
570
571
  // Store information for the num_desired_motions best transformations found
572
  // and the worst motion among them, as well as the motion currently under
573
  // consideration.
574
0
  RANSAC_MOTION *motions, *worst_kept_motion = NULL;
575
0
  RANSAC_MOTION current_motion;
576
577
  // Store the parameters and the indices of the inlier points for the motion
578
  // currently under consideration.
579
0
  double params_this_motion[MAX_PARAMDIM];
580
581
0
  double *cnp1, *cnp2;
582
583
0
  for (i = 0; i < num_desired_motions; ++i) {
584
0
    num_inliers_by_motion[i] = 0;
585
0
  }
586
0
  if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) {
587
0
    return 1;
588
0
  }
589
590
0
  points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2);
591
0
  points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2);
592
0
  corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2);
593
0
  corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2);
594
0
  image1_coord = (double *)aom_malloc(sizeof(*image1_coord) * npoints * 2);
595
596
0
  motions =
597
0
      (RANSAC_MOTION *)aom_malloc(sizeof(RANSAC_MOTION) * num_desired_motions);
598
0
  for (i = 0; i < num_desired_motions; ++i) {
599
0
    motions[i].inlier_indices =
600
0
        (int *)aom_malloc(sizeof(*motions->inlier_indices) * npoints);
601
0
    clear_motion(motions + i, npoints);
602
0
  }
603
0
  current_motion.inlier_indices =
604
0
      (int *)aom_malloc(sizeof(*current_motion.inlier_indices) * npoints);
605
0
  clear_motion(&current_motion, npoints);
606
607
0
  worst_kept_motion = motions;
608
609
0
  if (!(points1 && points2 && corners1 && corners2 && image1_coord && motions &&
610
0
        current_motion.inlier_indices)) {
611
0
    ret_val = 1;
612
0
    goto finish_ransac;
613
0
  }
614
615
0
  cnp1 = corners1;
616
0
  cnp2 = corners2;
617
0
  for (i = 0; i < npoints; ++i) {
618
0
    *(cnp1++) = *(matched_points++);
619
0
    *(cnp1++) = *(matched_points++);
620
0
    *(cnp2++) = *(matched_points++);
621
0
    *(cnp2++) = *(matched_points++);
622
0
  }
623
624
0
  while (MIN_TRIALS > trial_count) {
625
0
    double sum_distance = 0.0;
626
0
    double sum_distance_squared = 0.0;
627
628
0
    clear_motion(&current_motion, npoints);
629
630
0
    int degenerate = 1;
631
0
    int num_degenerate_iter = 0;
632
633
0
    while (degenerate) {
634
0
      num_degenerate_iter++;
635
0
      if (!get_rand_indices(npoints, minpts, indices, &seed)) {
636
0
        ret_val = 1;
637
0
        goto finish_ransac;
638
0
      }
639
640
0
      copy_points_at_indices(points1, corners1, indices, minpts);
641
0
      copy_points_at_indices(points2, corners2, indices, minpts);
642
643
0
      degenerate = is_degenerate(points1);
644
0
      if (num_degenerate_iter > MAX_DEGENERATE_ITER) {
645
0
        ret_val = 1;
646
0
        goto finish_ransac;
647
0
      }
648
0
    }
649
650
0
    if (find_transformation(minpts, points1, points2, params_this_motion)) {
651
0
      trial_count++;
652
0
      continue;
653
0
    }
654
655
0
    projectpoints(params_this_motion, corners1, image1_coord, npoints, 2, 2);
656
657
0
    for (i = 0; i < npoints; ++i) {
658
0
      double dx = image1_coord[i * 2] - corners2[i * 2];
659
0
      double dy = image1_coord[i * 2 + 1] - corners2[i * 2 + 1];
660
0
      double distance = sqrt(dx * dx + dy * dy);
661
662
0
      if (distance < INLIER_THRESHOLD) {
663
0
        current_motion.inlier_indices[current_motion.num_inliers++] = i;
664
0
        sum_distance += distance;
665
0
        sum_distance_squared += distance * distance;
666
0
      }
667
0
    }
668
669
0
    if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
670
0
        current_motion.num_inliers > 1) {
671
0
      double mean_distance;
672
0
      mean_distance = sum_distance / ((double)current_motion.num_inliers);
673
0
      current_motion.variance =
674
0
          sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
675
0
          mean_distance * mean_distance * ((double)current_motion.num_inliers) /
676
0
              ((double)current_motion.num_inliers - 1.0);
677
0
      if (is_better_motion(&current_motion, worst_kept_motion)) {
678
        // This motion is better than the worst currently kept motion. Remember
679
        // the inlier points and variance. The parameters for each kept motion
680
        // will be recomputed later using only the inliers.
681
0
        worst_kept_motion->num_inliers = current_motion.num_inliers;
682
0
        worst_kept_motion->variance = current_motion.variance;
683
0
        memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
684
0
               sizeof(*current_motion.inlier_indices) * npoints);
685
0
        assert(npoints > 0);
686
        // Determine the new worst kept motion and its num_inliers and variance.
687
0
        for (i = 0; i < num_desired_motions; ++i) {
688
0
          if (is_better_motion(worst_kept_motion, &motions[i])) {
689
0
            worst_kept_motion = &motions[i];
690
0
          }
691
0
        }
692
0
      }
693
0
    }
694
0
    trial_count++;
695
0
  }
696
697
  // Sort the motions, best first.
698
0
  qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions);
699
700
  // Recompute the motions using only the inliers.
701
0
  for (i = 0; i < num_desired_motions; ++i) {
702
0
    if (motions[i].num_inliers >= minpts) {
703
0
      copy_points_at_indices(points1, corners1, motions[i].inlier_indices,
704
0
                             motions[i].num_inliers);
705
0
      copy_points_at_indices(points2, corners2, motions[i].inlier_indices,
706
0
                             motions[i].num_inliers);
707
708
0
      find_transformation(motions[i].num_inliers, points1, points2,
709
0
                          params_by_motion[i].params);
710
0
      memcpy(params_by_motion[i].inliers, motions[i].inlier_indices,
711
0
             sizeof(*motions[i].inlier_indices) * npoints);
712
0
    }
713
0
    num_inliers_by_motion[i] = motions[i].num_inliers;
714
0
  }
715
716
0
finish_ransac:
717
0
  aom_free(points1);
718
0
  aom_free(points2);
719
0
  aom_free(corners1);
720
0
  aom_free(corners2);
721
0
  aom_free(image1_coord);
722
0
  aom_free(current_motion.inlier_indices);
723
0
  for (i = 0; i < num_desired_motions; ++i) {
724
0
    aom_free(motions[i].inlier_indices);
725
0
  }
726
0
  aom_free(motions);
727
728
0
  return ret_val;
729
0
}
730
731
0
static int is_collinear3(double *p1, double *p2, double *p3) {
732
0
  static const double collinear_eps = 1e-3;
733
0
  const double v =
734
0
      (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]);
735
0
  return fabs(v) < collinear_eps;
736
0
}
737
738
0
static int is_degenerate_translation(double *p) {
739
0
  return (p[0] - p[2]) * (p[0] - p[2]) + (p[1] - p[3]) * (p[1] - p[3]) <= 2;
740
0
}
741
742
0
static int is_degenerate_affine(double *p) {
743
0
  return is_collinear3(p, p + 2, p + 4);
744
0
}
745
746
static int ransac_translation(int *matched_points, int npoints,
747
                              int *num_inliers_by_motion,
748
                              MotionModel *params_by_motion,
749
0
                              int num_desired_motions) {
750
0
  return ransac(matched_points, npoints, num_inliers_by_motion,
751
0
                params_by_motion, num_desired_motions, 3,
752
0
                is_degenerate_translation, find_translation,
753
0
                project_points_double_translation);
754
0
}
755
756
static int ransac_rotzoom(int *matched_points, int npoints,
757
                          int *num_inliers_by_motion,
758
                          MotionModel *params_by_motion,
759
0
                          int num_desired_motions) {
760
0
  return ransac(matched_points, npoints, num_inliers_by_motion,
761
0
                params_by_motion, num_desired_motions, 3, is_degenerate_affine,
762
0
                find_rotzoom, project_points_double_rotzoom);
763
0
}
764
765
static int ransac_affine(int *matched_points, int npoints,
766
                         int *num_inliers_by_motion,
767
                         MotionModel *params_by_motion,
768
0
                         int num_desired_motions) {
769
0
  return ransac(matched_points, npoints, num_inliers_by_motion,
770
0
                params_by_motion, num_desired_motions, 3, is_degenerate_affine,
771
0
                find_affine, project_points_double_affine);
772
0
}
773
774
0
RansacFunc av1_get_ransac_type(TransformationType type) {
775
0
  switch (type) {
776
0
    case AFFINE: return ransac_affine;
777
0
    case ROTZOOM: return ransac_rotzoom;
778
0
    case TRANSLATION: return ransac_translation;
779
0
    default: assert(0); return NULL;
780
0
  }
781
0
}
782
783
static int ransac_translation_double_prec(double *matched_points, int npoints,
784
                                          int *num_inliers_by_motion,
785
                                          MotionModel *params_by_motion,
786
0
                                          int num_desired_motions) {
787
0
  return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
788
0
                            params_by_motion, num_desired_motions, 3,
789
0
                            is_degenerate_translation, find_translation,
790
0
                            project_points_double_translation);
791
0
}
792
793
static int ransac_rotzoom_double_prec(double *matched_points, int npoints,
794
                                      int *num_inliers_by_motion,
795
                                      MotionModel *params_by_motion,
796
0
                                      int num_desired_motions) {
797
0
  return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
798
0
                            params_by_motion, num_desired_motions, 3,
799
0
                            is_degenerate_affine, find_rotzoom,
800
0
                            project_points_double_rotzoom);
801
0
}
802
803
static int ransac_affine_double_prec(double *matched_points, int npoints,
804
                                     int *num_inliers_by_motion,
805
                                     MotionModel *params_by_motion,
806
0
                                     int num_desired_motions) {
807
0
  return ransac_double_prec(matched_points, npoints, num_inliers_by_motion,
808
0
                            params_by_motion, num_desired_motions, 3,
809
0
                            is_degenerate_affine, find_affine,
810
0
                            project_points_double_affine);
811
0
}
812
813
0
RansacFuncDouble av1_get_ransac_double_prec_type(TransformationType type) {
814
0
  switch (type) {
815
0
    case AFFINE: return ransac_affine_double_prec;
816
0
    case ROTZOOM: return ransac_rotzoom_double_prec;
817
0
    case TRANSLATION: return ransac_translation_double_prec;
818
0
    default: assert(0); return NULL;
819
0
  }
820
0
}