LCOV - code coverage report
Current view: top level - third_party/aom/av1/encoder - ransac.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 561 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13