summaryrefslogtreecommitdiffstats
path: root/video/out/filter_kernels.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/filter_kernels.c')
-rw-r--r--video/out/filter_kernels.c80
1 files changed, 44 insertions, 36 deletions
diff --git a/video/out/filter_kernels.c b/video/out/filter_kernels.c
index bfbd4e9465..d5df985395 100644
--- a/video/out/filter_kernels.c
+++ b/video/out/filter_kernels.c
@@ -5,10 +5,10 @@
* (https://github.com/glumpy/glumpy/blob/master/glumpy/library/build-spatial-filters.py)
*
* Also see:
- * - http://vector-agg.cvs.sourceforge.net/viewvc/vector-agg/agg-2.5/include/agg_image_filters.h
+ * - https://sourceforge.net/p/agg/svn/HEAD/tree/agg-2.4/include/agg_image_filters.h
* - Vapoursynth plugin fmtconv (WTFPL Licensed), which is based on
* dither plugin for avisynth from the same author:
- * https://github.com/vapoursynth/fmtconv/tree/master/src/fmtc
+ * https://gitlab.com/EleonoreMizo/fmtconv/-/tree/master/src/fmtc
* - Paul Heckbert's "zoom"
* - XBMC: ConvolutionKernels.cpp etc.
*
@@ -60,16 +60,19 @@ bool mp_init_filter(struct filter_kernel *filter, const int *sizes,
double inv_scale)
{
assert(filter->f.radius > 0);
+ double blur = filter->f.blur > 0.0 ? filter->f.blur : 1.0;
+ filter->radius = blur * filter->f.radius;
+
// Only downscaling requires widening the filter
filter->filter_scale = MPMAX(1.0, inv_scale);
- double src_radius = filter->f.radius * filter->filter_scale;
+ double src_radius = filter->radius * filter->filter_scale;
// Polar filters are dependent solely on the radius
if (filter->polar) {
filter->size = 1; // Not meaningful for EWA/polar scalers.
// Safety precaution to avoid generating a gigantic shader
if (src_radius > 16.0) {
src_radius = 16.0;
- filter->filter_scale = src_radius / filter->f.radius;
+ filter->filter_scale = src_radius / filter->radius;
return false;
}
return true;
@@ -89,7 +92,7 @@ bool mp_init_filter(struct filter_kernel *filter, const int *sizes,
// largest filter available. This is incorrect, but better than refusing
// to do anything.
filter->size = cursize[-1];
- filter->filter_scale = (filter->size/2.0) / filter->f.radius;
+ filter->filter_scale = (filter->size/2.0) / filter->radius;
return false;
}
}
@@ -116,7 +119,7 @@ static double sample_window(struct filter_window *kernel, double x)
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 w = sample_window(&filter->w, x / filter->radius * filter->w.radius);
double k = w * sample_window(&filter->f, x);
return k < 0 ? (1 - filter->clamp) * k : k;
}
@@ -158,10 +161,10 @@ void mp_compute_lut(struct filter_kernel *filter, int count, int stride,
filter->radius_cutoff = 0.0;
// Compute a 1D array indexed by radius
for (int x = 0; x < count; x++) {
- double r = x * filter->f.radius / (count - 1);
+ double r = x * filter->radius / (count - 1);
out_array[x] = sample_filter(filter, r);
- if (fabs(out_array[x]) > filter->value_cutoff)
+ if (fabs(out_array[x]) > 1e-3f)
filter->radius_cutoff = r;
}
} else {
@@ -187,6 +190,11 @@ static double triangle(params *p, double x)
return fmax(0.0, 1.0 - fabs(x / p->radius));
}
+static double cosine(params *p, double x)
+{
+ return cos(x);
+}
+
static double hanning(params *p, double x)
{
return 0.5 + 0.5 * cos(M_PI * x);
@@ -199,7 +207,7 @@ static double hamming(params *p, double x)
static double quadric(params *p, double x)
{
- if (x < 0.75) {
+ if (x < 0.5) {
return 0.75 - x * x;
} else if (x < 1.5) {
double t = x - 1.5;
@@ -208,15 +216,6 @@ static double quadric(params *p, double x)
return 0.0;
}
-#define POW3(x) ((x) <= 0 ? 0 : (x) * (x) * (x))
-static double bicubic(params *p, double x)
-{
- return (1.0/6.0) * ( POW3(x + 2)
- - 4 * POW3(x + 1)
- + 6 * POW3(x)
- - 4 * POW3(x - 1));
-}
-
static double bessel_i0(double x)
{
double s = 1.0;
@@ -235,7 +234,7 @@ static double kaiser(params *p, double x)
{
if (x > 1)
return 0;
- double i0a = 1.0 / bessel_i0(p->params[1]);
+ double i0a = 1.0 / bessel_i0(p->params[0]);
return bessel_i0(p->params[0] * sqrt(1.0 - x * x)) * i0a;
}
@@ -339,6 +338,7 @@ const struct filter_window mp_filter_windows[] = {
{"box", 1, box},
{"triangle", 1, triangle},
{"bartlett", 1, triangle},
+ {"cosine", M_PI_2, cosine},
{"hanning", 1, hanning},
{"tukey", 1, hanning, .taper = 0.5},
{"hamming", 1, hamming},
@@ -353,6 +353,9 @@ const struct filter_window mp_filter_windows[] = {
{0}
};
+#define JINC_R3 3.2383154841662362
+#define JINC_R4 4.2410628637960699
+
const struct filter_kernel mp_filter_kernels[] = {
// Spline filters
{{"spline16", 2, spline16}},
@@ -363,25 +366,30 @@ const struct filter_kernel mp_filter_kernels[] = {
{{"lanczos", 3, sinc, .resizable = true}, .window = "sinc"},
{{"ginseng", 3, sinc, .resizable = true}, .window = "jinc"},
// Jinc filters
- {{"jinc", 3, jinc, .resizable = true}, .polar = true},
- {{"ewa_lanczos", 3, jinc, .resizable = true}, .polar = true, .window = "jinc"},
- {{"ewa_hanning", 3, jinc, .resizable = true}, .polar = true, .window = "hanning" },
- {{"ewa_ginseng", 3, jinc, .resizable = true}, .polar = true, .window = "sinc"},
- // Radius is based on the true jinc radius, slightly sharpened as per
- // calculations by Nicolas Robidoux. Source: Imagemagick's magick/resize.c
- {{"ewa_lanczossharp", 3.2383154841662362, jinc, .blur = 0.9812505644269356,
- .resizable = true}, .polar = true, .window = "jinc"},
- // Similar to the above, but softened instead. This one makes hash patterns
- // disappear completely. Blur determined by trial and error.
- {{"ewa_lanczossoft", 3.2383154841662362, jinc, .blur = 1.015,
- .resizable = true}, .polar = true, .window = "jinc"},
+ {{"jinc", JINC_R3, jinc, .resizable = true}, .polar = true},
+ {{"ewa_lanczos", JINC_R3, jinc, .resizable = true}, .polar = true, .window = "jinc"},
+ {{"ewa_hanning", JINC_R3, jinc, .resizable = true}, .polar = true, .window = "hanning" },
+ {{"ewa_ginseng", JINC_R3, jinc, .resizable = true}, .polar = true, .window = "sinc"},
+ // Slightly sharpened to minimize the 1D step response error (to better
+ // preserve horizontal/vertical lines)
+ {{"ewa_lanczossharp", JINC_R3, jinc, .blur = 0.9812505837223707, .resizable = true},
+ .polar = true, .window = "jinc"},
+ // Similar to the above, but sharpened substantially to the point of
+ // minimizing the total impulse response error on an integer grid. Tends
+ // to preserve hash patterns well. Very sharp but rings a lot.
+ {{"ewa_lanczos4sharpest", JINC_R4, jinc, .blur = 0.8845120932605005, .resizable = true},
+ .polar = true, .window = "jinc"},
+ // Similar to the above, but softened instead, to make even/odd integer
+ // contributions exactly symmetrical. Designed to smooth out hash patterns.
+ {{"ewa_lanczossoft", JINC_R3, jinc, .blur = 1.0164667662867047, .resizable = true},
+ .polar = true, .window = "jinc"},
// Very soft (blurred) hanning-windowed jinc; removes almost all aliasing.
- // Blur paramater picked to match orthogonal and diagonal contributions
- {{"haasnsoft", 3.2383154841662362, jinc, .blur = 1.11, .resizable = true},
- .polar = true, .window = "hanning"},
+ // Blur parameter picked to match orthogonal and diagonal contributions
+ {{"haasnsoft", JINC_R3, jinc, .blur = 1.11, .resizable = true},
+ .polar = true, .window = "hanning"},
// Cubic filters
- {{"bicubic", 2, bicubic}},
- {{"bcspline", 2, cubic_bc, .params = {0.5, 0.5} }},
+ {{"bicubic", 2, cubic_bc, .params = {1.0, 0.0} }},
+ {{"hermite", 1, cubic_bc, .params = {0.0, 0.0} }},
{{"catmull_rom", 2, cubic_bc, .params = {0.0, 0.5} }},
{{"mitchell", 2, cubic_bc, .params = {1.0/3.0, 1.0/3.0} }},
{{"robidoux", 2, cubic_bc, .params = {12 / (19 + 9 * M_SQRT2),