]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/effect.c
(no commit message)
[imagemagick] / MagickCore / effect.c
index 7cd1a346c408de7baeed0b5efcc8c6aa92a38c21..e0072b87d4830b2fc67d69321ce5d3051a581571 100644 (file)
@@ -17,7 +17,7 @@
 %                                 October 1996                                %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -49,6 +49,7 @@
 #include "MagickCore/colorspace.h"
 #include "MagickCore/constitute.h"
 #include "MagickCore/decorate.h"
+#include "MagickCore/distort.h"
 #include "MagickCore/draw.h"
 #include "MagickCore/enhance.h"
 #include "MagickCore/exception.h"
@@ -56,6 +57,7 @@
 #include "MagickCore/effect.h"
 #include "MagickCore/fx.h"
 #include "MagickCore/gem.h"
+#include "MagickCore/gem-private.h"
 #include "MagickCore/geometry.h"
 #include "MagickCore/image-private.h"
 #include "MagickCore/list.h"
@@ -80,6 +82,7 @@
 #include "MagickCore/segment.h"
 #include "MagickCore/shear.h"
 #include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/thread-private.h"
 #include "MagickCore/transform.h"
 %  The format of the AdaptiveBlurImage method is:
 %
 %      Image *AdaptiveBlurImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -164,8 +169,8 @@ MagickExport MagickBooleanType AdaptiveLevelImage(Image *image,
   return(status);
 }
 
-MagickExport Image *AdaptiveBlurImage(const Image *image,
-  const double radius,const double sigma,ExceptionInfo *exception)
+MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
 #define AdaptiveBlurImageTag  "Convolve/Image"
 #define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
@@ -190,9 +195,6 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -225,7 +227,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   /*
     Edge detect the image brighness channel, level, blur, and level again.
   */
