• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config/aom_dsp_rtcd.h"
19 
20 #include "av1/encoder/global_motion.h"
21 
22 #include "av1/common/convolve.h"
23 #include "av1/common/resize.h"
24 #include "av1/common/warped_motion.h"
25 
26 #include "av1/encoder/segmentation.h"
27 #include "av1/encoder/corner_detect.h"
28 #include "av1/encoder/corner_match.h"
29 #include "av1/encoder/ransac.h"
30 
31 #define MIN_INLIER_PROB 0.1
32 
33 #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
34 
35 // Border over which to compute the global motion
36 #define ERRORADV_BORDER 0
37 
38 // Number of pyramid levels in disflow computation
39 #define N_LEVELS 2
40 // Size of square patches in the disflow dense grid
41 #define PATCH_SIZE 8
42 // Center point of square patch
43 #define PATCH_CENTER ((PATCH_SIZE + 1) >> 1)
44 // Step size between patches, lower value means greater patch overlap
45 #define PATCH_STEP 1
46 // Minimum size of border padding for disflow
47 #define MIN_PAD 7
48 // Warp error convergence threshold for disflow
49 #define DISFLOW_ERROR_TR 0.01
50 // Max number of iterations if warp convergence is not found
51 #define DISFLOW_MAX_ITR 10
52 
53 // Struct for an image pyramid
54 typedef struct {
55   int n_levels;
56   int pad_size;
57   int has_gradient;
58   int widths[N_LEVELS];
59   int heights[N_LEVELS];
60   int strides[N_LEVELS];
61   int level_loc[N_LEVELS];
62   unsigned char *level_buffer;
63   double *level_dx_buffer;
64   double *level_dy_buffer;
65 } ImagePyramid;
66 
av1_is_enough_erroradvantage(double best_erroradvantage,int params_cost,int erroradv_type)67 int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost,
68                                  int erroradv_type) {
69   assert(erroradv_type < GM_ERRORADV_TR_TYPES);
70   return best_erroradvantage < erroradv_tr[erroradv_type] &&
71          best_erroradvantage * params_cost < erroradv_prod_tr[erroradv_type];
72 }
73 
convert_to_params(const double * params,int32_t * model)74 static void convert_to_params(const double *params, int32_t *model) {
75   int i;
76   int alpha_present = 0;
77   model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
78   model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
79   model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
80              GM_TRANS_DECODE_FACTOR;
81   model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
82              GM_TRANS_DECODE_FACTOR;
83 
84   for (i = 2; i < 6; ++i) {
85     const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
86     model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
87     model[i] =
88         (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
89     alpha_present |= (model[i] != 0);
90     model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
91   }
92   for (; i < 8; ++i) {
93     model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
94     model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
95                GM_ROW3HOMO_DECODE_FACTOR;
96     alpha_present |= (model[i] != 0);
97   }
98 
99   if (!alpha_present) {
100     if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
101       model[0] = 0;
102       model[1] = 0;
103     }
104   }
105 }
106 
av1_convert_model_to_params(const double * params,WarpedMotionParams * model)107 void av1_convert_model_to_params(const double *params,
108                                  WarpedMotionParams *model) {
109   convert_to_params(params, model->wmmat);
110   model->wmtype = get_wmtype(model);
111   model->invalid = 0;
112 }
113 
114 // Adds some offset to a global motion parameter and handles
115 // all of the necessary precision shifts, clamping, and
116 // zero-centering.
add_param_offset(int param_index,int32_t param_value,int32_t offset)117 static int32_t add_param_offset(int param_index, int32_t param_value,
118                                 int32_t offset) {
119   const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
120                               GM_ROW3HOMO_PREC_DIFF };
121   const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
122   // type of param: 0 - translation, 1 - affine, 2 - homography
123   const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
124   const int is_one_centered = (param_index == 2 || param_index == 5);
125 
126   // Make parameter zero-centered and offset the shift that was done to make
127   // it compatible with the warped model
128   param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
129                 scale_vals[param_type];
130   // Add desired offset to the rescaled/zero-centered parameter
131   param_value += offset;
132   // Clamp the parameter so it does not overflow the number of bits allotted
133   // to it in the bitstream
134   param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
135                                clamp_vals[param_type]);
136   // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
137   // with the warped motion library
138   param_value *= (1 << scale_vals[param_type]);
139 
140   // Undo the zero-centering step if necessary
141   return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
142 }
143 
force_wmtype(WarpedMotionParams * wm,TransformationType wmtype)144 static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
145   switch (wmtype) {
146     case IDENTITY:
147       wm->wmmat[0] = 0;
148       wm->wmmat[1] = 0;
149       AOM_FALLTHROUGH_INTENDED;
150     case TRANSLATION:
151       wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
152       wm->wmmat[3] = 0;
153       AOM_FALLTHROUGH_INTENDED;
154     case ROTZOOM:
155       wm->wmmat[4] = -wm->wmmat[3];
156       wm->wmmat[5] = wm->wmmat[2];
157       AOM_FALLTHROUGH_INTENDED;
158     case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break;
159     default: assert(0);
160   }
161   wm->wmtype = wmtype;
162 }
163 
164 #if CONFIG_AV1_HIGHBITDEPTH
highbd_warp_error(WarpedMotionParams * wm,const uint16_t * const ref,int width,int height,int stride,const uint16_t * const dst,int p_col,int p_row,int p_width,int p_height,int p_stride,int subsampling_x,int subsampling_y,int bd,int64_t best_error,uint8_t * segment_map,int segment_map_stride)165 static int64_t highbd_warp_error(
166     WarpedMotionParams *wm, const uint16_t *const ref, int width, int height,
167     int stride, const uint16_t *const dst, int p_col, int p_row, int p_width,
168     int p_height, int p_stride, int subsampling_x, int subsampling_y, int bd,
169     int64_t best_error, uint8_t *segment_map, int segment_map_stride) {
170   int64_t gm_sumerr = 0;
171   const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
172   const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
173   uint16_t tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK];
174 
175   ConvolveParams conv_params = get_conv_params(0, 0, bd);
176   conv_params.use_dist_wtd_comp_avg = 0;
177   for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
178     for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
179       int seg_x = j >> WARP_ERROR_BLOCK_LOG;
180       int seg_y = i >> WARP_ERROR_BLOCK_LOG;
181       // Only compute the error if this block contains inliers from the motion
182       // model
183       if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
184       // avoid warping extra 8x8 blocks in the padded region of the frame
185       // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
186       const int warp_w = AOMMIN(error_bsize_w, p_col + p_width - j);
187       const int warp_h = AOMMIN(error_bsize_h, p_row + p_height - i);
188       highbd_warp_plane(wm, ref, width, height, stride, tmp, j, i, warp_w,
189                         warp_h, WARP_ERROR_BLOCK, subsampling_x, subsampling_y,
190                         bd, &conv_params);
191       gm_sumerr += av1_calc_highbd_frame_error(tmp, WARP_ERROR_BLOCK,
192                                                dst + j + i * p_stride, warp_w,
193                                                warp_h, p_stride, bd);
194       if (gm_sumerr > best_error) return INT64_MAX;
195     }
196   }
197   return gm_sumerr;
198 }
199 #endif
200 
warp_error(WarpedMotionParams * wm,const uint8_t * const ref,int width,int height,int stride,const uint8_t * const dst,int p_col,int p_row,int p_width,int p_height,int p_stride,int subsampling_x,int subsampling_y,int64_t best_error,uint8_t * segment_map,int segment_map_stride)201 static int64_t warp_error(WarpedMotionParams *wm, const uint8_t *const ref,
202                           int width, int height, int stride,
203                           const uint8_t *const dst, int p_col, int p_row,
204                           int p_width, int p_height, int p_stride,
205                           int subsampling_x, int subsampling_y,
206                           int64_t best_error, uint8_t *segment_map,
207                           int segment_map_stride) {
208   int64_t gm_sumerr = 0;
209   int warp_w, warp_h;
210   const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
211   const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
212   DECLARE_ALIGNED(16, uint8_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
213   ConvolveParams conv_params = get_conv_params(0, 0, 8);
214   conv_params.use_dist_wtd_comp_avg = 0;
215 
216   for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
217     for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
218       int seg_x = j >> WARP_ERROR_BLOCK_LOG;
219       int seg_y = i >> WARP_ERROR_BLOCK_LOG;
220       // Only compute the error if this block contains inliers from the motion
221       // model
222       if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
223       // avoid warping extra 8x8 blocks in the padded region of the frame
224       // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
225       warp_w = AOMMIN(error_bsize_w, p_col + p_width - j);
226       warp_h = AOMMIN(error_bsize_h, p_row + p_height - i);
227       warp_plane(wm, ref, width, height, stride, tmp, j, i, warp_w, warp_h,
228                  WARP_ERROR_BLOCK, subsampling_x, subsampling_y, &conv_params);
229 
230       gm_sumerr +=
231           av1_calc_frame_error(tmp, WARP_ERROR_BLOCK, dst + j + i * p_stride,
232                                warp_w, warp_h, p_stride);
233       if (gm_sumerr > best_error) return INT64_MAX;
234     }
235   }
236   return gm_sumerr;
237 }
238 
av1_warp_error(WarpedMotionParams * wm,int use_hbd,int bd,const uint8_t * ref,int width,int height,int stride,uint8_t * dst,int p_col,int p_row,int p_width,int p_height,int p_stride,int subsampling_x,int subsampling_y,int64_t best_error,uint8_t * segment_map,int segment_map_stride)239 int64_t av1_warp_error(WarpedMotionParams *wm, int use_hbd, int bd,
240                        const uint8_t *ref, int width, int height, int stride,
241                        uint8_t *dst, int p_col, int p_row, int p_width,
242                        int p_height, int p_stride, int subsampling_x,
243                        int subsampling_y, int64_t best_error,
244                        uint8_t *segment_map, int segment_map_stride) {
245   if (wm->wmtype <= AFFINE)
246     if (!av1_get_shear_params(wm)) return INT64_MAX;
247 #if CONFIG_AV1_HIGHBITDEPTH
248   if (use_hbd)
249     return highbd_warp_error(wm, CONVERT_TO_SHORTPTR(ref), width, height,
250                              stride, CONVERT_TO_SHORTPTR(dst), p_col, p_row,
251                              p_width, p_height, p_stride, subsampling_x,
252                              subsampling_y, bd, best_error, segment_map,
253                              segment_map_stride);
254 #endif
255   (void)use_hbd;
256   (void)bd;
257   return warp_error(wm, ref, width, height, stride, dst, p_col, p_row, p_width,
258                     p_height, p_stride, subsampling_x, subsampling_y,
259                     best_error, segment_map, segment_map_stride);
260 }
261 
262 // Factors used to calculate the thresholds for av1_warp_error
263 static double thresh_factors[GM_REFINEMENT_COUNT] = { 1.25, 1.20, 1.15, 1.10,
264                                                       1.05 };
265 
calc_approx_erroradv_threshold(double scaling_factor,int64_t erroradv_threshold)266 static INLINE int64_t calc_approx_erroradv_threshold(
267     double scaling_factor, int64_t erroradv_threshold) {
268   return erroradv_threshold <
269                  (int64_t)(((double)INT64_MAX / scaling_factor) + 0.5)
270              ? (int64_t)(scaling_factor * erroradv_threshold + 0.5)
271              : INT64_MAX;
272 }
273 
av1_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,uint8_t * segment_map,int segment_map_stride,int64_t erroradv_threshold)274 int64_t av1_refine_integerized_param(
275     WarpedMotionParams *wm, TransformationType wmtype, int use_hbd, int bd,
276     uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst,
277     int d_width, int d_height, int d_stride, int n_refinements,
278     int64_t best_frame_error, uint8_t *segment_map, int segment_map_stride,
279     int64_t erroradv_threshold) {
280   static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
281   const int border = ERRORADV_BORDER;
282   int i = 0, p;
283   int n_params = max_trans_model_params[wmtype];
284   int32_t *param_mat = wm->wmmat;
285   int64_t step_error, best_error;
286   int32_t step;
287   int32_t *param;
288   int32_t curr_param;
289   int32_t best_param;
290 
291   force_wmtype(wm, wmtype);
292   best_error =
293       av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
294                      dst + border * d_stride + border, border, border,
295                      d_width - 2 * border, d_height - 2 * border, d_stride, 0,
296                      0, best_frame_error, segment_map, segment_map_stride);
297   best_error = AOMMIN(best_error, best_frame_error);
298   step = 1 << (n_refinements - 1);
299   for (i = 0; i < n_refinements; i++, step >>= 1) {
300     int64_t error_adv_thresh =
301         calc_approx_erroradv_threshold(thresh_factors[i], erroradv_threshold);
302     for (p = 0; p < n_params; ++p) {
303       int step_dir = 0;
304       // Skip searches for parameters that are forced to be 0
305       param = param_mat + p;
306       curr_param = *param;
307       best_param = curr_param;
308       // look to the left
309       *param = add_param_offset(p, curr_param, -step);
310       step_error =
311           av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
312                          dst + border * d_stride + border, border, border,
313                          d_width - 2 * border, d_height - 2 * border, d_stride,
314                          0, 0, AOMMIN(best_error, error_adv_thresh),
315                          segment_map, segment_map_stride);
316       if (step_error < best_error) {
317         best_error = step_error;
318         best_param = *param;
319         step_dir = -1;
320       }
321 
322       // look to the right
323       *param = add_param_offset(p, curr_param, step);
324       step_error =
325           av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
326                          dst + border * d_stride + border, border, border,
327                          d_width - 2 * border, d_height - 2 * border, d_stride,
328                          0, 0, AOMMIN(best_error, error_adv_thresh),
329                          segment_map, segment_map_stride);
330       if (step_error < best_error) {
331         best_error = step_error;
332         best_param = *param;
333         step_dir = 1;
334       }
335       *param = best_param;
336 
337       // look to the direction chosen above repeatedly until error increases
338       // for the biggest step size
339       while (step_dir) {
340         *param = add_param_offset(p, best_param, step * step_dir);
341         step_error =
342             av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
343                            dst + border * d_stride + border, border, border,
344                            d_width - 2 * border, d_height - 2 * border,
345                            d_stride, 0, 0, AOMMIN(best_error, error_adv_thresh),
346                            segment_map, segment_map_stride);
347         if (step_error < best_error) {
348           best_error = step_error;
349           best_param = *param;
350         } else {
351           *param = best_param;
352           step_dir = 0;
353         }
354       }
355     }
356   }
357   force_wmtype(wm, wmtype);
358   wm->wmtype = get_wmtype(wm);
359   return best_error;
360 }
361 
av1_downconvert_frame(YV12_BUFFER_CONFIG * frm,int bit_depth)362 unsigned char *av1_downconvert_frame(YV12_BUFFER_CONFIG *frm, int bit_depth) {
363   int i, j;
364   uint16_t *orig_buf = CONVERT_TO_SHORTPTR(frm->y_buffer);
365   uint8_t *buf_8bit = frm->y_buffer_8bit;
366   assert(buf_8bit);
367   if (!frm->buf_8bit_valid) {
368     for (i = 0; i < frm->y_height; ++i) {
369       for (j = 0; j < frm->y_width; ++j) {
370         buf_8bit[i * frm->y_stride + j] =
371             orig_buf[i * frm->y_stride + j] >> (bit_depth - 8);
372       }
373     }
374     frm->buf_8bit_valid = 1;
375   }
376   return buf_8bit;
377 }
378 
get_inliers_from_indices(MotionModel * params,int * correspondences)379 static void get_inliers_from_indices(MotionModel *params,
380                                      int *correspondences) {
381   int *inliers_tmp = (int *)aom_malloc(2 * MAX_CORNERS * sizeof(*inliers_tmp));
382   memset(inliers_tmp, 0, 2 * MAX_CORNERS * sizeof(*inliers_tmp));
383 
384   for (int i = 0; i < params->num_inliers; i++) {
385     int index = params->inliers[i];
386     inliers_tmp[2 * i] = correspondences[4 * index];
387     inliers_tmp[2 * i + 1] = correspondences[4 * index + 1];
388   }
389   memcpy(params->inliers, inliers_tmp, sizeof(*inliers_tmp) * 2 * MAX_CORNERS);
390   aom_free(inliers_tmp);
391 }
392 
393 #define FEAT_COUNT_TR 3
394 #define SEG_COUNT_TR 0.40
av1_compute_feature_segmentation_map(uint8_t * segment_map,int width,int height,int * inliers,int num_inliers)395 void av1_compute_feature_segmentation_map(uint8_t *segment_map, int width,
396                                           int height, int *inliers,
397                                           int num_inliers) {
398   int seg_count = 0;
399   memset(segment_map, 0, sizeof(*segment_map) * width * height);
400 
401   for (int i = 0; i < num_inliers; i++) {
402     int x = inliers[i * 2];
403     int y = inliers[i * 2 + 1];
404     int seg_x = x >> WARP_ERROR_BLOCK_LOG;
405     int seg_y = y >> WARP_ERROR_BLOCK_LOG;
406     segment_map[seg_y * width + seg_x] += 1;
407   }
408 
409   for (int i = 0; i < height; i++) {
410     for (int j = 0; j < width; j++) {
411       uint8_t feat_count = segment_map[i * width + j];
412       segment_map[i * width + j] = (feat_count >= FEAT_COUNT_TR);
413       seg_count += (segment_map[i * width + j]);
414     }
415   }
416 
417   // If this motion does not make up a large enough portion of the frame,
418   // use the unsegmented version of the error metric
419   if (seg_count < (width * height * SEG_COUNT_TR))
420     memset(segment_map, 1, width * height * sizeof(*segment_map));
421 }
422 
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,YV12_BUFFER_CONFIG * ref,int bit_depth,int * num_inliers_by_motion,MotionModel * params_by_motion,int num_motions)423 static int compute_global_motion_feature_based(
424     TransformationType type, unsigned char *frm_buffer, int frm_width,
425     int frm_height, int frm_stride, int *frm_corners, int num_frm_corners,
426     YV12_BUFFER_CONFIG *ref, int bit_depth, int *num_inliers_by_motion,
427     MotionModel *params_by_motion, int num_motions) {
428   int i;
429   int num_ref_corners;
430   int num_correspondences;
431   int *correspondences;
432   int ref_corners[2 * MAX_CORNERS];
433   unsigned char *ref_buffer = ref->y_buffer;
434   RansacFunc ransac = av1_get_ransac_type(type);
435 
436   if (ref->flags & YV12_FLAG_HIGHBITDEPTH) {
437     ref_buffer = av1_downconvert_frame(ref, bit_depth);
438   }
439 
440   num_ref_corners =
441       av1_fast_corner_detect(ref_buffer, ref->y_width, ref->y_height,
442                              ref->y_stride, ref_corners, MAX_CORNERS);
443 
444   // find correspondences between the two images
445   correspondences =
446       (int *)malloc(num_frm_corners * 4 * sizeof(*correspondences));
447   num_correspondences = av1_determine_correspondence(
448       frm_buffer, (int *)frm_corners, num_frm_corners, ref_buffer,
449       (int *)ref_corners, num_ref_corners, frm_width, frm_height, frm_stride,
450       ref->y_stride, correspondences);
451 
452   ransac(correspondences, num_correspondences, num_inliers_by_motion,
453          params_by_motion, num_motions);
454 
455   // Set num_inliers = 0 for motions with too few inliers so they are ignored.
456   for (i = 0; i < num_motions; ++i) {
457     if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences ||
458         num_correspondences == 0) {
459       num_inliers_by_motion[i] = 0;
460     } else {
461       get_inliers_from_indices(&params_by_motion[i], correspondences);
462     }
463   }
464 
465   free(correspondences);
466 
467   // Return true if any one of the motions has inliers.
468   for (i = 0; i < num_motions; ++i) {
469     if (num_inliers_by_motion[i] > 0) return 1;
470   }
471   return 0;
472 }
473 
474 // Don't use points around the frame border since they are less reliable
valid_point(int x,int y,int width,int height)475 static INLINE int valid_point(int x, int y, int width, int height) {
476   return (x > (PATCH_SIZE + PATCH_CENTER)) &&
477          (x < (width - PATCH_SIZE - PATCH_CENTER)) &&
478          (y > (PATCH_SIZE + PATCH_CENTER)) &&
479          (y < (height - PATCH_SIZE - PATCH_CENTER));
480 }
481 
determine_disflow_correspondence(int * frm_corners,int num_frm_corners,double * flow_u,double * flow_v,int width,int height,int stride,double * correspondences)482 static int determine_disflow_correspondence(int *frm_corners,
483                                             int num_frm_corners, double *flow_u,
484                                             double *flow_v, int width,
485                                             int height, int stride,
486                                             double *correspondences) {
487   int num_correspondences = 0;
488   int x, y;
489   for (int i = 0; i < num_frm_corners; ++i) {
490     x = frm_corners[2 * i];
491     y = frm_corners[2 * i + 1];
492     if (valid_point(x, y, width, height)) {
493       correspondences[4 * num_correspondences] = x;
494       correspondences[4 * num_correspondences + 1] = y;
495       correspondences[4 * num_correspondences + 2] = x + flow_u[y * stride + x];
496       correspondences[4 * num_correspondences + 3] = y + flow_v[y * stride + x];
497       num_correspondences++;
498     }
499   }
500   return num_correspondences;
501 }
502 
getCubicValue(double p[4],double x)503 static double getCubicValue(double p[4], double x) {
504   return p[1] + 0.5 * x *
505                     (p[2] - p[0] +
506                      x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3] +
507                           x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
508 }
509 
get_subcolumn(unsigned char * ref,double col[4],int stride,int x,int y_start)510 static void get_subcolumn(unsigned char *ref, double col[4], int stride, int x,
511                           int y_start) {
512   int i;
513   for (i = 0; i < 4; ++i) {
514     col[i] = ref[(i + y_start) * stride + x];
515   }
516 }
517 
bicubic(unsigned char * ref,double x,double y,int stride)518 static double bicubic(unsigned char *ref, double x, double y, int stride) {
519   double arr[4];
520   int k;
521   int i = (int)x;
522   int j = (int)y;
523   for (k = 0; k < 4; ++k) {
524     double arr_temp[4];
525     get_subcolumn(ref, arr_temp, stride, i + k - 1, j - 1);
526     arr[k] = getCubicValue(arr_temp, y - j);
527   }
528   return getCubicValue(arr, x - i);
529 }
530 
531 // Interpolate a warped block using bicubic interpolation when possible
interpolate(unsigned char * ref,double x,double y,int width,int height,int stride)532 static unsigned char interpolate(unsigned char *ref, double x, double y,
533                                  int width, int height, int stride) {
534   if (x < 0 && y < 0)
535     return ref[0];
536   else if (x < 0 && y > height - 1)
537     return ref[(height - 1) * stride];
538   else if (x > width - 1 && y < 0)
539     return ref[width - 1];
540   else if (x > width - 1 && y > height - 1)
541     return ref[(height - 1) * stride + (width - 1)];
542   else if (x < 0) {
543     int v;
544     int i = (int)y;
545     double a = y - i;
546     if (y > 1 && y < height - 2) {
547       double arr[4];
548       get_subcolumn(ref, arr, stride, 0, i - 1);
549       return clamp((int)(getCubicValue(arr, a) + 0.5), 0, 255);
550     }
551     v = (int)(ref[i * stride] * (1 - a) + ref[(i + 1) * stride] * a + 0.5);
552     return clamp(v, 0, 255);
553   } else if (y < 0) {
554     int v;
555     int j = (int)x;
556     double b = x - j;
557     if (x > 1 && x < width - 2) {
558       double arr[4] = { ref[j - 1], ref[j], ref[j + 1], ref[j + 2] };
559       return clamp((int)(getCubicValue(arr, b) + 0.5), 0, 255);
560     }
561     v = (int)(ref[j] * (1 - b) + ref[j + 1] * b + 0.5);
562     return clamp(v, 0, 255);
563   } else if (x > width - 1) {
564     int v;
565     int i = (int)y;
566     double a = y - i;
567     if (y > 1 && y < height - 2) {
568       double arr[4];
569       get_subcolumn(ref, arr, stride, width - 1, i - 1);
570       return clamp((int)(getCubicValue(arr, a) + 0.5), 0, 255);
571     }
572     v = (int)(ref[i * stride + width - 1] * (1 - a) +
573               ref[(i + 1) * stride + width - 1] * a + 0.5);
574     return clamp(v, 0, 255);
575   } else if (y > height - 1) {
576     int v;
577     int j = (int)x;
578     double b = x - j;
579     if (x > 1 && x < width - 2) {
580       int row = (height - 1) * stride;
581       double arr[4] = { ref[row + j - 1], ref[row + j], ref[row + j + 1],
582                         ref[row + j + 2] };
583       return clamp((int)(getCubicValue(arr, b) + 0.5), 0, 255);
584     }
585     v = (int)(ref[(height - 1) * stride + j] * (1 - b) +
586               ref[(height - 1) * stride + j + 1] * b + 0.5);
587     return clamp(v, 0, 255);
588   } else if (x > 1 && y > 1 && x < width - 2 && y < height - 2) {
589     return clamp((int)(bicubic(ref, x, y, stride) + 0.5), 0, 255);
590   } else {
591     int i = (int)y;
592     int j = (int)x;
593     double a = y - i;
594     double b = x - j;
595     int v = (int)(ref[i * stride + j] * (1 - a) * (1 - b) +
596                   ref[i * stride + j + 1] * (1 - a) * b +
597                   ref[(i + 1) * stride + j] * a * (1 - b) +
598                   ref[(i + 1) * stride + j + 1] * a * b);
599     return clamp(v, 0, 255);
600   }
601 }
602 
603 // Warps a block using flow vector [u, v] and computes the mse
compute_warp_and_error(unsigned char * ref,unsigned char * frm,int width,int height,int stride,int x,int y,double u,double v,int16_t * dt)604 static double compute_warp_and_error(unsigned char *ref, unsigned char *frm,
605                                      int width, int height, int stride, int x,
606                                      int y, double u, double v, int16_t *dt) {
607   int i, j;
608   unsigned char warped;
609   double x_w, y_w;
610   double mse = 0;
611   int16_t err = 0;
612   for (i = y; i < y + PATCH_SIZE; ++i)
613     for (j = x; j < x + PATCH_SIZE; ++j) {
614       x_w = (double)j + u;
615       y_w = (double)i + v;
616       warped = interpolate(ref, x_w, y_w, width, height, stride);
617       err = warped - frm[j + i * stride];
618       mse += err * err;
619       dt[(i - y) * PATCH_SIZE + (j - x)] = err;
620     }
621 
622   mse /= (PATCH_SIZE * PATCH_SIZE);
623   return mse;
624 }
625 
626 // Computes the components of the system of equations used to solve for
627 // a flow vector. This includes:
628 // 1.) The hessian matrix for optical flow. This matrix is in the
629 // form of:
630 //
631 //       M = |sum(dx * dx)  sum(dx * dy)|
632 //           |sum(dx * dy)  sum(dy * dy)|
633 //
634 // 2.)   b = |sum(dx * dt)|
635 //           |sum(dy * dt)|
636 // Where the sums are computed over a square window of PATCH_SIZE.
compute_flow_system(const double * dx,int dx_stride,const double * dy,int dy_stride,const int16_t * dt,int dt_stride,double * M,double * b)637 static INLINE void compute_flow_system(const double *dx, int dx_stride,
638                                        const double *dy, int dy_stride,
639                                        const int16_t *dt, int dt_stride,
640                                        double *M, double *b) {
641   for (int i = 0; i < PATCH_SIZE; i++) {
642     for (int j = 0; j < PATCH_SIZE; j++) {
643       M[0] += dx[i * dx_stride + j] * dx[i * dx_stride + j];
644       M[1] += dx[i * dx_stride + j] * dy[i * dy_stride + j];
645       M[3] += dy[i * dy_stride + j] * dy[i * dy_stride + j];
646 
647       b[0] += dx[i * dx_stride + j] * dt[i * dt_stride + j];
648       b[1] += dy[i * dy_stride + j] * dt[i * dt_stride + j];
649     }
650   }
651 
652   M[2] = M[1];
653 }
654 
655 // Solves a general Mx = b where M is a 2x2 matrix and b is a 2x1 matrix
solve_2x2_system(const double * M,const double * b,double * output_vec)656 static INLINE void solve_2x2_system(const double *M, const double *b,
657                                     double *output_vec) {
658   double M_0 = M[0];
659   double M_3 = M[3];
660   double det = (M_0 * M_3) - (M[1] * M[2]);
661   if (det < 1e-5) {
662     // Handle singular matrix
663     // TODO(sarahparker) compare results using pseudo inverse instead
664     M_0 += 1e-10;
665     M_3 += 1e-10;
666     det = (M_0 * M_3) - (M[1] * M[2]);
667   }
668   const double det_inv = 1 / det;
669   const double mult_b0 = det_inv * b[0];
670   const double mult_b1 = det_inv * b[1];
671   output_vec[0] = M_3 * mult_b0 - M[1] * mult_b1;
672   output_vec[1] = -M[2] * mult_b0 + M_0 * mult_b1;
673 }
674 
675 /*
676 static INLINE void image_difference(const uint8_t *src, int src_stride,
677                                     const uint8_t *ref, int ref_stride,
678                                     int16_t *dst, int dst_stride, int height,
679                                     int width) {
680   const int block_unit = 8;
681   // Take difference in 8x8 blocks to make use of optimized diff function
682   for (int i = 0; i < height; i += block_unit) {
683     for (int j = 0; j < width; j += block_unit) {
684       aom_subtract_block(block_unit, block_unit, dst + i * dst_stride + j,
685                          dst_stride, src + i * src_stride + j, src_stride,
686                          ref + i * ref_stride + j, ref_stride);
687     }
688   }
689 }
690 */
691 
692 // Compute an image gradient using a sobel filter.
693 // If dir == 1, compute the x gradient. If dir == 0, compute y. This function
694 // assumes the images have been padded so that they can be processed in units
695 // of 8.
sobel_xy_image_gradient(const uint8_t * src,int src_stride,double * dst,int dst_stride,int height,int width,int dir)696 static INLINE void sobel_xy_image_gradient(const uint8_t *src, int src_stride,
697                                            double *dst, int dst_stride,
698                                            int height, int width, int dir) {
699   double norm = 1.0;
700   // TODO(sarahparker) experiment with doing this over larger block sizes
701   const int block_unit = 8;
702   // Filter in 8x8 blocks to eventually make use of optimized convolve function
703   for (int i = 0; i < height; i += block_unit) {
704     for (int j = 0; j < width; j += block_unit) {
705       av1_convolve_2d_sobel_y_c(src + i * src_stride + j, src_stride,
706                                 dst + i * dst_stride + j, dst_stride,
707                                 block_unit, block_unit, dir, norm);
708     }
709   }
710 }
711 
alloc_pyramid(int width,int height,int pad_size,int compute_gradient)712 static ImagePyramid *alloc_pyramid(int width, int height, int pad_size,
713                                    int compute_gradient) {
714   ImagePyramid *pyr = aom_malloc(sizeof(*pyr));
715   pyr->has_gradient = compute_gradient;
716   // 2 * width * height is the upper bound for a buffer that fits
717   // all pyramid levels + padding for each level
718   const int buffer_size = sizeof(*pyr->level_buffer) * 2 * width * height +
719                           (width + 2 * pad_size) * 2 * pad_size * N_LEVELS;
720   pyr->level_buffer = aom_malloc(buffer_size);
721   memset(pyr->level_buffer, 0, buffer_size);
722 
723   if (compute_gradient) {
724     const int gradient_size =
725         sizeof(*pyr->level_dx_buffer) * 2 * width * height +
726         (width + 2 * pad_size) * 2 * pad_size * N_LEVELS;
727     pyr->level_dx_buffer = aom_malloc(gradient_size);
728     pyr->level_dy_buffer = aom_malloc(gradient_size);
729     memset(pyr->level_dx_buffer, 0, gradient_size);
730     memset(pyr->level_dy_buffer, 0, gradient_size);
731   }
732   return pyr;
733 }
734 
free_pyramid(ImagePyramid * pyr)735 static void free_pyramid(ImagePyramid *pyr) {
736   aom_free(pyr->level_buffer);
737   if (pyr->has_gradient) {
738     aom_free(pyr->level_dx_buffer);
739     aom_free(pyr->level_dy_buffer);
740   }
741   aom_free(pyr);
742 }
743 
update_level_dims(ImagePyramid * frm_pyr,int level)744 static INLINE void update_level_dims(ImagePyramid *frm_pyr, int level) {
745   frm_pyr->widths[level] = frm_pyr->widths[level - 1] >> 1;
746   frm_pyr->heights[level] = frm_pyr->heights[level - 1] >> 1;
747   frm_pyr->strides[level] = frm_pyr->widths[level] + 2 * frm_pyr->pad_size;
748   // Point the beginning of the next level buffer to the correct location inside
749   // the padded border
750   frm_pyr->level_loc[level] =
751       frm_pyr->level_loc[level - 1] +
752       frm_pyr->strides[level - 1] *
753           (2 * frm_pyr->pad_size + frm_pyr->heights[level - 1]);
754 }
755 
756 // Compute coarse to fine pyramids for a frame
compute_flow_pyramids(unsigned char * frm,const int frm_width,const int frm_height,const int frm_stride,int n_levels,int pad_size,int compute_grad,ImagePyramid * frm_pyr)757 static void compute_flow_pyramids(unsigned char *frm, const int frm_width,
758                                   const int frm_height, const int frm_stride,
759                                   int n_levels, int pad_size, int compute_grad,
760                                   ImagePyramid *frm_pyr) {
761   int cur_width, cur_height, cur_stride, cur_loc;
762   assert((frm_width >> n_levels) > 0);
763   assert((frm_height >> n_levels) > 0);
764 
765   // Initialize first level
766   frm_pyr->n_levels = n_levels;
767   frm_pyr->pad_size = pad_size;
768   frm_pyr->widths[0] = frm_width;
769   frm_pyr->heights[0] = frm_height;
770   frm_pyr->strides[0] = frm_width + 2 * frm_pyr->pad_size;
771   // Point the beginning of the level buffer to the location inside
772   // the padded border
773   frm_pyr->level_loc[0] =
774       frm_pyr->strides[0] * frm_pyr->pad_size + frm_pyr->pad_size;
775   // This essentially copies the original buffer into the pyramid buffer
776   // without the original padding
777   av1_resize_plane(frm, frm_height, frm_width, frm_stride,
778                    frm_pyr->level_buffer + frm_pyr->level_loc[0],
779                    frm_pyr->heights[0], frm_pyr->widths[0],
780                    frm_pyr->strides[0]);
781 
782   if (compute_grad) {
783     cur_width = frm_pyr->widths[0];
784     cur_height = frm_pyr->heights[0];
785     cur_stride = frm_pyr->strides[0];
786     cur_loc = frm_pyr->level_loc[0];
787     assert(frm_pyr->has_gradient && frm_pyr->level_dx_buffer != NULL &&
788            frm_pyr->level_dy_buffer != NULL);
789     // Computation x gradient
790     sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
791                             frm_pyr->level_dx_buffer + cur_loc, cur_stride,
792                             cur_height, cur_width, 1);
793 
794     // Computation y gradient
795     sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
796                             frm_pyr->level_dy_buffer + cur_loc, cur_stride,
797                             cur_height, cur_width, 0);
798   }
799 
800   // Start at the finest level and resize down to the coarsest level
801   for (int level = 1; level < n_levels; ++level) {
802     update_level_dims(frm_pyr, level);
803     cur_width = frm_pyr->widths[level];
804     cur_height = frm_pyr->heights[level];
805     cur_stride = frm_pyr->strides[level];
806     cur_loc = frm_pyr->level_loc[level];
807 
808     av1_resize_plane(frm_pyr->level_buffer + frm_pyr->level_loc[level - 1],
809                      frm_pyr->heights[level - 1], frm_pyr->widths[level - 1],
810                      frm_pyr->strides[level - 1],
811                      frm_pyr->level_buffer + cur_loc, cur_height, cur_width,
812                      cur_stride);
813 
814     if (compute_grad) {
815       assert(frm_pyr->has_gradient && frm_pyr->level_dx_buffer != NULL &&
816              frm_pyr->level_dy_buffer != NULL);
817       // Computation x gradient
818       sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
819                               frm_pyr->level_dx_buffer + cur_loc, cur_stride,
820                               cur_height, cur_width, 1);
821 
822       // Computation y gradient
823       sobel_xy_image_gradient(frm_pyr->level_buffer + cur_loc, cur_stride,
824                               frm_pyr->level_dy_buffer + cur_loc, cur_stride,
825                               cur_height, cur_width, 0);
826     }
827   }
828 }
829 
compute_flow_at_point(unsigned char * frm,unsigned char * ref,double * dx,double * dy,int x,int y,int width,int height,int stride,double * u,double * v)830 static INLINE void compute_flow_at_point(unsigned char *frm, unsigned char *ref,
831                                          double *dx, double *dy, int x, int y,
832                                          int width, int height, int stride,
833                                          double *u, double *v) {
834   double M[4] = { 0 };
835   double b[2] = { 0 };
836   double tmp_output_vec[2] = { 0 };
837   double error = 0;
838   int16_t dt[PATCH_SIZE * PATCH_SIZE];
839   double o_u = *u;
840   double o_v = *v;
841 
842   for (int itr = 0; itr < DISFLOW_MAX_ITR; itr++) {
843     error = compute_warp_and_error(ref, frm, width, height, stride, x, y, *u,
844                                    *v, dt);
845     if (error <= DISFLOW_ERROR_TR) break;
846     compute_flow_system(dx, stride, dy, stride, dt, PATCH_SIZE, M, b);
847     solve_2x2_system(M, b, tmp_output_vec);
848     *u += tmp_output_vec[0];
849     *v += tmp_output_vec[1];
850   }
851   if (fabs(*u - o_u) > PATCH_SIZE || fabs(*v - o_u) > PATCH_SIZE) {
852     *u = o_u;
853     *v = o_v;
854   }
855 }
856 
857 // make sure flow_u and flow_v start at 0
compute_flow_field(ImagePyramid * frm_pyr,ImagePyramid * ref_pyr,double * flow_u,double * flow_v)858 static void compute_flow_field(ImagePyramid *frm_pyr, ImagePyramid *ref_pyr,
859                                double *flow_u, double *flow_v) {
860   int cur_width, cur_height, cur_stride, cur_loc, patch_loc, patch_center;
861   double *u_upscale =
862       aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
863   double *v_upscale =
864       aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
865 
866   assert(frm_pyr->n_levels == ref_pyr->n_levels);
867 
868   // Compute flow field from coarsest to finest level of the pyramid
869   for (int level = frm_pyr->n_levels - 1; level >= 0; --level) {
870     cur_width = frm_pyr->widths[level];
871     cur_height = frm_pyr->heights[level];
872     cur_stride = frm_pyr->strides[level];
873     cur_loc = frm_pyr->level_loc[level];
874 
875     for (int i = PATCH_SIZE; i < cur_height - PATCH_SIZE; i += PATCH_STEP) {
876       for (int j = PATCH_SIZE; j < cur_width - PATCH_SIZE; j += PATCH_STEP) {
877         patch_loc = i * cur_stride + j;
878         patch_center = patch_loc + PATCH_CENTER * cur_stride + PATCH_CENTER;
879         compute_flow_at_point(frm_pyr->level_buffer + cur_loc,
880                               ref_pyr->level_buffer + cur_loc,
881                               frm_pyr->level_dx_buffer + cur_loc + patch_loc,
882                               frm_pyr->level_dy_buffer + cur_loc + patch_loc, j,
883                               i, cur_width, cur_height, cur_stride,
884                               flow_u + patch_center, flow_v + patch_center);
885       }
886     }
887     // TODO(sarahparker) Replace this with upscale function in resize.c
888     if (level > 0) {
889       int h_upscale = frm_pyr->heights[level - 1];
890       int w_upscale = frm_pyr->widths[level - 1];
891       int s_upscale = frm_pyr->strides[level - 1];
892       for (int i = 0; i < h_upscale; ++i) {
893         for (int j = 0; j < w_upscale; ++j) {
894           u_upscale[j + i * s_upscale] =
895               flow_u[(int)(j >> 1) + (int)(i >> 1) * cur_stride];
896           v_upscale[j + i * s_upscale] =
897               flow_v[(int)(j >> 1) + (int)(i >> 1) * cur_stride];
898         }
899       }
900       memcpy(flow_u, u_upscale,
901              frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
902       memcpy(flow_v, v_upscale,
903              frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
904     }
905   }
906   aom_free(u_upscale);
907   aom_free(v_upscale);
908 }
909 
compute_global_motion_disflow_based(TransformationType type,unsigned char * frm_buffer,int frm_width,int frm_height,int frm_stride,int * frm_corners,int num_frm_corners,YV12_BUFFER_CONFIG * ref,int bit_depth,int * num_inliers_by_motion,MotionModel * params_by_motion,int num_motions)910 static int compute_global_motion_disflow_based(
911     TransformationType type, unsigned char *frm_buffer, int frm_width,
912     int frm_height, int frm_stride, int *frm_corners, int num_frm_corners,
913     YV12_BUFFER_CONFIG *ref, int bit_depth, int *num_inliers_by_motion,
914     MotionModel *params_by_motion, int num_motions) {
915   unsigned char *ref_buffer = ref->y_buffer;
916   const int ref_width = ref->y_width;
917   const int ref_height = ref->y_height;
918   const int pad_size = AOMMAX(PATCH_SIZE, MIN_PAD);
919   int num_correspondences;
920   double *correspondences;
921   RansacFuncDouble ransac = av1_get_ransac_double_prec_type(type);
922   assert(frm_width == ref_width);
923   assert(frm_height == ref_height);
924 
925   // Ensure the number of pyramid levels will work with the frame resolution
926   const int msb =
927       frm_width < frm_height ? get_msb(frm_width) : get_msb(frm_height);
928   const int n_levels = AOMMIN(msb, N_LEVELS);
929 
930   if (ref->flags & YV12_FLAG_HIGHBITDEPTH) {
931     ref_buffer = av1_downconvert_frame(ref, bit_depth);
932   }
933 
934   // TODO(sarahparker) We will want to do the source pyramid computation
935   // outside of this function so it doesn't get recomputed for every
936   // reference. We also don't need to compute every pyramid level for the
937   // reference in advance, since lower levels can be overwritten once their
938   // flow field is computed and upscaled. I'll add these optimizations
939   // once the full implementation is working.
940   // Allocate frm image pyramids
941   int compute_gradient = 1;
942   ImagePyramid *frm_pyr =
943       alloc_pyramid(frm_width, frm_height, pad_size, compute_gradient);
944   compute_flow_pyramids(frm_buffer, frm_width, frm_height, frm_stride, n_levels,
945                         pad_size, compute_gradient, frm_pyr);
946   // Allocate ref image pyramids
947   compute_gradient = 0;
948   ImagePyramid *ref_pyr =
949       alloc_pyramid(ref_width, ref_height, pad_size, compute_gradient);
950   compute_flow_pyramids(ref_buffer, ref_width, ref_height, ref->y_stride,
951                         n_levels, pad_size, compute_gradient, ref_pyr);
952 
953   double *flow_u =
954       aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
955   double *flow_v =
956       aom_malloc(frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
957 
958   memset(flow_u, 0,
959          frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_u));
960   memset(flow_v, 0,
961          frm_pyr->strides[0] * frm_pyr->heights[0] * sizeof(*flow_v));
962 
963   compute_flow_field(frm_pyr, ref_pyr, flow_u, flow_v);
964 
965   // find correspondences between the two images using the flow field
966   correspondences = aom_malloc(num_frm_corners * 4 * sizeof(*correspondences));
967   num_correspondences = determine_disflow_correspondence(
968       frm_corners, num_frm_corners, flow_u, flow_v, frm_width, frm_height,
969       frm_pyr->strides[0], correspondences);
970   ransac(correspondences, num_correspondences, num_inliers_by_motion,
971          params_by_motion, num_motions);
972 
973   free_pyramid(frm_pyr);
974   free_pyramid(ref_pyr);
975   aom_free(correspondences);
976   aom_free(flow_u);
977   aom_free(flow_v);
978   // Set num_inliers = 0 for motions with too few inliers so they are ignored.
979   for (int i = 0; i < num_motions; ++i) {
980     if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences) {
981       num_inliers_by_motion[i] = 0;
982     }
983   }
984 
985   // Return true if any one of the motions has inliers.
986   for (int i = 0; i < num_motions; ++i) {
987     if (num_inliers_by_motion[i] > 0) return 1;
988   }
989   return 0;
990 }
991 
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,YV12_BUFFER_CONFIG * ref,int bit_depth,GlobalMotionEstimationType gm_estimation_type,int * num_inliers_by_motion,MotionModel * params_by_motion,int num_motions)992 int av1_compute_global_motion(TransformationType type,
993                               unsigned char *frm_buffer, int frm_width,
994                               int frm_height, int frm_stride, int *frm_corners,
995                               int num_frm_corners, YV12_BUFFER_CONFIG *ref,
996                               int bit_depth,
997                               GlobalMotionEstimationType gm_estimation_type,
998                               int *num_inliers_by_motion,
999                               MotionModel *params_by_motion, int num_motions) {
1000   switch (gm_estimation_type) {
1001     case GLOBAL_MOTION_FEATURE_BASED:
1002       return compute_global_motion_feature_based(
1003           type, frm_buffer, frm_width, frm_height, frm_stride, frm_corners,
1004           num_frm_corners, ref, bit_depth, num_inliers_by_motion,
1005           params_by_motion, num_motions);
1006     case GLOBAL_MOTION_DISFLOW_BASED:
1007       return compute_global_motion_disflow_based(
1008           type, frm_buffer, frm_width, frm_height, frm_stride, frm_corners,
1009           num_frm_corners, ref, bit_depth, num_inliers_by_motion,
1010           params_by_motion, num_motions);
1011     default: assert(0 && "Unknown global motion estimation type");
1012   }
1013   return 0;
1014 }
1015