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 https://www.aomedia.org/license/software-license. 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 https://www.aomedia.org/license/patent-license.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>
15
16 #include "global_motion.h"
17 #include "EbUtility.h"
18 #include "corner_detect.h"
19 #include "corner_match.h"
20 #include "ransac.h"
21
22 #include "EbEncWarpedMotion.h"
23
24 #define MIN_INLIER_PROB 0.1
25
26 #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
27
28 // Border over which to compute the global motion
29 #define ERRORADV_BORDER 0
30
31 static const double erroradv_tr[] = {0.65, 0.60, 0.65};
32 static const double erroradv_prod_tr[] = {20000, 18000, 16000};
33
svt_av1_is_enough_erroradvantage(double best_erroradvantage,int params_cost,int erroradv_type)34 int svt_av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost,
35 int erroradv_type) {
36 assert(erroradv_type < GM_ERRORADV_TR_TYPES);
37 return best_erroradvantage < erroradv_tr[erroradv_type] &&
38 best_erroradvantage * params_cost < erroradv_prod_tr[erroradv_type];
39 }
40
convert_to_params(const double * params,int32_t * model)41 static void convert_to_params(const double *params, int32_t *model) {
42 int i;
43 int alpha_present = 0;
44 model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
45 model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
46 model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) * GM_TRANS_DECODE_FACTOR;
47 model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) * GM_TRANS_DECODE_FACTOR;
48
49 for (i = 2; i < 6; ++i) {
50 const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
51 model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
52 model[i] = (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
53 alpha_present |= (model[i] != 0);
54 model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
55 }
56 for (; i < 8; ++i) {
57 model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
58 model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
59 GM_ROW3HOMO_DECODE_FACTOR;
60 alpha_present |= (model[i] != 0);
61 }
62
63 if (!alpha_present) {
64 if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
65 model[0] = 0;
66 model[1] = 0;
67 }
68 }
69 }
70
get_wmtype(const EbWarpedMotionParams * gm)71 static INLINE TransformationType get_wmtype(const EbWarpedMotionParams *gm) {
72 if (gm->wmmat[5] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[4] &&
73 gm->wmmat[2] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[3]) {
74 return ((!gm->wmmat[1] && !gm->wmmat[0]) ? IDENTITY : TRANSLATION);
75 }
76 if (gm->wmmat[2] == gm->wmmat[5] && gm->wmmat[3] == -gm->wmmat[4])
77 return ROTZOOM;
78 else
79 return AFFINE;
80 }
81
svt_av1_convert_model_to_params(const double * params,EbWarpedMotionParams * model)82 void svt_av1_convert_model_to_params(const double *params, EbWarpedMotionParams *model) {
83 convert_to_params(params, model->wmmat);
84 model->wmtype = get_wmtype(model);
85 model->invalid = 0;
86 }
87
88 // Adds some offset to a global motion parameter and handles
89 // all of the necessary precision shifts, clamping, and
90 // zero-centering.
add_param_offset(int param_index,int32_t param_value,int32_t offset)91 static int32_t add_param_offset(int param_index, int32_t param_value, int32_t offset) {
92 const int scale_vals[3] = {GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF, GM_ROW3HOMO_PREC_DIFF};
93 const int clamp_vals[3] = {GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX};
94 // type of param: 0 - translation, 1 - affine, 2 - homography
95 const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
96 const int is_one_centered = (param_index == 2 || param_index == 5);
97
98 // Make parameter zero-centered and offset the shift that was done to make
99 // it compatible with the warped model
100 param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
101 scale_vals[param_type];
102 // Add desired offset to the rescaled/zero-centered parameter
103 param_value += offset;
104 // Clamp the parameter so it does not overflow the number of bits allotted
105 // to it in the Bitstream
106 param_value = (int32_t)clamp(param_value, -clamp_vals[param_type], clamp_vals[param_type]);
107 // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
108 // with the warped motion library
109 param_value *= (1 << scale_vals[param_type]);
110
111 // Undo the zero-centering step if necessary
112 return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
113 }
114
force_wmtype(EbWarpedMotionParams * wm,TransformationType wmtype)115 static void force_wmtype(EbWarpedMotionParams *wm, TransformationType wmtype) {
116 switch (wmtype) {
117 case IDENTITY:
118 wm->wmmat[0] = 0;
119 wm->wmmat[1] = 0;
120 AOM_FALLTHROUGH_INTENDED;
121 case TRANSLATION:
122 wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
123 wm->wmmat[3] = 0;
124 AOM_FALLTHROUGH_INTENDED;
125 case ROTZOOM:
126 wm->wmmat[4] = -wm->wmmat[3];
127 wm->wmmat[5] = wm->wmmat[2];
128 AOM_FALLTHROUGH_INTENDED;
129 case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break;
130 default: assert(0);
131 }
132 wm->wmtype = wmtype;
133 }
134
svt_av1_refine_integerized_param(EbWarpedMotionParams * wm,TransformationType wmtype,int use_hbd,int bd,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,int64_t best_frame_error)135 int64_t svt_av1_refine_integerized_param(EbWarpedMotionParams *wm, TransformationType wmtype,
136 int use_hbd, int bd, uint8_t *ref, int r_width,
137 int r_height, int r_stride, uint8_t *dst, int d_width,
138 int d_height, int d_stride, int n_refinements,
139 int64_t best_frame_error) {
140 static const int max_trans_model_params[TRANS_TYPES] = {0, 2, 4, 6};
141 const int border = ERRORADV_BORDER;
142 int i = 0, p;
143 int n_params = max_trans_model_params[wmtype];
144 int32_t * param_mat = wm->wmmat;
145 int64_t step_error, best_error;
146 int32_t step;
147 int32_t * param;
148 int32_t curr_param;
149 int32_t best_param;
150
151 force_wmtype(wm, wmtype);
152 best_error = svt_av1_warp_error(wm,
153 use_hbd,
154 bd,
155 ref,
156 r_width,
157 r_height,
158 r_stride,
159 dst + border * d_stride + border,
160 border,
161 border,
162 d_width - 2 * border,
163 d_height - 2 * border,
164 d_stride,
165 0,
166 0,
167 best_frame_error);
168 best_error = AOMMIN(best_error, best_frame_error);
169 step = 1 << (n_refinements - 1);
170 for (i = 0; i < n_refinements; i++, step >>= 1) {
171 for (p = 0; p < n_params; ++p) {
172 int step_dir = 0;
173 // Skip searches for parameters that are forced to be 0
174 param = param_mat + p;
175 curr_param = *param;
176 best_param = curr_param;
177 // look to the left
178 *param = add_param_offset(p, curr_param, -step);
179 step_error = svt_av1_warp_error(wm,
180 use_hbd,
181 bd,
182 ref,
183 r_width,
184 r_height,
185 r_stride,
186 dst + border * d_stride + border,
187 border,
188 border,
189 d_width - 2 * border,
190 d_height - 2 * border,
191 d_stride,
192 0,
193 0,
194 best_error);
195 if (step_error < best_error) {
196 best_error = step_error;
197 best_param = *param;
198 step_dir = -1;
199 }
200
201 // look to the right
202 *param = add_param_offset(p, curr_param, step);
203 step_error = svt_av1_warp_error(wm,
204 use_hbd,
205 bd,
206 ref,
207 r_width,
208 r_height,
209 r_stride,
210 dst + border * d_stride + border,
211 border,
212 border,
213 d_width - 2 * border,
214 d_height - 2 * border,
215 d_stride,
216 0,
217 0,
218 best_error);
219 if (step_error < best_error) {
220 best_error = step_error;
221 best_param = *param;
222 step_dir = 1;
223 }
224 *param = best_param;
225
226 // look to the direction chosen above repeatedly until error increases
227 // for the biggest step size
228 while (step_dir) {
229 *param = add_param_offset(p, best_param, step * step_dir);
230 step_error = svt_av1_warp_error(wm,
231 use_hbd,
232 bd,
233 ref,
234 r_width,
235 r_height,
236 r_stride,
237 dst + border * d_stride + border,
238 border,
239 border,
240 d_width - 2 * border,
241 d_height - 2 * border,
242 d_stride,
243 0,
244 0,
245 best_error);
246 if (step_error < best_error) {
247 best_error = step_error;
248 best_param = *param;
249 } else {
250 *param = best_param;
251 step_dir = 0;
252 }
253 }
254 }
255 }
256 force_wmtype(wm, wmtype);
257 wm->wmtype = get_wmtype(wm);
258 return best_error;
259 }
260
get_inliers_from_indices(MotionModel * params,int * correspondences)261 static void get_inliers_from_indices(MotionModel *params, int *correspondences) {
262 int *inliers_tmp = (int *)svt_aom_malloc(2 * MAX_CORNERS * sizeof(*inliers_tmp));
263 memset(inliers_tmp, 0, 2 * MAX_CORNERS * sizeof(*inliers_tmp));
264
265 for (int i = 0; i < params->num_inliers; i++) {
266 int index = params->inliers[i];
267 inliers_tmp[2 * i] = correspondences[4 * index];
268 inliers_tmp[2 * i + 1] = correspondences[4 * index + 1];
269 }
270 svt_memcpy(params->inliers, inliers_tmp, sizeof(*inliers_tmp) * 2 * MAX_CORNERS);
271 svt_aom_free(inliers_tmp);
272 }
273
compute_global_motion_feature_based(TransformationType type,unsigned char * frm_buffer,int frm_width,int frm_height,int frm_stride,int * frm_corners,int num_frm_corners,uint8_t * ref,int ref_stride,int bit_depth,int * num_inliers_by_motion,MotionModel * params_by_motion,int num_motions)274 static int compute_global_motion_feature_based(TransformationType type, unsigned char *frm_buffer,
275 int frm_width, int frm_height, int frm_stride,
276 int *frm_corners, int num_frm_corners, uint8_t *ref,
277 int ref_stride, int bit_depth,
278 int * num_inliers_by_motion,
279 MotionModel *params_by_motion, int num_motions) {
280 (void)bit_depth;
281 assert(bit_depth == EB_8BIT);
282 int i;
283 int num_ref_corners;
284 int num_correspondences;
285 int * correspondences;
286 int ref_corners[2 * MAX_CORNERS];
287 unsigned char *ref_buffer = ref;
288 RansacFunc ransac = svt_av1_get_ransac_type(type);
289
290 num_ref_corners = svt_av1_fast_corner_detect(
291 ref_buffer, frm_width, frm_height, ref_stride, ref_corners, MAX_CORNERS);
292
293 // find correspondences between the two images
294 correspondences = (int *)malloc(num_frm_corners * 4 * sizeof(*correspondences));
295 num_correspondences = svt_av1_determine_correspondence(frm_buffer,
296 (int *)frm_corners,
297 num_frm_corners,
298 ref_buffer,
299 (int *)ref_corners,
300 num_ref_corners,
301 frm_width,
302 frm_height,
303 frm_stride,
304 ref_stride,
305 correspondences);
306
307 ransac(
308 correspondences, num_correspondences, num_inliers_by_motion, params_by_motion, num_motions);
309
310 // Set num_inliers = 0 for motions with too few inliers so they are ignored.
311 for (i = 0; i < num_motions; ++i) {
312 if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences ||
313 num_correspondences == 0) {
314 num_inliers_by_motion[i] = 0;
315 } else {
316 get_inliers_from_indices(¶ms_by_motion[i], correspondences);
317 }
318 }
319
320 free(correspondences);
321
322 // Return true if any one of the motions has inliers.
323 for (i = 0; i < num_motions; ++i) {
324 if (num_inliers_by_motion[i] > 0)
325 return 1;
326 }
327 return 0;
328 }
329
svt_av1_compute_global_motion(TransformationType type,unsigned char * frm_buffer,int frm_width,int frm_height,int frm_stride,int * frm_corners,int num_frm_corners,uint8_t * ref,int ref_stride,int bit_depth,GlobalMotionEstimationType gm_estimation_type,int * num_inliers_by_motion,MotionModel * params_by_motion,int num_motions)330 int svt_av1_compute_global_motion(TransformationType type, unsigned char *frm_buffer, int frm_width,
331 int frm_height, int frm_stride, int *frm_corners,
332 int num_frm_corners, uint8_t *ref, int ref_stride, int bit_depth,
333 GlobalMotionEstimationType gm_estimation_type,
334 int *num_inliers_by_motion, MotionModel *params_by_motion,
335 int num_motions) {
336 switch (gm_estimation_type) {
337 case GLOBAL_MOTION_FEATURE_BASED:
338 return compute_global_motion_feature_based(type,
339 frm_buffer,
340 frm_width,
341 frm_height,
342 frm_stride,
343 frm_corners,
344 num_frm_corners,
345 ref,
346 ref_stride,
347 bit_depth,
348 num_inliers_by_motion,
349 params_by_motion,
350 num_motions);
351 default: assert(0 && "Unknown global motion estimation type");
352 }
353 return 0;
354 }
355