1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-18 13:47:04 +00:00

filter_kernels: add ability to taper kernels/windows

This allows us to define the tukey window (and other tapered windows).

Also add a missing option definition for `wblur` while we're at it, to
make testing out window-related stuff easier.
This commit is contained in:
Niklas Haas 2016-10-26 16:32:57 +02:00 committed by wm4
parent 5838322975
commit 654721c27b
5 changed files with 55 additions and 26 deletions

View File

@ -3874,12 +3874,19 @@ The following video options are currently all specific to ``--vo=opengl`` and
never interpolate, thus behaving as if the regular nearest neighbour
algorithm was used. Defaults to 0.0.
``--scale-blur=<value>``
Kernel scaling factor (also known as a blur factor). Decreasing this makes
the result sharper, increasing it makes it blurrier (default 0). If set to
0, the kernel's preferred blur factor is used. Note that setting this too
low (eg. 0.5) leads to bad results. It's generally recommended to stick to
values between 0.8 and 1.2.
``--scale-blur=<value>``, ``--scale-wblur=<value>``
Kernel/window scaling factor (also known as a blur factor). Decreasing this
makes the result sharper, increasing it makes it blurrier (default 0). If
set to 0, the kernel's preferred blur factor is used. Note that setting
this too low (eg. 0.5) leads to bad results. It's generally recommended to
stick to values between 0.8 and 1.2.
``--scale-taper=<value>``, ``--scale-wtaper=<value>``
Kernel/window taper factor. Increasing this flattens the filter function.
Value range is 0 to 1. A value of 0 (the default) means no flattening, a
value of 1 makes the filter completely flat (equivalent to a box function).
Values in between mean that some portion will be flat and the actual filter
function will be squeezed into the space in between.
``--scale-radius=<value>``
Set radius for tunable filters, must be a float number between 0.5 and

View File