-  edge_image=EdgeImage(image,radius,exception);
+  edge_image=EdgeImage(image,radius,sigma,exception);
   if (edge_image == (Image *) NULL)
     {
       blur_image=DestroyImage(blur_image);
@@ -243,7 +245,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
   width=GetOptimalKernelWidth2D(radius,sigma);
-  kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  kernel=(double **) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
   if (kernel == (double **) NULL)
     {
       edge_image=DestroyImage(edge_image);
@@ -253,7 +255,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
   for (i=0; i < (ssize_t) width; i+=2)
   {
-    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+    kernel[i]=(double *) AcquireAlignedMemory((size_t) (width-i),(width-i)*
       sizeof(**kernel));
     if (kernel[i] == (double *) NULL)
       break;
@@ -279,8 +281,8 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   if (i < (ssize_t) width)
     {
       for (i-=2; i >= 0; i-=2)
-        kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
-      kernel=(double **) RelinquishMagickMemory(kernel);
+        kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
+      kernel=(double **) RelinquishAlignedMemory(kernel);
       edge_image=DestroyImage(edge_image);
       blur_image=DestroyImage(blur_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -290,18 +292,15 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
   image_view=AcquireCacheView(image);
   edge_view=AcquireCacheView(edge_image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) blur_image->rows; y++)
   {
     register const Quantum
-      *restrict p,
       *restrict r;
 
     register Quantum
@@ -315,80 +314,115 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
     r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
     q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if ((r == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+    if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) blur_image->columns; x++)
     {
-      PixelInfo
-        pixel;
-
-      MagickRealType
-        alpha,
-        gamma;
-
-      register const double
-        *restrict k;
+      register const Quantum
+        *restrict p;
 
       register ssize_t
-        i,
-        u,
-        v;
+        i;
+
+      ssize_t
+        center,
+        j;
 
-      gamma=0.0;
-      i=(ssize_t) ceil((double) width*QuantumScale*
+      j=(ssize_t) ceil((double) width*QuantumScale*
         GetPixelIntensity(edge_image,r)-0.5);
-      if (i < 0)
-        i=0;
+      if (j < 0)
+        j=0;
       else
-        if (i > (ssize_t) width)
-          i=(ssize_t) width;
-      if ((i & 0x01) != 0)
-        i--;
-      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
-        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+        if (j > (ssize_t) width)
+          j=(ssize_t) width;
+      if ((j & 0x01) != 0)
+        j--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
+        (ssize_t) ((width-j)/2L),width-j,width-j,exception);
       if (p == (const Quantum *) NULL)
         break;
-      pixel=bias;
-      k=kernel[i];
-      for (v=0; v < (ssize_t) (width-i); v++)
+      center=(ssize_t) GetPixelChannels(image)*(width-j)*
+        ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2L);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        for (u=0; u < (ssize_t) (width-i); u++)
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          blur_traits,
+          traits;
+
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
+          }
+        k=kernel[j];
+        pixels=p;
+        pixel=bias;
+        gamma=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (v=0; v < (ssize_t) (width-j); v++)
+            {
+              for (u=0; u < (ssize_t) (width-j); u++)
+              {
+                pixel+=(*k)*pixels[i];
+                gamma+=(*k);
+                k++;
+                pixels+=GetPixelChannels(image);
+              }
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        for (v=0; v < (ssize_t) (width-j); v++)
         {
-          alpha=1.0;
-          if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->matte != MagickFalse))
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
-          gamma+=(*k)*alpha;
-          k++;
-          p+=GetPixelChannels(image);
+          for (u=0; u < (ssize_t) (width-j); u++)
+          {
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            pixel+=(*k)*alpha*pixels[i];
+            gamma+=(*k)*alpha;
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
       }
-      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
       q+=GetPixelChannels(blur_image);
       r+=GetPixelChannels(edge_image);
     }
@@ -400,7 +434,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_AdaptiveSharpenImage)
+        #pragma omp critical (MagickCore_AdaptiveBlurImage)
 #endif
         proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress++,
           image->rows);
@@ -414,8 +448,8 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
   image_view=DestroyCacheView(image_view);
   edge_image=DestroyImage(edge_image);
   for (i=0; i < (ssize_t) width;  i+=2)
-    kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
-  kernel=(double **) RelinquishMagickMemory(kernel);
+    kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
+  kernel=(double **) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);
@@ -441,7 +475,7 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
 %  The format of the AdaptiveSharpenImage method is:
 %
 %      Image *AdaptiveSharpenImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -452,11 +486,13 @@ MagickExport Image *AdaptiveBlurImage(const Image *image,
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
 #define AdaptiveSharpenImageTag  "Convolve/Image"
 #define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
@@ -481,9 +517,6 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -516,7 +549,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   /*
     Edge detect the image brighness channel, level, sharp, and level again.
   */
-  edge_image=EdgeImage(image,radius,exception);
+  edge_image=EdgeImage(image,radius,sigma,exception);
   if (edge_image == (Image *) NULL)
     {
       sharp_image=DestroyImage(sharp_image);
@@ -534,7 +567,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
     Create a set of kernels from maximum (radius,sigma) to minimum.
   */
   width=GetOptimalKernelWidth2D(radius,sigma);
-  kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  kernel=(double **) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
   if (kernel == (double **) NULL)
     {
       edge_image=DestroyImage(edge_image);
@@ -544,7 +577,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
   for (i=0; i < (ssize_t) width; i+=2)
   {
-    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+    kernel[i]=(double *) AcquireAlignedMemory((size_t) (width-i),(width-i)*
       sizeof(**kernel));
     if (kernel[i] == (double *) NULL)
       break;
@@ -570,8 +603,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   if (i < (ssize_t) width)
     {
       for (i-=2; i >= 0; i-=2)
-        kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
-      kernel=(double **) RelinquishMagickMemory(kernel);
+        kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
+      kernel=(double **) RelinquishAlignedMemory(kernel);
       edge_image=DestroyImage(edge_image);
       sharp_image=DestroyImage(sharp_image);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -581,18 +614,15 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
   image_view=AcquireCacheView(image);
   edge_view=AcquireCacheView(edge_image);
   sharp_view=AcquireCacheView(sharp_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) sharp_image->rows; y++)
   {
     register const Quantum
-      *restrict p,
       *restrict r;
 
     register Quantum
@@ -613,73 +643,108 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
       }
     for (x=0; x < (ssize_t) sharp_image->columns; x++)
     {
-      PixelInfo
-        pixel;
-
-      MagickRealType
-        alpha,
-        gamma;
-
-      register const double
-        *restrict k;
+      register const Quantum
+        *restrict p;
 
       register ssize_t
-        i,
-        u,
-        v;
+        i;
+
+      ssize_t
+        center,
+        j;
 
-      gamma=0.0;
-      i=(ssize_t) ceil((double) width*QuantumScale*
+      j=(ssize_t) ceil((double) width*QuantumScale*
         GetPixelIntensity(edge_image,r)-0.5);
-      if (i < 0)
-        i=0;
+      if (j < 0)
+        j=0;
       else
-        if (i > (ssize_t) width)
-          i=(ssize_t) width;
-      if ((i & 0x01) != 0)
-        i--;
-      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
-        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+        if (j > (ssize_t) width)
+          j=(ssize_t) width;
+      if ((j & 0x01) != 0)
+        j--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
+        (ssize_t) ((width-j)/2L),width-j,width-j,exception);
       if (p == (const Quantum *) NULL)
         break;
-      k=kernel[i];
-      pixel=bias;
-      for (v=0; v < (ssize_t) (width-i); v++)
+      center=(ssize_t) GetPixelChannels(image)*(width-j)*
+        ((width-j)/2L)+GetPixelChannels(image)*((width-j)/2);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        for (u=0; u < (ssize_t) (width-i); u++)
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          sharp_traits,
+          traits;
+
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        sharp_traits=GetPixelChannelMapTraits(sharp_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (sharp_traits == UndefinedPixelTrait))
+          continue;
+        if ((sharp_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(sharp_image,channel,p[center+i],q);
+            continue;
+          }
+        k=kernel[j];
+        pixels=p;
+        pixel=bias;
+        gamma=0.0;
+        if ((sharp_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (v=0; v < (ssize_t) (width-j); v++)
+            {
+              for (u=0; u < (ssize_t) (width-j); u++)
+              {
+                pixel+=(*k)*pixels[i];
+                gamma+=(*k);
+                k++;
+                pixels+=GetPixelChannels(image);
+              }
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        for (v=0; v < (ssize_t) (width-j); v++)
         {
-          alpha=1.0;
-          if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->matte != MagickFalse))
-            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
-          gamma+=(*k)*alpha;
-          k++;
-          p+=GetPixelChannels(image);
+          for (u=0; u < (ssize_t) (width-j); u++)
+          {
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+            pixel+=(*k)*alpha*pixels[i];
+            gamma+=(*k)*alpha;
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
       }
-      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(sharp_image,ClampToQuantum(gamma*pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(sharp_image,ClampToQuantum(gamma*pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(sharp_image,ClampToQuantum(gamma*pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(sharp_image,ClampToQuantum(gamma*pixel.black),q);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelAlpha(sharp_image,ClampToQuantum(pixel.alpha),q);
       q+=GetPixelChannels(sharp_image);
       r+=GetPixelChannels(edge_image);
     }
@@ -691,7 +756,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_AdaptiveSharpenImage)
+        #pragma omp critical (MagickCore_AdaptiveSharpenImage)
 #endif
         proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress++,
           image->rows);
@@ -705,8 +770,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
   image_view=DestroyCacheView(image_view);
   edge_image=DestroyImage(edge_image);
   for (i=0; i < (ssize_t) width;  i+=2)
-    kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
-  kernel=(double **) RelinquishMagickMemory(kernel);
+    kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
+  kernel=(double **) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     sharp_image=DestroyImage(sharp_image);
   return(sharp_image);
@@ -735,7 +800,7 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
 %  The format of the BlurImage method is:
 %
 %      Image *BlurImage(const Image *image,const double radius,
-%        const double sigma,ExceptionInfo *exception)
+%        const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -746,6 +811,8 @@ MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
 %
 %    o sigma: the standard deviation of the Gaussian, in pixels.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -767,7 +834,7 @@ static double *GetBlurKernel(const size_t width,const double sigma)
     Generate a 1-D convolution kernel.
   */
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
-  kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  kernel=(double *) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
   if (kernel == (double *) NULL)
     return(0);
   normalize=0.0;
@@ -786,7 +853,7 @@ static double *GetBlurKernel(const size_t width,const double sigma)
 }
 
 MagickExport Image *BlurImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
 #define BlurImageTag  "Blur/Image"
 
@@ -806,9 +873,6 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -816,6 +880,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     width;
 
   ssize_t
+    center,
     x,
     y;
 
@@ -855,7 +920,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
         *k;
 
       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
-        "  BlurImage with %.20g kernel:",(double) width);
+        "  blur image with kernel width %.20g:",(double) width);
       message=AcquireString("");
       k=kernel;
       for (i=0; i < (ssize_t) width; i++)
@@ -874,14 +939,13 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
+  center=(ssize_t) GetPixelChannels(image)*(width/2L);
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
       *restrict p;
@@ -896,108 +960,84 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
       continue;
     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y,
       image->columns+width,1,exception);
-    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+    q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register const Quantum
-        *restrict kernel_pixels;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      kernel_pixels=p;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) ||
-          (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
-          {
-            pixel.red+=(*k)*GetPixelRed(image,kernel_pixels);
-            pixel.green+=(*k)*GetPixelGreen(image,kernel_pixels);
-            pixel.blue+=(*k)*GetPixelBlue(image,kernel_pixels);
-            if (image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*GetPixelBlack(image,kernel_pixels);
-            k++;
-            kernel_pixels+=GetPixelChannels(image);
-          }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-            }
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
 
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
+        register ssize_t
+          u;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            alpha=(MagickRealType) (QuantumScale*
-              GetPixelAlpha(image,kernel_pixels));
-            pixel.red+=(*k)*alpha*GetPixelRed(image,kernel_pixels);
-            pixel.green+=(*k)*alpha*GetPixelGreen(image,kernel_pixels);
-            pixel.blue+=(*k)*alpha*GetPixelBlue(image,kernel_pixels);
-            if (image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*alpha*GetPixelBlack(image,kernel_pixels);
-            gamma+=(*k)*alpha;
-            k++;
-            kernel_pixels+=GetPixelChannels(image);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixels=p;
+        pixel=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (u=0; u < (ssize_t) width; u++)
             {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+              pixel+=(*k)*pixels[i];
+              k++;
+              pixels+=GetPixelChannels(image);
             }
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
+          }
+        /*
+          Alpha blending.
+        */
+        gamma=0.0;
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixels));
+          pixel+=(*k)*alpha*pixels[i];
+          gamma+=(*k)*alpha;
+          k++;
+          pixels+=GetPixelChannels(image);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
@@ -1009,7 +1049,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_BlurImage)
+        #pragma omp critical (MagickCore_BlurImage)
 #endif
         proceed=SetImageProgress(image,BlurImageTag,progress++,blur_image->rows+
           blur_image->columns);
@@ -1022,10 +1062,11 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   /*
     Blur columns.
   */
+  center=(ssize_t) GetPixelChannels(blur_image)*(width/2L);
   image_view=AcquireCacheView(blur_image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (x=0; x < (ssize_t) blur_image->columns; x++)
   {
@@ -1041,7 +1082,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,x,-((ssize_t) width/2L),1,
-      image->rows+width,exception);
+      blur_image->rows+width,exception);
     q=GetCacheViewAuthenticPixels(blur_view,x,0,1,blur_image->rows,exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
@@ -1050,99 +1091,76 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
       }
     for (y=0; y < (ssize_t) blur_image->rows; y++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register const Quantum
-        *restrict kernel_pixels;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      kernel_pixels=p;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) ||
-          (blur_image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        channel=GetPixelChannelMapChannel(blur_image,i);
+        traits=GetPixelChannelMapTraits(blur_image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            pixel.red+=(*k)*GetPixelRed(blur_image,kernel_pixels);
-            pixel.green+=(*k)*GetPixelGreen(blur_image,kernel_pixels);
-            pixel.blue+=(*k)*GetPixelBlue(blur_image,kernel_pixels);
-            if (blur_image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*GetPixelBlack(blur_image,kernel_pixels);
-            k++;
-            kernel_pixels+=GetPixelChannels(blur_image);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixels=p;
+        pixel=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            /*
+              No alpha blending.
+            */
+            for (u=0; u < (ssize_t) width; u++)
             {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(blur_image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+              pixel+=(*k)*pixels[i];
+              k++;
+              pixels+=GetPixelChannels(blur_image);
             }
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
-
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
-          {
-            alpha=(MagickRealType) (QuantumScale*
-              GetPixelAlpha(blur_image,kernel_pixels));
-            pixel.red+=(*k)*alpha*GetPixelRed(blur_image,kernel_pixels);
-            pixel.green+=(*k)*alpha*GetPixelGreen(blur_image,kernel_pixels);
-            pixel.blue+=(*k)*alpha*GetPixelBlue(blur_image,kernel_pixels);
-            if (blur_image->colorspace == CMYKColorspace)
-              pixel.black+=(*k)*alpha*GetPixelBlack(blur_image,kernel_pixels);
-            gamma+=(*k)*alpha;
-            k++;
-            kernel_pixels+=GetPixelChannels(blur_image);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (blur_image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              k=kernel;
-              kernel_pixels=p;
-              for (i=0; i < (ssize_t) width; i++)
-              {
-                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
-                k++;
-                kernel_pixels+=GetPixelChannels(blur_image);
-              }
-              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-            }
+        /*
+          Alpha blending.
+        */
+        gamma=0.0;
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(blur_image,
+            pixels));
+          pixel+=(*k)*alpha*pixels[i];
+          gamma+=(*k)*alpha;
+          k++;
+          pixels+=GetPixelChannels(blur_image);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(blur_image);
       q+=GetPixelChannels(blur_image);
     }
@@ -1154,7 +1172,7 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_BlurImage)
+        #pragma omp critical (MagickCore_BlurImage)
 #endif
         proceed=SetImageProgress(blur_image,BlurImageTag,progress++,
           blur_image->rows+blur_image->columns);
@@ -1164,10 +1182,10 @@ MagickExport Image *BlurImage(const Image *image,const double radius,
   }
   blur_view=DestroyCacheView(blur_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishMagickMemory(kernel);
+  kernel=(double *) RelinquishAlignedMemory(kernel);
+  blur_image->type=image->type;
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
-  blur_image->type=image->type;
   return(blur_image);
 }
 \f
@@ -1246,7 +1264,7 @@ MagickExport Image *ConvolveImage(const Image *image,
         format[MaxTextExtent],
         *message;
 
-      register const double
+      register const MagickRealType
         *k;
 
       register ssize_t
@@ -1274,17 +1292,21 @@ MagickExport Image *ConvolveImage(const Image *image,
       }
       message=DestroyString(message);
     }
+  status=AccelerateConvolveImage(image,kernel_info,convolve_image,exception);
+  if (status == MagickTrue)
+    return(convolve_image);
   /*
     Convolve image.
+    FUTURE: Use Morphology Convolve instead.
   */
   center=(ssize_t) GetPixelChannels(image)*(image->columns+kernel_info->width)*
-    (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2);
+    (kernel_info->height/2L)+GetPixelChannels(image)*(kernel_info->width/2L);
   status=MagickTrue;
   progress=0;
   image_view=AcquireCacheView(image);
   convolve_view=AcquireCacheView(convolve_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1328,7 +1350,7 @@ MagickExport Image *ConvolveImage(const Image *image,
           convolve_traits,
           traits;
 
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
@@ -1340,16 +1362,15 @@ MagickExport Image *ConvolveImage(const Image *image,
         ssize_t
           v;
 
-        traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
-        if (traits == UndefinedPixelTrait)
-          continue;
-        channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
         convolve_traits=GetPixelChannelMapTraits(convolve_image,channel);
-        if (convolve_traits == UndefinedPixelTrait)
+        if ((traits == UndefinedPixelTrait) ||
+            (convolve_traits == UndefinedPixelTrait))
           continue;
         if ((convolve_traits & CopyPixelTrait) != 0)
           {
-            q[channel]=p[center+i];
+            SetPixelChannel(convolve_image,channel,p[center+i],q);
             continue;
           }
         k=kernel_info->values;
@@ -1370,7 +1391,7 @@ MagickExport Image *ConvolveImage(const Image *image,
               }
               pixels+=image->columns*GetPixelChannels(image);
             }
-            q[channel]=ClampToQuantum(pixel);
+            SetPixelChannel(convolve_image,channel,ClampToQuantum(pixel),q);
             continue;
           }
         /*
@@ -1390,7 +1411,7 @@ MagickExport Image *ConvolveImage(const Image *image,
           pixels+=image->columns*GetPixelChannels(image);
         }
         gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-        q[channel]=ClampToQuantum(gamma*pixel);
+        SetPixelChannel(convolve_image,channel,ClampToQuantum(gamma*pixel),q);
       }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(convolve_image);
@@ -1403,7 +1424,7 @@ MagickExport Image *ConvolveImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ConvolveImage)
+        #pragma omp critical (MagickCore_ConvolveImage)
 #endif
         proceed=SetImageProgress(image,ConvolveImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -1430,7 +1451,10 @@ MagickExport Image *ConvolveImage(const Image *image,
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  DespeckleImage() reduces the speckle noise in an image while perserving the
-%  edges of the original image.
+%  edges of the original image.  A speckle removing filter uses a complementary %  hulling technique (raising pixels that are darker than their surrounding
+%  neighbors, then complementarily lowering pixels that are brighter than their
+%  surrounding neighbors) to reduce the speckle index of that image (reference
+%  Crimmins speckle removal).
 %
 %  The format of the DespeckleImage method is:
 %
@@ -1445,21 +1469,15 @@ MagickExport Image *ConvolveImage(const Image *image,
 */
 
 static void Hull(const ssize_t x_offset,const ssize_t y_offset,
-  const size_t columns,const size_t rows,Quantum *f,Quantum *g,
-  const int polarity)
+  const size_t columns,const size_t rows,const int polarity,Quantum *restrict f,
+  Quantum *restrict g)
 {
-  MagickRealType
-    v;
-
   register Quantum
     *p,
     *q,
     *r,
     *s;
 
-  register ssize_t
-    x;
-
   ssize_t
     y;
 
@@ -1467,80 +1485,76 @@ static void Hull(const ssize_t x_offset,const ssize_t y_offset,
   assert(g != (Quantum *) NULL);
   p=f+(columns+2);
   q=g+(columns+2);
-  r=p+(y_offset*((ssize_t) columns+2)+x_offset);
+  r=p+(y_offset*(columns+2)+x_offset);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static)
+#endif
   for (y=0; y < (ssize_t) rows; y++)
   {
-    p++;
-    q++;
-    r++;
+    register ssize_t
+      i,
+      x;
+
+    SignedQuantum
+      v;
+
+    i=(2*y+1)+y*columns;
     if (polarity > 0)
-      for (x=(ssize_t) columns; x != 0; x--)
+      for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(MagickRealType) (*p);
-        if ((MagickRealType) *r >= (v+(MagickRealType) ScaleCharToQuantum(2)))
+        v=(SignedQuantum) p[i];
+        if ((SignedQuantum) r[i] >= (v+ScaleCharToQuantum(2)))
           v+=ScaleCharToQuantum(1);
-        *q=(Quantum) v;
-        p++;
-        q++;
-        r++;
+        q[i]=(Quantum) v;
+        i++;
       }
     else
-      for (x=(ssize_t) columns; x != 0; x--)
+      for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(MagickRealType) (*p);
-        if ((MagickRealType) *r <= (v-(MagickRealType) ScaleCharToQuantum(2)))
-          v-=(ssize_t) ScaleCharToQuantum(1);
-        *q=(Quantum) v;
-        p++;
-        q++;
-        r++;
+        v=(SignedQuantum) p[i];
+        if ((SignedQuantum) r[i] <= (v-ScaleCharToQuantum(2)))
+          v-=ScaleCharToQuantum(1);
+        q[i]=(Quantum) v;
+        i++;
       }
-    p++;
-    q++;
-    r++;
   }
   p=f+(columns+2);
   q=g+(columns+2);
-  r=q+(y_offset*((ssize_t) columns+2)+x_offset);
-  s=q-(y_offset*((ssize_t) columns+2)+x_offset);
+  r=q+(y_offset*(columns+2)+x_offset);
+  s=q-(y_offset*(columns+2)+x_offset);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static)
+#endif
   for (y=0; y < (ssize_t) rows; y++)
   {
-    p++;
-    q++;
-    r++;
-    s++;
+    register ssize_t
+      i,
+      x;
+
+    SignedQuantum
+      v;
+
+    i=(2*y+1)+y*columns;
     if (polarity > 0)
-      for (x=(ssize_t) columns; x != 0; x--)
+      for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(MagickRealType) (*q);
-        if (((MagickRealType) *s >=
-             (v+(MagickRealType) ScaleCharToQuantum(2))) &&
-            ((MagickRealType) *r > v))
+        v=(SignedQuantum) q[i];
+        if (((SignedQuantum) s[i] >= (v+ScaleCharToQuantum(2))) &&
+            ((SignedQuantum) r[i] > v))
           v+=ScaleCharToQuantum(1);
-        *p=(Quantum) v;
-        p++;
-        q++;
-        r++;
-        s++;
+        p[i]=(Quantum) v;
+        i++;
       }
     else
-      for (x=(ssize_t) columns; x != 0; x--)
+      for (x=0; x < (ssize_t) columns; x++)
       {
-        v=(MagickRealType) (*q);
-        if (((MagickRealType) *s <=
-             (v-(MagickRealType) ScaleCharToQuantum(2))) &&
-            ((MagickRealType) *r < v))
-          v-=(MagickRealType) ScaleCharToQuantum(1);
-        *p=(Quantum) v;
-        p++;
-        q++;
-        r++;
-        s++;
+        v=(SignedQuantum) q[i];
+        if (((SignedQuantum) s[i] <= (v-ScaleCharToQuantum(2))) &&
+            ((SignedQuantum) r[i] < v))
+          v-=ScaleCharToQuantum(1);
+        p[i]=(Quantum) v;
+        i++;
       }
-    p++;
-    q++;
-    r++;
-    s++;
   }
 }
 
@@ -1558,16 +1572,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
   MagickBooleanType
     status;
 
-  register ssize_t
-    i;
-
   Quantum
-    *restrict buffers,
+    *restrict buffer,
     *restrict pixels;
 
+  register ssize_t
+    i;
+
   size_t
-    length,
-    number_channels;
+    length;
 
   static const ssize_t
     X[4] = {0, 1, 1,-1},
@@ -1582,25 +1595,25 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  despeckle_image=CloneImage(image,image->columns,image->rows,MagickTrue,
-    exception);
+  despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
   if (despeckle_image == (Image *) NULL)
     return((Image *) NULL);
-  if (SetImageStorageClass(despeckle_image,DirectClass,exception) == MagickFalse)
+  status=SetImageStorageClass(despeckle_image,DirectClass,exception);
+  if (status == MagickFalse)
     {
       despeckle_image=DestroyImage(despeckle_image);
       return((Image *) NULL);
     }
   /*
-    Allocate image buffers.
+    Allocate image buffer.
   */
   length=(size_t) ((image->columns+2)*(image->rows+2));
-  pixels=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
-  buffers=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
-  if ((pixels == (Quantum *) NULL) || (buffers == (Quantum *) NULL))
+  pixels=(Quantum *) AcquireQuantumMemory(length,sizeof(*pixels));
+  buffer=(Quantum *) AcquireQuantumMemory(length,sizeof(*buffer));
+  if ((pixels == (Quantum *) NULL) || (buffer == (Quantum *) NULL))
     {
-      if (buffers != (Quantum *) NULL)
-        buffers=(Quantum *) RelinquishMagickMemory(buffers);
+      if (buffer != (Quantum *) NULL)
+        buffer=(Quantum *) RelinquishMagickMemory(buffer);
       if (pixels != (Quantum *) NULL)
         pixels=(Quantum *) RelinquishMagickMemory(pixels);
       despeckle_image=DestroyImage(despeckle_image);
@@ -1610,14 +1623,16 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
     Reduce speckle in the image.
   */
   status=MagickTrue;
-  number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
   image_view=AcquireCacheView(image);
   despeckle_view=AcquireCacheView(despeckle_image);
-  for (i=0; i < (ssize_t) number_channels; i++)
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
-    register Quantum
-      *buffer,
-      *pixel;
+    PixelChannel
+       channel;
+
+    PixelTrait
+      despeckle_traits,
+      traits;
 
     register ssize_t
       k,
@@ -1629,9 +1644,15 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 
     if (status == MagickFalse)
       continue;
-    pixel=pixels;
-    (void) ResetMagickMemory(pixel,0,length*sizeof(*pixel));
-    buffer=buffers;
+    channel=GetPixelChannelMapChannel(image,i);
+    traits=GetPixelChannelMapTraits(image,channel);
+    despeckle_traits=GetPixelChannelMapTraits(despeckle_image,channel);
+    if ((traits == UndefinedPixelTrait) ||
+        (despeckle_traits == UndefinedPixelTrait))
+      continue;
+    if ((despeckle_traits & CopyPixelTrait) != 0)
+      continue;
+    (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
     j=(ssize_t) image->columns+2;
     for (y=0; y < (ssize_t) image->rows; y++)
     {
@@ -1640,31 +1661,25 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 
       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
       if (p == (const Quantum *) NULL)
-        break;
+        {
+          status=MagickFalse;
+          continue;
+        }
       j++;
       for (x=0; x < (ssize_t) image->columns; x++)
       {
-        switch (i)
-        {
-          case 0: pixel[j]=GetPixelRed(image,p); break;
-          case 1: pixel[j]=GetPixelGreen(image,p); break;
-          case 2: pixel[j]=GetPixelBlue(image,p); break;
-          case 3: pixel[j]=GetPixelAlpha(image,p); break;
-          case 4: pixel[j]=GetPixelBlack(image,p); break;
-          default: break;
-        }
+        pixels[j++]=p[i];
         p+=GetPixelChannels(image);
-        j++;
       }
       j++;
     }
     (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
     for (k=0; k < 4; k++)
     {
-      Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,1);
-      Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,1);
-      Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,-1);
-      Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,-1);
+      Hull(X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
+      Hull(-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
+      Hull(-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
+      Hull(X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
     }
     j=(ssize_t) image->columns+2;
     for (y=0; y < (ssize_t) image->rows; y++)
@@ -1675,31 +1690,22 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
       register Quantum
         *restrict q;
 
-      q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
-        1,exception);
-      if (q == (const Quantum *) NULL)
-        break;
+      q=QueueCacheViewAuthenticPixels(despeckle_view,0,y,
+        despeckle_image->columns,1,exception);
+      if (q == (Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
       j++;
       for (x=0; x < (ssize_t) image->columns; x++)
       {
-        switch (i)
-        {
-          case 0: SetPixelRed(despeckle_image,pixel[j],q); break;
-          case 1: SetPixelGreen(despeckle_image,pixel[j],q); break;
-          case 2: SetPixelBlue(despeckle_image,pixel[j],q); break;
-          case 3: SetPixelAlpha(despeckle_image,pixel[j],q); break;
-          case 4: SetPixelBlack(despeckle_image,pixel[j],q); break;
-          default: break;
-        }
+        SetPixelChannel(despeckle_image,channel,pixels[j++],q);
         q+=GetPixelChannels(despeckle_image);
-        j++;
       }
       sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
       if (sync == MagickFalse)
-        {
-          status=MagickFalse;
-          break;
-        }
+        status=MagickFalse;
       j++;
     }
     if (image->progress_monitor != (MagickProgressMonitor) NULL)
@@ -1708,14 +1714,14 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
           proceed;
 
         proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
-          number_channels);
+          GetPixelChannels(image));
         if (proceed == MagickFalse)
           status=MagickFalse;
       }
   }
   despeckle_view=DestroyCacheView(despeckle_view);
   image_view=DestroyCacheView(image_view);
-  buffers=(Quantum *) RelinquishMagickMemory(buffers);
+  buffer=(Quantum *) RelinquishMagickMemory(buffer);
   pixels=(Quantum *) RelinquishMagickMemory(pixels);
   despeckle_image->type=image->type;
   if (status == MagickFalse)
@@ -1741,7 +1747,7 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 %  The format of the EdgeImage method is:
 %
 %      Image *EdgeImage(const Image *image,const double radius,
-%        ExceptionInfo *exception)
+%        const double sigma,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1749,11 +1755,13 @@ MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
 %
 %    o radius: the radius of the pixel neighborhood.
 %
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *EdgeImage(const Image *image,const double radius,
-  ExceptionInfo *exception)
+  const double sigma,ExceptionInfo *exception)
 {
   Image
     *edge_image;
@@ -1778,15 +1786,15 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  width=GetOptimalKernelWidth1D(radius,0.5);
+  width=GetOptimalKernelWidth1D(radius,sigma);
   kernel_info=AcquireKernelInfo((const char *) NULL);
   if (kernel_info == (KernelInfo *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   kernel_info->width=width;
   kernel_info->height=width;
-  kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
-    kernel_info->width*sizeof(*kernel_info->values));
-  if (kernel_info->values == (double *) NULL)
+  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
+    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -1802,7 +1810,7 @@ MagickExport Image *EdgeImage(const Image *image,const double radius,
     }
   }
   kernel_info->values[i/2]=(double) (width*width-1.0);
-  kernel_info->bias=image->bias;
+  kernel_info->bias=image->bias;   /* FUTURE: User bias on a edge image? */
   edge_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(edge_image);
@@ -1868,15 +1876,15 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  width=GetOptimalKernelWidth2D(radius,sigma);
+  width=GetOptimalKernelWidth1D(radius,sigma);
   kernel_info=AcquireKernelInfo((const char *) NULL);
   if (kernel_info == (KernelInfo *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   kernel_info->width=width;
   kernel_info->height=width;
-  kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
-    kernel_info->width*sizeof(*kernel_info->values));
-  if (kernel_info->values == (double *) NULL)
+  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
+    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -1897,7 +1905,7 @@ MagickExport Image *EmbossImage(const Image *image,const double radius,
     }
     k--;
   }
-  kernel_info->bias=image->bias;
+  kernel_info->bias=image->bias;  /* FUTURE: user bias on an edge image */
   emboss_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   if (emboss_image != (Image *) NULL)
@@ -1972,9 +1980,9 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
   kernel_info->width=width;
   kernel_info->height=width;
   kernel_info->signature=MagickSignature;
-  kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
-    kernel_info->width*sizeof(*kernel_info->values));
-  if (kernel_info->values == (double *) NULL)
+  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
+    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -1990,7 +1998,6 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
       i++;
     }
   }
