Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/aom_dsp/flow_estimation/disflow.c
Line
Count
Source
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
// Dense Inverse Search flow algorithm
13
// Paper: https://arxiv.org/abs/1603.03590
14
15
#include <assert.h>
16
#include <math.h>
17
18
#include "aom_dsp/aom_dsp_common.h"
19
#include "aom_dsp/flow_estimation/corner_detect.h"
20
#include "aom_dsp/flow_estimation/disflow.h"
21
#include "aom_dsp/flow_estimation/ransac.h"
22
#include "aom_dsp/pyramid.h"
23
#include "aom_mem/aom_mem.h"
24
25
#include "config/aom_dsp_rtcd.h"
26
27
// Amount to downsample the flow field by.
28
// e.g., DOWNSAMPLE_SHIFT = 2 (DOWNSAMPLE_FACTOR == 4) means we calculate
29
// one flow point for each 4x4 pixel region of the frame
30
// Must be a power of 2
31
0
#define DOWNSAMPLE_SHIFT 3
32
0
#define DOWNSAMPLE_FACTOR (1 << DOWNSAMPLE_SHIFT)
33
34
// Filters used when upscaling the flow field from one pyramid level
35
// to another. See upscale_flow_component for details on kernel selection
36
0
#define FLOW_UPSCALE_TAPS 4
37
38
// Number of outermost flow field entries (on each edge) which can't be
39
// computed, because the patch they correspond to extends outside of the
40
// frame
41
// The border is (DISFLOW_PATCH_SIZE >> 1) pixels, which is
42
// (DISFLOW_PATCH_SIZE >> 1) >> DOWNSAMPLE_SHIFT many flow field entries
43
0
#define FLOW_BORDER_INNER ((DISFLOW_PATCH_SIZE >> 1) >> DOWNSAMPLE_SHIFT)
44
45
// Number of extra padding entries on each side of the flow field.
46
// These samples are added so that we do not need to apply clamping when
47
// interpolating or upsampling the flow field
48
0
#define FLOW_BORDER_OUTER (FLOW_UPSCALE_TAPS / 2)
49
50
// When downsampling the flow field, each flow field entry covers a square
51
// region of pixels in the image pyramid. This value is equal to the position
52
// of the center of that region, as an offset from the top/left edge.
53
//
54
// Note: Using ((DOWNSAMPLE_FACTOR - 1) / 2) is equivalent to the more
55
// natural expression ((DOWNSAMPLE_FACTOR / 2) - 1),
56
// unless DOWNSAMPLE_FACTOR == 1 (ie, no downsampling), in which case
57
// this gives the correct offset of 0 instead of -1.
58
0
#define UPSAMPLE_CENTER_OFFSET ((DOWNSAMPLE_FACTOR - 1) / 2)
59
60
static double flow_upscale_filter[2][FLOW_UPSCALE_TAPS] = {
61
  // Cubic interpolation kernels for phase=0.75 and phase=0.25, respectively
62
  { -3 / 128., 29 / 128., 111 / 128., -9 / 128. },
63
  { -9 / 128., 111 / 128., 29 / 128., -3 / 128. }
64
};
65
66
0
static inline void get_cubic_kernel_dbl(double x, double kernel[4]) {
67
  // Check that the fractional position is in range.
68
  //
69
  // Note: x is calculated from, e.g., `u_frac = u - floor(u)`.
70
  // Mathematically, this implies that 0 <= x < 1. However, in practice it is
71
  // possible to have x == 1 due to floating point rounding. This is fine,
72
  // and we still interpolate correctly if we allow x = 1.
73
0
  assert(0 <= x && x <= 1);
74
75
0
  double x2 = x * x;
76
0
  double x3 = x2 * x;
77
0
  kernel[0] = -0.5 * x + x2 - 0.5 * x3;
78
0
  kernel[1] = 1.0 - 2.5 * x2 + 1.5 * x3;
79
0
  kernel[2] = 0.5 * x + 2.0 * x2 - 1.5 * x3;
80
0
  kernel[3] = -0.5 * x2 + 0.5 * x3;
81
0
}
82
83
0
static inline void get_cubic_kernel_int(double x, int kernel[4]) {
84
0
  double kernel_dbl[4];
85
0
  get_cubic_kernel_dbl(x, kernel_dbl);
86
87
0
  kernel[0] = (int)rint(kernel_dbl[0] * (1 << DISFLOW_INTERP_BITS));
88
0
  kernel[1] = (int)rint(kernel_dbl[1] * (1 << DISFLOW_INTERP_BITS));
89
0
  kernel[2] = (int)rint(kernel_dbl[2] * (1 << DISFLOW_INTERP_BITS));
90
0
  kernel[3] = (int)rint(kernel_dbl[3] * (1 << DISFLOW_INTERP_BITS));
91
0
}
92
93
static inline double get_cubic_value_dbl(const double *p,
94
0
                                         const double kernel[4]) {
95
0
  return kernel[0] * p[0] + kernel[1] * p[1] + kernel[2] * p[2] +
96
0
         kernel[3] * p[3];
97
0
}
98
99
0
static inline int get_cubic_value_int(const int *p, const int kernel[4]) {
100
0
  return kernel[0] * p[0] + kernel[1] * p[1] + kernel[2] * p[2] +
101
0
         kernel[3] * p[3];
102
0
}
103
104
static inline double bicubic_interp_one(const double *arr, int stride,
105
                                        const double h_kernel[4],
106
0
                                        const double v_kernel[4]) {
107
0
  double tmp[1 * 4];
108
109
  // Horizontal convolution
110
0
  for (int i = -1; i < 3; ++i) {
111
0
    tmp[i + 1] = get_cubic_value_dbl(&arr[i * stride - 1], h_kernel);
112
0
  }
113
114
  // Vertical convolution
115
0
  return get_cubic_value_dbl(tmp, v_kernel);
116
0
}
117
118
static int determine_disflow_correspondence(const ImagePyramid *src_pyr,
119
                                            const ImagePyramid *ref_pyr,
120
                                            CornerList *corners,
121
                                            const FlowField *flow,
122
0
                                            Correspondence *correspondences) {
123
0
  const int width = flow->width;
124
0
  const int height = flow->height;
125
0
  const int stride = flow->stride;
126
127
0
  int num_correspondences = 0;
128
0
  for (int i = 0; i < corners->num_corners; ++i) {
129
0
    const int x0 = corners->corners[2 * i];
130
0
    const int y0 = corners->corners[2 * i + 1];
131
132
    // Offset points, to compensate for the fact that (say) a flow field entry
133
    // at horizontal index i, is nominally associated with the pixel at
134
    // horizontal coordinate (i << DOWNSAMPLE_FACTOR) + UPSAMPLE_CENTER_OFFSET
135
    // This offset must be applied before we split the coordinate into integer
136
    // and fractional parts, in order for the interpolation to be correct.
137
0
    const int x = x0 - UPSAMPLE_CENTER_OFFSET;
138
0
    const int y = y0 - UPSAMPLE_CENTER_OFFSET;
139
140
    // Split the pixel coordinates into integer flow field coordinates and
141
    // an offset for interpolation
142
0
    const int flow_x = x >> DOWNSAMPLE_SHIFT;
143
0
    const double flow_sub_x =
144
0
        (x & (DOWNSAMPLE_FACTOR - 1)) / (double)DOWNSAMPLE_FACTOR;
145
0
    const int flow_y = y >> DOWNSAMPLE_SHIFT;
146
0
    const double flow_sub_y =
147
0
        (y & (DOWNSAMPLE_FACTOR - 1)) / (double)DOWNSAMPLE_FACTOR;
148
149
    // Exclude points which would sample from the outer border of the flow
150
    // field, as this would give lower-quality results.
151
    //
152
    // Note: As we never read from the border region at pyramid level 0, we
153
    // can skip filling it in. If the conditions here are removed, or any
154
    // other logic is added which reads from this border region, then
155
    // compute_flow_field() will need to be modified to call
156
    // fill_flow_field_borders() at pyramid level 0 to set up the correct
157
    // border data.
158
0
    if (flow_x < 1 || (flow_x + 2) >= width) continue;
159
0
    if (flow_y < 1 || (flow_y + 2) >= height) continue;
160
161
0
    double h_kernel[4];
162
0
    double v_kernel[4];
163
0
    get_cubic_kernel_dbl(flow_sub_x, h_kernel);
164
0
    get_cubic_kernel_dbl(flow_sub_y, v_kernel);
165
166
0
    double flow_u = bicubic_interp_one(&flow->u[flow_y * stride + flow_x],
167
0
                                       stride, h_kernel, v_kernel);
168
0
    double flow_v = bicubic_interp_one(&flow->v[flow_y * stride + flow_x],
169
0
                                       stride, h_kernel, v_kernel);
170
171
    // Refine the interpolated flow vector one last time
172
0
    const int patch_tl_x = x0 - DISFLOW_PATCH_CENTER;
173
0
    const int patch_tl_y = y0 - DISFLOW_PATCH_CENTER;
174
0
    aom_compute_flow_at_point(
175
0
        src_pyr->layers[0].buffer, src_pyr->layers[0].stride,
176
0
        ref_pyr->layers[0].buffer, ref_pyr->layers[0].stride, patch_tl_x,
177
0
        patch_tl_y, src_pyr->layers[0].width, src_pyr->layers[0].height,
178
0
        &flow_u, &flow_v);
179
180
    // Use original points (without offsets) when filling in correspondence
181
    // array
182
0
    correspondences[num_correspondences].x = x0;
183
0
    correspondences[num_correspondences].y = y0;
184
0
    correspondences[num_correspondences].rx = x0 + flow_u;
185
0
    correspondences[num_correspondences].ry = y0 + flow_v;
186
0
    num_correspondences++;
187
0
  }
188
0
  return num_correspondences;
189
0
}
190
191
// Compare two regions of width x height pixels, one rooted at position
192
// (x, y) in src and the other at (x + u, y + v) in ref.
193
// This function returns the sum of squared pixel differences between
194
// the two regions.
195
static inline void compute_flow_vector(const uint8_t *src, int src_stride,
196
                                       const uint8_t *ref, int ref_stride,
197
                                       int width, int height, int x, int y,
198
                                       double u, double v, const int16_t *dx,
199
0
                                       const int16_t *dy, int *b) {
200
0
  memset(b, 0, 2 * sizeof(*b));
201
202
  // Split offset into integer and fractional parts, and compute cubic
203
  // interpolation kernels
204
0
  const int u_int = (int)floor(u);
205
0
  const int v_int = (int)floor(v);
206
0
  const double u_frac = u - floor(u);
207
0
  const double v_frac = v - floor(v);
208
209
0
  int h_kernel[4];
210
0
  int v_kernel[4];
211
0
  get_cubic_kernel_int(u_frac, h_kernel);
212
0
  get_cubic_kernel_int(v_frac, v_kernel);
213
214
  // Storage for intermediate values between the two convolution directions
215
0
  int tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 3)];
