Support trapezoidal models for global motion Adds functinoality for least-squares, RANSAC as well as encoding and decoding with new constrained homographies that warp blocks to horizontal and/or vertical trapezoids. This is for future experimentation. None of the models are actually enabled in the code. Change-Id: I1936018c6b11587d6fd83c3a2c63548cb641b33f
diff --git a/av1/common/entropymv.c b/av1/common/entropymv.c index 866bdb9..91d8d94 100644 --- a/av1/common/entropymv.c +++ b/av1/common/entropymv.c
@@ -128,30 +128,41 @@ }; #if CONFIG_GLOBAL_MOTION -#if GLOBAL_TRANS_TYPES == 5 +#if GLOBAL_TRANS_TYPES == 7 // All models const aom_tree_index av1_global_motion_types_tree[TREE_SIZE( - GLOBAL_TRANS_TYPES)] = { -IDENTITY, 2, -TRANSLATION, 4, - -ROTZOOM, 6, -AFFINE, -HOMOGRAPHY }; + GLOBAL_TRANS_TYPES)] = { -IDENTITY, 2, -TRANSLATION, 4, + -ROTZOOM, 6, -AFFINE, 8, + -HOMOGRAPHY, 10, -HORTRAPEZOID, -VERTRAPEZOID }; static const aom_prob default_global_motion_types_prob[GLOBAL_TRANS_TYPES - 1] = - { 224, 128, 192, 192 }; + { 224, 128, 192, 192, 32, 128 }; -#elif GLOBAL_TRANS_TYPES == 4 +#elif GLOBAL_TRANS_TYPES == 6 // Do not allow full homography +const aom_tree_index + av1_global_motion_types_tree[TREE_SIZE(GLOBAL_TRANS_TYPES)] = { + -IDENTITY, 2, -TRANSLATION, 4, -ROTZOOM, 6, -AFFINE, 8, -HORTRAPEZOID, + -VERTRAPEZOID + }; + +static const aom_prob default_global_motion_types_prob[GLOBAL_TRANS_TYPES - 1] = + { 224, 128, 192, 192, 128 }; + +#elif GLOBAL_TRANS_TYPES == 4 // Upto Affine const aom_tree_index av1_global_motion_types_tree[TREE_SIZE( GLOBAL_TRANS_TYPES)] = { -IDENTITY, 2, -TRANSLATION, 4, -ROTZOOM, -AFFINE }; static const aom_prob default_global_motion_types_prob[GLOBAL_TRANS_TYPES - 1] = { 224, 128, 240 }; -#elif GLOBAL_TRANS_TYPES == 3 +#elif GLOBAL_TRANS_TYPES == 3 // Upto rotation-zoom const aom_tree_index av1_global_motion_types_tree[TREE_SIZE( GLOBAL_TRANS_TYPES)] = { -IDENTITY, 2, -TRANSLATION, -ROTZOOM }; static const aom_prob default_global_motion_types_prob[GLOBAL_TRANS_TYPES - 1] = { 224, 128 }; -#endif // GLOBAL_TRANS_TYPES -#endif // CONFIG_GLOBAL_MOTION +#endif // GLOBAL_TRANS_TYPES +#endif // CONFIG_GLOBAL_MOTION static INLINE int mv_class_base(MV_CLASS_TYPE c) { return c ? CLASS0_SIZE << (c + 2) : 0;
diff --git a/av1/common/mv.h b/av1/common/mv.h index cd4b4e6..9275c23 100644 --- a/av1/common/mv.h +++ b/av1/common/mv.h
@@ -53,26 +53,33 @@ /* clang-format off */ typedef enum { - IDENTITY = 0, // identity transformation, 0-parameter - TRANSLATION = 1, // translational motion 2-parameter - ROTZOOM = 2, // simplified affine with rotation + zoom only, 4-parameter - AFFINE = 3, // affine, 6-parameter - HOMOGRAPHY = 4, // homography, 8-parameter - TRANS_TYPES = 5, + IDENTITY = 0, // identity transformation, 0-parameter + TRANSLATION = 1, // translational motion 2-parameter + ROTZOOM = 2, // simplified affine with rotation + zoom only, 4-parameter + AFFINE = 3, // affine, 6-parameter + HORTRAPEZOID = 4, // constrained homography, hor trapezoid, 6-parameter + VERTRAPEZOID = 5, // constrained homography, ver trapezoid, 6-parameter + HOMOGRAPHY = 6, // homography, 8-parameter + TRANS_TYPES = 7, } TransformationType; /* clang-format on */ // Number of types used for global motion (must be >= 3 and <= TRANS_TYPES) +// The following can be useful: +// GLOBAL_TRANS_TYPES 3 - up to rotation-zoom +// GLOBAL_TRANS_TYPES 4 - up to affine +// GLOBAL_TRANS_TYPES 6 - up to hor/ver trapezoids +// GLOBAL_TRANS_TYPES 7 - up to full homography #define GLOBAL_TRANS_TYPES 3 // number of parameters used by each transformation in TransformationTypes -static const int n_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6, 8 }; +static const int trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6, 6, 6, 8 }; // The order of values in the wmmat matrix below is best described // by the homography: -// [x' (m2 m3 m0 [x -// y' = m4 m5 m1 * y -// 1] m6 m7 1) 1] +// [x' (m2 m3 m0 [x +// z . y' = m4 m5 m1 * y +// 1] m6 m7 1) 1] typedef struct { TransformationType wmtype; int32_t wmmat[8]; @@ -134,6 +141,10 @@ #define GM_ROTZOOM_BITS (GM_TRANSLATION_BITS + (GM_ABS_ALPHA_BITS + 1) * 2) #define GM_AFFINE_BITS (GM_ROTZOOM_BITS + (GM_ABS_ALPHA_BITS + 1) * 2) #define GM_HOMOGRAPHY_BITS (GM_AFFINE_BITS + (GM_ABS_ROW3HOMO_BITS + 1) * 2) +#define GM_HORTRAPEZOID_BITS \ + (GM_AFFINE_BITS - GM_ABS_ALPHA_BITS + GM_ABS_ROW3HOMO_BITS) +#define GM_VERTRAPEZOID_BITS \ + (GM_AFFINE_BITS - GM_ABS_ALPHA_BITS + GM_ABS_ROW3HOMO_BITS) // Convert a global motion translation vector (which may have more bits than a // regular motion vector) into a motion vector @@ -154,7 +165,11 @@ } static INLINE TransformationType get_gmtype(const WarpedMotionParams *gm) { - // if (gm->wmmat[6] != 0 || gm->wmmat[7] != 0) return HOMOGRAPHY; + if (gm->wmmat[6] != 0 || gm->wmmat[7] != 0) { + if (!gm->wmmat[6] && !gm->wmmat[4]) return HORTRAPEZOID; + if (!gm->wmmat[7] && !gm->wmmat[3]) return VERTRAPEZOID; + return HOMOGRAPHY; + } if (gm->wmmat[5] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[4] && gm->wmmat[2] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[3]) { return ((!gm->wmmat[1] && !gm->wmmat[0]) ? IDENTITY : TRANSLATION);
diff --git a/av1/common/warped_motion.c b/av1/common/warped_motion.c index 9698c5f..86ba46c 100644 --- a/av1/common/warped_motion.c +++ b/av1/common/warped_motion.c
@@ -178,6 +178,72 @@ } } +void project_points_hortrapezoid(int32_t *mat, int *points, int *proj, + const int n, const int stride_points, + const int stride_proj, const int subsampling_x, + const int subsampling_y) { + int i; + int64_t x, y, Z; + int64_t xp, yp; + for (i = 0; i < n; ++i) { + x = *(points++), y = *(points++); + x = (subsampling_x ? 4 * x + 1 : 2 * x); + y = (subsampling_y ? 4 * y + 1 : 2 * y); + + Z = (mat[7] * y + (1 << (WARPEDMODEL_ROW3HOMO_PREC_BITS + 1))); + xp = (mat[2] * x + mat[3] * y + 2 * mat[0]) * + (1 << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS - + WARPEDMODEL_PREC_BITS)); + yp = (mat[5] * y + 2 * mat[1]) * + (1 << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS - + WARPEDMODEL_PREC_BITS)); + + xp = xp > 0 ? (xp + Z / 2) / Z : (xp - Z / 2) / Z; + yp = yp > 0 ? (yp + Z / 2) / Z : (yp - Z / 2) / Z; + + if (subsampling_x) xp = (xp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2; + if (subsampling_y) yp = (yp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2; + *(proj++) = xp; + *(proj++) = yp; + + points += stride_points - 2; + proj += stride_proj - 2; + } +} + +void project_points_vertrapezoid(int32_t *mat, int *points, int *proj, + const int n, const int stride_points, + const int stride_proj, const int subsampling_x, + const int subsampling_y) { + int i; + int64_t x, y, Z; + int64_t xp, yp; + for (i = 0; i < n; ++i) { + x = *(points++), y = *(points++); + x = (subsampling_x ? 4 * x + 1 : 2 * x); + y = (subsampling_y ? 4 * y + 1 : 2 * y); + + Z = (mat[6] * x + (1 << (WARPEDMODEL_ROW3HOMO_PREC_BITS + 1))); + xp = (mat[2] * x + 2 * mat[0]) * + (1 << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS - + WARPEDMODEL_PREC_BITS)); + yp = (mat[4] * x + mat[5] * y + 2 * mat[1]) * + (1 << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS - + WARPEDMODEL_PREC_BITS)); + + xp = xp > 0 ? (xp + Z / 2) / Z : (xp - Z / 2) / Z; + yp = yp > 0 ? (yp + Z / 2) / Z : (yp - Z / 2) / Z; + + if (subsampling_x) xp = (xp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2; + if (subsampling_y) yp = (yp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2; + *(proj++) = xp; + *(proj++) = yp; + + points += stride_points - 2; + proj += stride_proj - 2; + } +} + void project_points_homography(int32_t *mat, int *points, int *proj, const int n, const int stride_points, const int stride_proj, const int subsampling_x, @@ -1720,6 +1786,144 @@ return 0; } +int find_vertrapezoid(const int np, double *pts1, double *pts2, double *mat) { + const int np3 = np * 3; + double *a = (double *)aom_malloc(sizeof(*a) * np3 * 14); + double *U = a + np3 * 7; + double S[7], V[7 * 7], H[9]; + int i, mini; + double sx, sy, dx, dy; + double T1[9], T2[9]; + + normalize_homography(pts1, np, T1); + normalize_homography(pts2, np, T2); + + for (i = 0; i < np; ++i) { + dx = *(pts2++); + dy = *(pts2++); + sx = *(pts1++); + sy = *(pts1++); + + a[i * 3 * 7 + 0] = a[i * 3 * 7 + 1] = 0; + a[i * 3 * 7 + 2] = -sx; + a[i * 3 * 7 + 3] = -sy; + a[i * 3 * 7 + 4] = -1; + a[i * 3 * 7 + 5] = dy * sx; + a[i * 3 * 7 + 6] = dy; + + a[(i * 3 + 1) * 7 + 0] = sx; + a[(i * 3 + 1) * 7 + 1] = 1; + a[(i * 3 + 1) * 7 + 2] = a[(i * 3 + 1) * 7 + 3] = a[(i * 3 + 1) * 7 + 4] = + 0; + a[(i * 3 + 1) * 7 + 5] = -dx * sx; + a[(i * 3 + 1) * 7 + 6] = -dx; + + a[(i * 3 + 2) * 7 + 0] = -dy * sx; + a[(i * 3 + 2) * 7 + 1] = -dy; + a[(i * 3 + 2) * 7 + 2] = dx * sx; + a[(i * 3 + 2) * 7 + 3] = dx * sy; + a[(i * 3 + 2) * 7 + 4] = dx; + a[(i * 3 + 2) * 7 + 5] = a[(i * 3 + 2) * 7 + 6] = 0; + } + if (SVD(U, S, V, a, np3, 7)) { + aom_free(a); + return 1; + } else { + double minS = 1e12; + mini = -1; + for (i = 0; i < 7; ++i) { + if (S[i] < minS) { + minS = S[i]; + mini = i; + } + } + } + H[1] = H[7] = 0; + for (i = 0; i < 1; i++) H[i] = V[i * 7 + mini]; + for (; i < 6; i++) H[i + 1] = V[i * 7 + mini]; + for (; i < 7; i++) H[i + 2] = V[i * 7 + mini]; + + denormalize_homography_reorder(H, T1, T2); + aom_free(a); + if (H[8] == 0.0) { + return 1; + } else { + // normalize + double f = 1.0 / H[8]; + for (i = 0; i < 8; i++) mat[i] = f * H[i]; + } + return 0; +} + +int find_hortrapezoid(const int np, double *pts1, double *pts2, double *mat) { + const int np3 = np * 3; + double *a = (double *)aom_malloc(sizeof(*a) * np3 * 14); + double *U = a + np3 * 7; + double S[7], V[7 * 7], H[9]; + int i, mini; + double sx, sy, dx, dy; + double T1[9], T2[9]; + + normalize_homography(pts1, np, T1); + normalize_homography(pts2, np, T2); + + for (i = 0; i < np; ++i) { + dx = *(pts2++); + dy = *(pts2++); + sx = *(pts1++); + sy = *(pts1++); + + a[i * 3 * 7 + 0] = a[i * 3 * 7 + 1] = a[i * 3 * 7 + 2] = 0; + a[i * 3 * 7 + 3] = -sy; + a[i * 3 * 7 + 4] = -1; + a[i * 3 * 7 + 5] = dy * sy; + a[i * 3 * 7 + 6] = dy; + + a[(i * 3 + 1) * 7 + 0] = sx; + a[(i * 3 + 1) * 7 + 1] = sy; + a[(i * 3 + 1) * 7 + 2] = 1; + a[(i * 3 + 1) * 7 + 3] = a[(i * 3 + 1) * 7 + 4] = 0; + a[(i * 3 + 1) * 7 + 5] = -dx * sy; + a[(i * 3 + 1) * 7 + 6] = -dx; + + a[(i * 3 + 2) * 7 + 0] = -dy * sx; + a[(i * 3 + 2) * 7 + 1] = -dy * sy; + a[(i * 3 + 2) * 7 + 2] = -dy; + a[(i * 3 + 2) * 7 + 3] = dx * sy; + a[(i * 3 + 2) * 7 + 4] = dx; + a[(i * 3 + 2) * 7 + 5] = a[(i * 3 + 2) * 7 + 6] = 0; + } + + if (SVD(U, S, V, a, np3, 7)) { + aom_free(a); + return 1; + } else { + double minS = 1e12; + mini = -1; + for (i = 0; i < 7; ++i) { + if (S[i] < minS) { + minS = S[i]; + mini = i; + } + } + } + H[3] = H[6] = 0; + for (i = 0; i < 3; i++) H[i] = V[i * 7 + mini]; + for (; i < 5; i++) H[i + 1] = V[i * 7 + mini]; + for (; i < 7; i++) H[i + 2] = V[i * 7 + mini]; + + denormalize_homography_reorder(H, T1, T2); + aom_free(a); + if (H[8] == 0.0) { + return 1; + } else { + // normalize + double f = 1.0 / H[8]; + for (i = 0; i < 8; i++) mat[i] = f * H[i]; + } + return 0; +} + int find_homography(const int np, double *pts1, double *pts2, double *mat) { // Implemented from Peter Kovesi's normalized implementation const int np3 = np * 3;
diff --git a/av1/common/warped_motion.h b/av1/common/warped_motion.h index c1d8177..b3fb4f2 100644 --- a/av1/common/warped_motion.h +++ b/av1/common/warped_motion.h
@@ -51,6 +51,14 @@ const int stride_points, const int stride_proj, const int subsampling_x, const int subsampling_y); +void project_points_hortrapezoid(int32_t *mat, int *points, int *proj, + const int n, const int stride_points, + const int stride_proj, const int subsampling_x, + const int subsampling_y); +void project_points_vertrapezoid(int32_t *mat, int *points, int *proj, + const int n, const int stride_points, + const int stride_proj, const int subsampling_x, + const int subsampling_y); void project_points_homography(int32_t *mat, int *points, int *proj, const int n, const int stride_points, const int stride_proj, const int subsampling_x, @@ -85,6 +93,8 @@ int find_translation(const int np, double *pts1, double *pts2, double *mat); int find_rotzoom(const int np, double *pts1, double *pts2, double *mat); int find_affine(const int np, double *pts1, double *pts2, double *mat); +int find_hortrapezoid(const int np, double *pts1, double *pts2, double *mat); +int find_vertrapezoid(const int np, double *pts1, double *pts2, double *mat); int find_homography(const int np, double *pts1, double *pts2, double *mat); int find_projection(const int np, double *pts1, double *pts2, WarpedMotionParams *wm_params);
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 6d91cfe..4b98549 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -4449,20 +4449,29 @@ params->wmtype = type; switch (type) { case HOMOGRAPHY: - params->wmmat[6] = aom_read_primitive_symmetric(r, GM_ABS_ROW3HOMO_BITS) * - GM_ROW3HOMO_DECODE_FACTOR; - params->wmmat[7] = aom_read_primitive_symmetric(r, GM_ABS_ROW3HOMO_BITS) * - GM_ROW3HOMO_DECODE_FACTOR; + case HORTRAPEZOID: + case VERTRAPEZOID: + if (type != HORTRAPEZOID) + params->wmmat[6] = + aom_read_primitive_symmetric(r, GM_ABS_ROW3HOMO_BITS) * + GM_ROW3HOMO_DECODE_FACTOR; + if (type != VERTRAPEZOID) + params->wmmat[7] = + aom_read_primitive_symmetric(r, GM_ABS_ROW3HOMO_BITS) * + GM_ROW3HOMO_DECODE_FACTOR; case AFFINE: case ROTZOOM: params->wmmat[2] = aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * GM_ALPHA_DECODE_FACTOR + (1 << WARPEDMODEL_PREC_BITS); - params->wmmat[3] = aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * - GM_ALPHA_DECODE_FACTOR; - if (type == AFFINE || type == HOMOGRAPHY) { - params->wmmat[4] = aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * + if (type != VERTRAPEZOID) + params->wmmat[3] = aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * GM_ALPHA_DECODE_FACTOR; + if (type >= AFFINE) { + if (type != HORTRAPEZOID) + params->wmmat[4] = + aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * + GM_ALPHA_DECODE_FACTOR; params->wmmat[5] = aom_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * GM_ALPHA_DECODE_FACTOR + (1 << WARPEDMODEL_PREC_BITS);
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 8331e8a..e454200 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -4495,10 +4495,16 @@ &global_motion_types_encodings[type]); switch (type) { case HOMOGRAPHY: - aom_write_primitive_symmetric( - w, (params->wmmat[6] >> GM_ROW3HOMO_PREC_DIFF), GM_ABS_ROW3HOMO_BITS); - aom_write_primitive_symmetric( - w, (params->wmmat[7] >> GM_ROW3HOMO_PREC_DIFF), GM_ABS_ROW3HOMO_BITS); + case HORTRAPEZOID: + case VERTRAPEZOID: + if (type != HORTRAPEZOID) + aom_write_primitive_symmetric( + w, (params->wmmat[6] >> GM_ROW3HOMO_PREC_DIFF), + GM_ABS_ROW3HOMO_BITS); + if (type != VERTRAPEZOID) + aom_write_primitive_symmetric( + w, (params->wmmat[7] >> GM_ROW3HOMO_PREC_DIFF), + GM_ABS_ROW3HOMO_BITS); // fallthrough intended case AFFINE: case ROTZOOM: @@ -4506,11 +4512,13 @@ w, (params->wmmat[2] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS), GM_ABS_ALPHA_BITS); - aom_write_primitive_symmetric(w, (params->wmmat[3] >> GM_ALPHA_PREC_DIFF), - GM_ABS_ALPHA_BITS); - if (type == AFFINE || type == HOMOGRAPHY) { + if (type != VERTRAPEZOID) aom_write_primitive_symmetric( - w, (params->wmmat[4] >> GM_ALPHA_PREC_DIFF), GM_ABS_ALPHA_BITS); + w, (params->wmmat[3] >> GM_ALPHA_PREC_DIFF), GM_ABS_ALPHA_BITS); + if (type >= AFFINE) { + if (type != HORTRAPEZOID) + aom_write_primitive_symmetric( + w, (params->wmmat[4] >> GM_ALPHA_PREC_DIFF), GM_ABS_ALPHA_BITS); aom_write_primitive_symmetric(w, (params->wmmat[5] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS),
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index e408278..5bc8e60 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -3007,7 +3007,7 @@ #if CONFIG_GLOBAL_MOTION static int recode_loop_test_global_motion(AV1_COMP *cpi) { - static const int min_blocks[TRANS_TYPES] = { 0, 60, 120, 180, 240 }; + static const int min_blocks[TRANS_TYPES] = { 0, 60, 120, 180, 180, 180, 240 }; int i; int recode = 0; AV1_COMMON *const cm = &cpi->common;
diff --git a/av1/encoder/global_motion.c b/av1/encoder/global_motion.c index 8259c45..a213d8d 100644 --- a/av1/encoder/global_motion.c +++ b/av1/encoder/global_motion.c
@@ -104,7 +104,9 @@ wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS; wm->wmmat[3] = 0; case ROTZOOM: wm->wmmat[4] = -wm->wmmat[3]; wm->wmmat[5] = wm->wmmat[2]; - case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; + case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break; + case HORTRAPEZOID: wm->wmmat[6] = wm->wmmat[4] = 0; break; + case VERTRAPEZOID: wm->wmmat[7] = wm->wmmat[3] = 0; break; case HOMOGRAPHY: break; default: assert(0); } @@ -119,9 +121,12 @@ uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst, int d_width, int d_height, int d_stride, int n_refinements) { + static const int max_trans_model_params[TRANS_TYPES] = { + 0, 2, 4, 6, 8, 8, 8 + }; const int border = ERRORADV_BORDER; int i = 0, p; - int n_params = n_trans_model_params[wmtype]; + int n_params = max_trans_model_params[wmtype]; int32_t *param_mat = wm->wmmat; double step_error; int32_t step; @@ -143,6 +148,9 @@ for (i = 0; i < n_refinements; i++, step >>= 1) { for (p = 0; p < n_params; ++p) { int step_dir = 0; + // Skip searches for parameters that are forced to be 0 + if (wmtype == HORTRAPEZOID && (p == 4 || p == 6)) continue; + if (wmtype == VERTRAPEZOID && (p == 3 || p == 7)) continue; param = param_mat + p; curr_param = *param; best_param = curr_param; @@ -209,6 +217,8 @@ static INLINE RansacFunc get_ransac_type(TransformationType type) { switch (type) { case HOMOGRAPHY: return ransac_homography; + case HORTRAPEZOID: return ransac_hortrapezoid; + case VERTRAPEZOID: return ransac_vertrapezoid; case AFFINE: return ransac_affine; case ROTZOOM: return ransac_rotzoom; case TRANSLATION: return ransac_translation;
diff --git a/av1/encoder/global_motion.h b/av1/encoder/global_motion.h index 1f9b5a2..b3893b5 100644 --- a/av1/encoder/global_motion.h +++ b/av1/encoder/global_motion.h
@@ -23,6 +23,8 @@ 0.85, // Translation 0.75, // Rot zoom 0.65, // Affine + 0.65, // Hor Trapezoid + 0.65, // Ver Trapezoid 0.50, // Homography };
diff --git a/av1/encoder/ransac.c b/av1/encoder/ransac.c index 766a1cf..3b06710 100644 --- a/av1/encoder/ransac.c +++ b/av1/encoder/ransac.c
@@ -22,6 +22,9 @@ #define MAX_DEGENERATE_ITER 10 #define MINPTS_MULTIPLIER 5 +#define INLIER_THRESHOLD 1.0 +#define MIN_TRIALS 20 + //////////////////////////////////////////////////////////////////////////////// // ransac typedef int (*IsDegenerateFunc)(double *p); @@ -76,6 +79,42 @@ } } +static void project_points_double_hortrapezoid(double *mat, double *points, + double *proj, const int n, + const int stride_points, + const int stride_proj) { + int i; + double x, y, Z, Z_inv; + for (i = 0; i < n; ++i) { + x = *(points++), y = *(points++); + Z_inv = mat[7] * y + 1; + assert(fabs(Z_inv) > 0.000001); + Z = 1. / Z_inv; + *(proj++) = (mat[2] * x + mat[3] * y + mat[0]) * Z; + *(proj++) = (mat[5] * y + mat[1]) * Z; + points += stride_points - 2; + proj += stride_proj - 2; + } +} + +static void project_points_double_vertrapezoid(double *mat, double *points, + double *proj, const int n, + const int stride_points, + const int stride_proj) { + int i; + double x, y, Z, Z_inv; + for (i = 0; i < n; ++i) { + x = *(points++), y = *(points++); + Z_inv = mat[6] * x + 1; + assert(fabs(Z_inv) > 0.000001); + Z = 1. / Z_inv; + *(proj++) = (mat[2] * x + mat[0]) * Z; + *(proj++) = (mat[4] * x + mat[5] * y + mat[1]) * Z; + points += stride_points - 2; + proj += stride_proj - 2; + } +} + static void project_points_double_homography(double *mat, double *points, double *proj, const int n, const int stride_points, @@ -121,10 +160,8 @@ IsDegenerateFunc is_degenerate, FindTransformationFunc find_transformation, ProjectPointsDoubleFunc projectpoints) { - static const double inlier_threshold = 1.0; static const double PROBABILITY_REQUIRED = 0.9; static const double EPS = 1e-12; - static const int MIN_TRIALS = 20; int N = 10000, trial_count = 0; int i; @@ -223,7 +260,7 @@ double dy = image1_coord[i * 2 + 1] - corners2[i * 2 + 1]; double distance = sqrt(dx * dx + dy * dy); - inlier_mask[i] = distance < inlier_threshold; + inlier_mask[i] = distance < INLIER_THRESHOLD; if (inlier_mask[i]) { inlier_set1[num_inliers * 2] = corners1[i * 2]; inlier_set1[num_inliers * 2 + 1] = corners1[i * 2 + 1]; @@ -332,3 +369,19 @@ best_params, 4, is_degenerate_homography, find_homography, project_points_double_homography); } + +int ransac_hortrapezoid(int *matched_points, int npoints, + int *number_of_inliers, int *best_inlier_mask, + double *best_params) { + return ransac(matched_points, npoints, number_of_inliers, best_inlier_mask, + best_params, 4, is_degenerate_homography, find_hortrapezoid, + project_points_double_hortrapezoid); +} + +int ransac_vertrapezoid(int *matched_points, int npoints, + int *number_of_inliers, int *best_inlier_mask, + double *best_params) { + return ransac(matched_points, npoints, number_of_inliers, best_inlier_mask, + best_params, 4, is_degenerate_homography, find_vertrapezoid, + project_points_double_vertrapezoid); +}
diff --git a/av1/encoder/ransac.h b/av1/encoder/ransac.h index c45603c..91e6acb 100644 --- a/av1/encoder/ransac.h +++ b/av1/encoder/ransac.h
@@ -24,11 +24,17 @@ double *best_params); /* Each of these functions fits a motion model from a set of -corresponding points in 2 frames using RANSAC.*/ + corresponding points in 2 frames using RANSAC. */ int ransac_homography(int *matched_points, int npoints, int *number_of_inliers, int *best_inlier_indices, double *best_params); int ransac_affine(int *matched_points, int npoints, int *number_of_inliers, int *best_inlier_indices, double *best_params); +int ransac_hortrapezoid(int *matched_points, int npoints, + int *number_of_inliers, int *best_inlier_indices, + double *best_params); +int ransac_vertrapezoid(int *matched_points, int npoints, + int *number_of_inliers, int *best_inlier_indices, + double *best_params); int ransac_rotzoom(int *matched_points, int npoints, int *number_of_inliers, int *best_inlier_indices, double *best_params); int ransac_translation(int *matched_points, int npoints, int *number_of_inliers,
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 8717c0c..52a25bf 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -4911,10 +4911,13 @@ #if CONFIG_GLOBAL_MOTION static int GLOBAL_MOTION_RATE(const AV1_COMP *const cpi, int ref) { - static const int gm_amortization_blks[TRANS_TYPES] = { 4, 6, 8, 10, 12 }; + static const int gm_amortization_blks[TRANS_TYPES] = { + 4, 6, 8, 10, 10, 10, 12 + }; static const int gm_params_cost[TRANS_TYPES] = { - GM_IDENTITY_BITS, GM_TRANSLATION_BITS, GM_ROTZOOM_BITS, - GM_AFFINE_BITS, GM_HOMOGRAPHY_BITS, + GM_IDENTITY_BITS, GM_TRANSLATION_BITS, GM_ROTZOOM_BITS, + GM_AFFINE_BITS, GM_HORTRAPEZOID_BITS, GM_VERTRAPEZOID_BITS, + GM_HOMOGRAPHY_BITS, }; const WarpedMotionParams *gm = &cpi->common.global_motion[(ref)]; assert(gm->wmtype < GLOBAL_TRANS_TYPES);