-  kernel_info->bias=image->bias;
   blur_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(blur_image);
@@ -2018,7 +2025,8 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
 %  The format of the MotionBlurImage method is:
 %
 %    Image *MotionBlurImage(const Image *image,const double radius,
-%      const double sigma,const double angle,ExceptionInfo *exception)
+%      const double sigma,const double angle,const double bias,
+%      ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2031,6 +2039,8 @@ MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
 %
 %    o angle: Apply the effect along this angle.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
@@ -2048,7 +2058,7 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma)
    Generate a 1-D convolution kernel.
   */
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
-  kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  kernel=(double *) AcquireAlignedMemory((size_t) width,sizeof(*kernel));
   if (kernel == (double *) NULL)
     return(kernel);
   normalize=0.0;
@@ -2063,13 +2073,14 @@ static double *GetMotionBlurKernel(const size_t width,const double sigma)
   return(kernel);
 }
 
-MagickExport Image *MotionBlurImage(const Image *image,
-  const double radius,const double sigma,const double angle,
+MagickExport Image *MotionBlurImage(const Image *image,const double radius,
+  const double sigma,const double angle,const double bias,
   ExceptionInfo *exception)
 {
   CacheView
     *blur_view,
-    *image_view;
+    *image_view,
+    *motion_view;
 
   double
     *kernel;
@@ -2083,9 +2094,6 @@ MagickExport Image *MotionBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   OffsetInfo
     *offset;
 
@@ -2113,19 +2121,19 @@ MagickExport Image *MotionBlurImage(const Image *image,
   offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
   if (offset == (OffsetInfo *) NULL)
     {
-      kernel=(double *) RelinquishMagickMemory(kernel);
+      kernel=(double *) RelinquishAlignedMemory(kernel);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
     }
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     {
-      kernel=(double *) RelinquishMagickMemory(kernel);
+      kernel=(double *) RelinquishAlignedMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
       return((Image *) NULL);
     }
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
     {
-      kernel=(double *) RelinquishMagickMemory(kernel);
+      kernel=(double *) RelinquishAlignedMemory(kernel);
       offset=(OffsetInfo *) RelinquishMagickMemory(offset);
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
@@ -2142,14 +2150,17 @@ MagickExport Image *MotionBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
+  motion_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
+    register const Quantum
+      *restrict p;
+
     register Quantum
       *restrict q;
 
@@ -2158,100 +2169,92 @@ MagickExport Image *MotionBlurImage(const Image *image,
 
     if (status == MagickFalse)
       continue;
-    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        qixel;
+      register ssize_t
+        i;
 
-      PixelPacket
-        pixel;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          pixel;
 
-      register double
-        *restrict k;
+        PixelChannel
+          channel;
 
-      register ssize_t
-        i;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      k=kernel;
-      qixel=bias;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) width; i++)
+        register const Quantum
+          *restrict r;
+
+        register double
+          *restrict k;
+
+        register ssize_t
+          j;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
-              offset[i].y,&pixel,exception);
-            qixel.red+=(*k)*pixel.red;
-            qixel.green+=(*k)*pixel.green;
-            qixel.blue+=(*k)*pixel.blue;
-            qixel.alpha+=(*k)*pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=(*k)*pixel.black;
-            k++;
+            SetPixelChannel(blur_image,channel,p[i],q);
+            continue;
           }
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(qixel.alpha),q);
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
-
-          alpha=0.0;
-          gamma=0.0;
-          for (i=0; i < (ssize_t) width; i++)
+        k=kernel;
+        pixel=bias;
+        if ((blur_traits & BlendPixelTrait) == 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
-              offset[i].y,&pixel,exception);
-            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
-            qixel.red+=(*k)*alpha*pixel.red;
-            qixel.green+=(*k)*alpha*pixel.green;
-            qixel.blue+=(*k)*alpha*pixel.blue;
-            qixel.alpha+=(*k)*pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=(*k)*alpha*pixel.black;
-            gamma+=(*k)*alpha;
-            k++;
+            for (j=0; j < (ssize_t) width; j++)
+            {
+              r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
+                offset[j].y,1,1,exception);
+              if (r == (const Quantum *) NULL)
+                {
+                  status=MagickFalse;
+                  continue;
+                }
+              pixel+=(*k)*r[i];
+              k++;
+            }
+            SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(gamma*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(gamma*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(gamma*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(gamma*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(qixel.alpha),q);
+        alpha=0.0;
+        gamma=0.0;
+        for (j=0; j < (ssize_t) width; j++)
+        {
+          r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
+            1,exception);
+          if (r == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              continue;
+            }
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,r));
+          pixel+=(*k)*alpha*r[i];
+          gamma+=(*k)*alpha;
+          k++;
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
+      p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
@@ -2262,7 +2265,7 @@ MagickExport Image *MotionBlurImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_MotionBlurImage)
+        #pragma omp critical (MagickCore_MotionBlurImage)
 #endif
         proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -2270,8 +2273,9 @@ MagickExport Image *MotionBlurImage(const Image *image,
       }
   }
   blur_view=DestroyCacheView(blur_view);
