vpx/vp9/common/vp9_motion_model.c
Geza Lore 6d9bec4366 Configure tiles in tests when using row-tile.
With row-tile enabled, the encoder test driver needs to configure the
decoder in order to decode all tiles correctly.

Change-Id: I8b00a766cf5e41255625846f92fd71915c614ec1
2016-05-03 14:42:17 -07:00

387 lines
13 KiB
C

/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be
* found in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
#include "vp9/common/vp9_common_data.h"
#include "vp9/common/vp9_mv.h"
#include "vp9/common/vp9_motion_model.h"
inline projectPointsType get_projectPointsType(TransformationType type) {
switch (type) {
case HOMOGRAPHY:
return projectPointsHomography;
case AFFINE:
return projectPointsAffine;
case ROTZOOM:
return projectPointsRotZoom;
case TRANSLATION:
return projectPointsTranslation;
default:
assert(0);
return NULL;
}
}
void projectPointsTranslation(double *mat, double *points, double *proj,
const int n,
const int stride_points,
const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = x + mat[0];
*(proj++) = y + mat[1];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsRotZoom(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = mat[0] * x + mat[1] * y + mat[2];
*(proj++) = -mat[1] * x + mat[0] * y + mat[3];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsAffine(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = mat[0] * x + mat[1] * y + mat[4];
*(proj++) = mat[2] * x + mat[3] * y + mat[5];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsHomography(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
double x, y, Z;
for (i = 0; i < n; ++i) {
x = *(points++), y = *(points++);
Z = 1. / (mat[6] * x + mat[7] * y + mat[8]);
*(proj++) = (mat[0] * x + mat[1] * y + mat[2]) * Z;
*(proj++) = (mat[3] * x + mat[4] * y + mat[5]) * Z;
points += stride_points - 2;
proj += stride_proj - 2;
}
}
#define clip_pixel(v) ((v) < 0 ? 0 : ((v) > 255 ? 255 : (v)))
double getCubicValue(double p[4], double x) {
return p[1] + 0.5 * x * (p[2] - p[0]
+ x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3]
+ x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
}
void get_subcolumn(unsigned char *ref, double col[4],
int stride, int x, int y_start) {
int i;
for (i = 0; i < 4; ++i) {
col[i] = ref[(i + y_start) * stride + x];
}
}
double bicubic(unsigned char *ref, double x, double y, int stride) {
double arr[4];
int k;
int i = (int) x;
int j = (int) y;
for (k = 0; k < 4; ++k) {
double arr_temp[4];
get_subcolumn(ref, arr_temp, stride, i + k - 1, j - 1);
arr[k] = getCubicValue(arr_temp, y - j);
}
return getCubicValue(arr, x - i);
}
unsigned char interpolate(unsigned char *ref, double x, double y,
int width, int height, int stride) {
if (x < 0 && y < 0) return ref[0];
else if (x < 0 && y > height - 1)
return ref[(height - 1) * stride];
else if (x > width - 1 && y < 0)
return ref[width - 1];
else if (x > width - 1 && y > height - 1)
return ref[(height - 1) * stride + (width - 1)];
else if (x < 0) {
int v;
int i = (int) y;
double a = y - i;
if (y > 1 && y < height - 2) {
double arr[4];
get_subcolumn(ref, arr, stride, 0, i - 1);
return clip_pixel(getCubicValue(arr, a));
}
v = (int)(ref[i * stride] * (1 - a) + ref[(i + 1) * stride] * a + 0.5);
return clip_pixel(v);
} else if (y < 0) {
int v;
int j = (int) x;
double b = x - j;
if (x > 1 && x < width - 2) {
double arr[4] = {ref[j - 1], ref[j], ref[j + 1], ref[j + 2]};
return clip_pixel(getCubicValue(arr, b));
}
v = (int)(ref[j] * (1 - b) + ref[j + 1] * b + 0.5);
return clip_pixel(v);
} else if (x > width - 1) {
int v;
int i = (int) y;
double a = y - i;
if (y > 1 && y < height - 2) {
double arr[4];
get_subcolumn(ref, arr, stride, width - 1, i - 1);
return clip_pixel(getCubicValue(arr, a));
}
v = (int)(ref[i * stride + width - 1] * (1 - a) +
ref[(i + 1) * stride + width - 1] * a + 0.5);
return clip_pixel(v);
} else if (y > height - 1) {
int v;
int j = (int) x;
double b = x - j;
if (x > 1 && x < width - 2) {
int row = (height - 1) * stride;
double arr[4] = {ref[row + j - 1], ref[row + j],
ref[row + j + 1], ref[row + j + 2]};
return clip_pixel(getCubicValue(arr, b));
}
v = (int)(ref[(height - 1) * stride + j] * (1 - b) +
ref[(height - 1) * stride + j + 1] * b + 0.5);
return clip_pixel(v);
} else if (x > 1 && y > 1 && x < width -2 && y < height -2) {
return clip_pixel(bicubic(ref, x, y, stride));
} else {
int i = (int) y;
int j = (int) x;
double a = y - i;
double b = x - j;
int v = (int)(ref[i * stride + j] * (1 - a) * (1 - b) +
ref[i * stride + j + 1] * (1 - a) * b +
ref[(i + 1) * stride + j] * a * (1 - b) +
ref[(i + 1) * stride + j + 1] * a * b);
return clip_pixel(v);
}
}
static void WarpImage(TransformationType type, double *H,
unsigned char *ref,
int width, int height, int stride,
unsigned char *pred,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
int i, j;
projectPointsType projectPoints = get_projectPointsType(type);
if (projectPoints == NULL)
return;
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2];
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred[(j - p_col) + (i - p_row) * p_stride] =
interpolate(ref, out[0], out[1], width, height, stride);
}
}
}
double compute_warp_and_error(Global_Motion_Params *gm,
projectPointsType projectPoints,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
int i, j;
int64_t sumerr = 0;
if (projectPoints == NULL)
return -1;
vp9_convert_params_to_rotzoom(gm, H);
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2];
uint8_t pred;
int err;
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred = interpolate(ref, out[0], out[1], width, height, stride);
err = pred - src[(j - p_col) + (i - p_row) * p_stride];
sumerr += err * err;
}
}
return sumerr/(width * height);
}
// Computes the ratio of the warp error to the zero motion error
double vp9_warp_erroradv_unq(TransformationType type, double *H,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H_z_translation[] = {0, 0};
double H_z_rotzoom[] = {1, 0, 0, 0};
double H_z_affine[] = {1, 0, 0, 1, 0, 0};
double H_z_homography[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
double *H_z = H_z_rotzoom;
int i, j;
int64_t sumerr = 0;
int64_t sumerr_z = 0;
projectPointsType projectPoints = get_projectPointsType(type);
if (type == TRANSLATION)
H_z = H_z_translation;
else if (type == ROTZOOM)
H_z = H_z_rotzoom;
else if (type == AFFINE)
H_z = H_z_affine;
else if (type == HOMOGRAPHY)
H_z = H_z_homography;
else
assert(0 && "Unknown TransformationType");
if (projectPoints == NULL)
return -1;
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2], out_z[2];
uint8_t pred, pred_z;
int err, err_z;
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred = interpolate(ref, out[0], out[1], width, height, stride);
err = pred - src[(j - p_col) + (i - p_row) * p_stride];
sumerr += err * err;
projectPoints(H_z, in, out_z, 1, 2, 2);
out_z[0] = subsampling_col ? (out_z[0] - 0.5) / 2.0 : out_z[0];
out_z[1] = subsampling_row ? (out_z[1] - 0.5) / 2.0 : out_z[1];
out_z[0] *= x_scale / 16.0;
out_z[1] *= y_scale / 16.0;
pred_z = interpolate(ref, out_z[0], out_z[1], width, height, stride);
err_z = pred_z - src[(j - p_col) + (i - p_row) * p_stride];
sumerr_z += err_z * err_z;
}
}
return (double)sumerr / sumerr_z;
}
void vp9_convert_params_to_rotzoom(Global_Motion_Params *model,
double *H) {
double z = (double) model->zoom / (1 << ZOOM_PRECISION_BITS);
double r = (double) model->rotation / (1 << ROTATION_PRECISION_BITS);
H[0] = (1 + z) * cos(r * M_PI / 180.0);
H[1] = -(1 + z) * sin(r * M_PI / 180.0);
H[2] = (double) model->mv.as_mv.col / 8.0;
H[3] = (double) model->mv.as_mv.row / 8.0;
}
void vp9_warp_plane(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *pred,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
vp9_convert_params_to_rotzoom(gm, H);
WarpImage(ROTZOOM, H,
ref, width, height, stride,
pred, p_col, p_row, p_width, p_height, p_stride,
subsampling_col, subsampling_row,
x_scale, y_scale);
}
double vp9_warp_erroradv(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
vp9_convert_params_to_rotzoom(gm, H);
return vp9_warp_erroradv_unq(ROTZOOM, H,
ref, width, height, stride,
src, p_col, p_row, p_width, p_height, p_stride,
subsampling_col, subsampling_row,
x_scale, y_scale);
}
static int_mv vp9_get_global_mv(int col, int row, Global_Motion_Params *model) {
int_mv mv;
double H[4];
double x, y;
vp9_convert_params_to_rotzoom(model, H);
x = H[0] * col + H[1] * row + H[2];
y = -H[1] * col + H[0] * row + H[3];
mv.as_mv.col = (int)floor(x * 8 + 0.5) - col;
mv.as_mv.row = (int)floor(y * 8 + 0.5) - row;
return mv;
}
int_mv vp9_get_global_sb_center_mv(int col, int row, int bw, int bh,
Global_Motion_Params *model) {
col += bw / 2;
row += bh / 2;
return vp9_get_global_mv(col, row, model);
}
int_mv vp9_get_global_sub8x8_center_mv(int col, int row, int block,
Global_Motion_Params *model) {
if (block == 0 || block == 2)
col += 2;
else
col += 6;
if (block == 0 || block == 1)
row += 2;
else
row += 6;
return vp9_get_global_mv(col, row, model);
}