Add LanczosSharp filter, adjust Lanczos2D* filters
diff --git a/ChangeLog b/ChangeLog
index 56784f4..31beb1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,17 @@
+2010-10-25 6.6.5-1 Anthony Thyssen <A.Thyssen@griffith...>
+ * Added LanczosSharp (3-lobe Lanczos with sharpening)
+ * Lanczos2D and Lanczos2DSharp are now always a 2-lobe Jinc-Jinc filter
+ regardless of orthoginal (resize) or cylindrical (distort-EWA) usage.
+ This is a rare case where a Jinc filter is also useful for resize.
+ * Filter sharpening factors are also always applied regardless of usage.
+
2010-10-24 6.6.5-1 Nicolas Robidoux <nicolas.robidoux@gmail...>
* CubicBC filter formulas simplified by constant folding. In
particular, P1 coefficient (always zero) removed from coeff.
2010-10-22 6.6.5-1 Nicolas Robidoux <nicolas.robidoux@gmail...>
* Revert the Robidoux filter to a Keys cubic with C=(108 sqrt 2-29)/398
- (as is already in the documentation).
+ (as already specified in the documentation).
2010-10-14 6.6.5-1 Cristy <quetzlzacatenango@image...>
* Ignore PS bounding box offsets if -page is set.
diff --git a/magick/option.c b/magick/option.c
index 1e01e59..435b5f8 100644
--- a/magick/option.c
+++ b/magick/option.c
@@ -955,7 +955,8 @@
{ "Lagrange", (ssize_t) LagrangeFilter, MagickFalse },
{ "Lanczos", (ssize_t) LanczosFilter, MagickFalse },
{ "Lanczos2D", (ssize_t) Lanczos2DFilter, MagickFalse },
- { "Lanczos2DSharp", (ssize_t) Lanczos2DSharpFilter, MagickTrue },
+ { "Lanczos2DSharp", (ssize_t) Lanczos2DSharpFilter, MagickFalse },
+ { "LanczosSharp", (ssize_t) LanczosSharpFilter, MagickFalse },
{ "Mitchell", (ssize_t) MitchellFilter, MagickFalse },
{ "Parzen", (ssize_t) ParzenFilter, MagickFalse },
{ "Point", (ssize_t) PointFilter, MagickFalse },
@@ -966,7 +967,7 @@
{ "Triangle", (ssize_t) TriangleFilter, MagickFalse },
{ "Tent", (ssize_t) TriangleFilter, MagickFalse }, /* alias for Triangle*/
{ "Welsh", (ssize_t) WelshFilter, MagickFalse },
- /* For backward compatibility - set after "Jinc" */
+ /* For backward compatibility - must be after "Jinc" */
{ "Bessel", (ssize_t) JincFilter, MagickTrue },
{ (char *) NULL, (ssize_t) UndefinedFilter, MagickFalse }
},
diff --git a/magick/resample.h b/magick/resample.h
index bef5ab4..01f51c7 100644
--- a/magick/resample.h
+++ b/magick/resample.h
@@ -55,6 +55,7 @@
BohmanFilter,
BartlettFilter,
SincFastFilter,
+ LanczosSharpFilter,
Lanczos2DFilter,
Lanczos2DSharpFilter,
RobidouxFilter,
diff --git a/magick/resize.c b/magick/resize.c
index 5a128a0..51e413d 100644
--- a/magick/resize.c
+++ b/magick/resize.c
@@ -206,14 +206,14 @@
Mitchell.pdf.
Coefficents are determined from B,C values:
- P0 = ( 6 - 2*B )/6
+ P0 = ( 6 - 2*B )/6 = coeff[0]
P1 = 0
- P2 = (-18 +12*B + 6*C )/6
- P3 = ( 12 - 9*B - 6*C )/6
- Q0 = ( 8*B +24*C )/6
- Q1 = ( -12*B -48*C )/6
- Q2 = ( 6*B +30*C )/6
- Q3 = ( - 1*B - 6*C )/6
+ P2 = (-18 +12*B + 6*C )/6 = coeff[1]
+ P3 = ( 12 - 9*B - 6*C )/6 = coeff[2]
+ Q0 = ( 8*B +24*C )/6 = coeff[3]
+ Q1 = ( -12*B -48*C )/6 = coeff[4]
+ Q2 = ( 6*B +30*C )/6 = coeff[5]
+ Q3 = ( - 1*B - 6*C )/6 = coeff[6]
which are used to define the filter:
@@ -222,9 +222,6 @@
which ensures function is continuous in value and derivative
(slope).
-
- P1 is always zero; for this reason, it is skipped:
- coeff[0]=P0, coeff[1]=P2.
*/
if (x < 1.0)
return(resize_filter->coeff[0]+x*(x*
@@ -245,13 +242,14 @@
exp( -(x^2)/((2.0*sigma^2) ) / sqrt(2*PI*sigma^2)))
The constants are pre-calculated...
exp( -coeff[0]*(x^2)) ) * coeff[1]
- However the multiplier coefficent is not needed and not used.
+ However the multiplier coefficent (1) is not needed and not used.
This separates the gaussian 'sigma' value from the 'blur/support' settings
- allows for its use in special 'small sigma' gaussians, without the filter
- 'missing' pixels when blur and thus support becomes too small.
+ allowing for its use in special 'small sigma' gaussians, without the filter
+ 'missing' pixels when blurring because the support is too small.
*/
- return(exp((double)(-resize_filter->coeff[0]*x*x))); }
+ return(exp((double)(-resize_filter->coeff[0]*x*x)));
+}
static MagickRealType Hanning(const MagickRealType x,
const ResizeFilter *magick_unused(resize_filter))
@@ -459,7 +457,8 @@
{
/*
1st order (linear) B-Spline, bilinear interpolation, Tent 1D
- filter, or a Bartlett 2D Cone filter.
+ filter, or a Bartlett 2D Cone filter. Also used as a
+ Bartlett Windowing function for Sinc().
*/
if (x < 1.0)
return(1.0-x);
@@ -504,7 +503,7 @@
% Kaiser Lanczos
%
% Special purpose Filters
-% SincFast Lanczos2D Robidoux
+% SincFast LanczosSharp Lanczos2D Lanczos2DSharp Robidoux
%
% The users "-filter" selection is used to lookup the default 'expert'
% settings for that filter from a internal table. However any provided
@@ -530,6 +529,12 @@
% the cylindrical case) but defaulting to 3-lobe support, rather that
% the default 4 lobe support of the other windowed sinc/jinc filters.
%
+% LanczosSharp is a slightly sharpened (blur=0.9830391168464) form of
+% the Lanczos filter. It was designed specifically for cylindrical
+% (radial) EWA (Elliptical Weighted Average) distortion (using a
+% Jinc windowed Jinc), but can also be used as a slightly sharper
+% orthogonal Lanczos (Sinc-Sinc) filter.
+%
% Two forms of the 'Sinc' function are available: Sinc and SincFast.
% Sinc is computed using the traditional sin(pi*x)/(pi*x); it is
% selected if the user specifically specifies the use of a Sinc
@@ -537,12 +542,15 @@
% and rational (high Q) approximations, and will be used by default in
% most cases.
%
-% The Lanczos2D and Robidoux filters are tuned for cylindrical
-% (radial) EWA (Elliptical Weighted Average) distortion. Lanczos2D
-% is a 2 lobe Lanczos-like filter using Jinc (for EWA) or Sinc.
-% Robidoux used to be a sharpened version of Lanczos2D (with
-% blur=0.958033808). Now, Robidoux is the unique Keys cubic spline
-% filter satisfying the following condition:
+% The Lanczos2D and Lanczos2DSharp filters specific for EWA distorts.
+% They are both 2 lobe Lanczos-like filter but always using a
+% Jinc-Jinc filter function regardless of if used as a orthoginal
+% filter or not. The 'sharp' version has been sharpened using a
+% blur=0.958033808.
+%
+% Robidoux is a unique Keys cubic spline, developed from the previous
+% Lanczos2DSharp filter. It is designed to satisfy the following
+% condition:
%
% Robidoux exactly preserves images with only vertical or
% horizontal features when performing 'no-op" with EWA distortion.
@@ -555,12 +563,13 @@
%
% 'EXPERT' OPTIONS:
%
-% (Not recommended without expert knowledge of resampling and
-% filtering.)
+% These settings are not recommended for production use without expert
+% knowledge of resampling, filtering, and the effects they have on the
+% resulting resampled (resize ro distorted) image.
%
-% You can override any and all filter settings. Use "filter:verbose"
-% to make sure that the overall effect of your selections is as
-% expected.
+% You can override any and all filter settings, and it is recommended
+% you make good use of "filter:verbose" to make sure that the overall
+% effect of your selection (before and after) is as expected.
%
% "filter:verbose" Output the exact results of the filter
% selections made, as well as plotting data for graphing the
@@ -618,7 +627,7 @@
% 'Keys' type of filter such that B+2C=1, where Keys 'alpha'
% value = C
%
-% Examples:
+% Examples:
%
% Set a true un-windowed Sinc filter with 10 lobes (very slow):
% -define filter:filter=Sinc
@@ -628,6 +637,7 @@
% -filter Lanczos
% -define filter:lobes=8
%
+%
% The format of the AcquireResizeFilter method is:
%
% ResizeFilter *AcquireResizeFilter(const Image *image,
@@ -694,32 +704,33 @@
window;
} const mapping[SentinelFilter] =
{
- { UndefinedFilter, BoxFilter }, /* Undefined (default to Box) */
- { PointFilter, BoxFilter }, /* SPECIAL: Nearest neighbour */
- { BoxFilter, BoxFilter }, /* Box averaging filter */
- { TriangleFilter, BoxFilter }, /* Linear interpolation filter */
- { HermiteFilter, BoxFilter }, /* Hermite interpolation filter */
- { SincFastFilter, HanningFilter }, /* Hanning -- cosine-sinc */
- { SincFastFilter, HammingFilter }, /* Hamming -- '' variation */
- { SincFastFilter, BlackmanFilter }, /* Blackman -- 2*cosine-sinc */
- { GaussianFilter, BoxFilter }, /* Gaussian blur filter */
- { QuadraticFilter, BoxFilter }, /* Quadratic Gaussian approximation */
- { CubicFilter, BoxFilter }, /* Cubic B-Spline */
- { CatromFilter, BoxFilter }, /* Cubic interpolator */
- { MitchellFilter, BoxFilter }, /* 'Ideal' cubic filter */
- { LanczosFilter, SincFastFilter }, /* SPECIAL: 3-lobed sinc-sinc */
- { JincFilter, BoxFilter }, /* Raw 3-lobed Jinc function */
- { SincFilter, BoxFilter }, /* Raw 4-lobed Sinc function */
- { SincFastFilter, KaiserFilter }, /* Kaiser -- square root-sinc */
- { SincFastFilter, WelshFilter }, /* Welsh -- parabolic-sinc */
- { SincFastFilter, CubicFilter }, /* Parzen -- cubic-sinc */
- { LagrangeFilter, BoxFilter }, /* Lagrange self-windowing filter */
- { SincFastFilter, BohmanFilter }, /* Bohman -- 2*cosine-sinc */
- { SincFastFilter, TriangleFilter }, /* Bartlett -- triangle-sinc */
- { SincFastFilter, BoxFilter }, /* Raw fast sinc ("Pade"-type) */
- { Lanczos2DFilter, JincFilter }, /* SPECIAL: 2-lobed jinc-jinc */
- { Lanczos2DSharpFilter, JincFilter },/* SPECIAL: ditto sharpened */
- { RobidouxFilter, BoxFilter }, /* SPECIAL: Keys cubic tuned for EWA */
+ { UndefinedFilter, BoxFilter }, /* Undefined (default to Box) */
+ { PointFilter, BoxFilter }, /* SPECIAL: Nearest neighbour */
+ { BoxFilter, BoxFilter }, /* Box averaging filter */
+ { TriangleFilter, BoxFilter }, /* Linear interpolation filter */
+ { HermiteFilter, BoxFilter }, /* Hermite interpolation filter */
+ { SincFastFilter, HanningFilter }, /* Hanning -- cosine-sinc */
+ { SincFastFilter, HammingFilter }, /* Hamming -- '' variation */
+ { SincFastFilter, BlackmanFilter }, /* Blackman -- 2*cosine-sinc */
+ { GaussianFilter, BoxFilter }, /* Gaussian blur filter */
+ { QuadraticFilter, BoxFilter }, /* Quadratic Gaussian approx */
+ { CubicFilter, BoxFilter }, /* Cubic B-Spline */
+ { CatromFilter, BoxFilter }, /* Cubic-Keys interpolator */
+ { MitchellFilter, BoxFilter }, /* 'Ideal' Cubic-Keys filter */
+ { LanczosFilter, SincFastFilter }, /* SPECIAL: 3-lobed sinc-sinc */
+ { JincFilter, BoxFilter }, /* Raw 3-lobed Jinc function */
+ { SincFilter, BoxFilter }, /* Raw 4-lobed Sinc function */
+ { SincFastFilter, KaiserFilter }, /* Kaiser -- square root-sinc */
+ { SincFastFilter, WelshFilter }, /* Welsh -- parabolic-sinc */
+ { SincFastFilter, CubicFilter }, /* Parzen -- cubic-sinc */
+ { LagrangeFilter, BoxFilter }, /* Lagrange self-windowing */
+ { SincFastFilter, BohmanFilter }, /* Bohman -- 2*cosine-sinc */
+ { SincFastFilter, TriangleFilter }, /* Bartlett -- triangle-sinc */
+ { SincFastFilter, BoxFilter }, /* Raw fast sinc ("Pade"-type) */
+ { LanczosSharpFilter, SincFastFilter }, /* SPECIAL: Sharpened Lanczos */
+ { Lanczos2DFilter, JincFilter }, /* SPECIAL: 2-lobed jinc-jinc */
+ { Lanczos2DSharpFilter, JincFilter }, /* SPECIAL: ditto sharpened */
+ { RobidouxFilter, BoxFilter }, /* SPECIAL: Keys tuned for EWA */
};
/*
Table mapping the filter/window from the above table to an actual
@@ -760,15 +771,16 @@
{ SincFast, 3.0, 1.0, 0.0, 0.0 }, /* Lanczos, 3-lobed Sinc-Sinc */
{ Jinc, 3.0, 1.2196698912665045, 0.0, 0.0 }, /* Raw 3-lobed Jinc */
{ Sinc, 4.0, 1.0, 0.0, 0.0 }, /* Raw 4-lobed Sinc */
+ { SincFast, 4.0, 1.0, 0.0, 0.0 }, /* Raw fast sinc ("Pade"-type) */
{ Kaiser, 1.0, 1.0, 0.0, 0.0 }, /* Kaiser (square root window) */
{ Welsh, 1.0, 1.0, 0.0, 0.0 }, /* Welsh (parabolic window) */
{ CubicBC, 2.0, 2.0, 1.0, 0.0 }, /* Parzen (B-Spline window) */
{ Lagrange, 2.0, 1.0, 0.0, 0.0 }, /* Lagrange sinc approximation */
{ Bohman, 1.0, 1.0, 0.0, 0.0 }, /* Bohman, 2*Cosine window */
{ Triangle, 1.0, 1.0, 0.0, 0.0 }, /* Bartlett (triangle window) */
- { SincFast, 4.0, 1.0, 0.0, 0.0 }, /* Raw fast sinc ("Pade"-type) */
+ { SincFast, 3.0, 1.0, 0.0, 0.0 }, /* Sharpened 3-lobe Lanczos */
{ Jinc, 2.0, 1.2196698912665045, 0.0, 0.0 },
- /* Lanczos2D (Jinc-Jinc) */
+ /* 2-lobe Cylindrical Lanczos (Jinc-Jinc) */
{ Jinc, 2.0, 1.1684849904329952, 0.0, 0.0 },
/* Lanczos2D sharpened with blur=0.958033808 */
{ CubicBC, 2.0, 1.1685777620836932,
@@ -841,14 +853,19 @@
if ( filter != SincFastFilter )
filter_type=JincFilter;
break;
+ case LanczosSharpFilter:
+ /* A slightly sharper Lanczos */
+ resize_filter->blur *= 0.9830391168464;
+ /* fall-thru to promote it to Jinc-Jinc */
case LanczosFilter:
/* Promote Lanczos from a Sinc-Sinc to a Jinc-Jinc. */
filter_type=JincFilter;
window_type=JincFilter;
break;
case Lanczos2DSharpFilter:
- /* Sharpened by Nicolas Robidoux so as to optimize for minimal
- * blurring of orthogonal lines
+ /* Sharpen Lanczos2d so as to optimize for minimal blurring of
+ * orthogonal lines in EWA cylindrical usage. Value determined by
+ * Nicolas Robidoux. This filter is always a Jinc-Jinc.
*/
resize_filter->blur *= 0.958033808;
break;
@@ -861,10 +878,11 @@
else
switch (filter_type)
{
- case Lanczos2DFilter:
+ case LanczosSharpFilter:
+ resize_filter->blur *= 0.9830391168464; /* Orthogonal sharpen too */
+ break;
case Lanczos2DSharpFilter:
- /* Demote to a 2-lobe Sinc-Sinc for orthogonal use. */
- window_type=SincFastFilter;
+ resize_filter->blur *= 0.958033808; /* Orthogonal sharpen too */
break;
default:
break;
@@ -934,20 +952,9 @@
default:
break;
}
- else
- switch (filter_type)
- {
- case Lanczos2DFilter:
- case Lanczos2DSharpFilter:
- /* Demote to a 2-lobe Lanczos (Sinc-Sinc) for orthogonal use. */
- resize_filter->filter=SincFast;
- break;
- default:
- break;
- }
/*
- ** More Expert Option Modifications
+ ** Other Expert Option Modifications
*/
/* User Sigma Override - no support change */
@@ -979,7 +986,7 @@
lobes=1;
resize_filter->support=(MagickRealType) lobes;
}
- /* convert Jinc lobes to a real support value */
+ /* convert a Jinc function lobes value to a real support value */
if (resize_filter->filter == Jinc)
{
if (resize_filter->support > 16)
@@ -1041,14 +1048,14 @@
}
/* Convert B,C values into Cubic Coefficents. See CubicBC(). */
{
- const double twoB = B+B;
- resize_filter->coeff[0]=1.0-(1.0/3.0)*B;
- resize_filter->coeff[1]=-3.0+twoB+C;
- resize_filter->coeff[2]=2.0-1.5*B-C;
- resize_filter->coeff[3]=(4.0/3.0)*B+4.0*C;
- resize_filter->coeff[4]=-8.0*C-twoB;
- resize_filter->coeff[5]=B+5.0*C;
- resize_filter->coeff[6]=(-1.0/6.0)*B-C;
+ const double twoB = B+B;
+ resize_filter->coeff[0]=1.0-(1.0/3.0)*B;
+ resize_filter->coeff[1]=-3.0+twoB+C;
+ resize_filter->coeff[2]=2.0-1.5*B-C;
+ resize_filter->coeff[3]=(4.0/3.0)*B+4.0*C;
+ resize_filter->coeff[4]=-8.0*C-twoB;
+ resize_filter->coeff[5]=B+5.0*C;
+ resize_filter->coeff[6]=(-1.0/6.0)*B-C;
}
}
@@ -1063,15 +1070,14 @@
if (artifact != (const char *) NULL)
{
double
- support,
+ support,
x;
/*
Set the weighting function properly when the weighting
function may not exactly match the filter of the same name.
- EG: a Point filter really uses a Box weighting function
+ EG: a Point filter is really uses a Box weighting function
with a different support than is typically used.
-
*/
if (resize_filter->filter == Box) filter_type=BoxFilter;
if (resize_filter->filter == Sinc) filter_type=SincFilter;
@@ -1083,24 +1089,24 @@
*/
support=GetResizeFilterSupport(resize_filter); /* practical_support */
(void) fprintf(stdout,"# Resize Filter (for graphing)\n#\n");
- (void) fprintf(stdout,"# filter = %s\n",MagickOptionToMnemonic(
- MagickFilterOptions,filter_type));
- (void) fprintf(stdout,"# window = %s\n",MagickOptionToMnemonic(
- MagickFilterOptions, window_type));
- (void) fprintf(stdout,"# support = %.*g\n",GetMagickPrecision(),
- (double) resize_filter->support);
- (void) fprintf(stdout,"# win-support = %.*g\n",GetMagickPrecision(),
- (double) resize_filter->window_support);
- (void) fprintf(stdout,"# scale_blur = %.*g\n",GetMagickPrecision(),
- (double) resize_filter->blur);
+ (void) fprintf(stdout,"# filter = %s\n",
+ MagickOptionToMnemonic(MagickFilterOptions,filter_type));
+ (void) fprintf(stdout,"# window = %s\n",
+ MagickOptionToMnemonic(MagickFilterOptions, window_type));
+ (void) fprintf(stdout,"# support = %.*g\n",
+ GetMagickPrecision(),(double) resize_filter->support);
+ (void) fprintf(stdout,"# win-support = %.*g\n",
+ GetMagickPrecision(),(double) resize_filter->window_support);
+ (void) fprintf(stdout,"# scale_blur = %.*g\n",
+ GetMagickPrecision(), (double)resize_filter->blur);
if ( filter_type == GaussianFilter )
- (void) fprintf(stdout,"# gaussian_sigma = %.*g\n",GetMagickPrecision(),
- (double) sigma);
- (void) fprintf(stdout,"# practical_support = %.*g\n",GetMagickPrecision(),
- (double) support);
+ (void) fprintf(stdout,"# gaussian_sigma = %.*g\n",
+ GetMagickPrecision(), (double)sigma);
+ (void) fprintf(stdout,"# practical_support = %.*g\n",
+ GetMagickPrecision(), (double)support);
if ( filter_type == CubicFilter || window_type == CubicFilter )
- (void) fprintf(stdout,"# B,C = %.*g,%.*g\n",GetMagickPrecision(),
- (double) B,GetMagickPrecision(),(double) C);
+ (void) fprintf(stdout,"# B,C = %.*g,%.*g\n",
+ GetMagickPrecision(),(double)B, GetMagickPrecision(),(double)C);
(void) fprintf(stdout,"\n");
/*
Output values of resulting filter graph -- for graphing