+  motion_view=DestroyCacheView(motion_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishMagickMemory(kernel);
+  kernel=(double *) RelinquishAlignedMemory(kernel);
   offset=(OffsetInfo *) RelinquishMagickMemory(offset);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
@@ -2387,10 +2391,11 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       break;
     (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
       (void *) NULL);
-    (void) SetImageProperty(thumbnail,"label",DefaultTileLabel);
+    (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
     if (i == (NumberTiles/2))
       {
-        (void) QueryColorDatabase("#dfdfdf",&thumbnail->matte_color,exception);
+        (void) QueryColorCompliance("#dfdfdf",AllCompliance,
+          &thumbnail->matte_color,exception);
         AppendImageToList(&images,thumbnail);
         continue;
       }
@@ -2492,7 +2497,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         colors<<=1;
         quantize_info.number_colors=colors;
         quantize_info.colorspace=GRAYColorspace;
-        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) QuantizeImage(&quantize_info,preview_image,exception);
         (void) FormatLocaleString(label,MaxTextExtent,
           "-colorspace gray -colors %.20g",(double) colors);
         break;
@@ -2504,7 +2509,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         colors<<=1;
         quantize_info.number_colors=colors;
-        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) QuantizeImage(&quantize_info,preview_image,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"colors %.20g",(double)
           colors);
         break;
@@ -2580,14 +2585,17 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       }
       case SharpenPreview:
       {
-        preview_image=SharpenImage(thumbnail,radius,sigma,exception);
+        /* FUTURE: user bias on sharpen! This is non-sensical! */
+        preview_image=SharpenImage(thumbnail,radius,sigma,image->bias,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",
           radius,sigma);
         break;
       }
       case BlurPreview:
       {
-        preview_image=BlurImage(thumbnail,radius,sigma,exception);
+        /* FUTURE: user bias on blur! This is non-sensical! */
+        preview_image=BlurImage(thumbnail,radius,sigma,image->bias,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius,
           sigma);
         break;
@@ -2597,21 +2605,22 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
         if (preview_image == (Image *) NULL)
           break;
-        (void) BilevelImage(thumbnail,
-          (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
+        (void) BilevelImage(thumbnail,(double) (percentage*((MagickRealType)
+          QuantumRange+1.0))/100.0,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",
           (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
         break;
       }
       case EdgeDetectPreview:
       {
-        preview_image=EdgeImage(thumbnail,radius,exception);
+        preview_image=EdgeImage(thumbnail,radius,sigma,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"edge %g",radius);
         break;
       }
       case SpreadPreview:
       {
-        preview_image=SpreadImage(thumbnail,radius,exception);
+        preview_image=SpreadImage(thumbnail,radius,thumbnail->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"spread %g",
           radius+0.5);
         break;
@@ -2622,7 +2631,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
         if (preview_image == (Image *) NULL)
           break;
         (void) SolarizeImage(preview_image,(double) QuantumRange*
-          percentage/100.0);
+          percentage/100.0,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
           (QuantumRange*percentage)/100.0);
         break;
@@ -2658,14 +2667,15 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
           break;
         threshold+=0.4f;
         (void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold,
-          threshold);
+          threshold,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
           threshold,threshold);
         break;
       }
       case SwirlPreview:
       {
-        preview_image=SwirlImage(thumbnail,degrees,exception);
+        preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"swirl %g",degrees);
         degrees+=45.0;
         break;
@@ -2673,14 +2683,16 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       case ImplodePreview:
       {
         degrees+=0.1f;
-        preview_image=ImplodeImage(thumbnail,degrees,exception);
+        preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
+          exception);
         (void) FormatLocaleString(label,MaxTextExtent,"implode %g",degrees);
         break;
       }
       case WavePreview:
       {
         degrees+=5.0f;
-        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
+        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
+          image->interpolate,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",
           0.5*degrees,2.0*degrees);
         break;
@@ -2695,8 +2707,9 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
       }
       case CharcoalDrawingPreview:
       {
+        /* FUTURE: user bias on charcoal! This is non-sensical! */
         preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
-          exception);
+          image->bias,exception);
         (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
           radius,sigma);
         break;
