]> granicus.if.org Git - imagemagick/commitdiff
Addition of the "filter:sigma" expert setting for Gaussian Filters
authoranthony <anthony@git.imagemagick.org>
Tue, 12 Oct 2010 01:22:01 +0000 (01:22 +0000)
committeranthony <anthony@git.imagemagick.org>
Tue, 12 Oct 2010 01:22:01 +0000 (01:22 +0000)
ChangeLog
magick/resize.c

index bd58a019d89a841d8779a4f492f27aec86f9672d..7baccc317336fff19dcc6f40942c5e26201577e5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-10-12  6.6.5-0 Anthony Thyssen <A.Thyssen@griffith...>
+  * Added "filter:sigma" expert setting defining the 'sigma' for the Gaussian
+    filter only.  This is similar in action to 'blur' but only for Gaussians,
+    and does not modify the filters support, allowing you to set a very small
+    sigma, without the function 'missing' all pixels.
+    (This will allow future adjustment of Gaussians for variable blur mapping)
+
 2010-10-10  6.6.5-0 Cristy  <quetzlzacatenango@image...>
   * Patch for  DrawableRotation() and DrawableTranslation() (reference
     http://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=17246).
@@ -6,8 +13,8 @@
 2010-10-05  6.6.5-0 Anthony Thyssen <A.Thyssen@griffith...>
   * Replaced "Robidoux" with Cubic 'Keys' filter that is near equivelent to
     the previous sharped "Lanczos2D" filter. (C=0.31089212245300069)
-    This is very similer to a Mitchell filter but specifically designed for
-    EWA use and is the new default filter for Distorting Images.
+    This also is very similer to a Mitchell filter but specifically designed
+    for EWA use and is the new default filter for Distorting Images.
 
 2010-10-08  6.6.4-10 Jerry Gay  <jerry.gay@gmail..>
   * Autodetect file type support in Makefile.PL to prevent test failures
index 9906dbe26fe391b3585adceb4f8ad27484fffab8..2032ee729032b8e39501aca73b58ff46f74f977a 100644 (file)
@@ -85,7 +85,7 @@ struct _ResizeFilter
     window_support, /* window support, usally equal to support (expert only) */
     scale,          /* dimension scaling to fit window support (usally 1.0) */
     blur,           /* x-scale (blur-sharpen) */
-    cubic[8];       /* cubic coefficents for smooth Cubic filters */
+    coeff[8];       /* cubic coefficents for smooth Cubic filters */
 
   size_t
     signature;
@@ -223,24 +223,31 @@ static MagickRealType CubicBC(const MagickRealType x,
     which ensures function is continuous in value and derivative (slope).
   */
   if (x < 1.0)
-    return(resize_filter->cubic[0]+x*(resize_filter->cubic[1]+x*
-      (resize_filter->cubic[2]+x*resize_filter->cubic[3])));
+    return(resize_filter->coeff[0]+x*(resize_filter->coeff[1]+x*
+      (resize_filter->coeff[2]+x*resize_filter->coeff[3])));
   if (x < 2.0)
-    return(resize_filter->cubic[4]+x*(resize_filter->cubic[5]+x*
-      (resize_filter->cubic[6]+x*resize_filter->cubic[7])));
+    return(resize_filter->coeff[4]+x*(resize_filter->coeff[5]+x*
+      (resize_filter->coeff[6]+x*resize_filter->coeff[7])));
   return(0.0);
 }
 
 static MagickRealType Gaussian(const MagickRealType x,
-  const ResizeFilter *magick_unused(resize_filter))
+  const ResizeFilter *resize_filter)
 {
   /*
-    1D Gaussian with sigma=1/2:
-      exp(-2 x^2)/sqrt(pi/2))
+    Gaussian with a fixed sigma = 1/2
+
+    Gaussian Formula...
+        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.
+
+    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.
   */
-  /*const MagickRealType alpha = (MagickRealType) (2.0/MagickSQ2PI);*/
-  return(exp((double) (-2.0*x*x)));
-}
+  return(exp((double)(-resize_filter->coeff[0]*x*x))); }
 
 static MagickRealType Hanning(const MagickRealType x,
   const ResizeFilter *magick_unused(resize_filter))