216
0
  int *tmp = tmp_ + DISFLOW_PATCH_SIZE;  // Offset by one row
217
218
  // Clamp coordinates so that all pixels we fetch will remain within the
219
  // allocated border region, but allow them to go far enough out that
220
  // the border pixels' values do not change.
221
  // Since we are calculating an 8x8 block, the bottom-right pixel
222
  // in the block has coordinates (x0 + 7, y0 + 7). Then, the cubic
223
  // interpolation has 4 taps, meaning that the output of pixel
224
  // (x_w, y_w) depends on the pixels in the range
225
  // ([x_w - 1, x_w + 2], [y_w - 1, y_w + 2]).
226
  //
227
  // Thus the most extreme coordinates which will be fetched are
228
  // (x0 - 1, y0 - 1) and (x0 + 9, y0 + 9).
229
0
  const int x0 = clamp(x + u_int, -9, width);
230
0
  const int y0 = clamp(y + v_int, -9, height);
231
232
  // Horizontal convolution
233
0
  for (int i = -1; i < DISFLOW_PATCH_SIZE + 2; ++i) {
234
0
    const int y_w = y0 + i;
235
0
    for (int j = 0; j < DISFLOW_PATCH_SIZE; ++j) {
236
0
      const int x_w = x0 + j;
237
0
      int arr[4];
238
239
0
      arr[0] = (int)ref[y_w * ref_stride + (x_w - 1)];
240
0
      arr[1] = (int)ref[y_w * ref_stride + (x_w + 0)];
241
0
      arr[2] = (int)ref[y_w * ref_stride + (x_w + 1)];
242
0
      arr[3] = (int)ref[y_w * ref_stride + (x_w + 2)];
243
244
      // Apply kernel and round, keeping 6 extra bits of precision.
245
      //
246
      // 6 is the maximum allowable number of extra bits which will avoid
247
      // the intermediate values overflowing an int16_t. The most extreme
248
      // intermediate value occurs when:
249
      // * The input pixels are [0, 255, 255, 0]
250
      // * u_frac = 0.5
251
      // In this case, the un-scaled output is 255 * 1.125 = 286.875.
252
      // As an integer with 6 fractional bits, that is 18360, which fits
253
      // in an int16_t. But with 7 fractional bits it would be 36720,
254
      // which is too large.
255
0
      tmp[i * DISFLOW_PATCH_SIZE + j] = ROUND_POWER_OF_TWO(
256
0
          get_cubic_value_int(arr, h_kernel), DISFLOW_INTERP_BITS - 6);
257
0
    }
258
0
  }