@@ -2761,7 +2774,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
     if (preview_image == (Image *) NULL)
       break;
     (void) DeleteImageProperty(preview_image,"label");
-    (void) SetImageProperty(preview_image,"label",label);
+    (void) SetImageProperty(preview_image,"label",label,exception);
     AppendImageToList(&images,preview_image);
     proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
       NumberTiles);
@@ -2820,7 +2833,7 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
 %  The format of the RadialBlurImage method is:
 %
 %    Image *RadialBlurImage(const Image *image,const double angle,
-%      ExceptionInfo *exception)
+%      const double blur,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2828,15 +2841,18 @@ MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
 %
 %    o angle: the angle of the radial blur.
 %
+%    o blur: the blur.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport Image *RadialBlurImage(const Image *image,
-  const double angle,ExceptionInfo *exception)
+MagickExport Image *RadialBlurImage(const Image *image,const double angle,
+  const double bias,ExceptionInfo *exception)
 {
   CacheView
     *blur_view,
-    *image_view;
+    *image_view,
+    *radial_view;
 
   Image
     *blur_image;
@@ -2847,9 +2863,6 @@ MagickExport Image *RadialBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   MagickRealType
     blur_radius,
     *cos_theta,
@@ -2878,7 +2891,7 @@ MagickExport Image *RadialBlurImage(const Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     return((Image *) NULL);
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
@@ -2912,14 +2925,17 @@ MagickExport Image *RadialBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
+  radial_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
-  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
+    register const Quantum
+      *restrict p;
+
     register Quantum
       *restrict q;
 
@@ -2928,25 +2944,19 @@ MagickExport Image *RadialBlurImage(const Image *image,
 
     if (status == MagickFalse)
       continue;
-    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        qixel;
-
       MagickRealType
-        normalize,
         radius;
 
-      PixelPacket
-        pixel;
-
       PointInfo
         center;
 
@@ -2970,87 +2980,76 @@ MagickExport Image *RadialBlurImage(const Image *image,
             if (step >= n)
               step=n-1;
         }
-      normalize=0.0;
-      qixel=bias;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          gamma,
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          blur_traits,
+          traits;
+
+        register const Quantum
+          *restrict r;
+
+        register ssize_t
+          j;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
-              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
-              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
-              cos_theta[i]+0.5),&pixel,exception);
-            qixel.red+=pixel.red;
-            qixel.green+=pixel.green;
-            qixel.blue+=pixel.blue;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=pixel.black;
-            qixel.alpha+=pixel.alpha;
-            normalize+=1.0;
+            SetPixelChannel(blur_image,channel,p[i],q);
+            continue;
           }
-          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
-            normalize);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(normalize*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(normalize*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(normalize*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(normalize*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(normalize*qixel.alpha),q);
-        }
-      else
-        {
-          MagickRealType
-            alpha,
-            gamma;
-
-          alpha=1.0;
-          gamma=0.0;
-          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+        gamma=0.0;
+        pixel=bias;
+        if ((blur_traits & BlendPixelTrait) == 0)
           {
-            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
-              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
-              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
-              cos_theta[i]+0.5),&pixel,exception);
-            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
-            qixel.red+=alpha*pixel.red;
-            qixel.green+=alpha*pixel.green;
-            qixel.blue+=alpha*pixel.blue;
-            qixel.alpha+=pixel.alpha;
-            if (image->colorspace == CMYKColorspace)
-              qixel.black+=alpha*pixel.black;
-            gamma+=alpha;
-            normalize+=1.0;
+            for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
+            {
+              r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
+                center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
+                (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
+                1,1,exception);
+              if (r == (const Quantum *) NULL)
+                {
+                  status=MagickFalse;
+                  continue;
+                }
+              pixel+=r[i];
+              gamma++;
+            }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
           }
-          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
-            normalize);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelRed(blur_image,
-              ClampToQuantum(gamma*qixel.red),q);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelGreen(blur_image,
-              ClampToQuantum(gamma*qixel.green),q);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelBlue(blur_image,
-              ClampToQuantum(gamma*qixel.blue),q);
-          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-              (image->colorspace == CMYKColorspace))
-            SetPixelBlack(blur_image,
-              ClampToQuantum(gamma*qixel.black),q);
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            SetPixelAlpha(blur_image,
-              ClampToQuantum(normalize*qixel.alpha),q);
+        for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
+        {
+          r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
+            center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
+            (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
+            1,1,exception);
+          if (r == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              continue;
+            }
+          pixel+=GetPixelAlpha(image,r)*r[i];
+          gamma+=GetPixelAlpha(image,r);
         }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
+      p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
     if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
@@ -3061,7 +3060,7 @@ MagickExport Image *RadialBlurImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_RadialBlurImage)
+        #pragma omp critical (MagickCore_RadialBlurImage)
 #endif
         proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3069,6 +3068,7 @@ MagickExport Image *RadialBlurImage(const Image *image,
       }
   }
   blur_view=DestroyCacheView(blur_view);
+  radial_view=DestroyCacheView(radial_view);
   image_view=DestroyCacheView(image_view);
   cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
   sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
@@ -3095,7 +3095,8 @@ MagickExport Image *RadialBlurImage(const Image *image,
 %  The format of the SelectiveBlurImage method is:
 %
 %      Image *SelectiveBlurImage(const Image *image,const double radius,
-%        const double sigma,const double threshold,ExceptionInfo *exception)
+%        const double sigma,const double threshold,const double bias,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3109,11 +3110,13 @@ MagickExport Image *RadialBlurImage(const Image *image,
 %    o threshold: only pixels within this contrast threshold are included
 %      in the blur operation.
 %
+%    o bias: the bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport Image *SelectiveBlurImage(const Image *image,
-  const double radius,const double sigma,const double threshold,
+MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
+  const double sigma,const double threshold,const double bias,
   ExceptionInfo *exception)
 {
 #define SelectiveBlurImageTag  "SelectiveBlur/Image"
@@ -3134,9 +3137,6 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   register ssize_t
     i;
 
@@ -3144,6 +3144,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
     width;
 
   ssize_t
+    center,
     j,
     u,
     v,
@@ -3159,7 +3160,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
   width=GetOptimalKernelWidth1D(radius,sigma);
-  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  kernel=(double *) AcquireAlignedMemory((size_t) width,width*sizeof(*kernel));
   if (kernel == (double *) NULL)
     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
   j=(ssize_t) width/2;
@@ -3202,7 +3203,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
       }
       message=DestroyString(message);
     }
-  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
   if (blur_image == (Image *) NULL)
     return((Image *) NULL);
   if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
@@ -3215,12 +3216,12 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
-  SetPixelInfoBias(image,&bias);
+  center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*(width/2L)+
+    GetPixelChannels(image)*(width/2L));
   image_view=AcquireCacheView(image);
   blur_view=AcquireCacheView(blur_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3230,9 +3231,6 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
     MagickBooleanType
       sync;
 
-    MagickRealType
-      gamma;
-
     register const Quantum
       *restrict p;
 
@@ -3246,7 +3244,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
       continue;
     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
       (width/2L),image->columns+width,width,exception);
-    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+    q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
@@ -3255,165 +3253,103 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelInfo
-        pixel;
+      register ssize_t
+        i;
 
-      register const double
-        *restrict k;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          alpha,
+          gamma,
+          intensity,
+          pixel;
 
-      register ssize_t
-        u;
+        PixelChannel
+          channel;
 
-      ssize_t
-        j,
-        v;
+        PixelTrait
+          blur_traits,
+          traits;
 
-      pixel=bias;
-      k=kernel;
-      gamma=0.0;
-      j=0;
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) == 0) || (image->matte == MagickFalse))
-        {
-          for (v=0; v < (ssize_t) width; v++)
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict pixels;
+
+        register ssize_t
+          u;
+
+        ssize_t
+          v;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        blur_traits=GetPixelChannelMapTraits(blur_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (blur_traits == UndefinedPixelTrait))
+          continue;
+        if ((blur_traits & CopyPixelTrait) != 0)
           {
-            for (u=0; u < (ssize_t) width; u++)
-            {
-              contrast=GetPixelIntensity(image,p+(u+j)*GetPixelChannels(image))-
-                (double) GetPixelIntensity(blur_image,q);
-              if (fabs(contrast) < threshold)
-                {
-                  pixel.red+=(*k)*
-                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.green+=(*k)*
-                    GetPixelGreen(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.blue+=(*k)*
-                    GetPixelBlue(image,p+(u+j)*GetPixelChannels(image));
-                  if (image->colorspace == CMYKColorspace)
-                    pixel.black+=(*k)*
-                      GetPixelBlack(image,p+(u+j)*GetPixelChannels(image));
-                  gamma+=(*k);
-                  k++;
-                }
-            }
-            j+=(ssize_t) (image->columns+width);
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
           }
-          if (gamma != 0.0)
-            {
-              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-              if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-              if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-              if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-              if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-                  (image->colorspace == CMYKColorspace))
-                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-            }
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+        k=kernel;
+        pixel=bias;
+        pixels=p;
+        intensity=(MagickRealType) GetPixelIntensity(image,p+center);
+        gamma=0.0;
+        if ((blur_traits & BlendPixelTrait) == 0)
+          {
+            for (v=0; v < (ssize_t) width; v++)
             {
-              gamma=0.0;
-              j=0;
-              for (v=0; v < (ssize_t) width; v++)
+              for (u=0; u < (ssize_t) width; u++)
               {
-                for (u=0; u < (ssize_t) width; u++)
-                {
-                  contrast=GetPixelIntensity(image,p+(u+j)*
-                    GetPixelChannels(image))-(double)
-                    GetPixelIntensity(blur_image,q);
-                  if (fabs(contrast) < threshold)
-                    {
-                      pixel.alpha+=(*k)*
-                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
-                      gamma+=(*k);
-                      k++;
-                    }
-                }
-                j+=(ssize_t) (image->columns+width);
+                contrast=GetPixelIntensity(image,pixels)-intensity;
+                if (fabs(contrast) < threshold)
+                  {
+                    pixel+=(*k)*pixels[i];
+                    gamma+=(*k);
+                  }
+                k++;
+                pixels+=GetPixelChannels(image);
               }
-              if (gamma != 0.0)
-                {
-                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
-                    gamma);
-                  SetPixelAlpha(blur_image,ClampToQuantum(gamma*pixel.alpha),q);
-                }
+              pixels+=image->columns*GetPixelChannels(image);
             }
-        }
-      else
+            if (fabs((double) gamma) < MagickEpsilon)
+              {
+                SetPixelChannel(blur_image,channel,p[center+i],q);
+                continue;
+              }
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+            continue;
+          }
+        for (v=0; v < (ssize_t) width; v++)
         {
-          MagickRealType
-            alpha;
-
-          for (v=0; v < (ssize_t) width; v++)
+          for (u=0; u < (ssize_t) width; u++)
           {
-            for (u=0; u < (ssize_t) width; u++)
-            {
-              contrast=GetPixelIntensity(image,p+(u+j)*
-                GetPixelChannels(image))-(double)
-                GetPixelIntensity(blur_image,q);
-              if (fabs(contrast) < threshold)
-                {
-                  alpha=(MagickRealType) (QuantumScale*
-                    GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image)));
-                  pixel.red+=(*k)*alpha*
-                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
-                  pixel.green+=(*k)*alpha*GetPixelGreen(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  pixel.blue+=(*k)*alpha*GetPixelBlue(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  pixel.alpha+=(*k)*GetPixelAlpha(image,p+(u+j)*
-                    GetPixelChannels(image));
-                  if (image->colorspace == CMYKColorspace)
-                    pixel.black+=(*k)*GetPixelBlack(image,p+(u+j)*
-                      GetPixelChannels(image));
-                  gamma+=(*k)*alpha;
-                  k++;
-                }
-            }
-            j+=(ssize_t) (image->columns+width);
-          }
-          if (gamma != 0.0)
-            {
-              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-              if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
-              if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
-              if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
-              if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-                  (image->colorspace == CMYKColorspace))
-                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
-            }
-          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-            {
-              gamma=0.0;
-              j=0;
-              for (v=0; v < (ssize_t) width; v++)
+            contrast=GetPixelIntensity(image,pixels)-intensity;
+            if (fabs(contrast) < threshold)
               {
-                for (u=0; u < (ssize_t) width; u++)
-                {
-                  contrast=GetPixelIntensity(image,p+(u+j)*
-                    GetPixelChannels(image))-(double)
-                    GetPixelIntensity(blur_image,q);
-                  if (fabs(contrast) < threshold)
-                    {
-                      pixel.alpha+=(*k)*
-                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
-                      gamma+=(*k);
-                      k++;
-                    }
-                }
-                j+=(ssize_t) (image->columns+width);
+                alpha=(MagickRealType) (QuantumScale*
+                  GetPixelAlpha(image,pixels));
+                pixel+=(*k)*alpha*pixels[i];
+                gamma+=(*k)*alpha;
               }
-              if (gamma != 0.0)
-                {
-                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
-                    gamma);
-                  SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
-                }
-            }
+            k++;
+            pixels+=GetPixelChannels(image);
+          }
+          pixels+=image->columns*GetPixelChannels(image);
         }