@@ -502,7 +509,7 @@ static MagickRealType Welsh(const MagickRealType x,
 %  FIR filters are used as is, and are limited to that filters support
 %  window (unless over-ridden).  'Gaussian' while classed as an IIR
 %  filter, is also simply clipped by its support size (currently 1.5
-%  ro approximatally 3*sigma as recommended by many references)
+%  or approximatally 3*sigma as recommended by many references)
 %
 %  The selection is typically either a windowed Sinc, or interpolated
 %  filter, for use by functions such as ResizeImage().  However if a
@@ -578,6 +585,11 @@ static MagickRealType Welsh(const MagickRealType x,
 %        more ringing effects, while a value <1 will sharpen the
 %        resulting image with more aliasing and Morie effects.
 %
+%    "filter:sigma"    The sigma value to use for the Gaussian filter only.
+%        Defaults to '1/2' for orthogonal and 'sqrt(2)/2' for cylindrical
+%        usage. It effectially provides a alturnative to 'blur' for Gaussians
+%        without it also effecting the final 'practical support' size.
+%
 %    "filter:b"
 %    "filter:c"    Override the preset B,C values for a Cubic type of filter
 %         If only one of these are given it is assumes to be a 'Keys'
@@ -632,7 +644,8 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
 
   MagickRealType
     B,
-    C;
+    C,
+    sigma;
 
   register ResizeFilter
     *resize_filter;
@@ -716,7 +729,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
     { Hanning,   1.0, 1.0,     0.0, 0.0 }, /* Hanning, cosine window      */
     { Hamming,   1.0, 1.0,     0.0, 0.0 }, /* Hamming, '' variation       */
     { Blackman,  1.0, 1.0,     0.0, 0.0 }, /* Blackman, 2*cosine window   */
-    { Gaussian,  1.5, 1.5,     0.0, 0.0 }, /* Gaussian                    */
+    { Gaussian,  2.0, 1.5,     0.0, 0.0 }, /* Gaussian                    */
     { Quadratic, 1.5, 1.5,     0.0, 0.0 }, /* Quadratic gaussian          */
     { CubicBC,   2.0, 2.0,     1.0, 0.0 }, /* Cubic B-Spline (B=1,C=0)    */
     { CubicBC,   2.0, 1.0,     0.0, 0.5 }, /* Catmull-Rom    (B=0,C=1/2)  */
@@ -785,6 +798,8 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
   */
   filter_type=mapping[filter].filter;
   window_type=mapping[filter].window;
+  resize_filter->blur = blur;
+  sigma = 0.5;
   /* Cylindrical Filters should use Jinc instead of Sinc */
   if (cylindrical != MagickFalse)
     switch (filter_type)
@@ -805,6 +820,9 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         filter_type=JincFilter;
         window_type=JincFilter;
         break;
+      case GaussianFilter:
+        sigma = MagickSQ2/2;  /* Cylindrical Gaussian sigma is sqrt(2)/2 */
+        break;
       default:
         break;
     }
@@ -871,14 +889,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
   resize_filter->scale=filters[window_type].scale;
   resize_filter->signature=MagickSignature;
 
-  /* Filter blur -- scaling both filter and support window.  */
-  resize_filter->blur=blur;
-  artifact=GetImageArtifact(image,"filter:blur");
-  if (artifact != (const char *) NULL)
-    resize_filter->blur=StringToDouble(artifact);
-  if (resize_filter->blur < MagickEpsilon)
-    resize_filter->blur=(MagickRealType) MagickEpsilon;
-
+  /* Filter Modifications for orthogonal/cylindrical usage */
   if (cylindrical != MagickFalse)
     switch (filter_type)
     {
@@ -887,14 +898,6 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         /* Support for Cylindrical Box should be sqrt(2)/2 */
         resize_filter->support=(MagickRealType) MagickSQ1_2;
         break;
-      case GaussianFilter:
-        /* Cylindrical Gaussian should have a sigma of sqrt(2)/2
-         * and not the default sigma of 1/2 - so use blur to enlarge
-         * and adjust support so actual practical support = 2.0 by default
-         */
-        resize_filter->blur *= MagickSQ2;
-        resize_filter->support = (MagickRealType) MagickSQ2; /* which times blur => 2.0 */
-        break;
       default:
         break;
     }
@@ -909,7 +912,28 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         break;
     }
 
