Cheaper sinc computation for resize.c
Posted: 2010-08-28T16:35:02-07:00
I am an applied mathematician working on image filtering. For example, I am a regular contributor to the free open source VIPS/NIP2 system, and me and my students have contributed to the free open source GEGL library.
My masters student Chantal Racette and I have just discovered an highly accurate approximation method for the sinc (and related) functions on finite ranges.
I believe that this could be useful for your recize.c code, and would be delighted to see it integrated in IM right away. (We'll write the article later.)
Are you interested?
To give you an idea of what I'm talking about, here is an single piece polynomial approximation with 1e-8 maximum relative error over the interval [-3,3] (note that getting a low relative error is not trivial because the sinc function has zeros in the interval), which is a direct replacement for the corresponding Sinc function in resize.c:
static MagickRealType Sinc(const MagickRealType x,
const ResizeFilter *magick_unused(resize_filter))
{
#define FAST_LANCZOS_COEF_1 -0.2777777749828003702607348742700210983971e-1
#define FAST_LANCZOS_COEF_2 0.7883967237692122941462552028914990810270e-2
#define FAST_LANCZOS_COEF_3 -0.1014962147766290313113433635286152701178e-3
#define FAST_LANCZOS_COEF_4 0.7957122890011771235521289628748676216784e-4
#define FAST_LANCZOS_COEF_5 -0.4297822393998422516448009437099172798829e-5
#define FAST_LANCZOS_COEF_6 0.1707846962680966498461068335001167780751e-6
#define FAST_LANCZOS_COEF_7 -0.5110955098479687596630062395922169657449e-8
#define FAST_LANCZOS_COEF_8 0.1091121789464303759146861882233623802483e-9
#define FAST_LANCZOS_COEF_9 -0.1270023023877167259514316150814763206939e-11
const double x_squared = x*x;
if (x_squared <= 1.0)
{
const double p =
FAST_LANCZOS_COEF_1 + x_squared * (
FAST_LANCZOS_COEF_2 + x_squared * (
FAST_LANCZOS_COEF_3 + x_squared * (
FAST_LANCZOS_COEF_4 + x_squared * (
FAST_LANCZOS_COEF_5 + x_squared * (
FAST_LANCZOS_COEF_6 + x_squared * (
FAST_LANCZOS_COEF_7 + x_squared * (
FAST_LANCZOS_COEF_8 + x_squared * (
FAST_LANCZOS_COEF_9 ))))))));
const double s =
( (x_squared + -1.0) * (x_squared + -4.0) )
*
( (x_squared + -9.0) * p );
return(s);
}
else
return(sin(MagickPI*x)/(MagickPI*x));
}
(I have not taken the time to triple check this code. Apologies if it is not quite right.)
We can produce one-piece or piecewise polynomial approximations of arbitrary accuracy, and that we minimize the relative error because we have found that, in general, for an equal computation cost, the minimizer of relative error has a frequency response closer to the original than the minimizer of absolute error when used as a filter kernel.)
Basically, you tell us what you'd like, we compute for a bit, and you get the code.
We also have highly accurate approximations of the lanczos functions. Generally, 30 or so flops gives machine precision.
Nicolas Robidoux
Department of Mathematics and Computer Science
Universite Laurentienne/Laurentian University
Sudbuy Ontario Canada
My masters student Chantal Racette and I have just discovered an highly accurate approximation method for the sinc (and related) functions on finite ranges.
I believe that this could be useful for your recize.c code, and would be delighted to see it integrated in IM right away. (We'll write the article later.)
Are you interested?
To give you an idea of what I'm talking about, here is an single piece polynomial approximation with 1e-8 maximum relative error over the interval [-3,3] (note that getting a low relative error is not trivial because the sinc function has zeros in the interval), which is a direct replacement for the corresponding Sinc function in resize.c:
static MagickRealType Sinc(const MagickRealType x,
const ResizeFilter *magick_unused(resize_filter))
{
#define FAST_LANCZOS_COEF_1 -0.2777777749828003702607348742700210983971e-1
#define FAST_LANCZOS_COEF_2 0.7883967237692122941462552028914990810270e-2
#define FAST_LANCZOS_COEF_3 -0.1014962147766290313113433635286152701178e-3
#define FAST_LANCZOS_COEF_4 0.7957122890011771235521289628748676216784e-4
#define FAST_LANCZOS_COEF_5 -0.4297822393998422516448009437099172798829e-5
#define FAST_LANCZOS_COEF_6 0.1707846962680966498461068335001167780751e-6
#define FAST_LANCZOS_COEF_7 -0.5110955098479687596630062395922169657449e-8
#define FAST_LANCZOS_COEF_8 0.1091121789464303759146861882233623802483e-9
#define FAST_LANCZOS_COEF_9 -0.1270023023877167259514316150814763206939e-11
const double x_squared = x*x;
if (x_squared <= 1.0)
{
const double p =
FAST_LANCZOS_COEF_1 + x_squared * (
FAST_LANCZOS_COEF_2 + x_squared * (
FAST_LANCZOS_COEF_3 + x_squared * (
FAST_LANCZOS_COEF_4 + x_squared * (
FAST_LANCZOS_COEF_5 + x_squared * (
FAST_LANCZOS_COEF_6 + x_squared * (
FAST_LANCZOS_COEF_7 + x_squared * (
FAST_LANCZOS_COEF_8 + x_squared * (
FAST_LANCZOS_COEF_9 ))))))));
const double s =
( (x_squared + -1.0) * (x_squared + -4.0) )
*
( (x_squared + -9.0) * p );
return(s);
}
else
return(sin(MagickPI*x)/(MagickPI*x));
}
(I have not taken the time to triple check this code. Apologies if it is not quite right.)
We can produce one-piece or piecewise polynomial approximations of arbitrary accuracy, and that we minimize the relative error because we have found that, in general, for an equal computation cost, the minimizer of relative error has a frequency response closer to the original than the minimizer of absolute error when used as a filter kernel.)
Basically, you tell us what you'd like, we compute for a bit, and you get the code.
We also have highly accurate approximations of the lanczos functions. Generally, 30 or so flops gives machine precision.
Nicolas Robidoux
Department of Mathematics and Computer Science
Universite Laurentienne/Laurentian University
Sudbuy Ontario Canada