+        if (fabs((double) gamma) < MagickEpsilon)
+          {
+            SetPixelChannel(blur_image,channel,p[center+i],q);
+            continue;
+          }
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(blur_image);
     }
@@ -3426,7 +3362,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_SelectiveBlurImage)
+        #pragma omp critical (MagickCore_SelectiveBlurImage)
 #endif
         proceed=SetImageProgress(image,SelectiveBlurImageTag,progress++,
           image->rows);
@@ -3437,7 +3373,7 @@ MagickExport Image *SelectiveBlurImage(const Image *image,
   blur_image->type=image->type;
   blur_view=DestroyCacheView(blur_view);
   image_view=DestroyCacheView(image_view);
-  kernel=(double *) RelinquishMagickMemory(kernel);
+  kernel=(double *) RelinquishAlignedMemory(kernel);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);
@@ -3532,7 +3468,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
   image_view=AcquireCacheView(image);
   shade_view=AcquireCacheView(shade_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3545,10 +3481,10 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
       normal;
 
     register const Quantum
+      *restrict center,
       *restrict p,
-      *restrict s0,
-      *restrict s1,
-      *restrict s2;
+      *restrict post,
+      *restrict pre;
 
     register Quantum
       *restrict q;
@@ -3570,26 +3506,28 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
       Shade this row of pixels.
     */
     normal.z=2.0*(double) QuantumRange;  /* constant Z of surface normal */
-    s0=p+GetPixelChannels(image);
-    s1=s0+(image->columns+2)*GetPixelChannels(image);
-    s2=s1+(image->columns+2)*GetPixelChannels(image);
+    pre=p+GetPixelChannels(image);
+    center=pre+(image->columns+2)*GetPixelChannels(image);
+    post=center+(image->columns+2)*GetPixelChannels(image);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
+      register ssize_t
+        i;
+
       /*
         Determine the surface normal and compute shading.
       */
-      normal.x=(double) (GetPixelIntensity(image,s0-GetPixelChannels(image))+
-        GetPixelIntensity(image,s1-GetPixelChannels(image))+
-        GetPixelIntensity(image,s2-GetPixelChannels(image))-
-        GetPixelIntensity(image,s0+GetPixelChannels(image))-
-        GetPixelIntensity(image,s1+GetPixelChannels(image))-
-        GetPixelIntensity(image,s2+GetPixelChannels(image)));
-      normal.y=(double) (GetPixelIntensity(image,s2-GetPixelChannels(image))+
-        GetPixelIntensity(image,s2)+
-        GetPixelIntensity(image,s2+GetPixelChannels(image))-
-        GetPixelIntensity(image,s0-GetPixelChannels(image))-
-        GetPixelIntensity(image,s0)-
-        GetPixelIntensity(image,s0+GetPixelChannels(image)));
+      normal.x=(double) (GetPixelIntensity(image,pre-GetPixelChannels(image))+
+        GetPixelIntensity(image,center-GetPixelChannels(image))+
+        GetPixelIntensity(image,post-GetPixelChannels(image))-
+        GetPixelIntensity(image,pre+GetPixelChannels(image))-
+        GetPixelIntensity(image,center+GetPixelChannels(image))-
+        GetPixelIntensity(image,post+GetPixelChannels(image)));
+      normal.y=(double) (GetPixelIntensity(image,post-GetPixelChannels(image))+
+        GetPixelIntensity(image,post)+GetPixelIntensity(image,post+
+        GetPixelChannels(image))-GetPixelIntensity(image,pre-
+        GetPixelChannels(image))-GetPixelIntensity(image,pre)-
+        GetPixelIntensity(image,pre+GetPixelChannels(image)));
       if ((normal.x == 0.0) && (normal.y == 0.0))
         shade=light.z;
       else
@@ -3604,25 +3542,37 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
                 shade=distance/sqrt((double) normal_distance);
             }
         }
-      if (gray != MagickFalse)
-        {
-          SetPixelRed(shade_image,ClampToQuantum(shade),q);
-          SetPixelGreen(shade_image,ClampToQuantum(shade),q);
-          SetPixelBlue(shade_image,ClampToQuantum(shade),q);
-        }
-      else
-        {
-          SetPixelRed(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelRed(image,s1)),q);
-          SetPixelGreen(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelGreen(image,s1)),q);
-          SetPixelBlue(shade_image,ClampToQuantum(QuantumScale*shade*
-            GetPixelBlue(image,s1)),q);
-        }
-      SetPixelAlpha(shade_image,GetPixelAlpha(image,s1),q);
-      s0+=GetPixelChannels(image);
-      s1+=GetPixelChannels(image);
-      s2+=GetPixelChannels(image);
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          shade_traits,
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        shade_traits=GetPixelChannelMapTraits(shade_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (shade_traits == UndefinedPixelTrait))
+          continue;
+        if ((shade_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(shade_image,channel,center[i],q);
+            continue;
+          }
+        if (gray != MagickFalse)
+          {
+            SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
+            continue;
+          }
+        SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
+          center[i]),q);
+      }
+      pre+=GetPixelChannels(image);
+      center+=GetPixelChannels(image);
+      post+=GetPixelChannels(image);
       q+=GetPixelChannels(shade_image);
     }
     if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
@@ -3633,7 +3583,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ShadeImage)
+        #pragma omp critical (MagickCore_ShadeImage)
 #endif
         proceed=SetImageProgress(image,ShadeImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3671,7 +3621,7 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
 %  The format of the SharpenImage method is:
 %
 %    Image *SharpenImage(const Image *image,const double radius,
-%      const double sigma,ExceptionInfo *exception)
+%      const double sigma,const double bias,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3682,11 +3632,13 @@ MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
 %
 %    o sigma: the standard deviation of the Laplacian, in pixels.
 %
+%    o bias: bias.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *SharpenImage(const Image *image,const double radius,
-  const double sigma,ExceptionInfo *exception)
+  const double sigma,const double bias,ExceptionInfo *exception)
 {
   double
     normalize;
@@ -3721,10 +3673,11 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
   (void) ResetMagickMemory(kernel_info,0,sizeof(*kernel_info));
   kernel_info->width=width;
   kernel_info->height=width;
+  kernel_info->bias=bias;   /* FUTURE: user bias - non-sensical! */
   kernel_info->signature=MagickSignature;
-  kernel_info->values=(double *) AcquireAlignedMemory(kernel_info->width,
-    kernel_info->width*sizeof(*kernel_info->values));
-  if (kernel_info->values == (double *) NULL)
+  kernel_info->values=(MagickRealType *) AcquireAlignedMemory(
+    kernel_info->width,kernel_info->width*sizeof(*kernel_info->values));
+  if (kernel_info->values == (MagickRealType *) NULL)
     {
       kernel_info=DestroyKernelInfo(kernel_info);
       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
@@ -3743,7 +3696,6 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
     }
   }
   kernel_info->values[i/2]=(double) ((-2.0)*normalize);
-  kernel_info->bias=image->bias;
   sharp_image=ConvolveImage(image,kernel_info,exception);
   kernel_info=DestroyKernelInfo(kernel_info);
   return(sharp_image);
@@ -3766,19 +3718,21 @@ MagickExport Image *SharpenImage(const Image *image,const double radius,
 %  The format of the SpreadImage method is:
 %
 %      Image *SpreadImage(const Image *image,const double radius,
-%        ExceptionInfo *exception)
+%        const PixelInterpolateMethod method,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o radius:  Choose a random pixel in a neighborhood of this extent.
+%    o radius:  choose a random pixel in a neighborhood of this extent.
+%
+%    o method:  the pixel interpolation method.
 %
 %    o exception: return any errors or warnings in this structure.
 %
 */
 MagickExport Image *SpreadImage(const Image *image,const double radius,
-  ExceptionInfo *exception)
+  const PixelInterpolateMethod method,ExceptionInfo *exception)
 {
 #define SpreadImageTag  "Spread/Image"
 
@@ -3795,9 +3749,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   RandomInfo
     **restrict random_info;
 
@@ -3830,21 +3781,20 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(spread_image,&bias);
   width=GetOptimalKernelWidth1D(radius,0.5);
   random_info=AcquireRandomInfoThreadSet();
   image_view=AcquireCacheView(image);
   spread_view=AcquireCacheView(spread_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+  #pragma omp parallel for schedule(static,8) shared(progress,status)
 #endif
-  for (y=0; y < (ssize_t) spread_image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
     const int
       id = GetOpenMPThreadId();
 
-    PixelInfo
-      pixel;
+    register const Quantum
+      *restrict p;
 
     register Quantum
       *restrict q;
@@ -3854,21 +3804,23 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 
     if (status == MagickFalse)
       continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
     q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
       exception);
-    if (q == (const Quantum *) NULL)
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    pixel=bias;
-    for (x=0; x < (ssize_t) spread_image->columns; x++)
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      (void) InterpolatePixelInfo(image,image_view,
-        UndefinedInterpolatePixel,(double) x+width*(GetPseudoRandomValue(
-        random_info[id])-0.5),(double) y+width*(GetPseudoRandomValue(
-        random_info[id])-0.5),&pixel,exception);
-      SetPixelPixelInfo(spread_image,&pixel,q);
+      PointInfo
+        point;
+
+      point.x=GetPseudoRandomValue(random_info[id]);
+      point.y=GetPseudoRandomValue(random_info[id]);
+      status=InterpolatePixelChannels(image,image_view,spread_image,method,
+        (double) x+width*point.x-0.5,(double) y+width*point.y-0.5,q,exception);
       q+=GetPixelChannels(spread_image);
     }
     if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
@@ -3879,7 +3831,7 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_SpreadImage)
+        #pragma omp critical (MagickCore_SpreadImage)
 #endif
         proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3897,844 +3849,6 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%     S t a t i s t i c I m a g e                                             %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  StatisticImage() makes each pixel the min / max / median / mode / etc. of