-  /* Filter support overrides. */
+  /*
+  ** More Expert Option Modifications
+  */
+
+  /* User Sigma Override - no support change */
+  artifact=GetImageArtifact(image,"filter:sigma");
+  if (artifact != (const char *) NULL)
+    sigma=StringToDouble(artifact);
+  /* Define coefficents for Gaussian (assumes no cubic window) */
+  if ( GaussianFilter ) {
+    resize_filter->coeff[0] = 1.0/(2.0*sigma*sigma);
+    resize_filter->coeff[1] = 1.0/(Magick2PI*sigma*sigma); /* unused */
+  }
+
+  /* Blur Override */
+  artifact=GetImageArtifact(image,"filter:blur");
+  if (artifact != (const char *) NULL)
+    resize_filter->blur=StringToDouble(artifact);
+  if (resize_filter->blur < MagickEpsilon)
+    resize_filter->blur=(MagickRealType) MagickEpsilon;
+
+  /* Support Overrides */
   artifact=GetImageArtifact(image,"filter:lobes");
   if (artifact != (const char *) NULL)
     {
@@ -947,8 +971,9 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
     weighting function.  This avoids a division on every filter call.
   */
   resize_filter->scale /= resize_filter->window_support;
+
   /*
-    Set Cubic Spline B,C values, calculate Cubic coefficients.
+   * Set Cubic Spline B,C values, calculate Cubic coefficients.
   */
   B=0.0;
   C=0.0;
@@ -967,7 +992,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         {
           B=StringToDouble(artifact);
           C=(1.0-B)/2.0; /* Calculate C as if it is a Keys cubic filter. */
-          artifact=GetImageArtifact(image,"filter:c");
+          artifact=GetImageArtifact(image,"filter:c"); /* user C override */
           if (artifact != (const char *) NULL)
             C=StringToDouble(artifact);
         }
@@ -980,18 +1005,17 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
               B=1.0-2.0*C;  /* Calculate B as if it is a Keys cubic filter. */
             }
         }
-    /*
-      Convert B,C values into Cubic Coefficents.  See CubicBC().
-    */
-    resize_filter->cubic[0]=(6.0-2.0*B)/6.0;
-    resize_filter->cubic[1]=0.0;
-    resize_filter->cubic[2]=(-18.0+12.0*B+6.0*C)/6.0;
-    resize_filter->cubic[3]=(12.0-9.0*B-6.0*C)/6.0;
-    resize_filter->cubic[4]=(8.0*B+24.0*C)/6.0;
-    resize_filter->cubic[5]=(-12.0*B-48.0*C)/6.0;
-    resize_filter->cubic[6]=(6.0*B+30.0*C)/6.0;
-    resize_filter->cubic[7]=(-B-6.0*C)/6.0;
+    /* Convert B,C values into Cubic Coefficents.  See CubicBC().  */
+    resize_filter->coeff[0]=(6.0-2.0*B)/6.0;
+    resize_filter->coeff[1]=0.0;
+    resize_filter->coeff[2]=(-18.0+12.0*B+6.0*C)/6.0;
+    resize_filter->coeff[3]=(12.0-9.0*B-6.0*C)/6.0;
+    resize_filter->coeff[4]=(8.0*B+24.0*C)/6.0;
+    resize_filter->coeff[5]=(-12.0*B-48.0*C)/6.0;
+    resize_filter->coeff[6]=(6.0*B+30.0*C)/6.0;
+    resize_filter->coeff[7]=(-B-6.0*C)/6.0;
   }
+
   /*
     Expert Option Request for verbose details of the resulting filter.
   */
@@ -1021,7 +1045,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         /*
           Report Filter Details.
         */
-        support=GetResizeFilterSupport(resize_filter); /* support range */
+        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));
@@ -1031,9 +1055,12 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
            (double) resize_filter->support);
         (void) fprintf(stdout,"# win-support = %.*g\n",GetMagickPrecision(),
            (double) resize_filter->window_support);
-        (void) fprintf(stdout,"# blur = %.*g\n",GetMagickPrecision(),
+        (void) fprintf(stdout,"# scale_blur = %.*g\n",GetMagickPrecision(),
            (double) resize_filter->blur);
-       (void) fprintf(stdout,"# blurred_support = %.*g\n",GetMagickPrecision(),
+        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,"# B,C = %.*g,%.*g\n",GetMagickPrecision(),
            (double) B,GetMagickPrecision(),(double) C);
@@ -1049,11 +1076,12 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         (void) fprintf(stdout,"%5.2lf\t%.*g\n",support,GetMagickPrecision(),
           0.0);
       }
-      /* output the above once only for each image, and each setting */
+      /* Output the above once only for each image - remove setting */
       (void) DeleteImageArtifact((Image *) image,"filter:verbose");
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
     }
 #endif
+
   return(resize_filter);
 }
 \f