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 www.aomedia.org/license/software. 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 www.aomedia.org/license/patent.
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <memory.h>
15 #include <math.h>
16 #include <assert.h>
17 
18 #include "av1/encoder/global_motion.h"
19 
20 #include "av1/common/warped_motion.h"
21 
22 #include "av1/encoder/segmentation.h"
23 #include "av1/encoder/corner_detect.h"
24 #include "av1/encoder/corner_match.h"
25 #include "av1/encoder/ransac.h"
26 
27 #define MAX_CORNERS 4096
28 #define MIN_INLIER_PROB 0.1
29 
30 #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
31 
32 // Border over which to compute the global motion
33 #define ERRORADV_BORDER 0
34 
35 #define ERRORADV_MAX_THRESH 0.995
36 #define ERRORADV_COST_PRODUCT_THRESH 26000
37 
is_enough_erroradvantage(double best_erroradvantage,int params_cost)38 int is_enough_erroradvantage(double best_erroradvantage, int params_cost) {
39   return best_erroradvantage < ERRORADV_MAX_THRESH &&
40          best_erroradvantage * params_cost < ERRORADV_COST_PRODUCT_THRESH;
41 }
42 
convert_to_params(const double * params,int32_t * model)43 static void convert_to_params(const double *params, int32_t *model) {
44   int i;
45   int alpha_present = 0;
46   model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
47   model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
48   model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
49              GM_TRANS_DECODE_FACTOR;
50   model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
51              GM_TRANS_DECODE_FACTOR;
52 
53   for (i = 2; i < 6; ++i) {
54     const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
55     model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
56     model[i] =
57         (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
58     alpha_present |= (model[i] != 0);
59     model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
60   }
61   for (; i < 8; ++i) {
62     model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
63     model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
64                GM_ROW3HOMO_DECODE_FACTOR;
65     alpha_present |= (model[i] != 0);
66   }
67 
68   if (!alpha_present) {
69     if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
70       model[0] = 0;
71       model[1] = 0;
72     }
73   }
74 }
75 
convert_model_to_params(const double * params,WarpedMotionParams * model)76 void convert_model_to_params(const double *params, WarpedMotionParams *model) {
77   convert_to_params(params, model->wmmat);
78   model->wmtype = get_gmtype(model);
79 }
80 
81 // Adds some offset to a global motion parameter and handles
82 // all of the necessary precision shifts, clamping, and
83 // zero-centering.
add_param_offset(int param_index,int32_t param_value,int32_t offset)84 static int32_t add_param_offset(int param_index, int32_t param_value,
85                                 int32_t offset) {
86   const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
87                               GM_ROW3HOMO_PREC_DIFF };
88   const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
89   // type of param: 0 - translation, 1 - affine, 2 - homography
90   const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
91   const int is_one_centered = (param_index == 2 || param_index == 5);
92 
93   // Make parameter zero-centered and offset the shift that was done to make
94   // it compatible with the warped model
95   param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
96                 scale_vals[param_type];
97   // Add desired offset to the rescaled/zero-centered parameter
98   param_value += offset;
99   // Clamp the parameter so it does not overflow the number of bits allotted
100   // to it in the bitstream
101   param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
102                                clamp_vals[param_type]);
103   // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
104   // with the warped motion library
105   param_value *= (1 << scale_vals[param_type]);
106 
107   // Undo the zero-centering step if necessary
108   return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
109 }
110 
force_wmtype(WarpedMotionParams * wm,TransformationType wmtype)111 static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
112   switch (wmtype) {
113     case IDENTITY: wm->wmmat[0] = 0; wm->wmmat[1] = 0;
114     case TRANSLATION:
115       wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
116       wm->wmmat[3] = 0;
117     case ROTZOOM: wm->wmmat[4] = -wm->wmmat[3]; wm->wmmat[5] = wm->wmmat[2];
118     case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break;
119     case HORTRAPEZOID: wm->wmmat[6] = wm->wmmat[4] = 0; break;
120     case VERTRAPEZOID: wm->wmmat[7] = wm->wmmat[3] = 0; break;
121     case HOMOGRAPHY: break;
122     default: assert(0);
123   }
124   wm->wmtype = wmtype;
125 }
126 
refine_integerized_param(WarpedMotionParams * 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)127 int64_t refine_integerized_param(WarpedMotionParams *wm,
128                                  TransformationType wmtype,
129 #if CONFIG_HIGHBITDEPTH
130                                  int use_hbd, int bd,
131 #endif  // CONFIG_HIGHBITDEPTH
132                                  uint8_t *ref, int r_width, int r_height,
133                                  int r_stride, uint8_t *dst, int d_width,
134                                  int d_height, int d_stride, int n_refinements,
135                                  int64_t best_frame_error) {
136   static const int max_trans_model_params[TRANS_TYPES] = {
137     0, 2, 4, 6, 8, 8, 8
138   };
139   const int border = ERRORADV_BORDER;
140   int i = 0, p;
141   int n_params = max_trans_model_params[wmtype];
142   int32_t *param_mat = wm->wmmat;
143   int64_t step_error, best_error;
144   int32_t step;
145   int32_t *param;
146   int32_t curr_param;
147   int32_t best_param;
148 
149   force_wmtype(wm, wmtype);
150   best_error = av1_warp_error(
151       wm,
152 #if CONFIG_HIGHBITDEPTH
153       use_hbd, bd,
154 #endif  // CONFIG_HIGHBITDEPTH
155       ref, r_width, r_height, r_stride, dst + border * d_stride + border,
156       border, border, d_width - 2 * border, d_height - 2 * border, d_stride, 0,
157       0, SCALE_SUBPEL_SHIFTS, SCALE_SUBPEL_SHIFTS, best_frame_error);
158   best_error = AOMMIN(best_error, best_frame_error);
159   step = 1 << (n_refinements - 1);
160   for (i = 0; i < n_refinements; i++, step >>= 1) {
161     for (p = 0; p < n_params; ++p) {
162       int step_dir = 0;
163       // Skip searches for parameters that are forced to be 0
164       if (wmtype == HORTRAPEZOID && (p == 4 || p == 6)) continue;
165       if (wmtype == VERTRAPEZOID && (p == 3 || p == 7)) continue;
166       param = param_mat + p;
167       curr_param = *param;
168       best_param = curr_param;
169       // look to the left
170       *param = add_param_offset(p, curr_param, -step);
171       step_error = av1_warp_error(
172           wm,
173 #if CONFIG_HIGHBITDEPTH
174           use_hbd, bd,
175 #endif  // CONFIG_HIGHBITDEPTH
176           ref, r_width, r_height, r_stride, dst + border * d_stride + border,
177           border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
178           0, 0, SCALE_SUBPEL_SHIFTS, SCALE_SUBPEL_SHIFTS, best_error);
179       if (step_error < best_error) {
180         best_error = step_error;
181         best_param = *param;
182         step_dir = -1;
183       }
184 
185       // look to the right
186       *param = add_param_offset(p, curr_param, step);
187       step_error = av1_warp_error(
188           wm,
189 #if CONFIG_HIGHBITDEPTH
190           use_hbd, bd,
191 #endif  // CONFIG_HIGHBITDEPTH
192           ref, r_width, r_height, r_stride, dst + border * d_stride + border,
193           border, border, d_width - 2 * border, d_height - 2 * border, d_stride,
194           0, 0, SCALE_SUBPEL_SHIFTS, SCALE_SUBPEL_SHIFTS, best_error);
195       if (step_error < best_error) {
196         best_error = step_error;
197         best_param = *param;
198         step_dir = 1;
199       }
200       *param = best_param;
201 
202       // look to the direction chosen above repeatedly until error increases
203       // for the biggest step size
204       while (step_dir) {
205         *param = add_param_offset(p, best_param, step * step_dir);
206         step_error = av1_warp_error(
207             wm,
208 #if CONFIG_HIGHBITDEPTH
209             use_hbd, bd,
210 #endif  // CONFIG_HIGHBITDEPTH
211             ref, r_width, r_height, r_stride, dst + border * d_stride + border,
212             border, border, d_width - 2 * border, d_height - 2 * border,
213             d_stride, 0, 0, SCALE_SUBPEL_SHIFTS, SCALE_SUBPEL_SHIFTS,
214             best_error);
215         if (step_error < best_error) {
216           best_error = step_error;
217           best_param = *param;
218         } else {
219           *param = best_param;
220           step_dir = 0;
221         }
222       }
223     }
224   }
225   force_wmtype(wm, wmtype);
226   wm->wmtype = get_gmtype(wm);
227   return best_error;
228 }
229 
get_ransac_type(TransformationType type)230 static INLINE RansacFunc get_ransac_type(TransformationType type) {
231   switch (type) {
232     case HOMOGRAPHY: return ransac_homography;
233     case HORTRAPEZOID: return ransac_hortrapezoid;
234     case VERTRAPEZOID: return ransac_vertrapezoid;
235     case AFFINE: return ransac_affine;
236     case ROTZOOM: return ransac_rotzoom;
237     case TRANSLATION: return ransac_translation;
238     default: assert(0); return NULL;
239   }
240 }
241 
242 #if CONFIG_HIGHBITDEPTH
downconvert_frame(YV12_BUFFER_CONFIG * frm,int bit_depth)243 static unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm,
244                                         int bit_depth) {
245   int i, j;
246   uint16_t *orig_buf = CONVERT_TO_SHORTPTR(frm->y_buffer);
247   uint8_t *buf_8bit = frm->y_buffer_8bit;
248   assert(buf_8bit);
249   if (!frm->buf_8bit_valid) {
250     for (i = 0; i < frm->y_height; ++i) {
251       for (j = 0; j < frm->y_width; ++j) {
252         buf_8bit[i * frm->y_stride + j] =
253             orig_buf[i * frm->y_stride + j] >> (bit_depth - 8);
254       }
255     }
256     frm->buf_8bit_valid = 1;
257   }
258   return buf_8bit;
259 }
260 #endif
261 
compute_global_motion_feature_based(TransformationType type,YV12_BUFFER_CONFIG * frm,YV12_BUFFER_CONFIG * ref,int bit_depth,int * num_inliers_by_motion,double * params_by_motion,int num_motions)262 int compute_global_motion_feature_based(
263     TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
264 #if CONFIG_HIGHBITDEPTH
265     int bit_depth,
266 #endif
267     int *num_inliers_by_motion, double *params_by_motion, int num_motions) {
268   int i;
269   int num_frm_corners, num_ref_corners;
270   int num_correspondences;
271   int *correspondences;
272   int frm_corners[2 * MAX_CORNERS], ref_corners[2 * MAX_CORNERS];
273   unsigned char *frm_buffer = frm->y_buffer;
274   unsigned char *ref_buffer = ref->y_buffer;
275   RansacFunc ransac = get_ransac_type(type);
276 
277 #if CONFIG_HIGHBITDEPTH
278   if (frm->flags & YV12_FLAG_HIGHBITDEPTH) {
279     // The frame buffer is 16-bit, so we need to convert to 8 bits for the
280     // following code. We cache the result until the frame is released.
281     frm_buffer = downconvert_frame(frm, bit_depth);
282   }
283   if (ref->flags & YV12_FLAG_HIGHBITDEPTH) {
284     ref_buffer = downconvert_frame(ref, bit_depth);
285   }
286 #endif
287 
288   // compute interest points in images using FAST features
289   num_frm_corners = fast_corner_detect(frm_buffer, frm->y_width, frm->y_height,
290                                        frm->y_stride, frm_corners, MAX_CORNERS);
291   num_ref_corners = fast_corner_detect(ref_buffer, ref->y_width, ref->y_height,
292                                        ref->y_stride, ref_corners, MAX_CORNERS);
293 
294   // find correspondences between the two images
295   correspondences =
296       (int *)malloc(num_frm_corners * 4 * sizeof(*correspondences));
297   num_correspondences = determine_correspondence(
298       frm_buffer, (int *)frm_corners, num_frm_corners, ref_buffer,
299       (int *)ref_corners, num_ref_corners, frm->y_width, frm->y_height,
300       frm->y_stride, ref->y_stride, correspondences);
301 
302   ransac(correspondences, num_correspondences, num_inliers_by_motion,
303          params_by_motion, num_motions);
304 
305   free(correspondences);
306 
307   // Set num_inliers = 0 for motions with too few inliers so they are ignored.
308   for (i = 0; i < num_motions; ++i) {
309     if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences) {
310       num_inliers_by_motion[i] = 0;
311     }
312   }
313 
314   // Return true if any one of the motions has inliers.
315   for (i = 0; i < num_motions; ++i) {
316     if (num_inliers_by_motion[i] > 0) return 1;
317   }
318   return 0;
319 }
320