-%  the neighborhood of the specified width and height.
-%
-%  The format of the StatisticImage method is:
-%
-%      Image *StatisticImage(const Image *image,const StatisticType type,
-%        const size_t width,const size_t height,ExceptionInfo *exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o type: the statistic type (median, mode, etc.).
-%
-%    o width: the width of the pixel neighborhood.
-%
-%    o height: the height of the pixel neighborhood.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-
-#define ListChannels  5
-
-typedef struct _ListNode
-{
-  size_t
-    next[9],
-    count,
-    signature;
-} ListNode;
-
-typedef struct _SkipList
-{
-  ssize_t
-    level;
-
-  ListNode
-    *nodes;
-} SkipList;
-
-typedef struct _PixelList
-{
-  size_t
-    length,
-    seed,
-    signature;
-
-  SkipList
-    lists[ListChannels];
-} PixelList;
-
-static PixelList *DestroyPixelList(PixelList *pixel_list)
-{
-  register ssize_t
-    i;
-
-  if (pixel_list == (PixelList *) NULL)
-    return((PixelList *) NULL);
-  for (i=0; i < ListChannels; i++)
-    if (pixel_list->lists[i].nodes != (ListNode *) NULL)
-      pixel_list->lists[i].nodes=(ListNode *) RelinquishMagickMemory(
-        pixel_list->lists[i].nodes);
-  pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
-  return(pixel_list);
-}
-
-static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
-{
-  register ssize_t
-    i;
-
-  assert(pixel_list != (PixelList **) NULL);
-  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
-    if (pixel_list[i] != (PixelList *) NULL)
-      pixel_list[i]=DestroyPixelList(pixel_list[i]);
-  pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
-  return(pixel_list);
-}
-
-static PixelList *AcquirePixelList(const size_t width,const size_t height)
-{
-  PixelList
-    *pixel_list;
-
-  register ssize_t
-    i;
-
-  pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
-  if (pixel_list == (PixelList *) NULL)
-    return(pixel_list);
-  (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
-  pixel_list->length=width*height;
-  for (i=0; i < ListChannels; i++)
-  {
-    pixel_list->lists[i].nodes=(ListNode *) AcquireQuantumMemory(65537UL,
-      sizeof(*pixel_list->lists[i].nodes));
-    if (pixel_list->lists[i].nodes == (ListNode *) NULL)
-      return(DestroyPixelList(pixel_list));
-    (void) ResetMagickMemory(pixel_list->lists[i].nodes,0,65537UL*
-      sizeof(*pixel_list->lists[i].nodes));
-  }
-  pixel_list->signature=MagickSignature;
-  return(pixel_list);
-}
-
-static PixelList **AcquirePixelListThreadSet(const size_t width,
-  const size_t height)
-{
-  PixelList
-    **pixel_list;
-
-  register ssize_t
-    i;
-
-  size_t
-    number_threads;
-
-  number_threads=GetOpenMPMaximumThreads();
-  pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
-    sizeof(*pixel_list));
-  if (pixel_list == (PixelList **) NULL)
-    return((PixelList **) NULL);
-  (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
-  for (i=0; i < (ssize_t) number_threads; i++)
-  {
-    pixel_list[i]=AcquirePixelList(width,height);
-    if (pixel_list[i] == (PixelList *) NULL)
-      return(DestroyPixelListThreadSet(pixel_list));
-  }
-  return(pixel_list);
-}
-
-static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
-  const size_t color)
-{
-  register SkipList
-    *list;
-
-  register ssize_t
-    level;
-
-  size_t
-    search,
-    update[9];
-
-  /*
-    Initialize the node.
-  */
-  list=pixel_list->lists+channel;
-  list->nodes[color].signature=pixel_list->signature;
-  list->nodes[color].count=1;
-  /*
-    Determine where it belongs in the list.
-  */
-  search=65536UL;
-  for (level=list->level; level >= 0; level--)
-  {
-    while (list->nodes[search].next[level] < color)
-      search=list->nodes[search].next[level];
-    update[level]=search;
-  }
-  /*
-    Generate a pseudo-random level for this node.
-  */
-  for (level=0; ; level++)
-  {
-    pixel_list->seed=(pixel_list->seed*42893621L)+1L;
-    if ((pixel_list->seed & 0x300) != 0x300)
-      break;
-  }
-  if (level > 8)
-    level=8;
-  if (level > (list->level+2))
-    level=list->level+2;
-  /*
-    If we're raising the list's level, link back to the root node.
-  */
-  while (level > list->level)
-  {
-    list->level++;
-    update[list->level]=65536UL;
-  }
-  /*
-    Link the node into the skip-list.
-  */
-  do
-  {
-    list->nodes[color].next[level]=list->nodes[update[level]].next[level];
-    list->nodes[update[level]].next[level]=color;
-  } while (level-- > 0);
-}
-
-static PixelInfo GetMaximumPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color,
-    maximum;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[ListChannels];
-
-  /*
-    Find the maximum value for each of the color.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    maximum=list->nodes[color].next[0];
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (color > maximum)
-        maximum=color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) maximum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
-}
-
-static PixelInfo GetMeanPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  MagickRealType
-    sum;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[ListChannels];
-
-  /*
-    Find the mean value for each of the color.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    sum=0.0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      sum+=(MagickRealType) list->nodes[color].count*color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    sum/=pixel_list->length;
-    channels[channel]=(unsigned short) sum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
-}
-
-static PixelInfo GetMedianPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[ListChannels];
-
-  /*
-    Find the median value for each of the color.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      count+=list->nodes[color].count;
-    } while (count <= (ssize_t) (pixel_list->length >> 1));
-    channels[channel]=(unsigned short) color;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
-}
-
-static PixelInfo GetMinimumPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color,
-    minimum;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[ListChannels];
-
-  /*
-    Find the minimum value for each of the color.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    count=0;
-    color=65536UL;
-    minimum=list->nodes[color].next[0];
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (color < minimum)
-        minimum=color;
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) minimum;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
-}
-
-static PixelInfo GetModePixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color,
-    max_count,
-    mode;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[5];
-
-  /*
-    Make each pixel the 'predominant color' of the specified neighborhood.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    mode=color;
-    max_count=list->nodes[mode].count;
-    count=0;
-    do
-    {
-      color=list->nodes[color].next[0];
-      if (list->nodes[color].count > max_count)
-        {
-          mode=color;
-          max_count=list->nodes[mode].count;
-        }
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    channels[channel]=(unsigned short) mode;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  return(pixel);
-}
-
-static PixelInfo GetNonpeakPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color,
-    next,
-    previous;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[5];
-
-  /*
-    Finds the non peak value for each of the colors.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    next=list->nodes[color].next[0];
-    count=0;
-    do
-    {
-      previous=color;
-      color=next;
-      next=list->nodes[color].next[0];
-      count+=list->nodes[color].count;
-    } while (count <= (ssize_t) (pixel_list->length >> 1));
-    if ((previous == 65536UL) && (next != 65536UL))
-      color=next;
-    else
-      if ((previous != 65536UL) && (next == 65536UL))
-        color=previous;
-    channels[channel]=(unsigned short) color;
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
-}
-
-static PixelInfo GetStandardDeviationPixelList(PixelList *pixel_list)
-{
-  PixelInfo
-    pixel;
-
-  MagickRealType
-    sum,
-    sum_squared;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  size_t
-    color;
-
-  ssize_t
-    count;
-
-  unsigned short
-    channels[ListChannels];
-
-  /*
-    Find the standard-deviation value for each of the color.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    color=65536L;
-    count=0;
-    sum=0.0;
-    sum_squared=0.0;
-    do
-    {
-      register ssize_t
-        i;
-
-      color=list->nodes[color].next[0];
-      sum+=(MagickRealType) list->nodes[color].count*color;
-      for (i=0; i < (ssize_t) list->nodes[color].count; i++)
-        sum_squared+=((MagickRealType) color)*((MagickRealType) color);
-      count+=list->nodes[color].count;
-    } while (count < (ssize_t) pixel_list->length);
-    sum/=pixel_list->length;
-    sum_squared/=pixel_list->length;
-    channels[channel]=(unsigned short) sqrt(sum_squared-(sum*sum));
-  }
-  GetPixelInfo((const Image *) NULL,&pixel);
-  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
-  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
-  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
-  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
-  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
-  return(pixel);
-}
-
-static inline void InsertPixelList(const Image *image,const Quantum *pixel,
-  PixelList *pixel_list)
-{
-  size_t
-    signature;
-
-  unsigned short
-    index;
-
-  index=ScaleQuantumToShort(GetPixelRed(image,pixel));
-  signature=pixel_list->lists[0].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[0].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,0,index);
-  index=ScaleQuantumToShort(GetPixelGreen(image,pixel));
-  signature=pixel_list->lists[1].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[1].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,1,index);
-  index=ScaleQuantumToShort(GetPixelBlue(image,pixel));
-  signature=pixel_list->lists[2].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[2].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,2,index);
-  index=ScaleQuantumToShort(GetPixelAlpha(image,pixel));
-  signature=pixel_list->lists[3].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[3].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,3,index);
-  if (image->colorspace == CMYKColorspace)
-    index=ScaleQuantumToShort(GetPixelBlack(image,pixel));
-  signature=pixel_list->lists[4].nodes[index].signature;
-  if (signature == pixel_list->signature)
-    pixel_list->lists[4].nodes[index].count++;
-  else
-    AddNodePixelList(pixel_list,4,index);
-}
-
-static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
-{
-  if (x < 0)
-    return(-x);
-  return(x);
-}
-
-static void ResetPixelList(PixelList *pixel_list)
-{
-  int
-    level;
-
-  register ListNode
-    *root;
-
-  register SkipList
-    *list;
-
-  register ssize_t
-    channel;
-
-  /*
-    Reset the skip-list.
-  */
-  for (channel=0; channel < 5; channel++)
-  {
-    list=pixel_list->lists+channel;
-    root=list->nodes+65536UL;
-    list->level=0;
-    for (level=0; level < 9; level++)
-      root->next[level]=65536UL;
-  }
-  pixel_list->seed=pixel_list->signature++;
-}
-
-MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
-  const size_t width,const size_t height,ExceptionInfo *exception)
-{
-#define StatisticWidth \
-  (width == 0 ? GetOptimalKernelWidth2D((double) width,0.5) : width)
-#define StatisticHeight \
-  (height == 0 ? GetOptimalKernelWidth2D((double) height,0.5) : height)
-#define StatisticImageTag  "Statistic/Image"
-
-  CacheView
-    *image_view,
-    *statistic_view;
-
-  Image
-    *statistic_image;
-
-  MagickBooleanType
-    status;
-
-  MagickOffsetType
-    progress;
-
-  PixelList
-    **restrict pixel_list;
-
-  ssize_t
-    y;
-
-  /*
-    Initialize statistics image attributes.
-  */
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
-  statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
-    exception);
-  if (statistic_image == (Image *) NULL)
-    return((Image *) NULL);
-  if (SetImageStorageClass(statistic_image,DirectClass,exception) == MagickFalse)
-    {
-      statistic_image=DestroyImage(statistic_image);
-      return((Image *) NULL);
-    }
-  pixel_list=AcquirePixelListThreadSet(StatisticWidth,StatisticHeight);
-  if (pixel_list == (PixelList **) NULL)
-    {
-      statistic_image=DestroyImage(statistic_image);
-      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
-    }
-  /*
-    Make each pixel the min / max / median / mode / etc. of the neighborhood.
-  */
-  status=MagickTrue;
-  progress=0;
-  image_view=AcquireCacheView(image);
-  statistic_view=AcquireCacheView(statistic_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
-#endif
-  for (y=0; y < (ssize_t) statistic_image->rows; y++)
-  {
-    const int
-      id = GetOpenMPThreadId();
-
-    register const Quantum
-      *restrict p;
-
-    register Quantum
-      *restrict q;
-
-    register ssize_t
-      x;
-
-    if (status == MagickFalse)
-      continue;
-    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) StatisticWidth/2L),y-
-      (ssize_t) (StatisticHeight/2L),image->columns+StatisticWidth,
-      StatisticHeight,exception);
-    q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns,      1,exception);
-    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
-      {
-        status=MagickFalse;
-        continue;
-      }
-    for (x=0; x < (ssize_t) statistic_image->columns; x++)
-    {
-      PixelInfo
-        pixel;
-
-      register const Quantum
-        *restrict r;
-
-      register ssize_t
-        u,
-        v;
-
-      r=p;
-      ResetPixelList(pixel_list[id]);
-      for (v=0; v < (ssize_t) StatisticHeight; v++)
-      {
-        for (u=0; u < (ssize_t) StatisticWidth; u++)
-          InsertPixelList(image,r+u*GetPixelChannels(image),pixel_list[id]);
-        r+=(image->columns+StatisticWidth)*GetPixelChannels(image);
-      }
-      GetPixelInfo(image,&pixel);
-      SetPixelInfo(image,p+(StatisticWidth*StatisticHeight/2)*
-        GetPixelChannels(image),&pixel);
-      switch (type)
-      {
-        case GradientStatistic:
-        {
-          PixelInfo
-            maximum,
-            minimum;
-
-          minimum=GetMinimumPixelList(pixel_list[id]);
-          maximum=GetMaximumPixelList(pixel_list[id]);
-          pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
-          pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
-          pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
-          pixel.alpha=MagickAbsoluteValue(maximum.alpha-minimum.alpha);
-          if (image->colorspace == CMYKColorspace)
-            pixel.black=MagickAbsoluteValue(maximum.black-minimum.black);
-          break;
-        }
-        case MaximumStatistic:
-        {
-          pixel=GetMaximumPixelList(pixel_list[id]);
-          break;
-        }
-        case MeanStatistic:
-        {
-          pixel=GetMeanPixelList(pixel_list[id]);
-          break;
-        }
-        case MedianStatistic:
-        default:
-        {
-          pixel=GetMedianPixelList(pixel_list[id]);
-          break;
-        }
-        case MinimumStatistic:
-        {
-          pixel=GetMinimumPixelList(pixel_list[id]);
-          break;
-        }
-        case ModeStatistic:
-        {
-          pixel=GetModePixelList(pixel_list[id]);
-          break;
-        }
-        case NonpeakStatistic:
-        {
-          pixel=GetNonpeakPixelList(pixel_list[id]);
-          break;
-        }
-        case StandardDeviationStatistic:
-        {
-          pixel=GetStandardDeviationPixelList(pixel_list[id]);
-          break;
-        }
-      }
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelRed(statistic_image,ClampToQuantum(pixel.red),q);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelGreen(statistic_image,ClampToQuantum(pixel.green),q);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        SetPixelBlue(statistic_image,ClampToQuantum(pixel.blue),q);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        SetPixelBlack(statistic_image,ClampToQuantum(pixel.black),q);
-      if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->matte != MagickFalse))
-        SetPixelAlpha(statistic_image,ClampToQuantum(pixel.alpha),q);
-      p+=GetPixelChannels(image);
-      q+=GetPixelChannels(statistic_image);
-    }
-    if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
-      status=MagickFalse;
-    if (image->progress_monitor != (MagickProgressMonitor) NULL)
-      {
-        MagickBooleanType
-          proceed;
-
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_StatisticImage)
-#endif
-        proceed=SetImageProgress(image,StatisticImageTag,progress++,
-          image->rows);
-        if (proceed == MagickFalse)
-          status=MagickFalse;
-      }
-  }
-  statistic_view=DestroyCacheView(statistic_view);
-  image_view=DestroyCacheView(image_view);
-  pixel_list=DestroyPixelListThreadSet(pixel_list);
-  return(statistic_image);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 %     U n s h a r p M a s k I m a g e                                         %
 %                                                                             %
 %                                                                             %