259
260
  // Vertical convolution
261
0
  for (int i = 0; i < DISFLOW_PATCH_SIZE; ++i) {
262
0
    for (int j = 0; j < DISFLOW_PATCH_SIZE; ++j) {
263
0
      const int *p = &tmp[i * DISFLOW_PATCH_SIZE + j];
264
0
      const int arr[4] = { p[-DISFLOW_PATCH_SIZE], p[0], p[DISFLOW_PATCH_SIZE],
265
0
                           p[2 * DISFLOW_PATCH_SIZE] };
266
0
      const int result = get_cubic_value_int(arr, v_kernel);
267
268
      // Apply kernel and round.
269
      // This time, we have to round off the 6 extra bits which were kept
270
      // earlier, but we also want to keep DISFLOW_DERIV_SCALE_LOG2 extra bits
271
      // of precision to match the scale of the dx and dy arrays.
272
0
      const int round_bits = DISFLOW_INTERP_BITS + 6 - DISFLOW_DERIV_SCALE_LOG2;
273
0
      const int warped = ROUND_POWER_OF_TWO(result, round_bits);
274
0
      const int src_px = src[(x + j) + (y + i) * src_stride] << 3;
275
0
      const int dt = warped - src_px;
276
0
      b[0] += dx[i * DISFLOW_PATCH_SIZE + j] * dt;
277
0
      b[1] += dy[i * DISFLOW_PATCH_SIZE + j] * dt;
278
0
    }
279
0
  }
280
0
}
281
282
static inline void sobel_filter(const uint8_t *src, int src_stride,
283
0
                                int16_t *dst, int dst_stride, int dir) {
284
0
  int16_t tmp_[DISFLOW_PATCH_SIZE * (DISFLOW_PATCH_SIZE + 2)];
285
0
  int16_t *tmp = tmp_ + DISFLOW_PATCH_SIZE;
286
287
  // Sobel filter kernel
288
  // This must have an overall scale factor equal to DISFLOW_DERIV_SCALE,
289
  // in order to produce correctly scaled outputs.
290
  // To work out the scale factor, we multiply two factors:
291
  //
292
  // * For the derivative filter (sobel_a), comparing our filter
293
  //    image[x - 1] - image[x + 1]
294
  //   to the standard form
295
  //    d/dx image[x] = image[x+1] - image[x]
296
  //   tells us that we're actually calculating -2 * d/dx image[2]
297
  //
298
  // * For the smoothing filter (sobel_b), all coefficients are positive
299
  //   so the scale factor is just the sum of the coefficients
300
  //
301
  // Thus we need to make sure that DISFLOW_DERIV_SCALE = 2 * sum(sobel_b)
302
  // (and take care of the - sign from sobel_a elsewhere)
303
0
  static const int16_t sobel_a[3] = { 1, 0, -1 };
304
0
  static const int16_t sobel_b[3] = { 1, 2, 1 };
305
0
  const int taps = 3;
306
307
  // horizontal filter
308
0
  const int16_t *h_kernel = dir ? sobel_a : sobel_b;
309
310
0
  for (int y = -1; y < DISFLOW_PATCH_SIZE + 1; ++y) {
311
0
    for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) {
312
0
      int sum = 0;
313
0
      for (int k = 0; k < taps; ++k) {
314
0
        sum += h_kernel[k] * src[y * src_stride + (x + k - 1)];
315
0
      }
316
0
      tmp[y * DISFLOW_PATCH_SIZE + x] = sum;
317
0
    }
318
0
  }
