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(&params_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