]> granicus.if.org Git - imagemagick/commitdiff
Added "Lanczos2D" filter optimized for EWA resampling default
authoranthony <anthony@git.imagemagick.org>
Tue, 5 Oct 2010 02:33:31 +0000 (02:33 +0000)
committeranthony <anthony@git.imagemagick.org>
Tue, 5 Oct 2010 02:33:31 +0000 (02:33 +0000)
ChangeLog
magick/option.c
magick/resample.c
magick/resample.h
magick/resize.c

index 915e7dd4f792d69e4a8355fbe621c58943d3921a..82c5d53456047834b26ae3f085efae087cf0d8a6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,19 +1,25 @@
+2010-10-05  6.6.4-10 Anthony Thyssen <A.Thyssen@griffith...>
+  * Added new filter 'Lanczos2D' a 2-lobe Lanczos with a optimization
+    specifically for cylindrical Jinc-Jinc usage (now EWA resampling default)
+
+2010-10-05  6.6.4-10 Cristy  <quetzlzacatenango@image...>
+  * Add support for "pattern:vertical2" and "pattern:horizontal2".
+
 2010-10-03  6.6.4-9 Cristy  <quetzlzacatenango@image...>
   * Fix memory assertion with --enable-embeddable (reference
     http://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=17201).
   * Don't permit access to pixels when pinging an image (reference
     http://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=17194).
-  * Add support for pattern:vertical2 and pattern:horizontal2.
 
 2010-10-02  6.6.4-9 Anthony Thyssen <A.Thyssen@griffith...>
-  * Added sqrt(2) bluring default for Gaussian Filter if used as a
-    Cylindrical EWA filter.  This resulted in the last aliasing issue
-    that was present in tests for Gaussian EWA resampling.
-    However it is still a very blury filter for default use in EWA.
+  * Added sqrt(2) bluring default for Gaussian Filter if used as
+    a Cylindrical EWA filter.  This resulted removing the last aliasing
+    issue that was present in tests for Gaussian EWA resampling. Of course
+    it is still a very blury filter for default use in EWA.
   * Adjusted Variable Mapping Blur Composition so user arguments actual
     relate properly to the sigma of the blur for a maximum mapping value.
-  * Fix horizon anti-alising for output scaled perspective distortions.
-  * 'Bessel' filter is nor offically and more accuritally named 'Jinc'
+  * Fix horizon anti-alising for output-scaled perspective distortions.
+  * 'Bessel' filter is now offically and more accuritally named 'Jinc'
     however 'Bessel' while not visible as a filter option can still be used
     as an internal alias for 'Jinc'.
 
   * Temporary files not always deleted (reference
     http://www.imagemagick.org/discourse-server/viewtopic.php?f=2&t=15960).
 
+2010-09-28  6.6.4-8 Anthony Thyssen <A.Thyssen@griffith...>
+  * Bug fix for -filter point distorts (occasional generating black pixels)
+
 2010-09-27  6.6.4-8 Nicolas Robidoux <nicolas.robidoux@gmail...>
-  * Simplified the ClampUpAxes code, the use of its outputs, its
-    comments, and credited Craig DeForest for the "clamp singular values"
-    idea.
+  * Simplified the ClampUpAxes code, the use of its outputs, its comments,
+    and credited Craig DeForest for the "clamp singular values" idea.
   * No reason to have "insane" precision Sinc in resize.c: Use
     the 1.2e-12 max. abs. relative error version for Q64 as well as Q32.
 
@@ -36,7 +44,6 @@
   * Replace the blurry "High Quality EWA" technique with a 'Clamped EWA'
     for Distort Resampling.  This makes -distort a whole lot nicer
     and allows for the use of better cylindrical filters.
-  * Bug fix for -filter point distorts (occasional generating black pixels)
 
 2010-09-26  6.6.4-7 Anthony Thyssen <A.Thyssen@griffith...>
   * Fix Point filter for ResizeImage() caused by support limiting the
index d7892f93888eee9cb4a968474cc74add12993669..8d30d48ef996fc4dcc70273f63751b3b3786d93b 100644 (file)
@@ -935,7 +935,6 @@ static const OptionInfo
   {
     { "Undefined", (ssize_t) UndefinedFilter, MagickTrue },
     { "Bartlett", (ssize_t) BartlettFilter, MagickFalse },
-    { "Bessel", (ssize_t) JincFilter, MagickTrue }, /* backward compat name */
     { "Blackman", (ssize_t) BlackmanFilter, MagickFalse },
     { "Bohman", (ssize_t) BohmanFilter, MagickFalse },
     { "Box", (ssize_t) BoxFilter, MagickFalse },
@@ -946,9 +945,11 @@ static const OptionInfo
     { "Hanning", (ssize_t) HanningFilter, MagickFalse },
     { "Hermite", (ssize_t) HermiteFilter, MagickFalse },
     { "Jinc", (ssize_t) JincFilter, MagickFalse },
+    { "Bessel", (ssize_t) JincFilter, MagickTrue }, /* Set it after "Jinc" */
     { "Kaiser", (ssize_t) KaiserFilter, MagickFalse },
     { "Lagrange", (ssize_t) LagrangeFilter, MagickFalse },
     { "Lanczos", (ssize_t) LanczosFilter, MagickFalse },
+    { "Lanczos2D", (ssize_t) Lanczos2DFilter, MagickTrue },
     { "Mitchell", (ssize_t) MitchellFilter, MagickFalse },
     { "Parzen", (ssize_t) ParzenFilter, MagickFalse },
     { "Point", (ssize_t) PointFilter, MagickFalse },
index 5070b833a3e2024be8420919474b8581ba3a41f3..e41cdf3ee7deea8cc2ebc085c29bb844430af5b7 100644 (file)
@@ -1766,8 +1766,9 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
       return;  /* EWA turned off - nothing more to do */
     }
 
+  /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
   if ( filter == UndefinedFilter )
-    resample_filter->filter = MitchellFilter;  /* a far less blurry filter */
+    resample_filter->filter = Lanczos2DFilter;
 
   resize_filter = AcquireResizeFilter(resample_filter->image,
        resample_filter->filter,blur,MagickTrue,resample_filter->exception);
@@ -1844,7 +1845,7 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
         printf("#\n");
         printf("# Note: values in table are using a squared radius lookup.\n");
         printf("# And the whole table represents the filters support.\n");
-        printf("#\n");
+        printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
         for(Q=0; Q<WLUT_WIDTH; Q++)
           printf("%8.*g %.*g\n",
                GetMagickPrecision(),sqrt((double)Q)*r_scale,
index cc9fee9564acf6a34a45fedc414e45e091475d0e..faddfad4b2dc3d32ee5aecf9a9f68dbbbd9899e9 100644 (file)
@@ -55,6 +55,7 @@ typedef enum
   BohmanFilter,
   BartlettFilter,
   SincFastFilter,
+  Lanczos2DFilter,
   SentinelFilter  /* a count of all the filters, not a real filter */
 } FilterTypes;
 
index 3e81fe11682ad124edd0e0c56be5e321b9540c86..9c5bfeb8149bf8d4d1a724c913a970e3edc28c87 100644 (file)
@@ -492,6 +492,9 @@ static MagickRealType Welsh(const MagickRealType x,
 %      Blackman     Hanning     Hamming
 %      Kaiser       Lanczos
 %
+%  Special purpose Filters
+%      SincFast  Lanczos2D
+%
 %  The users "-filter" selection is used to lookup the default 'expert'
 %  settings for that filter from a internal table.  However any provided
 %  'expert' settings (see below) may override this selection.
@@ -523,11 +526,16 @@ static MagickRealType Welsh(const MagickRealType x,
 %  and rational (high Q) approximations, and will be used by default in
 %  most cases.
 %
+%  The Lanczos2D filter is just a normal 2-lobed Lanczos filter. But if
+%  selected as a cylindrical (radial) filter, the 2-lobed Jinc windowed
+%  Jinc will be modified by a blur factor to negate the effect of windowing
+%  the Jinc function, and greatly reduce resulting blur.
+%
 %  Special 'expert' options can be used to override any and all filter
 %  settings. This is not advised unless you have expert knowledge of
 %  the use of resampling filtered techniques.  Check on the results of
 %  your selections using the "filter:verbose" setting to make sure you
-%  got what you requested.
+%  get the exact filter that you are tring to achieve.
 %
 %    "filter:filter"    Select the main function associated with
 %        this filter name, as the weighting function of the filter.
@@ -671,6 +679,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
     { 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       */
   };
   /*
     Table mapping the filter/window from the above table to an actual
@@ -689,34 +698,35 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
   {
     MagickRealType
       (*function)(const MagickRealType, const ResizeFilter*),
-      support,  /* default support size for function as a weighting filter */
+      lobes,    /* default lobes/support size of the weighting filter */
       scale,    /* windowing function range, for scaling windowing function */
       B,C;      /* Cubic Filter factors for a CubicBC function, else ignored */
   } const filters[SentinelFilter] =
   {
-    { Box,       0.5,    0.5,    0.0, 0.0 }, /* Undefined (default to Box)  */
-    { Box,       0.0,    0.5,    0.0, 0.0 }, /* Point (special handling)    */
-    { Box,       0.5,    0.5,    0.0, 0.0 }, /* Box                         */
-    { Triangle,  1.0,    1.0,    0.0, 0.0 }, /* Triangle                    */
-    { CubicBC,   1.0,    1.0,    0.0, 0.0 }, /* Hermite (cubic  B=C=0)      */
-    { 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                    */
-    { 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)  */
-    { CubicBC,   2.0,    1.0, 1./3., 1./3. }, /* Mitchell      (B=C=1/3)    */
-    { SincFast,  3.0,    1.0,    0.0, 0.0 }, /* Lanczos, 3-lobed sinc-sinc  */
-    { Jinc,      3.2383, 1.2197, 0.0, 0.0 }, /* Raw 3-lobed Jinc          */
-    { Sinc,      4.0,    1.0,    0.0, 0.0 }, /* Raw 4-lobed Sinc            */
-    { 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) */
+    { Box,       0.5, 0.5,     0.0, 0.0 }, /* Undefined (default to Box)  */
+    { Box,       0.0, 0.5,     0.0, 0.0 }, /* Point (special handling)    */
+    { Box,       0.5, 0.5,     0.0, 0.0 }, /* Box                         */
+    { Triangle,  1.0, 1.0,     0.0, 0.0 }, /* Triangle                    */
+    { CubicBC,   1.0, 1.0,     0.0, 0.0 }, /* Hermite (cubic  B=C=0)      */
+    { 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                    */
+    { 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)  */
+    { CubicBC,   2.0, 1.0, 1./3., 1./3. }, /* Mitchell      (B=C=1/3)    */
+    { SincFast,  3.0, 1.0,     0.0, 0.0 }, /* Lanczos, 3-lobed sinc-sinc  */
+    { Jinc,      3.0, 1.21967, 0.0, 0.0 }, /* Raw 3-lobed Jinc          */
+    { Sinc,      4.0, 1.0,     0.0, 0.0 }, /* Raw 4-lobed Sinc            */
+    { 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) */
+    { Jinc,      2.0, 1.0,     0.0, 0.0 }, /* Lanczos2D, adjusted below   */
   };
   /*
     The known zero crossings of the Jinc() or more accuritally the Jinc(x*PI)
@@ -781,34 +791,38 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         if ( filter != SincFastFilter )
           filter_type=JincFilter;
         break;
+
       case LanczosFilter:
         /* Promote Lanczos from a Sinc-Sinc to a Jinc-Jinc */
         filter_type=JincFilter;
         window_type=JincFilter;
         break;
       default:
-        /*
-          What about other filters to make them 'cylindrical friendly'?
-          For example Mitchell is already actually quite close to a
-          cylindrical Lanczos (Jinc-Jinc) with support 2.  Are there
-          other well known 'cylindrical' specific filters?
-        */
         break;
     }
+  else
+    switch (filter_type)
+    {
+      case Lanczos2DFilter:
+        /* depromote to a 2-lobe Sinc-Sinc for orthoginal use */
+        window_type=SincFastFilter;
+        break;
+      default:
+        break;
+    }
+
   artifact=GetImageArtifact(image,"filter:filter");
   if (artifact != (const char *) NULL)
     {
       option=ParseMagickOption(MagickFilterOptions,MagickFalse,artifact);
       if ((UndefinedFilter < option) && (option < SentinelFilter))
-        {
-          /* Raw filter request - no window function. */
+        { /* Raw filter request - no window function. */
           filter_type=(FilterTypes) option;
           window_type=BoxFilter;
         }
       if (option == LanczosFilter)
-        {
-          /* Lanczos is not a real filter but a self windowing Sinc/Jinc. */
-          filter_type=cylindrical != MagickFalse ? JincFilter : LanczosFilter;
+        { /* Lanczos is not a real filter but a self windowing Sinc/Jinc. */
+          filter_type=cylindrical != MagickFalse ? JincFilter : Lanczos2DFilter;
           window_type=cylindrical != MagickFalse ? JincFilter : SincFastFilter;
         }
       /* Filter override with a specific window function. */
@@ -836,18 +850,19 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
             artifact);
           if ((UndefinedFilter < option) && (option < SentinelFilter))
             {
-              filter_type=cylindrical != MagickFalse ? JincFilter :
-                SincFastFilter;
+              filter_type=cylindrical != MagickFalse ?
+                         JincFilter : SincFastFilter;
               window_type=(FilterTypes) option;
             }
         }
     }
   /* Assign the real functions to use for the filters selected. */
   resize_filter->filter=filters[filter_type].function;
-  resize_filter->support=filters[filter_type].support;
+  resize_filter->support=filters[filter_type].lobes;
   resize_filter->window=filters[window_type].function;
   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");
@@ -872,9 +887,27 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         resize_filter->blur *= MagickSQ2;
         resize_filter->support = (MagickRealType) MagickSQ2; /* which times blur => 2.0 */
         break;
+      case Lanczos2DFilter:
+        /* Special 2 lobed cylindrical Jinc-Jinc filter,
+         * with a special blur adjustment to remove the blurring effect
+         * of the windowing of the Jinc function (in the 2 lobed case only).
+         * To be used as the default filter for EWA Resampling and Distorts.
+         */
+        resize_filter->blur *= (MagickRealType) 0.9549921738;
+      default:
+        break;
+    }
+  else
+    switch (filter_type)
+    {
+      case Lanczos2DFilter:
+        /* depromote to a 2-lobe Sinc-Sinc for orthoginal use */
+        resize_filter->filter=SincFast;
+        break;
       default:
         break;
     }
+
   /* Filter support overrides. */
   artifact=GetImageArtifact(image,"filter:lobes");
   if (artifact != (const char *) NULL)
@@ -886,13 +919,16 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
       if (lobes < 1)
         lobes=1;
       resize_filter->support=(MagickRealType) lobes;
-      if (filter_type == JincFilter)
-        {
-          if (lobes > 16)
-            lobes=16;
-          resize_filter->support = jinc_zeros[lobes-1];
-        }
     }
+  /* convert Jinc lobes to a real support value */
+  if (resize_filter->filter == Jinc)
+    {
+      if (resize_filter->support > 16)
+        resize_filter->support=jinc_zeros[15];  /* largest entry in table */
+      else
+        resize_filter->support = jinc_zeros[((long)resize_filter->support)-1];
+    }
+  /* expert override of the support setting */
   artifact=GetImageArtifact(image,"filter:support");
   if (artifact != (const char *) NULL)
     resize_filter->support=fabs(StringToDouble(artifact));
@@ -959,7 +995,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
     Expert Option Request for verbose details of the resulting filter.
   */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  /* if( GetOpenMPThreadId() == 0 ) { */
+  if( GetOpenMPThreadId() == 0 ) {
 #endif
     artifact=GetImageArtifact(image,"filter:verbose");
     if (artifact != (const char *) NULL)
@@ -978,12 +1014,13 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
         if (resize_filter->filter == Box)       filter_type=BoxFilter;
         if (resize_filter->filter == Sinc)      filter_type=SincFilter;
         if (resize_filter->filter == SincFast)  filter_type=SincFastFilter;
+        if (resize_filter->filter == Jinc)      filter_type=JincFilter;
         if (resize_filter->filter == CubicBC)   filter_type=CubicFilter;
         /*
           Report Filter Details.
         */
         support=GetResizeFilterSupport(resize_filter); /* support range */
-        (void) fprintf(stdout,"#\n# Resize Filter (for graphing)\n#\n");
+        (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(
@@ -998,7 +1035,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
            (double) support);
         (void) fprintf(stdout,"# B,C = %.*g,%.*g\n",GetMagickPrecision(),
            (double) B,GetMagickPrecision(),(double) C);
-        (void) fprintf(stdout,"#\n");
+        (void) fprintf(stdout,"\n");
         /*
           Output values of resulting filter graph -- for graphing
           filter result.
@@ -1011,7 +1048,7 @@ MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
           0.0);
       }
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-    /* } */
+    }
 #endif
   return(resize_filter);
 }