@@ -4769,9 +3883,9 @@ MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport Image *UnsharpMaskImage(const Image *image,
-  const double radius,const double sigma,const double amount,
-  const double threshold,ExceptionInfo *exception)
+MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
+  const double sigma,const double amount,const double threshold,
+  ExceptionInfo *exception)
 {
 #define SharpenImageTag  "Sharpen/Image"
 
@@ -4788,9 +3902,6 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   MagickOffsetType
     progress;
 
-  PixelInfo
-    bias;
-
   MagickRealType
     quantum_threshold;
 
@@ -4802,7 +3913,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  unsharp_image=BlurImage(image,radius,sigma,exception);
+  unsharp_image=BlurImage(image,radius,sigma,image->bias,exception);
   if (unsharp_image == (Image *) NULL)
     return((Image *) NULL);
   quantum_threshold=(MagickRealType) QuantumRange*threshold;
@@ -4811,17 +3922,13 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
   */
   status=MagickTrue;
   progress=0;
-  GetPixelInfo(image,&bias);
   image_view=AcquireCacheView(image);
   unsharp_view=AcquireCacheView(unsharp_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
-    PixelInfo
-      pixel;
-
     register const Quantum
       *restrict p;
 
@@ -4834,80 +3941,48 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
-    q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
+    q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
       exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    pixel=bias;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.red=GetPixelRed(image,p)-(MagickRealType) GetPixelRed(image,q);
-          if (fabs(2.0*pixel.red) < quantum_threshold)
-            pixel.red=(MagickRealType) GetPixelRed(image,p);
-          else
-            pixel.red=(MagickRealType) GetPixelRed(image,p)+(pixel.red*amount);
-          SetPixelRed(unsharp_image,ClampToQuantum(pixel.red),q);
-        }
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.green=GetPixelGreen(image,p)-
-            (MagickRealType) GetPixelGreen(image,q);
-          if (fabs(2.0*pixel.green) < quantum_threshold)
-            pixel.green=(MagickRealType)
-              GetPixelGreen(image,p);
-          else
-            pixel.green=(MagickRealType)
-              GetPixelGreen(image,p)+
-              (pixel.green*amount);
-          SetPixelGreen(unsharp_image,
-            ClampToQuantum(pixel.green),q);
-        }
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.blue=GetPixelBlue(image,p)-
-            (MagickRealType) GetPixelBlue(image,q);
-          if (fabs(2.0*pixel.blue) < quantum_threshold)
-            pixel.blue=(MagickRealType)
-              GetPixelBlue(image,p);
-          else
-            pixel.blue=(MagickRealType)
-              GetPixelBlue(image,p)+(pixel.blue*amount);
-          SetPixelBlue(unsharp_image,
-            ClampToQuantum(pixel.blue),q);
-        }
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (image->colorspace == CMYKColorspace))
-        {
-          pixel.black=GetPixelBlack(image,p)-
-            (MagickRealType) GetPixelBlack(image,q);
-          if (fabs(2.0*pixel.black) < quantum_threshold)
-            pixel.black=(MagickRealType)
-              GetPixelBlack(image,p);
-          else
-            pixel.black=(MagickRealType)
-              GetPixelBlack(image,p)+(pixel.black*
-              amount);
-          SetPixelBlack(unsharp_image,
-            ClampToQuantum(pixel.black),q);
-        }
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        {
-          pixel.alpha=GetPixelAlpha(image,p)-
-            (MagickRealType) GetPixelAlpha(image,q);
-          if (fabs(2.0*pixel.alpha) < quantum_threshold)
-            pixel.alpha=(MagickRealType)
-              GetPixelAlpha(image,p);
-          else
-            pixel.alpha=GetPixelAlpha(image,p)+
-              (pixel.alpha*amount);
-          SetPixelAlpha(unsharp_image,
-            ClampToQuantum(pixel.alpha),q);
-        }
+      register ssize_t
+        i;
+
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          traits,
+          unsharp_traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        unsharp_traits=GetPixelChannelMapTraits(unsharp_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (unsharp_traits == UndefinedPixelTrait))
+          continue;
+        if ((unsharp_traits & CopyPixelTrait) != 0)
+          {
+            SetPixelChannel(unsharp_image,channel,p[i],q);
+            continue;
+          }
+        pixel=p[i]-(MagickRealType) GetPixelChannel(unsharp_image,channel,q);
+        if (fabs(2.0*pixel) < quantum_threshold)
+          pixel=(MagickRealType) p[i];
+        else
+          pixel=(MagickRealType) p[i]+amount*pixel;
+        SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(unsharp_image);
     }
@@ -4919,7 +3994,7 @@ MagickExport Image *UnsharpMaskImage(const Image *image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_UnsharpMaskImage)
+        #pragma omp critical (MagickCore_UnsharpMaskImage)
 #endif
         proceed=SetImageProgress(image,SharpenImageTag,progress++,image->rows);
         if (proceed == MagickFalse)