2 * This file is part of mplayer2.
4 * Most code for computing the weights is taken from Anti-Grain Geometry (AGG)
5 * (licensed under GPL 2 or later), with modifications.
6 * Copyright (C) 2002-2006 Maxim Shemanarev
7 * http://vector-agg.cvs.sourceforge.net/viewvc/vector-agg/agg-2.5/include/agg_image_filters.h?view=markup
9 * Also see glumpy (BSD licensed), contains the same code in Python:
10 * http://code.google.com/p/glumpy/source/browse/glumpy/image/filter.py
12 * Also see: Paul Heckbert's "zoom"
14 * Also see XBMC: ConvolutionKernels.cpp etc.
16 * mplayer2 is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * mplayer2 is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License along
27 * with mplayer2; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 #include "filter_kernels.h"
38 // NOTE: all filters are separable, symmetric, and are intended for use with
39 // a lookup table/texture.
41 const struct filter_kernel
*mp_find_filter_kernel(const char *name
)
43 for (const struct filter_kernel
*k
= mp_filter_kernels
; k
->name
; k
++) {
44 if (strcmp(k
->name
, name
) == 0)
50 // sizes = sorted list of available filter sizes, terminated with size 0
51 // inv_scale = source_size / dest_size
52 bool mp_init_filter(struct filter_kernel
*filter
, const int *sizes
,
55 // only downscaling requires widening the filter
56 filter
->inv_scale
= inv_scale
>= 1.0 ? inv_scale
: 1.0;
57 double support
= filter
->radius
* filter
->inv_scale
;
58 int size
= ceil(2.0 * support
);
59 // round up to smallest available size that's still large enough
62 const int *cursize
= sizes
;
63 while (size
> *cursize
&& *cursize
)
66 filter
->size
= *cursize
;
69 // The filter doesn't fit - instead of failing completely, use the
70 // largest filter available. This is incorrect, but better than refusing
72 filter
->size
= cursize
[-1];
73 filter
->inv_scale
= filter
->size
/ 2.0 / filter
->radius
;
78 // Calculate the 1D filtering kernel for N sample points.
79 // N = number of samples, which is filter->size
80 // The weights will be stored in out_w[0] to out_w[N - 1]
81 // f = x0 - abs(x0), subpixel position in the range [0,1) or [0,1].
82 void mp_compute_weights(struct filter_kernel
*filter
, double f
, float *out_w
)
84 assert(filter
->size
> 0);
86 for (int n
= 0; n
< filter
->size
; n
++) {
87 double x
= f
- (n
- filter
->size
/ 2 + 1);
88 double w
= filter
->weight(filter
, fabs(x
) / filter
->inv_scale
);
93 for (int n
= 0; n
< filter
->size
; n
++)
97 // Fill the given array with weights for the range [0.0, 1.0]. The array is
98 // interpreted as rectangular array of count * filter->size items.
99 void mp_compute_lut(struct filter_kernel
*filter
, int count
, float *out_array
)
101 for (int n
= 0; n
< count
; n
++) {
102 mp_compute_weights(filter
, n
/ (double)(count
- 1),
103 out_array
+ filter
->size
* n
);
107 typedef struct filter_kernel kernel
;
109 static double bilinear(kernel
*k
, double x
)
114 static double hanning(kernel
*k
, double x
)
116 return 0.5 + 0.5 * cos(M_PI
* x
);
119 static double hamming(kernel
*k
, double x
)
121 return 0.54 + 0.46 * cos(M_PI
* x
);
124 static double hermite(kernel
*k
, double x
)
126 return (2.0 * x
- 3.0) * x
* x
+ 1.0;
129 static double quadric(kernel
*k
, double x
)
131 // NOTE: glumpy uses 0.75, AGG uses 0.5
135 return 0.5 * (x
- 1.5) * (x
- 1.5);
139 static double bc_pow3(double x
)
141 return (x
<= 0) ? 0 : x
* x
* x
;
144 static double bicubic(kernel
*k
, double x
)
146 return (1.0/6.0) * ( bc_pow3(x
+ 2)
149 - 4 * bc_pow3(x
- 1));
152 static double bessel_i0(double epsilon
, double x
)
155 double y
= x
* x
/ 4;
157 for (int i
= 2; t
> epsilon
; i
++) {
164 static double kaiser(kernel
*k
, double x
)
166 double a
= k
->params
[0];
167 double b
= k
->params
[1];
168 double epsilon
= 1e-12;
169 double i0a
= 1 / bessel_i0(epsilon
, b
);
170 return bessel_i0(epsilon
, a
* sqrt(1 - x
* x
)) * i0a
;
173 static double catmull_rom(kernel
*k
, double x
)
176 return 0.5 * (2.0 + x
* x
* (-5.0 + x
* 3.0));
178 return 0.5 * (4.0 + x
* (-8.0 + x
* (5.0 - x
)));
182 // Mitchell-Netravali
183 static double mitchell(kernel
*k
, double x
)
185 double b
= k
->params
[0];
186 double c
= k
->params
[1];
188 p0
= (6.0 - 2.0 * b
) / 6.0,
189 p2
= (-18.0 + 12.0 * b
+ 6.0 * c
) / 6.0,
190 p3
= (12.0 - 9.0 * b
- 6.0 * c
) / 6.0,
191 q0
= (8.0 * b
+ 24.0 * c
) / 6.0,
192 q1
= (-12.0 * b
- 48.0 * c
) / 6.0,
193 q2
= (6.0 * b
+ 30.0 * c
) / 6.0,
194 q3
= (-b
- 6.0 * c
) / 6.0;
196 return p0
+ x
* x
* (p2
+ x
* p3
);
198 return q0
+ x
* (q1
+ x
* (q2
+ x
* q3
));
202 static double spline16(kernel
*k
, double x
)
205 return ((x
- 9.0/5.0 ) * x
- 1.0/5.0 ) * x
+ 1.0;
206 return ((-1.0/3.0 * (x
-1) + 4.0/5.0) * (x
-1) - 7.0/15.0 ) * (x
-1);
209 static double spline36(kernel
*k
, double x
)
212 return ((13.0/11.0 * x
- 453.0/209.0) * x
- 3.0/209.0) * x
+ 1.0;
214 return ((-6.0/11.0 * (x
- 1) + 270.0/209.0) * (x
- 1) - 156.0/209.0)
216 return ((1.0/11.0 * (x
- 2) - 45.0/209.0) * (x
- 2) + 26.0/209.0)
220 static double gaussian(kernel
*k
, double x
)
222 return exp(-2.0 * x
* x
) * sqrt(2.0 / M_PI
);
225 static double sinc(kernel
*k
, double x
)
229 double pix
= M_PI
* x
;
230 return sin(pix
) / pix
;
233 static double lanczos(kernel
*k
, double x
)
235 double radius
= k
->size
/ 2;
236 if (x
< -radius
|| x
> radius
)
240 double pix
= M_PI
* x
;
241 return radius
* sin(pix
) * sin(pix
/ radius
) / (pix
* pix
);
244 static double blackman(kernel
*k
, double x
)
246 double radius
= k
->size
/ 2;
252 double xr
= x
/ radius
;
253 return (sin(x
) / x
) * (0.42 + 0.5 * cos(xr
) + 0.08 * cos(2 * xr
));
256 const struct filter_kernel mp_filter_kernels
[] = {
257 {"bilinear_slow", 1, bilinear
},
258 {"hanning", 1, hanning
},
259 {"hamming", 1, hamming
},
260 {"hermite", 1, hermite
},
261 {"quadric", 1.5, quadric
},
262 {"bicubic", 2, bicubic
},
263 {"kaiser", 1, kaiser
, .params
= {6.33, 6.33} },
264 {"catmull_rom", 2, catmull_rom
},
265 {"mitchell", 2, mitchell
, .params
= {1.0/3.0, 1.0/3.0} },
266 {"spline16", 2, spline16
},
267 {"spline36", 3, spline36
},
268 {"gaussian", 2, gaussian
},
272 {"lanczos2", 2, lanczos
},
273 {"lanczos3", 3, lanczos
},
274 {"lanczos4", 4, lanczos
},
275 {"blackman2", 2, blackman
},
276 {"blackman3", 3, blackman
},
277 {"blackman4", 4, blackman
},