Global motion experiment

Added a function to compute a motion field for a pair of buffers, for use in
finding an affine transform or homography.

Change-Id: Id5169cc811a61037e877dfd57fccaca89d93936f
This commit is contained in:
Spencer Egart 2015-02-04 11:43:39 -08:00
parent 2aef964519
commit edffe3f956
4 changed files with 346 additions and 8 deletions

1
configure vendored
View File

@ -291,6 +291,7 @@ EXPERIMENT_LIST="
interintra
wedge_partition
compound_modes
global_motion
"
CONFIG_LIST="
external_build

View File

@ -0,0 +1,308 @@
/*
* Copyright (c) 2010 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 <limits.h>
#include "vpx_mem/vpx_mem.h"
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_mcomp.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/encoder/vp9_global_motion.h"
static unsigned int do_motion_iteration(VP9_COMP *cpi,
const MV *ref_mv,
MV *dst_mv,
int bsize,
int mb_row,
int mb_col,
unsigned int *sse) {
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
PREDICTION_MODE tmp_mode = xd->mi[0].src_mi->mbmi.mode;
MV tmp_mv = xd->mi[0].src_mi->mbmi.mv[0].as_mv;
int tmp_frame = xd->mi[0].src_mi->mbmi.ref_frame[1];
struct macroblockd_plane *const tmp_pd = &xd->plane[0];
struct macroblockd_plane otherpd;
const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv;
const int tmp_col_min = x->mv_col_min;
const int tmp_col_max = x->mv_col_max;
const int tmp_row_min = x->mv_row_min;
const int tmp_row_max = x->mv_row_max;
MV ref_full;
int cost_list[5];
int sad = INT32_MAX;
uint8_t tmpbuf[4096];
BLOCK_SIZE block = bsize == 16 ? BLOCK_16X16 : BLOCK_8X8;
const vp9_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[block];
// Further step/diamond searches as necessary
int step_param = mv_sf->reduce_first_step_size;
step_param = MIN(step_param, MAX_MVSEARCH_STEPS - 2);
otherpd.dst.buf = tmpbuf;
xd->plane[0] = otherpd;
vp9_set_mv_search_range(x, ref_mv);
ref_full.col = ref_mv->col >> 3;
ref_full.row = ref_mv->row >> 3;
/*cpi->sf.search_method == HEX*/
vp9_hex_search(x, &ref_full, step_param, x->errorperbit, 0,
cond_cost_list(cpi, cost_list),
&v_fn_ptr, 0, ref_mv, dst_mv);
// Try sub-pixel MC
// if (bestsme > error_thresh && bestsme < INT_MAX)
{
int distortion;
unsigned int sse;
cpi->find_fractional_mv_step(
x, dst_mv, ref_mv, cpi->common.allow_high_precision_mv, x->errorperbit,
&v_fn_ptr, 0, mv_sf->subpel_iters_per_step,
cond_cost_list(cpi, cost_list),
NULL, NULL,
&distortion, &sse, NULL, 0, 0);
}
#if CONFIG_COMPOUND_MODES
if (has_second_ref(&xd->mi[0].src_mi->mbmi)) {
xd->mi[0].src_mi->mbmi.mode = NEW_NEWMV;
} else {
#endif
xd->mi[0].src_mi->mbmi.mode = NEWMV;
#if CONFIG_COMPOUND_MODES
}
#endif
xd->mi[0].src_mi->mbmi.mv[0].as_mv = *dst_mv;
#if CONFIG_INTERINTRA
xd->mi[0].src_mi->mbmi.ref_frame[1] = NONE;
#endif
vp9_build_inter_predictors_sby(xd, mb_row, mb_col, block);
/* restore UMV window */
x->mv_col_min = tmp_col_min;
x->mv_col_max = tmp_col_max;
x->mv_row_min = tmp_row_min;
x->mv_row_max = tmp_row_max;
if (bsize == 16) {
sad = vp9_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
vp9_variance16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride, sse);
} else if (bsize == 8) {
sad = vp9_sad8x8(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride);
vp9_variance8x8(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].dst.buf, xd->plane[0].dst.stride, sse);
}
xd->mi[0].src_mi->mbmi.mode = tmp_mode;
xd->mi[0].src_mi->mbmi.mv[0].as_mv = tmp_mv;
xd->mi[0].src_mi->mbmi.ref_frame[1] = tmp_frame;
xd->plane[0] = *tmp_pd;
return sad;
}
static int do_motion_search(VP9_COMP *cpi, const MV *ref_mv, int bsize,
int_mv *dst_mv, int mb_row, int mb_col,
unsigned int *sse) {
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
unsigned int err, tmp_err;
MV tmp_mv;
// Try zero MV first
// FIXME should really use something like near/nearest MV and/or MV prediction
if (bsize == 16) {
err = vp9_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
} else {
err = vp9_sad8x8(x->plane[0].src.buf, x->plane[0].src.stride,
xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride);
}
dst_mv->as_int = 0;
// Test last reference frame using the previous best mv as the
// starting point (best reference) for the search
tmp_err = do_motion_iteration(cpi, ref_mv, &tmp_mv,
bsize, mb_row, mb_col, sse);
if (tmp_err < err) {
err = tmp_err;
dst_mv->as_mv = tmp_mv;
}
// If the current best reference mv is not centered on 0,0 then do a 0,0
// based search as well.
if (ref_mv->row != 0 || ref_mv->col != 0) {
unsigned int tmp_err;
MV zero_ref_mv = {0, 0}, tmp_mv;
tmp_err = do_motion_iteration(cpi, &zero_ref_mv, &tmp_mv, bsize,
mb_row, mb_col, sse);
if (tmp_err < err) {
dst_mv->as_mv = tmp_mv;
err = tmp_err;
}
}
return err;
}
static void get_mb_motionfield(VP9_COMP *cpi,
YV12_BUFFER_CONFIG *buf,
int mb_y_offset,
YV12_BUFFER_CONFIG *ref,
const MV *prev_ref_mv,
int bsize,
int mb_row,
int mb_col,
MV *mv,
double *confidence) {
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
VP9_COMMON *cm = &cpi->common;
uint8_t *tmp_buf = x->plane[0].src.buf;
int tmp_stride = x->plane[0].src.stride;
uint8_t *tmp_dst_buf = xd->plane[0].dst.buf;
int tmp_dst_stride = xd->plane[0].dst.stride;
// FIXME in practice we're completely ignoring chroma here
x->plane[0].src.buf = buf->y_buffer + mb_y_offset;
x->plane[0].src.stride = buf->y_stride;
xd->plane[0].dst.buf = get_frame_new_buffer(cm)->y_buffer + mb_y_offset;
xd->plane[0].dst.stride = get_frame_new_buffer(cm)->y_stride;
// Golden frame MV search, if it exists and is different than last frame
if (ref) {
int_mv intmv;
unsigned int sse, sad;
xd->plane[0].pre[0].buf = ref->y_buffer + mb_y_offset;
xd->plane[0].pre[0].stride = ref->y_stride;
sad = do_motion_search(cpi,
prev_ref_mv,
bsize,
&intmv,
mb_row, mb_col, &sse);
*confidence = (sse)/(sad+1);
*mv = intmv.as_mv;
}
x->plane[0].src.buf = tmp_buf;
x->plane[0].src.stride = tmp_stride;
xd->plane[0].dst.buf = tmp_dst_buf;
xd->plane[0].dst.stride = tmp_dst_stride;
}
static void get_frame_motionfield(VP9_COMP *cpi,
YV12_BUFFER_CONFIG *buf,
YV12_BUFFER_CONFIG *ref,
int blocksize,
MV *motionfield,
double *confidence) {
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
VP9_COMMON *const cm = &cpi->common;
int mb_col, mb_row, offset = 0;
int mb_y_offset = 0, ref_y_offset = 0;
int tmp_mv_row_min = x->mv_row_min, tmp_mv_row_max = x->mv_row_max;
int tmp_up_available = xd->up_available;
int tmp_left_available = xd->left_available;
int tmp_y_dst_stride = xd->plane[0].dst.stride;
int tmp_y_pre_stride = xd->plane[0].pre[0].stride;
int tmp_uv_dst_stride = xd->plane[1].dst.stride;
int bsize = blocksize;
int border = BORDER_MV_PIXELS_B16;
MV ref_top_mv = {0, 0};
MODE_INFO mi_local;
MODE_INFO *tmp_mi = xd->mi[0].src_mi;
vp9_zero(mi_local);
// Set up limit values for motion vectors to prevent them extending outside
// // the UMV borders.
x->mv_row_min = -border;
x->mv_row_max = (cm->mb_rows - 1) * (bsize/2) + border;
xd->up_available = 0;
xd->plane[0].dst.stride = buf->y_stride;
xd->plane[0].pre[0].stride = buf->y_stride;
xd->plane[1].dst.stride = buf->uv_stride;
xd->mi[0].src_mi = &mi_local;
mi_local.mbmi.sb_type = bsize == 16 ? BLOCK_16X16 : BLOCK_8X8;
mi_local.mbmi.ref_frame[0] = LAST_FRAME;
mi_local.mbmi.ref_frame[1] = NONE;
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
MV ref_left_mv = ref_top_mv;
int mb_y_in_offset = mb_y_offset;
int ref_y_in_offset = ref_y_offset;
// Set up limit values for motion vectors to prevent them extending outside
// the UMV borders.
x->mv_col_min = -border;
x->mv_col_max = (cm->mb_cols - 1) * (bsize/2) + border;
xd->left_available = 0;
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
MV mv;
get_mb_motionfield(cpi, buf, mb_y_in_offset,
ref, &ref_left_mv,
blocksize,
mb_row, mb_col, &mv,
&confidence[mb_row*cm->mb_cols + mb_col]);
motionfield[mb_row*cm->mb_cols + mb_col] = mv;
if (mb_col == 0) {
ref_top_mv = ref_left_mv;
}
xd->left_available = 1;
mb_y_in_offset += bsize;
ref_y_in_offset += bsize;
x->mv_col_min -= bsize;
x->mv_col_max -= bsize;
}
xd->up_available = 1;
mb_y_offset += buf->y_stride * bsize;
ref_y_offset += ref->y_stride * bsize;
x->mv_row_min -= bsize;
x->mv_row_max -= bsize;
offset += cm->mb_cols;
}
xd->mi[0].src_mi = tmp_mi;
x->mv_row_min = tmp_mv_row_min;
x->mv_row_max = tmp_mv_row_max;
xd->up_available = tmp_up_available;
xd->left_available = tmp_left_available;
xd->plane[0].dst.stride = tmp_y_dst_stride;
xd->plane[0].pre[0].stride = tmp_y_pre_stride;
xd->plane[1].dst.stride = tmp_uv_dst_stride;
}
void vp9_get_motionfield(VP9_COMP *cpi, int ref, int blocksize,
MV *motionfield, double *confidence) {
YV12_BUFFER_CONFIG *ref_buf = get_ref_frame_buffer(cpi, ref);
struct lookahead_entry *q_cur = vp9_lookahead_peek(cpi->lookahead, 0);
if (q_cur) {
get_frame_motionfield(cpi, &q_cur->img, ref_buf,
blocksize, motionfield, confidence);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2010 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.
*/
#ifndef VP9_ENCODER_VP9_MOTIONMODEL_H_
#define VP9_ENCODER_VP9_MOTIONMODEL_H_
#ifdef __cplusplus
extern "C" {
#endif
struct VP9_COMP;
void vp9_get_motionfield(struct VP9_COMP *cpi, int ref,
int blocksize, MV *motionfield, double *confidence);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_ENCODER_VP9_MOTIONMODEL_H_

View File

@ -74,14 +74,16 @@ VP9_CX_SRCS-yes += encoder/vp9_subexp.h
VP9_CX_SRCS-yes += encoder/vp9_svc_layercontext.c
VP9_CX_SRCS-yes += encoder/vp9_resize.c
VP9_CX_SRCS-yes += encoder/vp9_resize.h
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_ransac.c
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_ransac.h
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_detect.c
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_detect.h
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_match.c
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_match.h
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_global_motion.c
VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_global_motion.h
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_ransac.c
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_ransac.h
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_corner_detect.c
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_corner_detect.h
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_corner_match.c
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_corner_match.h
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_global_motion.c
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_global_motion.h
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_motionmodel.c
VP9_CX_SRCS-$(CONFIG_GLOBAL_MOTION) += encoder/vp9_motionmodel.h
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.c
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.h
VP9_CX_SRCS-yes += encoder/vp9_tokenize.c