319
320
  // vertical filter
321
0
  const int16_t *v_kernel = dir ? sobel_b : sobel_a;
322
323
0
  for (int y = 0; y < DISFLOW_PATCH_SIZE; ++y) {
324
0
    for (int x = 0; x < DISFLOW_PATCH_SIZE; ++x) {
325
0
      int sum = 0;
326
0
      for (int k = 0; k < taps; ++k) {
327
0
        sum += v_kernel[k] * tmp[(y + k - 1) * DISFLOW_PATCH_SIZE + x];
328
0
      }
329
0
      dst[y * dst_stride + x] = sum;
330
0
    }
331
0
  }
332
0
}
333
334
// Computes the components of the system of equations used to solve for
335
// a flow vector.
336
//
337
// The flow equations are a least-squares system, derived as follows:
338
//
339
// For each pixel in the patch, we calculate the current error `dt`,
340
// and the x and y gradients `dx` and `dy` of the source patch.
341
// This means that, to first order, the squared error for this pixel is
342
//
343
//    (dt + u * dx + v * dy)^2
344
//
345
// where (u, v) are the incremental changes to the flow vector.
346
//
347
// We then want to find the values of u and v which minimize the sum
348
// of the squared error across all pixels. Conveniently, this fits exactly
349
// into the form of a least squares problem, with one equation
350
//
351
//   u * dx + v * dy = -dt
352
//
353
// for each pixel.
354
//
355
// Summing across all pixels in a square window of size DISFLOW_PATCH_SIZE,
356
// and absorbing the - sign elsewhere, this results in the least squares system
357
//
358
//   M = |sum(dx * dx)  sum(dx * dy)|
359
//       |sum(dx * dy)  sum(dy * dy)|
360
//
361
//   b = |sum(dx * dt)|
362
//       |sum(dy * dt)|
363
static inline void compute_flow_matrix(const int16_t *dx, int dx_stride,
364
                                       const int16_t *dy, int dy_stride,
365
0
                                       double *M) {
366
0
  int tmp[4] = { 0 };
367
368
0
  for (int i = 0; i < DISFLOW_PATCH_SIZE; i++) {
369
0
    for (int j = 0; j < DISFLOW_PATCH_SIZE; j++) {
370
0
      tmp[0] += dx[i * dx_stride + j] * dx[i * dx_stride + j];
371
0
      tmp[1] += dx[i * dx_stride + j] * dy[i * dy_stride + j];
372
      // Don't compute tmp[2], as it should be equal to tmp[1]
373
0
      tmp[3] += dy[i * dy_stride + j] * dy[i * dy_stride + j];
374
0
    }
375
0
  }
376
377
  // Apply regularization
378
  // We follow the standard regularization method of adding `k * I` before
379
  // inverting. This ensures that the matrix will be invertible.
380
  //
381
  // Setting the regularization strength k to 1 seems to work well here, as
382
  // typical values coming from the other equations are very large (1e5 to
383
  // 1e6, with an upper limit of around 6e7, at the time of writing).
384
  // It also preserves the property that all matrix values are whole numbers,
385
  // which is convenient for integerized SIMD implementation.
386
0
  tmp[0] += 1;
387
0
  tmp[3] += 1;
388
389
0
  tmp[2] = tmp[1];
390
391
0
  M[0] = (double)tmp[0];
392
0
  M[1] = (double)tmp[1];
393
0
  M[2] = (double)tmp[2];
394
0
  M[3] = (double)tmp[3];
395
0
}
396
397
// Try to invert the matrix M
398
// Note: Due to the nature of how a least-squares matrix is constructed, all of
399
// the eigenvalues will be >= 0, and therefore det M >= 0 as well.
400
// The regularization term `+ k * I` further ensures that det M >= k^2.
401
// As mentioned in compute_flow_matrix(), here we use k = 1, so det M >= 1.
402
// So we don't have to worry about non-invertible matrices here.
403
0
static inline void invert_2x2(const double *M, double *M_inv) {
404
0
  double det = (M[0] * M[3]) - (M[1] * M[2]);
405
0
  assert(det >= 1);
406
0
  const double det_inv = 1 / det;
407
408
0
  M_inv[0] = M[3] * det_inv;
409
0
  M_inv[1] = -M[1] * det_inv;
410
0
  M_inv[2] = -M[2] * det_inv;
411
0
  M_inv[3] = M[0] * det_inv;
412
0
}
413
414
void aom_compute_flow_at_point_c(const uint8_t *src, int src_stride,
415
                                 const uint8_t *ref, int ref_stride, int x,
416
                                 int y, int width, int height, double *u,
417
0
                                 double *v) {
418
0
  double M[4];
419
0
  double M_inv[4];
420
0
  int b[2];
421
0
  int16_t dx[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE];
422
0
  int16_t dy[DISFLOW_PATCH_SIZE * DISFLOW_PATCH_SIZE];
423
424
  // Compute gradients within this patch
425
0
  const uint8_t *src_patch = &src[y * src_stride + x];
426
0
  sobel_filter(src_patch, src_stride, dx, DISFLOW_PATCH_SIZE, 1);
427
0
  sobel_filter(src_patch, src_stride, dy, DISFLOW_PATCH_SIZE, 0);
428
429
0
  compute_flow_matrix(dx, DISFLOW_PATCH_SIZE, dy, DISFLOW_PATCH_SIZE, M);
430
0
  invert_2x2(M, M_inv);
431
432
0
  for (int itr = 0; itr < DISFLOW_MAX_ITR; itr++) {
433
0
    compute_flow_vector(src, src_stride, ref, ref_stride, width, height, x, y,
434
0
                        *u, *v, dx, dy, b);
435
436
    // Solve flow equations to find a better estimate for the flow vector
437
    // at this point
438
0
    const double step_u = M_inv[0] * b[0] + M_inv[1] * b[1];
439
0
    const double step_v = M_inv[2] * b[0] + M_inv[3] * b[1];
440
0
    *u += fclamp(step_u * DISFLOW_STEP_SIZE, -2, 2);
441
0
    *v += fclamp(step_v * DISFLOW_STEP_SIZE, -2, 2);
442
443
0
    if (fabs(step_u) + fabs(step_v) < DISFLOW_STEP_SIZE_THRESOLD) {
444
      // Stop iteration when we're close to convergence
445
0
      break;
446
0
    }
447
0
  }
448
0
}
449
450
static void fill_flow_field_borders(double *flow, int width, int height,
451
0
                                    int stride) {
452
0
  if (width <= 2 * FLOW_BORDER_INNER || height <= 2 * FLOW_BORDER_INNER) return;
453
0
  assert(width + 2 * FLOW_BORDER_OUTER <= stride);
454
455
  // Calculate the bounds of the rectangle which was filled in by
456
  // compute_flow_field() before calling this function.
457
  // These indices are inclusive on both ends.
458
0
  const int left_index = FLOW_BORDER_INNER;
459
0
  const int right_index = (width - FLOW_BORDER_INNER - 1);
460
0
  const int top_index = FLOW_BORDER_INNER;
461
0
  const int bottom_index = (height - FLOW_BORDER_INNER - 1);
462
463
  // Left area
464
0
  for (int i = top_index; i <= bottom_index; i += 1) {
465
0
    double *row = flow + i * stride;
466
0
    const double left = row[left_index];
467
0
    for (int j = -FLOW_BORDER_OUTER; j < left_index; j++) {
468
0
      row[j] = left;
469
0
    }
470
0
  }
471
472
  // Right area
473
0
  for (int i = top_index; i <= bottom_index; i += 1) {
474
0
    double *row = flow + i * stride;
475
0
    const double right = row[right_index];
476
0
    for (int j = right_index + 1; j < width + FLOW_BORDER_OUTER; j++) {
477
0
      row[j] = right;
478
0
    }
479
0
  }
480
481
  // Top area
482
0
  const double *top_row = flow + top_index * stride - FLOW_BORDER_OUTER;
483
0
  for (int i = -FLOW_BORDER_OUTER; i < top_index; i++) {
484
0
    double *row = flow + i * stride - FLOW_BORDER_OUTER;
485
0
    size_t length = width + 2 * FLOW_BORDER_OUTER;
486
0
    memmove(row, top_row, length * sizeof(*row));
487
0
  }
488
489
  // Bottom area
490
0
  const double *bottom_row = flow + bottom_index * stride - FLOW_BORDER_OUTER;
491
0
  for (int i = bottom_index + 1; i < height + FLOW_BORDER_OUTER; i++) {
492
0
    double *row = flow + i * stride - FLOW_BORDER_OUTER;
493
0
    size_t length = width + 2 * FLOW_BORDER_OUTER;
494
0
    memmove(row, bottom_row, length * sizeof(*row));
495
0
  }
496
0
}
497
498
// Upscale one component of the flow field, from a size of
499
// cur_width x cur_height to a size of (2*cur_width) x (2*cur_height), storing
500
// the result back into the same buffer. This function also scales the flow
501
// vector by 2, so that when we move to the next pyramid level down, the implied
502
// motion vector is the same.
503
//
504
// The temporary buffer tmpbuf must be large enough to hold an intermediate
505
// array of size stride * cur_height, *plus* FLOW_BORDER_OUTER rows above and
506
// below. In other words, indices from -FLOW_BORDER_OUTER * stride to
507
// (cur_height + FLOW_BORDER_OUTER) * stride - 1 must be valid.
508
//
509
// Note that the same stride is used for u before and after upscaling
510
// and for the temporary buffer, for simplicity.
511
//
512
// A note on phasing:
513
//
514
// The flow fields at two adjacent pyramid levels are offset from each other,
515
// and we need to account for this in the construction of the interpolation
516
// kernels.
517
//
518
// Consider an 8x8 pixel patch at pyramid level n. This is split into four
519
// patches at pyramid level n-1. Bringing these patches back up to pyramid level
520
// n, each sub-patch covers 4x4 pixels, and between them they cover the same
521
// 8x8 region.
522
//
523
// Therefore, at pyramid level n, two adjacent patches look like this:
524
//
525
//    + - - - - - - - + - - - - - - - +
526
//    |               |               |
527
//    |   x       x   |   x       x   |
528
//    |               |               |
529
//    |       #       |       #       |
530
//    |               |               |
531
//    |   x       x   |   x       x   |
532
//    |               |               |
533
//    + - - - - - - - + - - - - - - - +
534
//
535
// where # marks the center of a patch at pyramid level n (the input to this
536
// function), and x marks the center of a patch at pyramid level n-1 (the output
537
// of this function).
538
//
539
// By counting pixels (marked by +, -, and |), we can see that the flow vectors
540
// at pyramid level n-1 are offset relative to the flow vectors at pyramid
541
// level n, by 1/4 of the larger (input) patch size. Therefore, our
542
// interpolation kernels need to have phases of 0.25 and 0.75.
543
//
544
// In addition, in order to handle the frame edges correctly, we need to
545
// generate one output vector to the left and one to the right of each input
546
// vector, even though these must be interpolated using different source points.
547
static void upscale_flow_component(double *flow, int cur_width, int cur_height,
548
0
                                   int stride, double *tmpbuf) {
549
0
  assert(cur_width > 0);
550
0
  assert(cur_height > 0);
551
0
  assert(2 * cur_width <= stride);
552
553
0
  const int half_len = FLOW_UPSCALE_TAPS / 2;
554
555
  // Check that the outer border is large enough to avoid needing to clamp
556
  // the source locations
557
0
  assert(half_len <= FLOW_BORDER_OUTER);
558
559
  // Horizontal upscale and multiply by 2
560
0
  for (int i = 0; i < cur_height; i++) {
561
0
    for (int j = 0; j < cur_width; j++) {
562
0
      double left = 0;
563
0
      for (int k = -half_len; k < half_len; k++) {
564
0
        left +=
565
0
            flow[i * stride + (j + k)] * flow_upscale_filter[0][k + half_len];
566
0
      }
567
0
      tmpbuf[i * stride + (2 * j + 0)] = 2.0 * left;
568
569
      // Right output pixel is 0.25 units to the right of the input pixel
570
0
      double right = 0;
571
0
      for (int k = -(half_len - 1); k < (half_len + 1); k++) {
572
0
        right += flow[i * stride + (j + k)] *
573
0
                 flow_upscale_filter[1][k + (half_len - 1)];
574
0
      }
575
0
      tmpbuf[i * stride + (2 * j + 1)] = 2.0 * right;
576
0
    }
577
0
  }
578
579
  // Fill in top and bottom borders of tmpbuf
580
0
  const double *top_row = &tmpbuf[0];
581
0
  for (int i = -FLOW_BORDER_OUTER; i < 0; i++) {
582
0
    double *row = &tmpbuf[i * stride];
583
0
    memmove(row, top_row, 2 * cur_width * sizeof(*row));
584
0
  }
585
586
0
  const double *bottom_row = &tmpbuf[(cur_height - 1) * stride];
587
0
  for (int i = cur_height; i < cur_height + FLOW_BORDER_OUTER; i++) {
588
0
    double *row = &tmpbuf[i * stride];
589
0
    memmove(row, bottom_row, 2 * cur_width * sizeof(*row));
590
0
  }
591
592
  // Vertical upscale
593
0
  int upscaled_width = cur_width * 2;
594
0
  for (int i = 0; i < cur_height; i++) {
595
0
    for (int j = 0; j < upscaled_width; j++) {
596
0
      double top = 0;
597
0
      for (int k = -half_len; k < half_len; k++) {
598
0
        top +=
599
0
            tmpbuf[(i + k) * stride + j] * flow_upscale_filter[0][k + half_len];
600
0
      }
601
0
      flow[(2 * i) * stride + j] = top;
602
603
0
      double bottom = 0;
604
0
      for (int k = -(half_len - 1); k < (half_len + 1); k++) {
605
0
        bottom += tmpbuf[(i + k) * stride + j] *
606
0
                  flow_upscale_filter[1][k + (half_len - 1)];
607
0
      }
608
0
      flow[(2 * i + 1) * stride + j] = bottom;
609
0
    }
610
0
  }
611
0
}
612
613
// make sure flow_u and flow_v start at 0
614
static bool compute_flow_field(const ImagePyramid *src_pyr,
615
                               const ImagePyramid *ref_pyr, int n_levels,
616
0
                               FlowField *flow) {
617
0
  bool mem_status = true;
618
619
0
  double *flow_u = flow->u;
620
0
  double *flow_v = flow->v;
621
622
0
  double *tmpbuf0;
623
0
  double *tmpbuf;
624
625
0
  if (n_levels < 2) {
626
    // tmpbuf not needed
627
0
    tmpbuf0 = NULL;
628
0
    tmpbuf = NULL;
629
0
  } else {
630
    // This line must match the calculation of cur_flow_height below
631
0
    const int layer1_height = src_pyr->layers[1].height >> DOWNSAMPLE_SHIFT;
632
633
0
    const size_t tmpbuf_size =
634
0
        (layer1_height + 2 * FLOW_BORDER_OUTER) * flow->stride;
635
0
    tmpbuf0 = aom_malloc(tmpbuf_size * sizeof(*tmpbuf0));
636
0
    if (!tmpbuf0) {
637
0
      mem_status = false;
638
0
      goto free_tmpbuf;
639
0
    }
640
0
    tmpbuf = tmpbuf0 + FLOW_BORDER_OUTER * flow->stride;
641
0
  }
642
643
  // Compute flow field from coarsest to finest level of the pyramid
644
  //
645
  // Note: We stop after refining pyramid level 1 and interpolating it to
646
  // generate an initial flow field at level 0. We do *not* refine the dense
647
  // flow field at level 0. Instead, we wait until we have generated
648
  // correspondences by interpolating this flow field, and then refine the
649
  // correspondences themselves. This is both faster and gives better output
650
  // compared to refining the flow field at level 0 and then interpolating.
651
0
  for (int level = n_levels - 1; level >= 1; --level) {
652
0
    const PyramidLayer *cur_layer = &src_pyr->layers[level];
653
0
    const int cur_width = cur_layer->width;
654
0
    const int cur_height = cur_layer->height;
655
656
0
    const uint8_t *src_buffer = cur_layer->buffer;
657
0
    const int src_stride = cur_layer->stride;
658
0
    const uint8_t *ref_buffer = ref_pyr->layers[level].buffer;
659
0
    const int ref_stride = ref_pyr->layers[level].stride;
660
661
0
    const int cur_flow_width = cur_width >> DOWNSAMPLE_SHIFT;
662
0
    const int cur_flow_height = cur_height >> DOWNSAMPLE_SHIFT;
663
0
    const int cur_flow_stride = flow->stride;
664
665
0
    for (int i = FLOW_BORDER_INNER; i < cur_flow_height - FLOW_BORDER_INNER;
666
0
         i += 1) {
667
0
      for (int j = FLOW_BORDER_INNER; j < cur_flow_width - FLOW_BORDER_INNER;
668
0
           j += 1) {
669
0
        const int flow_field_idx = i * cur_flow_stride + j;
670
671
        // Calculate the position of a patch of size DISFLOW_PATCH_SIZE pixels,
672
        // which is centered on the region covered by this flow field entry
673
0
        const int patch_center_x =
674
0
            (j << DOWNSAMPLE_SHIFT) + UPSAMPLE_CENTER_OFFSET;  // In pixels
675
0
        const int patch_center_y =
676
0
            (i << DOWNSAMPLE_SHIFT) + UPSAMPLE_CENTER_OFFSET;  // In pixels
677
0
        const int patch_tl_x = patch_center_x - DISFLOW_PATCH_CENTER;
678
0
        const int patch_tl_y = patch_center_y - DISFLOW_PATCH_CENTER;
679
0
        assert(patch_tl_x >= 0);
680
0
        assert(patch_tl_y >= 0);
681
682
0
        aom_compute_flow_at_point(src_buffer, src_stride, ref_buffer,
683
0
                                  ref_stride, patch_tl_x, patch_tl_y, cur_width,
684
0
                                  cur_height, &flow_u[flow_field_idx],
685
0
                                  &flow_v[flow_field_idx]);
686
0
      }
687
0
    }
688
689
    // Fill in the areas which we haven't explicitly computed, with copies
690
    // of the outermost values which we did compute
691
0
    fill_flow_field_borders(flow_u, cur_flow_width, cur_flow_height,
692
0
                            cur_flow_stride);
693
0
    fill_flow_field_borders(flow_v, cur_flow_width, cur_flow_height,
694
0
                            cur_flow_stride);
695
696
0
    if (level > 0) {
697
0
      const int upscale_flow_width = cur_flow_width << 1;
698
0
      const int upscale_flow_height = cur_flow_height << 1;
699
0
      const int upscale_stride = flow->stride;
700
701
0
      upscale_flow_component(flow_u, cur_flow_width, cur_flow_height,
702
0
                             cur_flow_stride, tmpbuf);
703
0
      upscale_flow_component(flow_v, cur_flow_width, cur_flow_height,
704
0
                             cur_flow_stride, tmpbuf);
705
706
      // If we didn't fill in the rightmost column or bottommost row during
707
      // upsampling (in order to keep the ratio to exactly 2), fill them
708
      // in here by copying the next closest column/row
709
0
      const PyramidLayer *next_layer = &src_pyr->layers[level - 1];
710
0
      const int next_flow_width = next_layer->width >> DOWNSAMPLE_SHIFT;
711
0
      const int next_flow_height = next_layer->height >> DOWNSAMPLE_SHIFT;
712
713
      // Rightmost column
714
0
      if (next_flow_width > upscale_flow_width) {
715
0
        assert(next_flow_width == upscale_flow_width + 1);
716
0
        for (int i = 0; i < upscale_flow_height; i++) {
717
0
          const int index = i * upscale_stride + upscale_flow_width;
718
0
          flow_u[index] = flow_u[index - 1];
719
0
          flow_v[index] = flow_v[index - 1];
720
0
        }
721
0
      }
722
723
      // Bottommost row
724
0
      if (next_flow_height > upscale_flow_height) {
725
0
        assert(next_flow_height == upscale_flow_height + 1);
726
0
        for (int j = 0; j < next_flow_width; j++) {
727
0
          const int index = upscale_flow_height * upscale_stride + j;
728
0
          flow_u[index] = flow_u[index - upscale_stride];
729
0
          flow_v[index] = flow_v[index - upscale_stride];
730
0
        }
731
0
      }
732
0
    }
733
0
  }
734
735
0
free_tmpbuf:
736
0
  aom_free(tmpbuf0);
737
0
  return mem_status;
738
0
}
739
740
0
static FlowField *alloc_flow_field(int frame_width, int frame_height) {
741
0
  const int flow_width = frame_width >> DOWNSAMPLE_SHIFT;
742
0
  const int flow_height = frame_height >> DOWNSAMPLE_SHIFT;
743
0
  assert(flow_width > 0);
744
0
  assert(flow_height > 0);
745
746
0
  FlowField *flow = (FlowField *)aom_malloc(sizeof(FlowField));
747
0
  if (flow == NULL) return NULL;
748
749
  // Calculate the size of the bottom (largest) layer of the flow pyramid
750
0
  flow->width = flow_width;
751
0
  flow->height = flow_height;
752
0
  flow->stride = flow->width + 2 * FLOW_BORDER_OUTER;
753
754
0
  const size_t flow_size =
755
0
      flow->stride * (size_t)(flow->height + 2 * FLOW_BORDER_OUTER);
756
757
0
  flow->buf0 = aom_calloc(2 * flow_size, sizeof(*flow->buf0));
758
0
  if (!flow->buf0) {
759
0
    aom_free(flow);
760
0
    return NULL;
761
0
  }
762
763
0
  flow->u = flow->buf0 + FLOW_BORDER_OUTER * flow->stride + FLOW_BORDER_OUTER;
764
0
  flow->v = flow->u + flow_size;
765
766
0
  return flow;
767
0
}
768
769
0
static void free_flow_field(FlowField *flow) {
770
0
  aom_free(flow->buf0);
771
0
  aom_free(flow);
772
0
}
773
774
// Compute flow field between `src` and `ref`, and then use that flow to
775
// compute a global motion model relating the two frames.
776
//
777
// Following the convention in flow_estimation.h, the flow vectors are computed
778
// at fixed points in `src` and point to the corresponding locations in `ref`,
779
// regardless of the temporal ordering of the frames.
780
bool av1_compute_global_motion_disflow(
781
    TransformationType type, YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *ref,
782
    int bit_depth, int downsample_level, MotionModel *motion_models,
783
0
    int num_motion_models, bool *mem_alloc_failed) {
784
  // Precompute information we will need about each frame
785
0
  ImagePyramid *src_pyramid = src->y_pyramid;
786
0
  CornerList *src_corners = src->corners;
787
0
  ImagePyramid *ref_pyramid = ref->y_pyramid;
788
789
0
  const int src_layers =
790
0
      aom_compute_pyramid(src, bit_depth, DISFLOW_PYRAMID_LEVELS, src_pyramid);
791
0
  const int ref_layers =
792
0
      aom_compute_pyramid(ref, bit_depth, DISFLOW_PYRAMID_LEVELS, ref_pyramid);
793
794
0
  if (src_layers < 0 || ref_layers < 0) {
795
0
    *mem_alloc_failed = true;
796
0
    return false;
797
0
  }
798
799
0
  if (src_layers != ref_layers) {
800
0
    return false;
801
0
  }
802
803
0
  if (!av1_compute_corner_list(src, bit_depth, downsample_level, src_corners)) {
804
0
    *mem_alloc_failed = true;
805
0
    return false;
806
0
  }
807
808
0
  const int src_width = src_pyramid->layers[0].width;
809
0
  const int src_height = src_pyramid->layers[0].height;
810
0
  if (ref_pyramid->layers[0].width != src_width ||
811
0
      ref_pyramid->layers[0].height != src_height) {
812
0
    return false;
813
0
  }
814
815
0
  if (src_width < (1 << DOWNSAMPLE_SHIFT) ||
816
0
      src_height < (1 << DOWNSAMPLE_SHIFT)) {
817
0
    return false;
818
0
  }
819
0
  if (src_corners->num_corners == 0) {
820
0
    return false;
821
0
  }
822
823
0
  FlowField *flow = alloc_flow_field(src_width, src_height);
824
0
  if (!flow) {
825
0
    *mem_alloc_failed = true;
826
0
    return false;
827
0
  }
828
829
0
  if (!compute_flow_field(src_pyramid, ref_pyramid, src_layers, flow)) {
830
0
    *mem_alloc_failed = true;
831
0
    free_flow_field(flow);
832
0
    return false;
833
0
  }
834
835
  // find correspondences between the two images using the flow field
836
0
  Correspondence *correspondences =
837
0
      aom_malloc(src_corners->num_corners * sizeof(*correspondences));
838
0
  if (!correspondences) {
839
0
    *mem_alloc_failed = true;
840
0
    free_flow_field(flow);
841
0
    return false;
842
0
  }
843
844
0
  const int num_correspondences = determine_disflow_correspondence(
845
0
      src_pyramid, ref_pyramid, src_corners, flow, correspondences);
846
847
0
  bool result = ransac(correspondences, num_correspondences, type,
848
0
                       motion_models, num_motion_models, mem_alloc_failed);
849
850
0
  aom_free(correspondences);
851
0
  free_flow_field(flow);
852
0
  return result;
853
0
}