@ -92,34 +92,45 @@ bool mp_init_filter(struct filter_kernel *filter, const int *sizes,
}
}
// Sample from the blurred, windowed kernel. Note: The window is always
// stretched to the true radius, regardless of the filter blur/scale.
static double sample_filter(struct filter_kernel *filter,
struct filter_window *window, double x)
// Sample from a blurred and tapered window
static double sample_window(struct filter_window *kernel, double x)
{
double bk = filter->f.blur > 0.0 ? filter->f.blur : 1.0;
double bw = window->blur > 0.0 ? window->blur : 1.0;
double c = fabs(x) / (filter->inv_scale * bk);
double w = window->weight ? window->weight(window, x/bw * window->radius
/ filter->f.radius)
: 1.0;
double v = c < filter->f.radius ? w * filter->f.weight(&filter->f, c) : 0.0;
return filter->clamp ? fmax(0.0, fmin(1.0, v)) : v;
if (!kernel->weight)
return 1.0;
// All windows are symmetric, this makes life easier
x = fabs(x);
if (x >= kernel->radius)
return 0.0;
// Stretch and taper the window size as needed
x = kernel->blur > 0.0 ? x / kernel->blur : x;
x = x <= kernel->taper ? 0.0 : (x - kernel->taper) / (1 - kernel->taper);
return kernel->weight(kernel, x);
}
// Evaluate a filter's kernel and window at a given absolute position
static double sample_filter(struct filter_kernel *filter, double x)
{
// The window is always stretched to the entire kernel
double w = sample_window(&filter->w, x / filter->f.radius * filter->w.radius);
double k = sample_window(&filter->f, x / filter->inv_scale);
return filter->clamp ? fmax(0.0, fmin(1.0, w * k)) : w * k;
}
// Calculate the 1D filtering kernel for N sample points.
// N = number of samples, which is filter->size
// The weights will be stored in out_w[0] to out_w[N - 1]
// f = x0 - abs(x0), subpixel position in the range [0,1) or [0,1].
static void mp_compute_weights(struct filter_kernel *filter,
struct filter_window *window,
double f, float *out_w)
static void mp_compute_weights(struct filter_kernel *filter, double f,
float *out_w)
{
assert(filter->size > 0);
double sum = 0;
for (int n = 0; n < filter->size; n++) {
double x = f - (n - filter->size / 2 + 1);
double w = sample_filter(filter, window, x);
double w = sample_filter(filter, x);
out_w[n] = w;
sum += w;
}
@ -138,17 +149,16 @@ static void mp_compute_weights(struct filter_kernel *filter,
// [0.5 / count, 1.0 - 0.5 / count].
void mp_compute_lut(struct filter_kernel *filter, int count, float *out_array)
{
struct filter_window *window = &filter->w;
if (filter->polar) {
// Compute a 1D array indexed by radius
for (int x = 0; x < count; x++) {
double r = x * filter->f.radius / (count - 1);
out_array[x] = sample_filter(filter, window, r);
out_array[x] = sample_filter(filter, r);
}
} else {
// Compute a 2D array indexed by subpixel position
for (int n = 0; n < count; n++) {
mp_compute_weights(filter, window, n / (double)(count - 1),
mp_compute_weights(filter, n / (double)(count - 1),
out_array + filter->size * n);
}
}
@ -321,6 +331,7 @@ const struct filter_window mp_filter_windows[] = {
{"triangle", 1, triangle},
{"bartlett", 1, triangle},
{"hanning", 1, hanning},
{"tukey", 1, hanning, .taper = 0.5},
{"hamming", 1, hamming},
{"quadric", 1.5, quadric},
{"welch", 1, welch},

View File

@ -22,6 +22,7 @@ struct filter_window {
double params[2]; // User-defined custom filter parameters. Not used by
// all filters
double blur; // Blur coefficient (sharpens or widens the filter)
double taper; // Taper coefficient (flattens the filter's center)
};
struct filter_kernel {

View File

@ -340,7 +340,10 @@ static int validate_window_opt(struct mp_log *log, const m_option_t *opt,
OPT_FLOAT(n"-param1", scaler[i].kernel.params[0], 0), \
OPT_FLOAT(n"-param2", scaler[i].kernel.params[1], 0), \
OPT_FLOAT(n"-blur", scaler[i].kernel.blur, 0), \
OPT_FLOATRANGE(n"-taper", scaler[i].kernel.taper, 0, 0.0, 1.0), \
OPT_FLOAT(n"-wparam", scaler[i].window.params[0], 0), \
OPT_FLOAT(n"-wblur", scaler[i].window.blur, 0), \
OPT_FLOATRANGE(n"-wtaper", scaler[i].window.taper, 0, 0.0, 1.0), \
OPT_FLAG(n"-clamp", scaler[i].clamp, 0), \
OPT_FLOATRANGE(n"-radius", scaler[i].radius, 0, 0.5, 16.0), \
OPT_FLOATRANGE(n"-antiring", scaler[i].antiring, 0, 0.0, 1.0), \
@ -1357,7 +1360,8 @@ static bool scaler_fun_eq(struct scaler_fun a, struct scaler_fun b)
return ((!a.name && !b.name) || strcmp(a.name, b.name) == 0) &&
double_seq(a.params[0], b.params[0]) &&
double_seq(a.params[1], b.params[1]) &&
a.blur == b.blur;
a.blur == b.blur &&
a.taper == b.taper;
}
static bool scaler_conf_eq(struct scaler_config a, struct scaler_config b)
@ -1418,6 +1422,11 @@ static void reinit_scaler(struct gl_video *p, struct scaler *scaler,
if (conf->window.blur > 0.0)
scaler->kernel->w.blur = conf->window.blur;
if (conf->kernel.taper > 0.0)
scaler->kernel->f.taper = conf->kernel.taper;
if (conf->window.taper > 0.0)
scaler->kernel->w.taper = conf->window.taper;
if (scaler->kernel->f.resizable && conf->radius > 0.0)
scaler->kernel->f.radius = conf->radius;

View File

@ -35,6 +35,7 @@ struct scaler_fun {
char *name;
float params[2];
float blur;
float taper;
};
struct scaler_config {