From 62a0d226212d5e0857c62effb1cb41e5f4af6707 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 18 Jan 2020 13:43:33 +0100 Subject: [PATCH] avfilter/vf_v360: add gaussian interpolation --- doc/filters.texi | 3 +++ libavfilter/v360.h | 1 + libavfilter/vf_v360.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/doc/filters.texi b/doc/filters.texi index c8ac4311f5..252eb4b7ad 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -19027,6 +19027,9 @@ Lanczos interpolation. @item sp16 @item spline16 Spline16 interpolation. +@item gauss +@item gaussian +Gaussian interpolation. @end table Default value is @b{@samp{line}}. diff --git a/libavfilter/v360.h b/libavfilter/v360.h index 9f74272133..29bf27565c 100644 --- a/libavfilter/v360.h +++ b/libavfilter/v360.h @@ -55,6 +55,7 @@ enum InterpMethod { BICUBIC, LANCZOS, SPLINE16, + GAUSSIAN, NB_INTERP_METHODS, }; diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c index b56f6cc96b..452f52dce6 100644 --- a/libavfilter/vf_v360.c +++ b/libavfilter/vf_v360.c @@ -101,6 +101,8 @@ static const AVOption v360_options[] = { { "lanczos", "lanczos interpolation", 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, "interp" }, { "sp16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, "interp" }, { "spline16", "spline16 interpolation", 0, AV_OPT_TYPE_CONST, {.i64=SPLINE16}, 0, 0, FLAGS, "interp" }, + { "gauss", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, "interp" }, + { "gaussian", "gaussian interpolation", 0, AV_OPT_TYPE_CONST, {.i64=GAUSSIAN}, 0, 0, FLAGS, "interp" }, { "w", "output width", OFFSET(width), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "w"}, { "h", "output height", OFFSET(height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT16_MAX, FLAGS, "h"}, { "in_stereo", "input stereo format", OFFSET(in_stereo), AV_OPT_TYPE_INT, {.i64=STEREO_2D}, 0, NB_STEREO_FMTS-1, FLAGS, "stereo" }, @@ -317,6 +319,7 @@ void ff_v360_init(V360Context *s, int depth) case BICUBIC: case LANCZOS: case SPLINE16: + case GAUSSIAN: s->remap_line = depth <= 8 ? remap4_8bit_line_c : remap4_16bit_line_c; break; } @@ -511,6 +514,59 @@ static void spline16_kernel(float du, float dv, const XYRemap *rmap, } } +/** + * Calculate 1-dimensional gaussian coefficients. + * + * @param t relative coordinate + * @param coeffs coefficients + */ +static void calculate_gaussian_coeffs(float t, float *coeffs) +{ + float sum = 0.f; + + for (int i = 0; i < 4; i++) { + const float x = t - (i - 1); + if (x == 0.f) { + coeffs[i] = 1.f; + } else { + coeffs[i] = expf(-2.f * x * x) * expf(-x * x / 2.f); + } + sum += coeffs[i]; + } + + for (int i = 0; i < 4; i++) { + coeffs[i] /= sum; + } +} + +/** + * Calculate kernel for gaussian interpolation. + * + * @param du horizontal relative coordinate + * @param dv vertical relative coordinate + * @param rmap calculated 4x4 window + * @param u u remap data + * @param v v remap data + * @param ker ker remap data + */ +static void gaussian_kernel(float du, float dv, const XYRemap *rmap, + uint16_t *u, uint16_t *v, int16_t *ker) +{ + float du_coeffs[4]; + float dv_coeffs[4]; + + calculate_gaussian_coeffs(du, du_coeffs); + calculate_gaussian_coeffs(dv, dv_coeffs); + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + u[i * 4 + j] = rmap->u[i][j]; + v[i * 4 + j] = rmap->v[i][j]; + ker[i * 4 + j] = lrintf(du_coeffs[j] * dv_coeffs[i] * 16385.f); + } + } +} + /** * Modulo operation with only positive remainders. * @@ -2733,6 +2789,13 @@ static int config_output(AVFilterLink *outlink) sizeof_uv = sizeof(uint16_t) * s->elements; sizeof_ker = sizeof(uint16_t) * s->elements; break; + case GAUSSIAN: + s->calculate_kernel = gaussian_kernel; + s->remap_slice = depth <= 8 ? remap4_8bit_slice : remap4_16bit_slice; + s->elements = 4 * 4; + sizeof_uv = sizeof(uint16_t) * s->elements; + sizeof_ker = sizeof(uint16_t) * s->elements; + break; default: av_assert0(0); }