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 <stdbool.h>
15 #include <memory.h>
16 #include <math.h>
17 #include <assert.h>
18
19 #include "config/aom_dsp_rtcd.h"
20
21 #include "av1/encoder/global_motion.h"
22
23 #include "av1/common/convolve.h"
24 #include "av1/common/warped_motion.h"
25
26 #include "av1/encoder/segmentation.h"
27
28 #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
29
30 // Border over which to compute the global motion
31 #define ERRORADV_BORDER 0
32
av1_is_enough_erroradvantage(double best_erroradvantage,int params_cost)33 int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost) {
34 return best_erroradvantage < erroradv_tr &&
35 best_erroradvantage * params_cost < erroradv_prod_tr;
36 }
37
convert_to_params(const double * params,int32_t * model)38 static void convert_to_params(const double *params, int32_t *model) {
39 int i;
40 model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
41 model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
42 model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
43 GM_TRANS_DECODE_FACTOR;
44 model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
45 GM_TRANS_DECODE_FACTOR;
46
47 for (i = 2; i < 6; ++i) {
48 const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
49 model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
50 model[i] =
51 (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
52 model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
53 }
54 }
55
av1_convert_model_to_params(const double * params,WarpedMotionParams * model)56 void av1_convert_model_to_params(const double *params,
57 WarpedMotionParams *model) {
58 convert_to_params(params, model->wmmat);
59 model->wmtype = get_wmtype(model);
60 model->invalid = 0;
61 }
62
63 // Adds some offset to a global motion parameter and handles
64 // all of the necessary precision shifts, clamping, and
65 // zero-centering.
add_param_offset(int param_index,int32_t param_value,int32_t offset)66 static int32_t add_param_offset(int param_index, int32_t param_value,
67 int32_t offset) {
68 const int scale_vals[2] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF };
69 const int clamp_vals[2] = { GM_TRANS_MAX, GM_ALPHA_MAX };
70 // type of param: 0 - translation, 1 - affine
71 const int param_type = (param_index < 2 ? 0 : 1);
72 const int is_one_centered = (param_index == 2 || param_index == 5);
73
74 // Make parameter zero-centered and offset the shift that was done to make
75 // it compatible with the warped model
76 param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
77 scale_vals[param_type];
78 // Add desired offset to the rescaled/zero-centered parameter
79 param_value += offset;
80 // Clamp the parameter so it does not overflow the number of bits allotted
81 // to it in the bitstream
82 param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
83 clamp_vals[param_type]);
84 // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
85 // with the warped motion library
86 param_value *= (1 << scale_vals[param_type]);
87
88 // Undo the zero-centering step if necessary
89 return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
90 }
91
force_wmtype(WarpedMotionParams * wm,TransformationType wmtype)92 static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
93 switch (wmtype) {
94 case IDENTITY:
95 wm->wmmat[0] = 0;
96 wm->wmmat[1] = 0;
97 AOM_FALLTHROUGH_INTENDED;
98 case TRANSLATION:
99 wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
100 wm->wmmat[3] = 0;
101 AOM_FALLTHROUGH_INTENDED;
102 case ROTZOOM:
103 wm->wmmat[4] = -wm->wmmat[3];
104 wm->wmmat[5] = wm->wmmat[2];
105 AOM_FALLTHROUGH_INTENDED;
106 case AFFINE: break;
107 default: assert(0);
108 }
109 wm->wmtype = wmtype;
110 }
111
112 #if CONFIG_AV1_HIGHBITDEPTH
generic_sad_highbd(const uint16_t * const ref,int ref_stride,const uint16_t * const dst,int dst_stride,int p_width,int p_height)113 static inline int generic_sad_highbd(const uint16_t *const ref, int ref_stride,
114 const uint16_t *const dst, int dst_stride,
115 int p_width, int p_height) {
116 // This function should only be called for patches smaller than
117 // WARP_ERROR_BLOCK x WARP_ERROR_BLOCK. This keeps the number of pixels
118 // small enough that we don't need a 64-bit accumulator
119 assert(p_width <= WARP_ERROR_BLOCK && p_height <= WARP_ERROR_BLOCK);
120
121 int sad = 0;
122 for (int i = 0; i < p_height; ++i) {
123 for (int j = 0; j < p_width; ++j) {
124 sad += abs(dst[j + i * dst_stride] - ref[j + i * ref_stride]);
125 }
126 }
127 return sad;
128 }
129
130 #if WARP_ERROR_BLOCK != 32
131 #error "Need to change SAD call size in highbd_segmented_frame_error"
132 #endif // WARP_ERROR_BLOCK != 32
highbd_segmented_frame_error(const uint16_t * const ref,int ref_stride,const uint16_t * const dst,int dst_stride,int p_width,int p_height,int bd,uint8_t * segment_map,int segment_map_stride)133 static int64_t highbd_segmented_frame_error(
134 const uint16_t *const ref, int ref_stride, const uint16_t *const dst,
135 int dst_stride, int p_width, int p_height, int bd, uint8_t *segment_map,
136 int segment_map_stride) {
137 (void)bd;
138 int patch_w, patch_h;
139 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
140 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
141 int64_t sum_error = 0;
142 for (int i = 0; i < p_height; i += WARP_ERROR_BLOCK) {
143 for (int j = 0; j < p_width; j += WARP_ERROR_BLOCK) {
144 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
145 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
146 // Only compute the error if this block contains inliers from the motion
147 // model
148 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
149
150 // avoid computing error into the frame padding
151 patch_w = AOMMIN(error_bsize_w, p_width - j);
152 patch_h = AOMMIN(error_bsize_h, p_height - i);
153
154 if (patch_w == WARP_ERROR_BLOCK && patch_h == WARP_ERROR_BLOCK) {
155 sum_error += aom_highbd_sad32x32(
156 CONVERT_TO_BYTEPTR(ref + j + i * ref_stride), ref_stride,
157 CONVERT_TO_BYTEPTR(dst + j + i * dst_stride), dst_stride);
158 } else {
159 sum_error += generic_sad_highbd(ref + j + i * ref_stride, ref_stride,
160 dst + j + i * dst_stride, dst_stride,
161 patch_w, patch_h);
162 }
163 }
164 }
165 return sum_error;
166 }
167
168 #if WARP_ERROR_BLOCK != 32
169 #error "Need to change SAD call size in highbd_warp_error"
170 #endif // WARP_ERROR_BLOCK != 32
highbd_warp_error(WarpedMotionParams * wm,const uint16_t * const ref,int ref_width,int ref_height,int ref_stride,const uint16_t * const dst,int dst_stride,int p_col,int p_row,int p_width,int p_height,int subsampling_x,int subsampling_y,int bd,int64_t best_error,uint8_t * segment_map,int segment_map_stride)171 static int64_t highbd_warp_error(WarpedMotionParams *wm,
172 const uint16_t *const ref, int ref_width,
173 int ref_height, int ref_stride,
174 const uint16_t *const dst, int dst_stride,
175 int p_col, int p_row, int p_width,
176 int p_height, int subsampling_x,
177 int subsampling_y, int bd, int64_t best_error,
178 uint8_t *segment_map, int segment_map_stride) {
179 int64_t gm_sumerr = 0;
180 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
181 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
182 DECLARE_ALIGNED(32, uint16_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
183
184 ConvolveParams conv_params = get_conv_params(0, 0, bd);
185 conv_params.use_dist_wtd_comp_avg = 0;
186 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
187 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
188 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
189 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
190 // Only compute the error if this block contains inliers from the motion
191 // model
192 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
193 // avoid warping extra 8x8 blocks in the padded region of the frame
194 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
195 const int warp_w = AOMMIN(error_bsize_w, p_col + ref_width - j);
196 const int warp_h = AOMMIN(error_bsize_h, p_row + ref_height - i);
197 highbd_warp_plane(wm, ref, ref_width, ref_height, ref_stride, tmp, j, i,
198 warp_w, warp_h, WARP_ERROR_BLOCK, subsampling_x,
199 subsampling_y, bd, &conv_params);
200
201 if (warp_w == WARP_ERROR_BLOCK && warp_h == WARP_ERROR_BLOCK) {
202 gm_sumerr += aom_highbd_sad32x32(
203 CONVERT_TO_BYTEPTR(tmp), WARP_ERROR_BLOCK,
204 CONVERT_TO_BYTEPTR(dst + j + i * dst_stride), dst_stride);
205 } else {
206 gm_sumerr +=
207 generic_sad_highbd(tmp, WARP_ERROR_BLOCK, dst + j + i * dst_stride,
208 dst_stride, warp_w, warp_h);
209 }
210
211 if (gm_sumerr > best_error) return INT64_MAX;
212 }
213 }
214 return gm_sumerr;
215 }
216 #endif
217
generic_sad(const uint8_t * const ref,int ref_stride,const uint8_t * const dst,int dst_stride,int p_width,int p_height)218 static inline int generic_sad(const uint8_t *const ref, int ref_stride,
219 const uint8_t *const dst, int dst_stride,
220 int p_width, int p_height) {
221 // This function should only be called for patches smaller than
222 // WARP_ERROR_BLOCK x WARP_ERROR_BLOCK. This keeps the number of pixels
223 // small enough that we don't need a 64-bit accumulator
224 assert(p_width <= WARP_ERROR_BLOCK && p_height <= WARP_ERROR_BLOCK);
225
226 int sad = 0;
227 for (int i = 0; i < p_height; ++i) {
228 for (int j = 0; j < p_width; ++j) {
229 sad += abs(dst[j + i * dst_stride] - ref[j + i * ref_stride]);
230 }
231 }
232 return sad;
233 }
234
235 #if WARP_ERROR_BLOCK != 32
236 #error "Need to change SAD call size in segmented_warp_error"
237 #endif // WARP_ERROR_BLOCK != 32
segmented_frame_error(const uint8_t * const ref,int ref_stride,const uint8_t * const dst,int dst_stride,int p_width,int p_height,uint8_t * segment_map,int segment_map_stride)238 static int64_t segmented_frame_error(const uint8_t *const ref, int ref_stride,
239 const uint8_t *const dst, int dst_stride,
240 int p_width, int p_height,
241 uint8_t *segment_map,
242 int segment_map_stride) {
243 int patch_w, patch_h;
244 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
245 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
246 int64_t sum_error = 0;
247 for (int i = 0; i < p_height; i += WARP_ERROR_BLOCK) {
248 for (int j = 0; j < p_width; j += WARP_ERROR_BLOCK) {
249 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
250 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
251 // Only compute the error if this block contains inliers from the motion
252 // model
253 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
254
255 // avoid computing error into the frame padding
256 patch_w = AOMMIN(error_bsize_w, p_width - j);
257 patch_h = AOMMIN(error_bsize_h, p_height - i);
258
259 if (patch_w == WARP_ERROR_BLOCK && patch_h == WARP_ERROR_BLOCK) {
260 sum_error += aom_sad32x32(ref + j + i * ref_stride, ref_stride,
261 dst + j + i * dst_stride, dst_stride);
262 } else {
263 sum_error +=
264 generic_sad(ref + j + i * ref_stride, ref_stride,
265 dst + j + i * dst_stride, dst_stride, patch_w, patch_h);
266 }
267 }
268 }
269 return sum_error;
270 }
271
272 #if WARP_ERROR_BLOCK != 32
273 #error "Need to change SAD call size in warp_error"
274 #endif // WARP_ERROR_BLOCK != 32
warp_error(WarpedMotionParams * wm,const uint8_t * const ref,int ref_width,int ref_height,int ref_stride,const uint8_t * const dst,int dst_stride,int p_col,int p_row,int p_width,int p_height,int subsampling_x,int subsampling_y,int64_t best_error,uint8_t * segment_map,int segment_map_stride)275 static int64_t warp_error(WarpedMotionParams *wm, const uint8_t *const ref,
276 int ref_width, int ref_height, int ref_stride,
277 const uint8_t *const dst, int dst_stride, int p_col,
278 int p_row, int p_width, int p_height,
279 int subsampling_x, int subsampling_y,
280 int64_t best_error, uint8_t *segment_map,
281 int segment_map_stride) {
282 int64_t gm_sumerr = 0;
283 int warp_w, warp_h;
284 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
285 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
286 DECLARE_ALIGNED(16, uint8_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
287 ConvolveParams conv_params = get_conv_params(0, 0, 8);
288 conv_params.use_dist_wtd_comp_avg = 0;
289
290 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
291 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
292 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
293 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
294 // Only compute the error if this block contains inliers from the motion
295 // model
296 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
297 // avoid warping extra 8x8 blocks in the padded region of the frame
298 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
299 warp_w = AOMMIN(error_bsize_w, p_col + ref_width - j);
300 warp_h = AOMMIN(error_bsize_h, p_row + ref_height - i);
301 warp_plane(wm, ref, ref_width, ref_height, ref_stride, tmp, j, i, warp_w,
302 warp_h, WARP_ERROR_BLOCK, subsampling_x, subsampling_y,
303 &conv_params);
304
305 if (warp_w == WARP_ERROR_BLOCK && warp_h == WARP_ERROR_BLOCK) {
306 gm_sumerr += aom_sad32x32(tmp, WARP_ERROR_BLOCK,
307 dst + j + i * dst_stride, dst_stride);
308 } else {
309 gm_sumerr +=
310 generic_sad(tmp, WARP_ERROR_BLOCK, dst + j + i * dst_stride,
311 dst_stride, warp_w, warp_h);
312 }
313
314 if (gm_sumerr > best_error) return INT64_MAX;
315 }
316 }
317 return gm_sumerr;
318 }
319
av1_segmented_frame_error(int use_hbd,int bd,const uint8_t * ref,int ref_stride,uint8_t * dst,int dst_stride,int p_width,int p_height,uint8_t * segment_map,int segment_map_stride)320 int64_t av1_segmented_frame_error(int use_hbd, int bd, const uint8_t *ref,
321 int ref_stride, uint8_t *dst, int dst_stride,
322 int p_width, int p_height,
323 uint8_t *segment_map,
324 int segment_map_stride) {
325 #if CONFIG_AV1_HIGHBITDEPTH
326 if (use_hbd) {
327 return highbd_segmented_frame_error(
328 CONVERT_TO_SHORTPTR(ref), ref_stride, CONVERT_TO_SHORTPTR(dst),
329 dst_stride, p_width, p_height, bd, segment_map, segment_map_stride);
330 }
331 #endif
332 (void)use_hbd;
333 (void)bd;
334 return segmented_frame_error(ref, ref_stride, dst, dst_stride, p_width,
335 p_height, segment_map, segment_map_stride);
336 }
337
338 // Returns the error between the result of applying motion 'wm' to the frame
339 // described by 'ref' and the frame described by 'dst'.
get_warp_error(WarpedMotionParams * wm,int use_hbd,int bd,const uint8_t * ref,int ref_width,int ref_height,int ref_stride,uint8_t * dst,int dst_stride,int p_col,int p_row,int p_width,int p_height,int subsampling_x,int subsampling_y,int64_t best_error,uint8_t * segment_map,int segment_map_stride)340 static int64_t get_warp_error(WarpedMotionParams *wm, int use_hbd, int bd,
341 const uint8_t *ref, int ref_width, int ref_height,
342 int ref_stride, uint8_t *dst, int dst_stride,
343 int p_col, int p_row, int p_width, int p_height,
344 int subsampling_x, int subsampling_y,
345 int64_t best_error, uint8_t *segment_map,
346 int segment_map_stride) {
347 if (!av1_get_shear_params(wm)) return INT64_MAX;
348 #if CONFIG_AV1_HIGHBITDEPTH
349 if (use_hbd)
350 return highbd_warp_error(wm, CONVERT_TO_SHORTPTR(ref), ref_width,
351 ref_height, ref_stride, CONVERT_TO_SHORTPTR(dst),
352 dst_stride, p_col, p_row, p_width, p_height,
353 subsampling_x, subsampling_y, bd, best_error,
354 segment_map, segment_map_stride);
355 #endif
356 (void)use_hbd;
357 (void)bd;
358 return warp_error(wm, ref, ref_width, ref_height, ref_stride, dst, dst_stride,
359 p_col, p_row, p_width, p_height, subsampling_x,
360 subsampling_y, best_error, segment_map, segment_map_stride);
361 }
362
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 ref_frame_error,uint8_t * segment_map,int segment_map_stride)363 int64_t av1_refine_integerized_param(
364 WarpedMotionParams *wm, TransformationType wmtype, int use_hbd, int bd,
365 uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst,
366 int d_width, int d_height, int d_stride, int n_refinements,
367 int64_t ref_frame_error, uint8_t *segment_map, int segment_map_stride) {
368 static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
369 const int border = ERRORADV_BORDER;
370 int i = 0, p;
371 int n_params = max_trans_model_params[wmtype];
372 int32_t *param_mat = wm->wmmat;
373 int64_t step_error, best_error;
374 int32_t step;
375 int32_t *param;
376 int32_t curr_param;
377 int32_t best_param;
378
379 force_wmtype(wm, wmtype);
380 wm->wmtype = get_wmtype(wm);
381
382 if (n_refinements == 0) {
383 // Compute the maximum error value that will be accepted, so that
384 // get_warp_error can terminate early if it proves the model will not
385 // be accepted.
386 int64_t selection_threshold = (int64_t)lrint(ref_frame_error * erroradv_tr);
387 return get_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
388 dst + border * d_stride + border, d_stride, border,
389 border, d_width - 2 * border, d_height - 2 * border,
390 0, 0, selection_threshold, segment_map,
391 segment_map_stride);
392 }
393
394 // When refining, use a slightly higher threshold for the initial error
395 // calculation - see comment above erroradv_early_tr for why.
396 int64_t selection_threshold =
397 (int64_t)lrint(ref_frame_error * erroradv_early_tr);
398 best_error =
399 get_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
400 dst + border * d_stride + border, d_stride, border, border,
401 d_width - 2 * border, d_height - 2 * border, 0, 0,
402 selection_threshold, segment_map, segment_map_stride);
403
404 if (best_error > selection_threshold) {
405 return INT64_MAX;
406 }
407
408 step = 1 << (n_refinements - 1);
409 for (i = 0; i < n_refinements; i++, step >>= 1) {
410 for (p = 0; p < n_params; ++p) {
411 int step_dir = 0;
412 param = param_mat + p;
413 curr_param = *param;
414 best_param = curr_param;
415 // look to the left
416 // Note: We have to use force_wmtype() to keep the proper symmetry for
417 // ROTZOOM type models
418 *param = add_param_offset(p, curr_param, -step);
419 force_wmtype(wm, wmtype);
420 step_error =
421 get_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
422 dst + border * d_stride + border, d_stride, border,
423 border, d_width - 2 * border, d_height - 2 * border, 0,
424 0, best_error, segment_map, segment_map_stride);
425 if (step_error < best_error) {
426 best_error = step_error;
427 best_param = *param;
428 step_dir = -1;
429 }
430
431 // look to the right
432 *param = add_param_offset(p, curr_param, step);
433 force_wmtype(wm, wmtype);
434 step_error =
435 get_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
436 dst + border * d_stride + border, d_stride, border,
437 border, d_width - 2 * border, d_height - 2 * border, 0,
438 0, best_error, segment_map, segment_map_stride);
439 if (step_error < best_error) {
440 best_error = step_error;
441 best_param = *param;
442 step_dir = 1;
443 }
444
445 // look to the direction chosen above repeatedly until error increases
446 // for the biggest step size
447 while (step_dir) {
448 *param = add_param_offset(p, best_param, step * step_dir);
449 force_wmtype(wm, wmtype);
450 step_error =
451 get_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
452 dst + border * d_stride + border, d_stride, border,
453 border, d_width - 2 * border, d_height - 2 * border,
454 0, 0, best_error, segment_map, segment_map_stride);
455 if (step_error < best_error) {
456 best_error = step_error;
457 best_param = *param;
458 } else {
459 step_dir = 0;
460 }
461 }
462
463 // Restore best parameter value so far
464 *param = best_param;
465 force_wmtype(wm, wmtype);
466 }
467 }
468
469 wm->wmtype = get_wmtype(wm);
470 // Recompute shear params for the refined model
471 // This should never fail, because we only ever consider warp-able models
472 if (!av1_get_shear_params(wm)) {
473 assert(0);
474 }
475 return best_error;
476 }
477
478 #define FEAT_COUNT_TR 3
479 #define SEG_COUNT_TR 48
av1_compute_feature_segmentation_map(uint8_t * segment_map,int width,int height,int * inliers,int num_inliers)480 void av1_compute_feature_segmentation_map(uint8_t *segment_map, int width,
481 int height, int *inliers,
482 int num_inliers) {
483 int seg_count = 0;
484 memset(segment_map, 0, sizeof(*segment_map) * width * height);
485
486 for (int i = 0; i < num_inliers; i++) {
487 int x = inliers[i * 2];
488 int y = inliers[i * 2 + 1];
489 int seg_x = x >> WARP_ERROR_BLOCK_LOG;
490 int seg_y = y >> WARP_ERROR_BLOCK_LOG;
491 segment_map[seg_y * width + seg_x] += 1;
492 }
493
494 for (int i = 0; i < height; i++) {
495 for (int j = 0; j < width; j++) {
496 uint8_t feat_count = segment_map[i * width + j];
497 segment_map[i * width + j] = (feat_count >= FEAT_COUNT_TR);
498 seg_count += (segment_map[i * width + j]);
499 }
500 }
501
502 // If this motion does not make up a large enough portion of the frame,
503 // use the unsegmented version of the error metric
504 if (seg_count < SEG_COUNT_TR)
505 memset(segment_map, 1, width * height * sizeof(*segment_map));
506 }
507