LCOV - code coverage report
Current view: top level - Codec - global_motion.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 127 142 89.4 %
Date: 2019-11-25 17:38:06 Functions: 10 10 100.0 %

          Line data    Source code
       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 "global_motion.h"
      21             : 
      22             : //#include "segmentation.h"
      23             : #include "corner_detect.h"
      24             : #include "corner_match.h"
      25             : #include "ransac.h"
      26             : 
      27             : #include "EbWarpedMotion.h"
      28             : 
      29             : #define MIN_INLIER_PROB 0.1
      30             : 
      31             : #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
      32             : 
      33             : // Border over which to compute the global motion
      34             : #define ERRORADV_BORDER 0
      35             : 
      36             : // TODO(sarahparker) These need to be retuned for speed 0 and 1 to
      37             : // maximize gains from segmented error metric
      38             : static const double erroradv_tr[] = { 0.65, 0.60, 0.65 };
      39             : static const double erroradv_prod_tr[] = { 20000, 18000, 16000 };
      40             : 
      41         113 : int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost,
      42             :                                  int erroradv_type) {
      43         113 :   assert(erroradv_type < GM_ERRORADV_TR_TYPES);
      44         226 :   return best_erroradvantage < erroradv_tr[erroradv_type] &&
      45         113 :          best_erroradvantage * params_cost < erroradv_prod_tr[erroradv_type];
      46             : }
      47             : 
      48        2173 : static void convert_to_params(const double *params, int32_t *model) {
      49             :   int i;
      50        2173 :   int alpha_present = 0;
      51        2173 :   model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
      52        2173 :   model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
      53        2173 :   model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
      54             :              GM_TRANS_DECODE_FACTOR;
      55        2173 :   model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
      56             :              GM_TRANS_DECODE_FACTOR;
      57             : 
      58       10865 :   for (i = 2; i < 6; ++i) {
      59        8692 :     const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
      60        8692 :     model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
      61       17384 :     model[i] =
      62        8692 :         (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
      63        8692 :     alpha_present |= (model[i] != 0);
      64        8692 :     model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
      65             :   }
      66        6519 :   for (; i < 8; ++i) {
      67        4346 :     model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
      68        4346 :     model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
      69             :                GM_ROW3HOMO_DECODE_FACTOR;
      70        4346 :     alpha_present |= (model[i] != 0);
      71             :   }
      72             : 
      73        2173 :   if (!alpha_present) {
      74           0 :     if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
      75           0 :       model[0] = 0;
      76           0 :       model[1] = 0;
      77             :     }
      78             :   }
      79        2173 : }
      80             : 
      81             : 
      82        4346 : static INLINE TransformationType get_wmtype(const EbWarpedMotionParams *gm) {
      83        4346 :   if (gm->wmmat[5] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[4] &&
      84           0 :       gm->wmmat[2] == (1 << WARPEDMODEL_PREC_BITS) && !gm->wmmat[3]) {
      85           0 :     return ((!gm->wmmat[1] && !gm->wmmat[0]) ? IDENTITY : TRANSLATION);
      86             :   }
      87        4346 :   if (gm->wmmat[2] == gm->wmmat[5] && gm->wmmat[3] == -gm->wmmat[4])
      88        4346 :     return ROTZOOM;
      89             :   else
      90           0 :     return AFFINE;
      91             : }
      92             : 
      93        2173 : void av1_convert_model_to_params(const double *params,
      94             :                                  EbWarpedMotionParams *model) {
      95        2173 :   convert_to_params(params, model->wmmat);
      96        2173 :   model->wmtype = get_wmtype(model);
      97        2173 :   model->invalid = 0;
      98        2173 : }
      99             : 
     100             : // Adds some offset to a global motion parameter and handles
     101             : // all of the necessary precision shifts, clamping, and
     102             : // zero-centering.
     103       89060 : static int32_t add_param_offset(int param_index, int32_t param_value,
     104             :                                 int32_t offset) {
     105       89060 :   const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
     106             :                               GM_ROW3HOMO_PREC_DIFF };
     107       89060 :   const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
     108             :   // type of param: 0 - translation, 1 - affine, 2 - homography
     109       89060 :   const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
     110       89060 :   const int is_one_centered = (param_index == 2 || param_index == 5);
     111             : 
     112             :   // Make parameter zero-centered and offset the shift that was done to make
     113             :   // it compatible with the warped model
     114       89060 :   param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
     115       89060 :                 scale_vals[param_type];
     116             :   // Add desired offset to the rescaled/zero-centered parameter
     117       89060 :   param_value += offset;
     118             :   // Clamp the parameter so it does not overflow the number of bits allotted
     119             :   // to it in the bitstream
     120       89060 :   param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
     121             :                                clamp_vals[param_type]);
     122             :   // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
     123             :   // with the warped motion library
     124       89060 :   param_value *= (1 << scale_vals[param_type]);
     125             : 
     126             :   // Undo the zero-centering step if necessary
     127       89060 :   return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
     128             : }
     129             : 
     130        4346 : static void force_wmtype(EbWarpedMotionParams *wm, TransformationType wmtype) {
     131        4346 :   switch (wmtype) {
     132           0 :     case IDENTITY:
     133           0 :       wm->wmmat[0] = 0;
     134           0 :       wm->wmmat[1] = 0;
     135             :       AOM_FALLTHROUGH_INTENDED;
     136           0 :     case TRANSLATION:
     137           0 :       wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
     138           0 :       wm->wmmat[3] = 0;
     139             :       AOM_FALLTHROUGH_INTENDED;
     140        4346 :     case ROTZOOM:
     141        4346 :       wm->wmmat[4] = -wm->wmmat[3];
     142        4346 :       wm->wmmat[5] = wm->wmmat[2];
     143             :       AOM_FALLTHROUGH_INTENDED;
     144        4346 :     case AFFINE: wm->wmmat[6] = wm->wmmat[7] = 0; break;
     145           0 :     default: assert(0);
     146             :   }
     147        4346 :   wm->wmtype = wmtype;
     148        4346 : }
     149             : 
     150        2173 : int64_t av1_refine_integerized_param(
     151             :     EbWarpedMotionParams *wm, TransformationType wmtype, int use_hbd, int bd,
     152             :     uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst,
     153             :     int d_width, int d_height, int d_stride, int n_refinements,
     154             :     int64_t best_frame_error) {
     155             :   static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
     156        2173 :   const int border = ERRORADV_BORDER;
     157        2173 :   int i = 0, p;
     158        2173 :   int n_params = max_trans_model_params[wmtype];
     159        2173 :   int32_t *param_mat = wm->wmmat;
     160             :   int64_t step_error, best_error;
     161             :   int32_t step;
     162             :   int32_t *param;
     163             :   int32_t curr_param;
     164             :   int32_t best_param;
     165             : 
     166        2173 :   force_wmtype(wm, wmtype);
     167             :   best_error =
     168        2173 :       eb_av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
     169        2173 :                      dst + border * d_stride + border, border, border,
     170        2173 :                      d_width - 2 * border, d_height - 2 * border, d_stride, 0,
     171             :                      0, best_frame_error);
     172        2173 :   best_error = AOMMIN(best_error, best_frame_error);
     173        2173 :   step = 1 << (n_refinements - 1);
     174       13038 :   for (i = 0; i < n_refinements; i++, step >>= 1) {
     175       54325 :     for (p = 0; p < n_params; ++p) {
     176       43460 :       int step_dir = 0;
     177             :       // Skip searches for parameters that are forced to be 0
     178       43460 :       param = param_mat + p;
     179       43460 :       curr_param = *param;
     180       43460 :       best_param = curr_param;
     181             :       // look to the left
     182       43460 :       *param = add_param_offset(p, curr_param, -step);
     183             :       step_error =
     184       43460 :           eb_av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
     185       43460 :                          dst + border * d_stride + border, border, border,
     186       43460 :                          d_width - 2 * border, d_height - 2 * border, d_stride,
     187             :                          0, 0, best_error);
     188       43460 :       if (step_error < best_error) {
     189         753 :         best_error = step_error;
     190         753 :         best_param = *param;
     191         753 :         step_dir = -1;
     192             :       }
     193             : 
     194             :       // look to the right
     195       43460 :       *param = add_param_offset(p, curr_param, step);
     196             :       step_error =
     197       43460 :           eb_av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
     198       43460 :                          dst + border * d_stride + border, border, border,
     199       43460 :                          d_width - 2 * border, d_height - 2 * border, d_stride,
     200             :                          0, 0, best_error);
     201       43460 :       if (step_error < best_error) {
     202         835 :         best_error = step_error;
     203         835 :         best_param = *param;
     204         835 :         step_dir = 1;
     205             :       }
     206       43460 :       *param = best_param;
     207             : 
     208             :       // look to the direction chosen above repeatedly until error increases
     209             :       // for the biggest step size
     210       45600 :       while (step_dir) {
     211        2140 :         *param = add_param_offset(p, best_param, step * step_dir);
     212        2140 :         step_error = eb_av1_warp_error(
     213             :             wm, use_hbd, bd, ref, r_width, r_height, r_stride,
     214        2140 :             dst + border * d_stride + border, border, border,
     215        2140 :             d_width - 2 * border, d_height - 2 * border, d_stride, 0, 0,
     216             :             best_error);
     217        2140 :         if (step_error < best_error) {
     218         552 :           best_error = step_error;
     219         552 :           best_param = *param;
     220             :         } else {
     221        1588 :           *param = best_param;
     222        1588 :           step_dir = 0;
     223             :         }
     224             :       }
     225             :     }
     226             :   }
     227        2173 :   force_wmtype(wm, wmtype);
     228        2173 :   wm->wmtype = get_wmtype(wm);
     229        2173 :   return best_error;
     230             : }
     231             : 
     232             : 
     233        2173 : static void get_inliers_from_indices(MotionModel *params,
     234             :                                      int *correspondences) {
     235        2173 :   int *inliers_tmp = (int *)eb_aom_malloc(2 * MAX_CORNERS * sizeof(*inliers_tmp));
     236        2173 :   memset(inliers_tmp, 0, 2 * MAX_CORNERS * sizeof(*inliers_tmp));
     237             : 
     238     4715300 :   for (int i = 0; i < params->num_inliers; i++) {
     239     4713120 :     int index = params->inliers[i];
     240     4713120 :     inliers_tmp[2 * i] = correspondences[4 * index];
     241     4713120 :     inliers_tmp[2 * i + 1] = correspondences[4 * index + 1];
     242             :   }
     243        2173 :   memcpy(params->inliers, inliers_tmp, sizeof(*inliers_tmp) * 2 * MAX_CORNERS);
     244        2173 :   eb_aom_free(inliers_tmp);
     245        2173 : }
     246             : 
     247             : 
     248         113 : static int compute_global_motion_feature_based(
     249             :     TransformationType type, unsigned char *frm_buffer, int frm_width,
     250             :     int frm_height, int frm_stride, int *frm_corners, int num_frm_corners,
     251             :     uint8_t *ref, int ref_stride, int bit_depth, int *num_inliers_by_motion,
     252             :     MotionModel *params_by_motion, int num_motions) {
     253             :   (void)bit_depth;
     254         113 :   assert(bit_depth == EB_8BIT);
     255             :   int i;
     256             :   int num_ref_corners;
     257             :   int num_correspondences;
     258             :   int *correspondences;
     259             :   int ref_corners[2 * MAX_CORNERS];
     260         113 :   unsigned char *ref_buffer = ref;
     261         113 :   RansacFunc ransac = av1_get_ransac_type(type);
     262             : 
     263             :   num_ref_corners =
     264         113 :       av1_fast_corner_detect(ref_buffer, frm_width, frm_height,
     265             :                              ref_stride, ref_corners, MAX_CORNERS);
     266             : 
     267             :   // find correspondences between the two images
     268             :   correspondences =
     269         113 :       (int *)malloc(num_frm_corners * 4 * sizeof(*correspondences));
     270         113 :   num_correspondences = av1_determine_correspondence(
     271             :       frm_buffer, (int *)frm_corners, num_frm_corners, ref_buffer,
     272             :       (int *)ref_corners, num_ref_corners, frm_width, frm_height, frm_stride,
     273             :       ref_stride, correspondences);
     274             : 
     275         113 :   ransac(correspondences, num_correspondences, num_inliers_by_motion,
     276             :          params_by_motion, num_motions);
     277             : 
     278             :   // Set num_inliers = 0 for motions with too few inliers so they are ignored.
     279       11413 :   for (i = 0; i < num_motions; ++i) {
     280       11300 :     if (num_inliers_by_motion[i] < MIN_INLIER_PROB * num_correspondences ||
     281             :         num_correspondences == 0) {
     282        9127 :       num_inliers_by_motion[i] = 0;
     283             :     } else {
     284        2173 :       get_inliers_from_indices(&params_by_motion[i], correspondences);
     285             :     }
     286             :   }
     287             : 
     288         113 :   free(correspondences);
     289             : 
     290             :   // Return true if any one of the motions has inliers.
     291         113 :   for (i = 0; i < num_motions; ++i) {
     292         113 :     if (num_inliers_by_motion[i] > 0) return 1;
     293             :   }
     294           0 :   return 0;
     295             : }
     296             : 
     297             : 
     298         113 : int av1_compute_global_motion(TransformationType type,
     299             :                               unsigned char *frm_buffer, int frm_width,
     300             :                               int frm_height, int frm_stride, int *frm_corners,
     301             :                               int num_frm_corners, uint8_t *ref, int ref_stride,
     302             :                               int bit_depth,
     303             :                               GlobalMotionEstimationType gm_estimation_type,
     304             :                               int *num_inliers_by_motion,
     305             :                               MotionModel *params_by_motion, int num_motions) {
     306         113 :   switch (gm_estimation_type) {
     307         113 :     case GLOBAL_MOTION_FEATURE_BASED:
     308         113 :       return compute_global_motion_feature_based(
     309             :           type, frm_buffer, frm_width, frm_height, frm_stride, frm_corners,
     310             :           num_frm_corners, ref, ref_stride, bit_depth, num_inliers_by_motion,
     311             :           params_by_motion, num_motions);
     312           0 :     default: assert(0 && "Unknown global motion estimation type");
     313             :   }
     314             :   return 0;
     315             : }

Generated by: LCOV version 1.14