Commit f3477635 authored by emilkeyder@google.com's avatar emilkeyder@google.com Committed by Emil Keyder

Compute multiple global motions and pick best by error adv.

Modify ransac to keep the N best global motions by num_inliers and
variance rather than a single one. Compute the error advantage for
each in encode_frame_internal(), and use the best as the global motion
for that pair of <target, reference> frames.

Improvements for different values of N:

N                     %PSNR gain on lowres
1 (current impl)      1.287
2                     1.328
4                     1.370
8                     1.419
16                    1.427
32                    1.439

Change-Id: Ic0c9066a3f175a5ea0a78828cd244104e70144ba
parent 5bd2d2f9
......@@ -26,6 +26,7 @@
#include "av1/common/entropy.h"
#include "av1/common/entropymode.h"
#include "av1/common/idct.h"
#include "av1/common/mv.h"
#include "av1/common/mvref_common.h"
#include "av1/common/pred_common.h"
#include "av1/common/quant_common.h"
......@@ -5041,23 +5042,45 @@ static void encode_frame_internal(AV1_COMP *cpi) {
!cpi->global_motion_search_done) {
YV12_BUFFER_CONFIG *ref_buf;
int frame;
double erroradvantage = 0;
double params[8] = { 0, 0, 1, 0, 0, 1, 0, 0 };
double params_by_motion[RANSAC_NUM_MOTIONS * (MAX_PARAMDIM - 1)];
const double *params_this_motion;
int inliers_by_motion[RANSAC_NUM_MOTIONS];
WarpedMotionParams tmp_wm_params;
static const double kInfiniteErrAdv = 1e12;
static const double kIdentityParams[MAX_PARAMDIM - 1] = {
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0
};
for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) {
ref_buf = get_ref_frame_buffer(cpi, frame);
if (ref_buf) {
TransformationType model;
aom_clear_system_state();
for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES; ++model) {
if (compute_global_motion_feature_based(model, cpi->Source, ref_buf,
double best_erroradvantage = kInfiniteErrAdv;
// Initially set all params to identity.
for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) {
memcpy(params_by_motion + (MAX_PARAMDIM - 1) * i, kIdentityParams,
(MAX_PARAMDIM - 1) * sizeof(*params_by_motion));
}
compute_global_motion_feature_based(
model, cpi->Source, ref_buf,
#if CONFIG_AOM_HIGHBITDEPTH
cpi->common.bit_depth,
cpi->common.bit_depth,
#endif // CONFIG_AOM_HIGHBITDEPTH
params)) {
convert_model_to_params(params, &cm->global_motion[frame]);
if (cm->global_motion[frame].wmtype != IDENTITY) {
erroradvantage = refine_integerized_param(
&cm->global_motion[frame], cm->global_motion[frame].wmtype,
inliers_by_motion, params_by_motion, RANSAC_NUM_MOTIONS);
for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) {
if (inliers_by_motion[i] == 0) continue;
params_this_motion = params_by_motion + (MAX_PARAMDIM - 1) * i;
convert_model_to_params(params_this_motion, &tmp_wm_params);
if (tmp_wm_params.wmtype != IDENTITY) {
const double erroradv_this_motion = refine_integerized_param(
&tmp_wm_params, tmp_wm_params.wmtype,
#if CONFIG_AOM_HIGHBITDEPTH
xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
#endif // CONFIG_AOM_HIGHBITDEPTH
......@@ -5065,12 +5088,23 @@ static void encode_frame_internal(AV1_COMP *cpi) {
ref_buf->y_stride, cpi->Source->y_buffer,
cpi->Source->y_width, cpi->Source->y_height,
cpi->Source->y_stride, 3);
if (erroradvantage >
gm_advantage_thresh[cm->global_motion[frame].wmtype]) {
set_default_gmparams(&cm->global_motion[frame]);
if (erroradv_this_motion < best_erroradvantage) {
best_erroradvantage = erroradv_this_motion;
// Save the wm_params modified by refine_integerized_param()
// rather than motion index to avoid rerunning refine() below.
memcpy(&(cm->global_motion[frame]), &tmp_wm_params,
sizeof(WarpedMotionParams));
}
}
}
// If the best error advantage found doesn't meet the threshold for
// this motion type, revert to IDENTITY.
if (best_erroradvantage >
gm_advantage_thresh[cm->global_motion[frame].wmtype]) {
set_default_gmparams(&cm->global_motion[frame]);
}
if (cm->global_motion[frame].wmtype != IDENTITY) break;
}
aom_clear_system_state();
......
......@@ -238,24 +238,6 @@ static INLINE RansacFunc get_ransac_type(TransformationType type) {
}
}
// computes global motion parameters by fitting a model using RANSAC
static int compute_global_motion_params(TransformationType type,
int *correspondences,
int num_correspondences,
double *params) {
int result;
int num_inliers = 0;
RansacFunc ransac = get_ransac_type(type);
if (ransac == NULL) return 0;
result = ransac(correspondences, num_correspondences, &num_inliers, params);
if (!result && num_inliers < MIN_INLIER_PROB * num_correspondences) {
result = 1;
num_inliers = 0;
}
return num_inliers;
}
#if CONFIG_AOM_HIGHBITDEPTH
unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm, int bit_depth) {
int i, j;
......@@ -271,20 +253,20 @@ unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm, int bit_depth) {
}
#endif
int compute_global_motion_feature_based(TransformationType type,
YV12_BUFFER_CONFIG *frm,
YV12_BUFFER_CONFIG *ref,
int compute_global_motion_feature_based(
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
#if CONFIG_AOM_HIGHBITDEPTH
int bit_depth,
int bit_depth,
#endif
double *params) {
int *num_inliers_by_motion, double *params_by_motion, int num_motions) {
int i;
int num_frm_corners, num_ref_corners;
int num_correspondences;
int *correspondences;
int num_inliers;
int frm_corners[2 * MAX_CORNERS], ref_corners[2 * MAX_CORNERS];
unsigned char *frm_buffer = frm->y_buffer;
unsigned char *ref_buffer = ref->y_buffer;
RansacFunc ransac = get_ransac_type(type);
#if CONFIG_AOM_HIGHBITDEPTH
if (frm->flags & YV12_FLAG_HIGHBITDEPTH) {
......@@ -317,8 +299,21 @@ int compute_global_motion_feature_based(TransformationType type,
(int *)ref_corners, num_ref_corners, frm->y_width, frm->y_height,
frm->y_stride, ref->y_stride, correspondences);
num_inliers = compute_global_motion_params(type, correspondences,
num_correspondences, params);
ransac(correspondences, num_correspondences, num_inliers_by_motion,
params_by_motion, num_motions);
free(correspondences);
return (num_inliers > 0);
// Set num_inliers = 0 for motions with too few inliers so they are ignored.
for (i = 0; i < num_motions; ++i) {
if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences) {
num_inliers_by_motion[i] = 0;
}
}
// Return true if any one of the motions has inliers.
for (i = 0; i < num_motions; ++i) {
if (num_inliers_by_motion[i] > 0) return 1;
}
return 0;
}
......@@ -20,6 +20,8 @@
extern "C" {
#endif
#define RANSAC_NUM_MOTIONS 1
extern const double gm_advantage_thresh[TRANS_TYPES];
void convert_to_params(const double *params, int32_t *model);
......@@ -43,23 +45,24 @@ double refine_integerized_param(WarpedMotionParams *wm,
int d_height, int d_stride, int n_refinements);
/*
Computes global motion parameters between two frames. The array
"params" should be length 9, where the first 2 slots are translation
parameters in (row, col) order, and the remaining slots correspond
to values in the transformation matrix of the corresponding motion
model. They are arranged in "params" such that values on the tx-matrix
diagonal have odd numbered indices so the folowing matrix:
A | B
C | D
would produce params = [trans row, trans col, B, A, C, D]
Computes "num_motions" candidate global motion parameters between two frames.
The array "params_by_motion" should be length 8 * "num_motions", where the
first 2 slots in each group of 8 parameters are the translation parameters in
(row, col) order, and the remaining slots correspond to values in the
transformation matrix of the corresponding motion model. They are arranged in
"params" such that values on the tx-matrix diagonal have odd numbered indices
so the folowing matrix: A | B C | D would produce params = [trans row, trans
col, B, A, C, D].
"num_inliers" should be length "num_motions", and will be populated with the
number of inlier feature points for each motion. Params for which the
num_inliers entry is 0 should be ignored by the caller.
*/
int compute_global_motion_feature_based(TransformationType type,
YV12_BUFFER_CONFIG *frm,
YV12_BUFFER_CONFIG *ref,
int compute_global_motion_feature_based(
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
#if CONFIG_AOM_HIGHBITDEPTH
int bit_depth,
int bit_depth,
#endif
double *params);
int *num_inliers_by_motion, double *params_by_motion, int num_motions);
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -916,8 +916,50 @@ static int get_rand_indices(int npoints, int minpts, int *indices,
return 1;
}
static int ransac(int *matched_points, int npoints, int *number_of_inliers,
double *best_params, const int minpts,
typedef struct {
int num_inliers;
double variance;
int *inlier_indices;
} RANSAC_MOTION;
// Return -1 if 'a' is a better motion, 1 if 'b' is better, 0 otherwise.
static int compare_motions(const void *arg_a, const void *arg_b) {
const RANSAC_MOTION *motion_a = (RANSAC_MOTION *)arg_a;
const RANSAC_MOTION *motion_b = (RANSAC_MOTION *)arg_b;
if (motion_a->num_inliers > motion_b->num_inliers) return -1;
if (motion_a->num_inliers < motion_b->num_inliers) return 1;
if (motion_a->variance < motion_b->variance) return -1;
if (motion_a->variance > motion_b->variance) return 1;
return 0;
}
static int is_better_motion(const RANSAC_MOTION *motion_a,
const RANSAC_MOTION *motion_b) {
return compare_motions(motion_a, motion_b) < 0;
}
static void copy_points_at_indices(double *dest, const double *src,
const int *indices, int num_points) {
for (int i = 0; i < num_points; ++i) {
const int index = indices[i];
dest[i * 2] = src[index * 2];
dest[i * 2 + 1] = src[index * 2 + 1];
}
}
static const double kInfiniteVariance = 1e12;
static void clear_motion(RANSAC_MOTION *motion, int num_points) {
motion->num_inliers = 0;
motion->variance = kInfiniteVariance;
memset(motion->inlier_indices, 0,
sizeof(*motion->inlier_indices * num_points));
}
static int ransac(const int *matched_points, int npoints,
int *num_inliers_by_motion, double *params_by_motion,
int num_desired_motions, const int minpts,
IsDegenerateFunc is_degenerate,
FindTransformationFunc find_transformation,
ProjectPointsDoubleFunc projectpoints) {
......@@ -925,51 +967,61 @@ static int ransac(int *matched_points, int npoints, int *number_of_inliers,
static const double EPS = 1e-12;
int N = 10000, trial_count = 0;
int i;
int i = 0;
int ret_val = 0;
unsigned int seed = (unsigned int)npoints;
int max_inliers = 0;
double best_variance = 0.0;
double params[MAX_PARAMDIM];
WarpedMotionParams wm;
double points1[2 * MAX_MINPTS];
double points2[2 * MAX_MINPTS];
int indices[MAX_MINPTS] = { 0 };
double *best_inlier_set1;
double *best_inlier_set2;
double *inlier_set1;
double *inlier_set2;
double *corners1;
double *corners2;
double *points1, *points2;
double *corners1, *corners2;
double *image1_coord;
// Store information for the num_desired_motions best transformations found
// and the worst motion among them, as well as the motion currently under
// consideration.
RANSAC_MOTION *motions, *worst_kept_motion = NULL;
RANSAC_MOTION current_motion;
// Store the parameters and the indices of the inlier points for the motion
// currently under consideration.
double params_this_motion[MAX_PARAMDIM];
double *cnp1, *cnp2;
*number_of_inliers = 0;
if (npoints < minpts * MINPTS_MULTIPLIER || npoints == 0) {
return 1;
}
memset(&wm, 0, sizeof(wm));
best_inlier_set1 =
(double *)aom_malloc(sizeof(*best_inlier_set1) * npoints * 2);
best_inlier_set2 =
(double *)aom_malloc(sizeof(*best_inlier_set2) * npoints * 2);
inlier_set1 = (double *)aom_malloc(sizeof(*inlier_set1) * npoints * 2);
inlier_set2 = (double *)aom_malloc(sizeof(*inlier_set2) * npoints * 2);
points1 = (double *)aom_malloc(sizeof(*points1) * npoints * 2);
points2 = (double *)aom_malloc(sizeof(*points2) * npoints * 2);
corners1 = (double *)aom_malloc(sizeof(*corners1) * npoints * 2);
corners2 = (double *)aom_malloc(sizeof(*corners2) * npoints * 2);
image1_coord = (double *)aom_malloc(sizeof(*image1_coord) * npoints * 2);
if (!(best_inlier_set1 && best_inlier_set2 && inlier_set1 && inlier_set2 &&
corners1 && corners2 && image1_coord)) {
motions =
(RANSAC_MOTION *)aom_malloc(sizeof(RANSAC_MOTION) * num_desired_motions);
for (i = 0; i < num_desired_motions; ++i) {
motions[i].inlier_indices =
(int *)aom_malloc(sizeof(*motions->inlier_indices) * npoints);
clear_motion(motions + i, npoints);
}
current_motion.inlier_indices =
(int *)aom_malloc(sizeof(*current_motion.inlier_indices) * npoints);
clear_motion(&current_motion, npoints);
worst_kept_motion = motions;
if (!(points1 && points2 && corners1 && corners2 && image1_coord && motions &&
current_motion.inlier_indices)) {
ret_val = 1;
goto finish_ransac;
}
for (cnp1 = corners1, cnp2 = corners2, i = 0; i < npoints; ++i) {
cnp1 = corners1;
cnp2 = corners2;
for (i = 0; i < npoints; ++i) {
*(cnp1++) = *(matched_points++);
*(cnp1++) = *(matched_points++);
*(cnp2++) = *(matched_points++);
......@@ -978,28 +1030,24 @@ static int ransac(int *matched_points, int npoints, int *number_of_inliers,
matched_points -= 4 * npoints;
while (N > trial_count) {
int num_inliers = 0;
double sum_distance = 0.0;
double sum_distance_squared = 0.0;
clear_motion(&current_motion, npoints);
int degenerate = 1;
int num_degenerate_iter = 0;
while (degenerate) {
num_degenerate_iter++;
if (!get_rand_indices(npoints, minpts, indices, &seed)) {
ret_val = 1;
goto finish_ransac;
}
i = 0;
while (i < minpts) {
int index = indices[i];
// add to list
points1[i * 2] = corners1[index * 2];
points1[i * 2 + 1] = corners1[index * 2 + 1];
points2[i * 2] = corners2[index * 2];
points2[i * 2 + 1] = corners2[index * 2 + 1];
i++;
}
copy_points_at_indices(points1, corners1, indices, minpts);
copy_points_at_indices(points2, corners2, indices, minpts);
degenerate = is_degenerate(points1);
if (num_degenerate_iter > MAX_DEGENERATE_ITER) {
ret_val = 1;
......@@ -1007,12 +1055,12 @@ static int ransac(int *matched_points, int npoints, int *number_of_inliers,
}
}
if (find_transformation(minpts, points1, points2, params)) {
if (find_transformation(minpts, points1, points2, params_this_motion)) {
trial_count++;
continue;
}
projectpoints(params, corners1, image1_coord, npoints, 2, 2);
projectpoints(params_this_motion, corners1, image1_coord, npoints, 2, 2);
for (i = 0; i < npoints; ++i) {
double dx = image1_coord[i * 2] - corners2[i * 2];
......@@ -1020,60 +1068,79 @@ static int ransac(int *matched_points, int npoints, int *number_of_inliers,
double distance = sqrt(dx * dx + dy * dy);
if (distance < INLIER_THRESHOLD) {
inlier_set1[num_inliers * 2] = corners1[i * 2];
inlier_set1[num_inliers * 2 + 1] = corners1[i * 2 + 1];
inlier_set2[num_inliers * 2] = corners2[i * 2];
inlier_set2[num_inliers * 2 + 1] = corners2[i * 2 + 1];
num_inliers++;
current_motion.inlier_indices[current_motion.num_inliers++] = i;
sum_distance += distance;
sum_distance_squared += distance * distance;
}
}
if (num_inliers >= max_inliers && num_inliers > 1) {
if (current_motion.num_inliers >= worst_kept_motion->num_inliers &&
current_motion.num_inliers > 1) {
int temp;
double fracinliers, pNoOutliers, mean_distance, variance;
mean_distance = sum_distance / ((double)num_inliers);
variance = sum_distance_squared / ((double)num_inliers - 1.0) -
mean_distance * mean_distance * ((double)num_inliers) /
((double)num_inliers - 1.0);
if ((num_inliers > max_inliers) ||
(num_inliers == max_inliers && variance < best_variance)) {
best_variance = variance;
max_inliers = num_inliers;
// Save parameters, excluding the implicit '1' in the bottom-right
// entry of the parameter matrix
memcpy(best_params, params, (MAX_PARAMDIM - 1) * sizeof(*best_params));
memcpy(best_inlier_set1, inlier_set1,
num_inliers * 2 * sizeof(*best_inlier_set1));
memcpy(best_inlier_set2, inlier_set2,
num_inliers * 2 * sizeof(*best_inlier_set2));
double fracinliers, pNoOutliers, mean_distance;
mean_distance = sum_distance / ((double)current_motion.num_inliers);
current_motion.variance =
sum_distance_squared / ((double)current_motion.num_inliers - 1.0) -
mean_distance * mean_distance * ((double)current_motion.num_inliers) /
((double)current_motion.num_inliers - 1.0);
if (is_better_motion(&current_motion, worst_kept_motion)) {
// This motion is better than the worst currently kept motion. Remember
// the inlier points and variance. The parameters for each kept motion
// will be recomputed later using only the inliers.
worst_kept_motion->num_inliers = current_motion.num_inliers;
worst_kept_motion->variance = current_motion.variance;
memcpy(worst_kept_motion->inlier_indices, current_motion.inlier_indices,
sizeof(*current_motion.inlier_indices) * npoints);
assert(npoints > 0);
fracinliers = (double)num_inliers / (double)npoints;
fracinliers = (double)current_motion.num_inliers / (double)npoints;
pNoOutliers = 1 - pow(fracinliers, minpts);
pNoOutliers = fmax(EPS, pNoOutliers);
pNoOutliers = fmin(1 - EPS, pNoOutliers);
temp = (int)(log(1.0 - PROBABILITY_REQUIRED) / log(pNoOutliers));
if (temp > 0 && temp < N) {
N = AOMMAX(temp, MIN_TRIALS);
}
// Determine the new worst kept motion and its num_inliers and variance.
for (i = 0; i < num_desired_motions; ++i) {
if (is_better_motion(worst_kept_motion, &motions[i])) {
worst_kept_motion = &motions[i];
}
}
}
}
trial_count++;
}
find_transformation(max_inliers, best_inlier_set1, best_inlier_set2,
best_params);
*number_of_inliers = max_inliers;
// Sort the motions, best first.
qsort(motions, num_desired_motions, sizeof(RANSAC_MOTION), compare_motions);
// Recompute the motions using only the inliers.
for (i = 0; i < num_desired_motions; ++i) {
copy_points_at_indices(points1, corners1, motions[i].inlier_indices,
motions[i].num_inliers);
copy_points_at_indices(points2, corners2, motions[i].inlier_indices,
motions[i].num_inliers);
find_transformation(motions[i].num_inliers, points1, points2,
params_by_motion + (MAX_PARAMDIM - 1) * i);
num_inliers_by_motion[i] = motions[i].num_inliers;
}
finish_ransac:
aom_free(best_inlier_set1);
aom_free(best_inlier_set2);
aom_free(inlier_set1);
aom_free(inlier_set2);
aom_free(points1);
aom_free(points2);
aom_free(corners1);
aom_free(corners2);
aom_free(image1_coord);
aom_free(current_motion.inlier_indices);
for (i = 0; i < num_desired_motions; ++i) {
aom_free(motions[i].inlier_indices);
}
aom_free(motions);
return ret_val;
}
......@@ -1097,44 +1164,52 @@ static int is_degenerate_homography(double *p) {
is_collinear3(p, p + 4, p + 6) || is_collinear3(p + 2, p + 4, p + 6);
}
int ransac_translation(int *matched_points, int npoints, int *number_of_inliers,
double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 3,
int ransac_translation(int *matched_points, int npoints,
int *num_inliers_by_motion, double *params_by_motion,
int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 3,
is_degenerate_translation, find_translation,
project_points_double_translation);
}
int ransac_rotzoom(int *matched_points, int npoints, int *number_of_inliers,
double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 3,
is_degenerate_affine, find_rotzoom,
project_points_double_rotzoom);
int ransac_rotzoom(int *matched_points, int npoints, int *num_inliers_by_motion,
double *params_by_motion, int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 3, is_degenerate_affine,
find_rotzoom, project_points_double_rotzoom);
}
int ransac_affine(int *matched_points, int npoints, int *number_of_inliers,
double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 3,
is_degenerate_affine, find_affine,
project_points_double_affine);
int ransac_affine(int *matched_points, int npoints, int *num_inliers_by_motion,
double *params_by_motion, int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 3, is_degenerate_affine,
find_affine, project_points_double_affine);
}
int ransac_homography(int *matched_points, int npoints, int *number_of_inliers,
double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 4,
int ransac_homography(int *matched_points, int npoints,
int *num_inliers_by_motion, double *params_by_motion,
int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 4,
is_degenerate_homography, find_homography,
project_points_double_homography);
}
int ransac_hortrapezoid(int *matched_points, int npoints,
int *number_of_inliers, double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 4,
int *num_inliers_by_motion, double *params_by_motion,
int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 4,
is_degenerate_homography, find_hortrapezoid,
project_points_double_hortrapezoid);
}
int ransac_vertrapezoid(int *matched_points, int npoints,
int *number_of_inliers, double *best_params) {
return ransac(matched_points, npoints, number_of_inliers, best_params, 4,
int *num_inliers_by_motion, double *params_by_motion,
int num_desired_motions) {
return ransac(matched_points, npoints, num_inliers_by_motion,
params_by_motion, num_desired_motions, 4,
is_degenerate_homography, find_vertrapezoid,
project_points_double_vertrapezoid);
}
......@@ -20,20 +20,25 @@
#include "av1/common/warped_motion.h"
typedef int (*RansacFunc)(int *matched_points, int npoints,
int *number_of_inliers, double *best_params);
int *num_inliers_by_motion, double *params_by_motion,
int num_motions);
/* Each of these functions fits a motion model from a set of
corresponding points in 2 frames using RANSAC. */
int ransac_homography(int *matched_points, int npoints, int *number_of_inliers,
double *best_params);
int ransac_affine(int *matched_points, int npoints, int *number_of_inliers,
double *best_params);
int ransac_homography(int *matched_points, int npoints,
int *num_inliers_by_motion, double *params_by_motion,
int num_motions);
int ransac_affine(int *matched_points, int npoints, int *num_inliers_by_motion,
double *params_by_motion, int num_motions);
int ransac_hortrapezoid(int *matched_points, int npoints,
int *number_of_inliers, double *best_params);
int *num_inliers_by_motion, double *params_by_motion,
int num_motions);
int ransac_vertrapezoid(int *matched_points, int npoints,
int *number_of_inliers, double *best_params);
int ransac_rotzoom(int *matched_points, int npoints, int *number_of_inliers,
double *best_params);
int ransac_translation(int *matched_points, int npoints, int *number_of_inliers,
double *best_params);
int *num_inliers_by_motion, double *params_by_motion,
int num_motions);
int ransac_rotzoom(int *matched_points, int npoints, int *num_inliers_by_motion,
double *params_by_motion, int num_motions);
int ransac_translation(int *matched_points, int npoints,
int *num_inliers_by_motion, double *params_by_motion,
int num_motions);
#endif // AV1_ENCODER_RANSAC_H_