Some refactoring and improvements to gobal motion
To facilitate further experiments.
Fixes border, uses standard interpolation filters for
translation only global model, and some refactoring.
Change-Id: I38af6cb83723f92baed23e28d7fc9a0a9544757e
diff --git a/av1/common/mv.h b/av1/common/mv.h
index 43b74c0..7e2304d 100644
--- a/av1/common/mv.h
+++ b/av1/common/mv.h
@@ -152,12 +152,12 @@
return AFFINE;
}
-static INLINE void set_default_gmparams(WarpedMotionParams *gm) {
- static const int32_t default_gm_params[8] = {
+static INLINE void set_default_gmparams(WarpedMotionParams *wm) {
+ static const int32_t default_wm_mat[8] = {
0, 0, (1 << WARPEDMODEL_PREC_BITS), 0, 0, (1 << WARPEDMODEL_PREC_BITS), 0, 0
};
- memcpy(gm->wmmat, default_gm_params, sizeof(gm->wmmat));
- gm->wmtype = IDENTITY;
+ memcpy(wm->wmmat, default_wm_mat, sizeof(wm->wmmat));
+ wm->wmtype = IDENTITY;
}
#endif // CONFIG_GLOBAL_MOTION
diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c
index a0c4e10..3642f90 100644
--- a/av1/common/reconinter.c
+++ b/av1/common/reconinter.c
@@ -558,7 +558,7 @@
for (ref = 0; ref < 1 + is_compound; ++ref) {
gm[ref] = &xd->global_motion[mi->mbmi.ref_frame[ref]];
is_global[ref] =
- (get_y_mode(mi, block) == ZEROMV && gm[ref]->wmtype != IDENTITY);
+ (get_y_mode(mi, block) == ZEROMV && gm[ref]->wmtype > TRANSLATION);
}
// TODO(sarahparker) remove these once gm works with all experiments
(void)gm;
diff --git a/av1/common/warped_motion.c b/av1/common/warped_motion.c
index dab6eb9..222585d 100644
--- a/av1/common/warped_motion.c
+++ b/av1/common/warped_motion.c
@@ -531,8 +531,8 @@
gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
highbd_warp_interpolate(ref, out[0], out[1], width, height,
stride, bd);
- no_gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
- ref[(j - p_col) + (i - p_row) * stride];
+ no_gm_err =
+ dst[(j - p_col) + (i - p_row) * p_stride] - ref[j + i * stride];
gm_sumerr += highbd_error_measure(gm_err, bd);
no_gm_sumerr += highbd_error_measure(no_gm_err, bd);
}
@@ -596,8 +596,8 @@
out[1] = ROUND_POWER_OF_TWO_SIGNED(out[1] * y_scale, 4);
gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
warp_interpolate(ref, out[0], out[1], width, height, stride);
- no_gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
- ref[(j - p_col) + (i - p_row) * stride];
+ no_gm_err =
+ dst[(j - p_col) + (i - p_row) * p_stride] - ref[j + i * stride];
gm_sumerr += error_measure(gm_err);
no_gm_sumerr += error_measure(no_gm_err);
}
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index bc1c77e..ab1a1c9 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4613,114 +4613,17 @@
#if CONFIG_GLOBAL_MOTION
#define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
-#define GLOBAL_MOTION_ADVANTAGE_THRESH 0.75
-// Adds some offset to a global motion parameter and handles
-// all of the necessary precision shifts, clamping, and
-// zero-centering.
-static int32_t add_param_offset(int param_index, int32_t param_value,
- int32_t offset) {
- const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
- GM_ROW3HOMO_PREC_DIFF };
- const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
- // type of param: 0 - translation, 1 - affine, 2 - homography
- const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
- const int is_one_centered = (param_index == 2 || param_index == 5);
+// Border over which to compute the global motion
+#define ERRORADV_BORDER 0
- // Make parameter zero-centered and offset the shift that was done to make
- // it compatible with the warped model
- param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
- scale_vals[param_type];
- // Add desired offset to the rescaled/zero-centered parameter
- param_value += offset;
- // Clamp the parameter so it does not overflow the number of bits allotted
- // to it in the bitstream
- param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
- clamp_vals[param_type]);
- // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
- // with the warped motion library
- param_value *= (1 << scale_vals[param_type]);
-
- // Undo the zero-centering step if necessary
- return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
-}
-
-static void refine_integerized_param(WarpedMotionParams *wm,
-#if CONFIG_AOM_HIGHBITDEPTH
- int use_hbd, int bd,
-#endif // CONFIG_AOM_HIGHBITDEPTH
- 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) {
- int i = 0, p;
- int n_params = n_trans_model_params[wm->wmtype];
- int32_t *param_mat = wm->wmmat;
- double step_error;
- int32_t step;
- int32_t *param;
- int32_t curr_param;
- int32_t best_param;
-
- double best_error =
- av1_warp_erroradv(wm,
-#if CONFIG_AOM_HIGHBITDEPTH
- use_hbd, bd,
-#endif // CONFIG_AOM_HIGHBITDEPTH
- ref, r_width, r_height, r_stride, dst, 0, 0, d_width,
- d_height, d_stride, 0, 0, 16, 16);
- for (p = 0; p < n_params; ++p) {
- param = param_mat + p;
- step = 1 << (n_refinements + 1);
- curr_param = *param;
- best_param = curr_param;
- for (i = 0; i < n_refinements; i++) {
- // look to the left
- *param = add_param_offset(p, curr_param, -step);
- step_error =
- av1_warp_erroradv(wm,
-#if CONFIG_AOM_HIGHBITDEPTH
- use_hbd, bd,
-#endif // CONFIG_AOM_HIGHBITDEPTH
- ref, r_width, r_height, r_stride, dst, 0, 0,
- d_width, d_height, d_stride, 0, 0, 16, 16);
- if (step_error < best_error) {
- step >>= 1;
- best_error = step_error;
- best_param = *param;
- curr_param = best_param;
- continue;
- }
-
- // look to the right
- *param = add_param_offset(p, curr_param, step);
- step_error =
- av1_warp_erroradv(wm,
-#if CONFIG_AOM_HIGHBITDEPTH
- use_hbd, bd,
-#endif // CONFIG_AOM_HIGHBITDEPTH
- ref, r_width, r_height, r_stride, dst, 0, 0,
- d_width, d_height, d_stride, 0, 0, 16, 16);
- if (step_error < best_error) {
- step >>= 1;
- best_error = step_error;
- best_param = *param;
- curr_param = best_param;
- continue;
- }
-
- // no improvement found-> means we're either already at a minimum or
- // step is too wide
- step >>= 1;
- }
- *param = best_param;
- }
- // For rotzoom model enforce the constraints on mat[4] and mat[5]
- if (wm->wmtype == ROTZOOM) {
- param_mat[5] = param_mat[2];
- param_mat[4] = -param_mat[3];
- }
-}
+static const double gm_advantage_thresh[TRANS_TYPES] = {
+ 1.00, // Identity (not used)
+ 0.85, // Translation
+ 0.75, // Rot zoom
+ 0.65, // Affine
+ 0.50, // Homography
+};
static void convert_to_params(const double *params, int32_t *model) {
int i;
@@ -4760,6 +4663,132 @@
convert_to_params(params, model->wmmat);
model->wmtype = get_gmtype(model);
}
+
+// Adds some offset to a global motion parameter and handles
+// all of the necessary precision shifts, clamping, and
+// zero-centering.
+static int32_t add_param_offset(int param_index, int32_t param_value,
+ int32_t offset) {
+ const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
+ GM_ROW3HOMO_PREC_DIFF };
+ const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
+ // type of param: 0 - translation, 1 - affine, 2 - homography
+ const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
+ const int is_one_centered = (param_index == 2 || param_index == 5);
+
+ // Make parameter zero-centered and offset the shift that was done to make
+ // it compatible with the warped model
+ param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
+ scale_vals[param_type];
+ // Add desired offset to the rescaled/zero-centered parameter
+ param_value += offset;
+ // Clamp the parameter so it does not overflow the number of bits allotted
+ // to it in the bitstream
+ param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
+ clamp_vals[param_type]);
+ // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
+ // with the warped motion library
+ param_value *= (1 << scale_vals[param_type]);
+
+ // Undo the zero-centering step if necessary
+ return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
+}
+
+static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
+ switch (wmtype) {
+ case IDENTITY: wm->wmmat[0] = 0; wm->wmmat[1] = 0;
+ case TRANSLATION:
+ 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 HOMOGRAPHY: break;
+ default: assert(0);
+ }
+ wm->wmtype = wmtype;
+}
+
+static double refine_integerized_param(WarpedMotionParams *wm,
+ TransformationType wmtype,
+#if CONFIG_AOM_HIGHBITDEPTH
+ int use_hbd, int bd,
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ 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) {
+ const int border = ERRORADV_BORDER;
+ int i = 0, p;
+ int n_params = n_trans_model_params[wmtype];
+ int32_t *param_mat = wm->wmmat;
+ double step_error;
+ int32_t step;
+ int32_t *param;
+ int32_t curr_param;
+ int32_t best_param;
+ double best_error;
+
+ force_wmtype(wm, wmtype);
+ best_error = av1_warp_erroradv(wm,
+#if CONFIG_AOM_HIGHBITDEPTH
+ use_hbd, bd,
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ ref, r_width, r_height, r_stride,
+ dst + border * d_stride + border, border,
+ border, d_width - 2 * border,
+ d_height - 2 * border, d_stride, 0, 0, 16, 16);
+ for (p = 0; p < n_params; ++p) {
+ param = param_mat + p;
+ step = 1 << (n_refinements + 1);
+ curr_param = *param;
+ best_param = curr_param;
+ for (i = 0; i < n_refinements; i++) {
+ // look to the left
+ *param = add_param_offset(p, curr_param, -step);
+ step_error = av1_warp_erroradv(
+ wm,
+#if CONFIG_AOM_HIGHBITDEPTH
+ use_hbd, bd,
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ ref, r_width, r_height, r_stride, dst + border * d_stride + border,
+ border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
+ 0, 0, 16, 16);
+ if (step_error < best_error) {
+ step >>= 1;
+ best_error = step_error;
+ best_param = *param;
+ curr_param = best_param;
+ continue;
+ }
+
+ // look to the right
+ *param = add_param_offset(p, curr_param, step);
+ step_error = av1_warp_erroradv(
+ wm,
+#if CONFIG_AOM_HIGHBITDEPTH
+ use_hbd, bd,
+#endif // CONFIG_AOM_HIGHBITDEPTH
+ ref, r_width, r_height, r_stride, dst + border * d_stride + border,
+ border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
+ 0, 0, 16, 16);
+ if (step_error < best_error) {
+ step >>= 1;
+ best_error = step_error;
+ best_param = *param;
+ curr_param = best_param;
+ continue;
+ }
+
+ // no improvement found-> means we're either already at a minimum or
+ // step is too wide
+ step >>= 1;
+ }
+ *param = best_param;
+ }
+ force_wmtype(wm, wmtype);
+ wm->wmtype = get_gmtype(wm);
+ return best_error;
+}
#endif // CONFIG_GLOBAL_MOTION
static void encode_frame_internal(AV1_COMP *cpi) {
@@ -4803,27 +4832,18 @@
params)) {
convert_model_to_params(params, &cm->global_motion[frame]);
if (cm->global_motion[frame].wmtype != IDENTITY) {
- refine_integerized_param(
- &cm->global_motion[frame],
+ erroradvantage = refine_integerized_param(
+ &cm->global_motion[frame], cm->global_motion[frame].wmtype,
#if CONFIG_AOM_HIGHBITDEPTH
xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
#endif // CONFIG_AOM_HIGHBITDEPTH
ref_buf->y_buffer, ref_buf->y_width, ref_buf->y_height,
ref_buf->y_stride, cpi->Source->y_buffer, cpi->Source->y_width,
cpi->Source->y_height, cpi->Source->y_stride, 3);
- // compute the advantage of using gm parameters over 0 motion
- erroradvantage = av1_warp_erroradv(
- &cm->global_motion[frame],
-#if CONFIG_AOM_HIGHBITDEPTH
- xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, xd->bd,
-#endif // CONFIG_AOM_HIGHBITDEPTH
- ref_buf->y_buffer, ref_buf->y_width, ref_buf->y_height,
- ref_buf->y_stride, cpi->Source->y_buffer, 0, 0,
- cpi->Source->y_width, cpi->Source->y_height,
- cpi->Source->y_stride, 0, 0, 16, 16);
- if (erroradvantage > GLOBAL_MOTION_ADVANTAGE_THRESH)
- // Not enough advantage in using a global model. Make identity.
+ if (erroradvantage >
+ gm_advantage_thresh[cm->global_motion[frame].wmtype]) {
set_default_gmparams(&cm->global_motion[frame]);
+ }
}
}
aom_clear_system_state();