]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/morphology.c
(no commit message)
[imagemagick] / MagickCore / morphology.c
index e12f0fbccaf92c01dda4df3ed16a061e2679f280..7fa89f0e8af9be4b1d28e5f2558e730510725e72 100644 (file)
@@ -17,7 +17,7 @@
 %                               January 2010                                  %
 %                                                                             %
 %                                                                             %
-%  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  %
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/gem.h"
+#include "MagickCore/gem-private.h"
 #include "MagickCore/hashmap.h"
 #include "MagickCore/image.h"
 #include "MagickCore/image-private.h"
 #include "MagickCore/list.h"
 #include "MagickCore/magick.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/memory-private.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/morphology.h"
 #include "MagickCore/morphology-private.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/prepress.h"
 #include "MagickCore/quantize.h"
+#include "MagickCore/resource_.h"
 #include "MagickCore/registry.h"
 #include "MagickCore/semaphore.h"
 #include "MagickCore/splay-tree.h"
 #include "MagickCore/statistic.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
 #include "MagickCore/token.h"
 #include "MagickCore/utility.h"
+#include "MagickCore/utility-private.h"
 \f
 
 /*
@@ -89,7 +94,7 @@
 ** part of the kernel neighbourhood for convolution or morphology processing,
 ** and thus should be ignored.  This allows the use of 'shaped' kernels.
 **
-** The special properity that two NaN's are never equal, even if they are from
+** The special property that two NaN's are never equal, even if they are from
 ** the same variable allow you to test if a value is special NaN value.
 **
 ** This macro  IsNaN() is thus is only true if the value given is NaN.
@@ -110,6 +115,21 @@ static inline double MagickMax(const double x,const double y)
 #define Minimize(assign,value) assign=MagickMin(assign,value)
 #define Maximize(assign,value) assign=MagickMax(assign,value)
 
+/* Integer Factorial Function - for a Binomial kernel */
+#if 1
+static inline size_t fact(size_t n)
+{
+  size_t f,l;
+  for(f=1, l=2; l <= n; f=f*l, l++);
+  return(f);
+}
+#elif 1 /* glibc floating point alternatives */
+#define fact(n) ((size_t)tgamma((double)n+1))
+#else
+#define fact(n) ((size_t)lgamma((double)n+1))
+#endif
+
+
 /* Currently these are only internal to this module */
 static void
   CalcKernelMetaData(KernelInfo *),
@@ -238,7 +258,7 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
   GeometryInfo
     args;
 
-  kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
+  kernel=(KernelInfo *) AcquireQuantumMemory(1,sizeof(*kernel));
   if (kernel == (KernelInfo *)NULL)
     return(kernel);
   (void) ResetMagickMemory(kernel,0,sizeof(*kernel));
@@ -247,6 +267,8 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
   kernel->type = UserDefinedKernel;
   kernel->next = (KernelInfo *) NULL;
   kernel->signature = MagickSignature;
+  if (kernel_string == (const char *) NULL)
+    return(kernel);
 
   /* find end of this specific kernel definition string */
   end = strchr(kernel_string, ';');
@@ -256,7 +278,9 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
   /* clear flags - for Expanding kernel lists thorugh rotations */
    flags = NoValue;
 
-  /* Has a ':' in argument - New user kernel specification */
+  /* Has a ':' in argument - New user kernel specification
+     FUTURE: this split on ':' could be done by StringToken()
+   */
   p = strchr(kernel_string, ':');
   if ( p != (char *) NULL && p < end)
     {
@@ -280,9 +304,9 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
       if ( args.xi  < 0.0 || args.psi < 0.0 )
         return(DestroyKernelInfo(kernel));
       kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
-                                               : (ssize_t) (kernel->width-1)/2;
+                                        : (ssize_t) (kernel->width-1)/2;
       kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
-                                               : (ssize_t) (kernel->height-1)/2;
+                                        : (ssize_t) (kernel->height-1)/2;
       if ( kernel->x >= (ssize_t) kernel->width ||
            kernel->y >= (ssize_t) kernel->height )
         return(DestroyKernelInfo(kernel));
@@ -310,15 +334,13 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
     }
 
   /* Read in the kernel values from rest of input string argument */
-  kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                        kernel->height*sizeof(double));
-  if (kernel->values == (double *) NULL)
+  kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
+    kernel->width,kernel->height*sizeof(*kernel->values)));
+  if (kernel->values == (MagickRealType *) NULL)
     return(DestroyKernelInfo(kernel));
-
   kernel->minimum = +MagickHuge;
   kernel->maximum = -MagickHuge;
   kernel->negative_range = kernel->positive_range = 0.0;
-
   for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
   {
     GetMagickToken(p,&p,token);
@@ -326,10 +348,10 @@ static KernelInfo *ParseKernelArray(const char *kernel_string)
       GetMagickToken(p,&p,token);
     if (    LocaleCompare("nan",token) == 0
         || LocaleCompare("-",token) == 0 ) {
-      kernel->values[i] = nan; /* do not include this value in kernel */
+      kernel->values[i] = nan; /* this value is not part of neighbourhood */
     }
     else {
-      kernel->values[i] = InterpretLocaleValue(token,(char **) NULL);
+      kernel->values[i] = StringToDouble(token,(char **) NULL);
       ( kernel->values[i] < 0)
           ?  ( kernel->negative_range += kernel->values[i] )
           :  ( kernel->positive_range += kernel->values[i] );
@@ -499,6 +521,8 @@ MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string)
   size_t
     kernel_number;
 
+  if (kernel_string == (const char *) NULL)
+    return(ParseKernelArray(kernel_string));
   p = kernel_string;
   kernel = NULL;
   kernel_number = 0;
@@ -625,6 +649,10 @@ MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string)
 %       Note that the first argument is the width of the kernel and not the
 %       radius of the kernel.
 %
+%    Binomial:[{radius}]
+%       Generate a discrete kernel using a 2 dimentional Pascel's Triangle
+%       of values. Used for special forma of image filters.
+%
 %    # Still to be implemented...
 %    #
 %    # Filter2D
@@ -987,6 +1015,7 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
     case LoGKernel:
     case BlurKernel:
     case CometKernel:
+    case BinomialKernel:
     case DiamondKernel:
     case SquareKernel:
     case RectangleKernel:
@@ -1024,8 +1053,9 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
       {
         kernel->height = kernel->width = (size_t) 1;
         kernel->x = kernel->y = (ssize_t) 0;
-        kernel->values=(double *) AcquireQuantumMemory(1,sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(1,sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
         kernel->maximum = kernel->values[0] = args->rho;
         break;
@@ -1047,9 +1077,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
           kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
         kernel->height = kernel->width;
         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         /* WARNING: The following generates a 'sampled gaussian' kernel.
@@ -1138,9 +1169,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
         kernel->x = (ssize_t) (kernel->width-1)/2;
         kernel->y = 0;
         kernel->negative_range = kernel->positive_range = 0.0;
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
 #if 1
@@ -1175,7 +1207,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
         else /* special case - generate a unity kernel */
           kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
 #else
-        /* Direct calculation without curve averaging */
+        /* Direct calculation without curve averaging
+           This is equivelent to a KernelRank of 1 */
 
         /* Calculate a Positive Gaussian */
         if ( sigma > MagickEpsilon )
@@ -1192,10 +1225,11 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
 #endif
         /* Note the above kernel may have been 'clipped' by a user defined
         ** radius, producing a smaller (darker) kernel.  Also for very small
-        ** sigma's (> 0.1) the central value becomes larger than one, and thus
-        ** producing a very bright kernel.
+        ** sigma's (> 0.1) the central value becomes larger than one, as a
+        ** result of not generating a actual 'discrete' kernel, and thus
+        ** producing a very bright 'impulse'.
         **
-        ** Normalization will still be needed.
+        ** Becuase of these two factors Normalization is required!
         */
 
         /* Normalize the 1D Gaussian Kernel
@@ -1222,9 +1256,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
         kernel->x = kernel->y = 0;
         kernel->height = 1;
         kernel->negative_range = kernel->positive_range = 0.0;
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         /* A comet blur is half a 1D gaussian curve, so that the object is
@@ -1259,8 +1294,7 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             /* B = 1.0/(MagickSQ2PI*sigma); */
             for ( i=0; i < (ssize_t) kernel->width; i++)
               kernel->positive_range +=
-                kernel->values[i] =
-                  exp(-((double)(i*i))*A);
+                kernel->values[i] = exp(-((double)(i*i))*A);
                 /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */
 #endif
           }
@@ -1279,6 +1313,38 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
         RotateKernelInfo(kernel, args->xi); /* Rotate by angle */
         break;
       }
+    case BinomialKernel:
+      {
+        size_t
+          order_f;
+
+        if (args->rho < 1.0)
+          kernel->width = kernel->height = 3;  /* default radius = 1 */
+        else
+          kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+        kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+        order_f = fact(kernel->width-1);
+
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        /* set all kernel values within diamond area to scale given */
+        for ( i=0, v=0; v < (ssize_t)kernel->height; v++)
+          { size_t
+              alpha = order_f / ( fact((size_t) v) * fact(kernel->height-v-1) );
+            for ( u=0; u < (ssize_t)kernel->width; u++, i++)
+              kernel->positive_range += kernel->values[i] = (double)
+                (alpha * order_f / ( fact((size_t) u) * fact(kernel->height-u-1) ));
+          }
+        kernel->minimum = 1.0;
+        kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width];
+        kernel->negative_range = 0.0;
+        break;
+      }
 
     /*
       Convolution Kernels - Well Known Named Constant Kernels
@@ -1377,8 +1443,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[3] = +MagickSQ2;
-            kernel->values[5] = -MagickSQ2;
+            kernel->values[3] = +(MagickRealType) MagickSQ2;
+            kernel->values[5] = -(MagickRealType) MagickSQ2;
             CalcKernelMetaData(kernel);     /* recalculate meta-data */
             break;
           case 2:
@@ -1386,8 +1452,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[1] = kernel->values[3] = +MagickSQ2;
-            kernel->values[5] = kernel->values[7] = -MagickSQ2;
+            kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2;
+            kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2;
             CalcKernelMetaData(kernel);     /* recalculate meta-data */
             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
             break;
@@ -1402,8 +1468,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[3] = +MagickSQ2;
-            kernel->values[5] = -MagickSQ2;
+            kernel->values[3] = +(MagickRealType) MagickSQ2;
+            kernel->values[5] = -(MagickRealType) MagickSQ2;
             CalcKernelMetaData(kernel);     /* recalculate meta-data */
             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
             break;
@@ -1412,8 +1478,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[1] = +MagickSQ2;
-            kernel->values[7] = +MagickSQ2;
+            kernel->values[1] = +(double) MagickSQ2;
+            kernel->values[7] = +(double) MagickSQ2;
             CalcKernelMetaData(kernel);
             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
             break;
@@ -1422,8 +1488,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[0] = +MagickSQ2;
-            kernel->values[8] = -MagickSQ2;
+            kernel->values[0] = +(MagickRealType) MagickSQ2;
+            kernel->values[8] = -(MagickRealType) MagickSQ2;
             CalcKernelMetaData(kernel);
             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
             break;
@@ -1432,8 +1498,8 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             if (kernel == (KernelInfo *) NULL)
               return(kernel);
             kernel->type = type;
-            kernel->values[2] = -MagickSQ2;
-            kernel->values[6] = +MagickSQ2;
+            kernel->values[2] = -(MagickRealType) MagickSQ2;
+            kernel->values[6] = +(MagickRealType) MagickSQ2;
             CalcKernelMetaData(kernel);
             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
             break;
@@ -1473,7 +1539,7 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
             break;
         }
-        if ( fabs(args->sigma) > MagickEpsilon )
+        if ( fabs(args->sigma) >= MagickEpsilon )
           /* Rotate by correctly supplied 'angle' */
           RotateKernelInfo(kernel, args->sigma);
         else if ( args->rho > 30.0 || args->rho < -30.0 )
@@ -1493,9 +1559,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         /* set all kernel values within diamond area to scale given */
@@ -1534,9 +1601,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->y = (ssize_t) args->psi;
             scale = 1.0;
           }
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         /* set all kernel values to scale given */
@@ -1555,9 +1623,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
@@ -1581,9 +1650,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
@@ -1603,9 +1673,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           /* set all kernel values along axises to given scale */
@@ -1624,9 +1695,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           /* set all kernel values along axises to given scale */
@@ -1665,9 +1737,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
 
           kernel->height = kernel->width;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */
@@ -2035,9 +2108,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
@@ -2055,9 +2129,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                                kernel->height*sizeof(double));
-          if (kernel->values == (double *) NULL)
+          kernel->values=(MagickRealType *) MagickAssumeAligned(
+            AcquireAlignedMemory(kernel->width,kernel->height*
+            sizeof(*kernel->values)));
+          if (kernel->values == (MagickRealType *) NULL)
             return(DestroyKernelInfo(kernel));
 
           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
@@ -2075,9 +2150,10 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
@@ -2100,15 +2176,16 @@ MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
 
-        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-                              kernel->height*sizeof(double));
-        if (kernel->values == (double *) NULL)
+        kernel->values=(MagickRealType *) MagickAssumeAligned(
+          AcquireAlignedMemory(kernel->width,kernel->height*
+          sizeof(*kernel->values)));
+        if (kernel->values == (MagickRealType *) NULL)
           return(DestroyKernelInfo(kernel));
 
         for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
           for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
             kernel->positive_range += ( kernel->values[i] =
-                 args->sigma*sqrt((double)(u*u+v*v)) );
+              args->sigma*sqrt((double)(u*u+v*v)) );
         kernel->maximum = kernel->values[0];
         break;
       }
@@ -2165,9 +2242,9 @@ MagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
   *new_kernel=(*kernel); /* copy values in structure */
 
   /* replace the values with a copy of the values */
-  new_kernel->values=(double *) AcquireQuantumMemory(kernel->width,
-    kernel->height*sizeof(double));
-  if (new_kernel->values == (double *) NULL)
+  new_kernel->values=(MagickRealType *) MagickAssumeAligned(
+    AcquireAlignedMemory(kernel->width,kernel->height*sizeof(*kernel->values)));
+  if (new_kernel->values == (MagickRealType *) NULL)
     return(DestroyKernelInfo(new_kernel));
   for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
     new_kernel->values[i]=kernel->values[i];
@@ -2208,12 +2285,10 @@ MagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
 MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
 {
   assert(kernel != (KernelInfo *) NULL);
-
   if ( kernel->next != (KernelInfo *) NULL )
-    kernel->next = DestroyKernelInfo(kernel->next);
-
-  kernel->values = (double *)RelinquishMagickMemory(kernel->values);
-  kernel = (KernelInfo *) RelinquishMagickMemory(kernel);
+    kernel->next=DestroyKernelInfo(kernel->next);
+  kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
+  kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
   return(kernel);
 }
 \f
@@ -2346,7 +2421,7 @@ static MagickBooleanType SameKernelInfo(const KernelInfo *kernel1,
     if ( IsNan(kernel2->values[i]) && !IsNan(kernel1->values[i]) )
       return MagickFalse;
     /* Test actual values are equivalent */
-    if ( fabs(kernel1->values[i] - kernel2->values[i]) > MagickEpsilon )
+    if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
       return MagickFalse;
   }
 
@@ -2441,7 +2516,9 @@ static void CalcKernelMetaData(KernelInfo *kernel)
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  MorphologyApply() applies a morphological method, multiple times using
-%  a list of multiple kernels.
+%  a list of multiple kernels.  This is the method that should be called by
+%  other 'operators' that internally use morphology operations as part of
+%  their processing.
 %
 %  It is basically equivalent to as MorphologyImage() (see below) but
 %  without any user controls.  This allows internel programs to use this
@@ -2451,10 +2528,9 @@ static void CalcKernelMetaData(KernelInfo *kernel)
 %  It is MorphologyImage() task to extract any such user controls, and
 %  pass them to this function for processing.
 %
-%  More specifically kernels are not normalized/scaled/blended by the
-%  'convolve:scale' Image Artifact (setting), nor is the convolve bias
-%  (-bias setting or image->bias) loooked at, but must be supplied from the
-%  function arguments.
+%  More specifically all given kernels should already be scaled, normalised,
+%  and blended appropriatally before being parred to this routine. The
+%  appropriate bias, and compose (typically 'UndefinedComposeOp') given.
 %
 %  The format of the MorphologyApply method is:
 %
@@ -2530,8 +2606,8 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
   changed=0;
   progress=0;
 
-  image_view=AcquireCacheView(image);
-  morphology_view=AcquireCacheView(morphology_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
   virt_width=image->columns+kernel->width-1;
 
   /* Some methods (including convolve) needs use a reflected kernel.
@@ -2543,7 +2619,7 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
     case ConvolveMorphology:
     case DilateMorphology:
     case DilateIntensityMorphology:
-    /*case DistanceMorphology:*/
+    case IterativeDistanceMorphology:
       /* kernel needs to used with reflection about origin */
       offx = (ssize_t) kernel->width-offx-1;
       offy = (ssize_t) kernel->height-offy-1;
@@ -2560,7 +2636,6 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
       break;
   }
 
-
   if ( method == ConvolveMorphology && kernel->width == 1 )
   { /* Special handling (for speed) of vertical (blur) kernels.
     ** This performs its handling in columns rather than in rows.
@@ -2581,7 +2656,8 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
       x;
 
 #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) \
+      dynamic_number_threads(image,image->columns,image->rows,1)
 #endif
     for (x=0; x < (ssize_t) image->columns; x++)
     {
@@ -2599,9 +2675,10 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
 
       if (status == MagickFalse)
         continue;
-      p=GetCacheViewVirtualPixels(image_view, x,  -offy,1,
-          image->rows+kernel->height-1, exception);
-      q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,morphology_image->rows,exception);
+      p=GetCacheViewVirtualPixels(image_view,x,-offy,1,image->rows+
+        kernel->height-1,exception);
+      q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,
+        morphology_image->rows,exception);
       if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
         {
           status=MagickFalse;
@@ -2612,37 +2689,37 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
 
       for (y=0; y < (ssize_t) image->rows; y++)
       {
-        register ssize_t
-          v;
+        PixelInfo
+          result;
 
-        register const double
+        register const MagickRealType
           *restrict k;
 
         register const Quantum
           *restrict k_pixels;
 
-        PixelInfo
-          result;
+        register ssize_t
+          v;
 
         /* Copy input image to the output image for unused channels
         * This removes need for 'cloning' a new image every iteration
         */
         SetPixelRed(morphology_image,GetPixelRed(image,p+r*
-          GetPixelComponents(image)),q);
+          GetPixelChannels(image)),q);
         SetPixelGreen(morphology_image,GetPixelGreen(image,p+r*
-          GetPixelComponents(image)),q);
+          GetPixelChannels(image)),q);
         SetPixelBlue(morphology_image,GetPixelBlue(image,p+r*
-          GetPixelComponents(image)),q);
+          GetPixelChannels(image)),q);
         if (image->colorspace == CMYKColorspace)
           SetPixelBlack(morphology_image,GetPixelBlack(image,p+r*
-            GetPixelComponents(image)),q);
+            GetPixelChannels(image)),q);
 
         /* Set the bias of the weighted average output */
-        result.red     =
-        result.green   =
-        result.blue    =
+        result.red   =
+        result.green =
+        result.blue  =
         result.alpha =
-        result.black   = bias;
+        result.black = bias;
 
 
         /* Weighted Average of pixels using reflected kernel
@@ -2653,10 +2730,10 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
         */
         k = &kernel->values[ kernel->height-1 ];
         k_pixels = p;
-        if ( (image->sync == MagickFalse) ||
-             (image->matte == MagickFalse) )
+        if ( (image->channel_mask != DefaultChannels) ||
+             (image->alpha_trait != BlendPixelTrait) )
           { /* No 'Sync' involved.
-            ** Convolution is simple greyscale channel operation
+            ** Convolution is just a simple greyscale channel operation
             */
             for (v=0; v < (ssize_t) kernel->height; v++) {
               if ( IsNan(*k) ) continue;
@@ -2667,19 +2744,19 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
                 result.black+=(*k)*GetPixelBlack(image,k_pixels);
               result.alpha += (*k)*GetPixelAlpha(image,k_pixels);
               k--;
-              k_pixels++;
+              k_pixels+=GetPixelChannels(image);
             }
-            if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+            if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
               SetPixelRed(morphology_image,ClampToQuantum(result.red),q);
-            if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+            if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
               SetPixelGreen(morphology_image,ClampToQuantum(result.green),q);
-            if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+            if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
               SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q);
-            if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+            if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
                 (image->colorspace == CMYKColorspace))
               SetPixelBlack(morphology_image,ClampToQuantum(result.black),q);
-            if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-                (image->matte == MagickTrue))
+            if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
+                (image->alpha_trait == BlendPixelTrait))
               SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
           }
         else
@@ -2687,49 +2764,49 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
             ** Weight the color channels with Alpha Channel so that
             ** transparent pixels are not part of the results.
             */
-            MagickRealType
-              alpha,  /* alpha weighting of colors : kernel*alpha  */
-              gamma;  /* divisor, sum of color weighting values */
+            double
+              alpha,  /* alpha weighting for colors : alpha  */
+              gamma;  /* divisor, sum of color alpha weighting */
+            size_t
+              count;  /* alpha valus collected, number kernel values */
 
+            count=0;
             gamma=0.0;
             for (v=0; v < (ssize_t) kernel->height; v++) {
               if ( IsNan(*k) ) continue;
-              alpha=(*k)*(QuantumScale*GetPixelAlpha(image,k_pixels));
-              gamma += alpha;
+              alpha=QuantumScale*GetPixelAlpha(image,k_pixels);
+              gamma += alpha; /* normalize alpha weights only */
+              count++;        /* number of alpha values collected */
+              alpha*=(*k);    /* include kernel weighting now */
               result.red     += alpha*GetPixelRed(image,k_pixels);
               result.green   += alpha*GetPixelGreen(image,k_pixels);
               result.blue    += alpha*GetPixelBlue(image,k_pixels);
               if (image->colorspace == CMYKColorspace)
                 result.black += alpha*GetPixelBlack(image,k_pixels);
-              result.alpha += (*k)*GetPixelAlpha(image,k_pixels);
+              result.alpha   += (*k)*GetPixelAlpha(image,k_pixels);
               k--;
-              k_pixels++;
+              k_pixels+=GetPixelChannels(image);
             }
             /* Sync'ed channels, all channels are modified */
-            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-            SetPixelRed(morphology_image,
-              ClampToQuantum(gamma*result.red),q);
-            SetPixelGreen(morphology_image,
-              ClampToQuantum(gamma*result.green),q);
-            SetPixelBlue(morphology_image,
-              ClampToQuantum(gamma*result.blue),q);
+            gamma=(double)count/(fabs((double) gamma) < MagickEpsilon ? MagickEpsilon : gamma);
+            SetPixelRed(morphology_image,ClampToQuantum(gamma*result.red),q);
+            SetPixelGreen(morphology_image,ClampToQuantum(gamma*result.green),q);
+            SetPixelBlue(morphology_image,ClampToQuantum(gamma*result.blue),q);
             if (image->colorspace == CMYKColorspace)
-              SetPixelBlack(morphology_image,
-                ClampToQuantum(gamma*result.black),q);
-            SetPixelAlpha(morphology_image,
-              ClampToQuantum(result.alpha),q);
+              SetPixelBlack(morphology_image,ClampToQuantum(gamma*result.black),q);
+            SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
           }
 
         /* Count up changed pixels */
-        if ((GetPixelRed(image,p+r) != GetPixelRed(morphology_image,q))
-            || (GetPixelGreen(image,p+r) != GetPixelGreen(morphology_image,q))
-            || (GetPixelBlue(image,p+r) != GetPixelBlue(morphology_image,q))
-            || (GetPixelAlpha(image,p+r) != GetPixelAlpha(morphology_image,q))
+        if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q))
+            || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q))
+            || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q))
+            || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q))
             || ((image->colorspace == CMYKColorspace) &&
-                (GetPixelBlack(image,p+r) != GetPixelBlack(morphology_image,q))))
+                (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q))))
           changed++;  /* The pixel was changed in some way! */
-        p+=GetPixelComponents(image);
-        q+=GetPixelComponents(morphology_image);
+        p+=GetPixelChannels(image);
+        q+=GetPixelChannels(morphology_image);
       } /* y */
       if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
         status=MagickFalse;
@@ -2739,7 +2816,7 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
             proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_MorphologyImage)
+          #pragma omp critical (MagickCore_MorphologyImage)
 #endif
           proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows);
           if (proceed == MagickFalse)
@@ -2756,7 +2833,8 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
   ** Normal handling of horizontal or rectangular kernels (row by row)
   */
 #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) \
+    dynamic_number_threads(image,image->columns,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2775,9 +2853,9 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view, -offx, y-offy, virt_width,
-         kernel->height,  exception);
-    q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,1,
-         exception);
+      kernel->height,  exception);
+    q=GetCacheViewAuthenticPixels(morphology_view,0,y,
+      morphology_image->columns,1,exception);
     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
@@ -2788,55 +2866,55 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
 
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-       ssize_t
-        v;
-
-      register ssize_t
-        u;
+      PixelInfo
+        result,
+        min,
+        max;
 
-      register const double
+      register const MagickRealType
         *restrict k;
 
       register const Quantum
         *restrict k_pixels;
 
-      PixelInfo
-        result,
-        min,
-        max;
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
 
       /* Copy input image to the output image for unused channels
        * This removes need for 'cloning' a new image every iteration
        */
       SetPixelRed(morphology_image,GetPixelRed(image,p+r*
-        GetPixelComponents(image)),q);
+        GetPixelChannels(image)),q);
       SetPixelGreen(morphology_image,GetPixelGreen(image,p+r*
-        GetPixelComponents(image)),q);
+        GetPixelChannels(image)),q);
       SetPixelBlue(morphology_image,GetPixelBlue(image,p+r*
-        GetPixelComponents(image)),q);
+        GetPixelChannels(image)),q);
       if (image->colorspace == CMYKColorspace)
         SetPixelBlack(morphology_image,GetPixelBlack(image,p+r*
-          GetPixelComponents(image)),q);
+          GetPixelChannels(image)),q);
 
       /* Defaults */
       min.red     =
       min.green   =
       min.blue    =
       min.alpha =
-      min.black   = (MagickRealType) QuantumRange;
+      min.black   = (double) QuantumRange;
       max.red     =
       max.green   =
       max.blue    =
       max.alpha =
-      max.black   = (MagickRealType) 0;
+      max.black   = (double) 0;
       /* default result is the original pixel value */
-      result.red     = (MagickRealType) GetPixelRed(image,p+r);
-      result.green   = (MagickRealType) GetPixelGreen(image,p+r);
-      result.blue    = (MagickRealType) GetPixelBlue(image,p+r);
+      result.red     = (double) GetPixelRed(image,p+r*GetPixelChannels(image));
+      result.green   = (double) GetPixelGreen(image,p+r*GetPixelChannels(image));
+      result.blue    = (double) GetPixelBlue(image,p+r*GetPixelChannels(image));
       result.black   = 0.0;
       if (image->colorspace == CMYKColorspace)
-         result.black = (MagickRealType) GetPixelBlack(image,p+r);
-      result.alpha=(MagickRealType) GetPixelAlpha(image,p+r);
+        result.black = (double) GetPixelBlack(image,p+r*GetPixelChannels(image));
+      result.alpha=(double) GetPixelAlpha(image,p+r*GetPixelChannels(image));
 
       switch (method) {
         case ConvolveMorphology:
@@ -2878,8 +2956,8 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
             */
             k = &kernel->values[ kernel->width*kernel->height-1 ];
             k_pixels = p;
-            if ( (image->sync == MagickFalse) ||
-                 (image->matte == MagickFalse) )
+            if ( (image->channel_mask != DefaultChannels) ||
+                 (image->alpha_trait != BlendPixelTrait) )
               { /* No 'Sync' involved.
                 ** Convolution is simple greyscale channel operation
                 */
@@ -2887,34 +2965,34 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
                   for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                     if ( IsNan(*k) ) continue;
                     result.red     += (*k)*
-                      GetPixelRed(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelRed(image,k_pixels+u*GetPixelChannels(image));
                     result.green   += (*k)*
-                      GetPixelGreen(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelGreen(image,k_pixels+u*GetPixelChannels(image));
                     result.blue    += (*k)*
-                      GetPixelBlue(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelBlue(image,k_pixels+u*GetPixelChannels(image));
                     if (image->colorspace == CMYKColorspace)
                       result.black += (*k)*
-                        GetPixelBlack(image,k_pixels+u*GetPixelComponents(image));
+                        GetPixelBlack(image,k_pixels+u*GetPixelChannels(image));
                     result.alpha += (*k)*
-                      GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image));
                   }
-                  k_pixels += virt_width*GetPixelComponents(image);
+                  k_pixels += virt_width*GetPixelChannels(image);
                 }
-                if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+                if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
                   SetPixelRed(morphology_image,ClampToQuantum(result.red),
                     q);
-                if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+                if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
                   SetPixelGreen(morphology_image,ClampToQuantum(result.green),
                     q);
-                if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+                if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
                   SetPixelBlue(morphology_image,ClampToQuantum(result.blue),
                     q);
-                if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+                if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
                     (image->colorspace == CMYKColorspace))
                   SetPixelBlack(morphology_image,ClampToQuantum(result.black),
                     q);
-                if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-                    (image->matte == MagickTrue))
+                if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
+                    (image->alpha_trait == BlendPixelTrait))
                   SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),
                     q);
               }
@@ -2923,33 +3001,38 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
                 ** Weight the color channels with Alpha Channel so that
                 ** transparent pixels are not part of the results.
                 */
-                MagickRealType
-                  alpha,  /* alpha weighting of colors : kernel*alpha  */
-                  gamma;  /* divisor, sum of color weighting values */
+                double
+                  alpha,  /* alpha weighting for colors : alpha  */
+                  gamma;  /* divisor, sum of color alpha weighting */
+                size_t
+                  count;  /* alpha valus collected, number kernel values */
 
+                count=0;
                 gamma=0.0;
                 for (v=0; v < (ssize_t) kernel->height; v++) {
                   for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                     if ( IsNan(*k) ) continue;
-                    alpha=(*k)*(QuantumScale*
-                      GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
-                    gamma += alpha;
+                    alpha=QuantumScale*GetPixelAlpha(image,
+                                k_pixels+u*GetPixelChannels(image));
+                    gamma += alpha;    /* normalize alpha weights only */
+                    count++;           /* number of alpha values collected */
+                    alpha=alpha*(*k);  /* include kernel weighting now */
                     result.red     += alpha*
-                      GetPixelRed(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelRed(image,k_pixels+u*GetPixelChannels(image));
                     result.green   += alpha*
-                      GetPixelGreen(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelGreen(image,k_pixels+u*GetPixelChannels(image));
                     result.blue    += alpha*
-                      GetPixelBlue(image,k_pixels+u*GetPixelComponents(image));
+                      GetPixelBlue(image,k_pixels+u*GetPixelChannels(image));
                     if (image->colorspace == CMYKColorspace)
-                      result.black+=alpha*
-                        GetPixelBlack(image,k_pixels+u*GetPixelComponents(image));
-                    result.alpha += (*k)*
-                      GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image));
+                      result.black += alpha*
+                        GetPixelBlack(image,k_pixels+u*GetPixelChannels(image));
+                    result.alpha   += (*k)*
+                      GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image));
                   }
-                  k_pixels += virt_width*GetPixelComponents(image);
+                  k_pixels += virt_width*GetPixelChannels(image);
                 }
                 /* Sync'ed channels, all channels are modified */
-                gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+                gamma=(double)count/(fabs((double) gamma) < MagickEpsilon ? MagickEpsilon : gamma);
                 SetPixelRed(morphology_image,
                   ClampToQuantum(gamma*result.red),q);
                 SetPixelGreen(morphology_image,
@@ -2978,18 +3061,18 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
               for (u=0; u < (ssize_t) kernel->width; u++, k++) {
                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
                 Minimize(min.red,     (double)
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
-                Minimize(min.green,   (double) 
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(min.green,   (double)
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(min.blue,    (double)
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(min.alpha,   (double)
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
                 if (image->colorspace == CMYKColorspace)
-                  Minimize(min.black,(double)
-                    GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
-                Minimize(min.alpha,(double)
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                  Minimize(min.black,  (double)
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             break;
 
@@ -3011,18 +3094,18 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
                 Maximize(max.red,     (double)
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
-                Maximize(max.green,   (double) 
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
-                Maximize(max.blue,    (double) 
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.green,   (double)
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.blue,    (double)
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.alpha,   (double)
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
                 if (image->colorspace == CMYKColorspace)
                   Maximize(max.black,   (double)
-                    GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
-                Maximize(max.alpha,(double) 
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             break;
 
@@ -3048,40 +3131,40 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
                 if ( (*k) > 0.7 )
                 { /* minimim of foreground pixels */
                   Minimize(min.red,     (double)
-                    GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                   Minimize(min.green,   (double)
-                    GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                   Minimize(min.blue,    (double)
-                    GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                  Minimize(min.alpha,(double)
+                    GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
                   if ( image->colorspace == CMYKColorspace)
                     Minimize(min.black,(double)
-                      GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
-                  Minimize(min.alpha,(double)
-                    GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                      GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
                 }
                 else if ( (*k) < 0.3 )
                 { /* maximum of background pixels */
                   Maximize(max.red,     (double)
-                    GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                   Maximize(max.green,   (double)
-                    GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                   Maximize(max.blue,    (double)
-                    GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                  Maximize(max.alpha,(double)
+                    GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
                   if (image->colorspace == CMYKColorspace)
                     Maximize(max.black,   (double)
-                      GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
-                  Maximize(max.alpha,(double)
-                    GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                      GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
                 }
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             /* Pattern Match if difference is positive */
             min.red     -= max.red;     Maximize( min.red,     0.0 );
             min.green   -= max.green;   Maximize( min.green,   0.0 );
             min.blue    -= max.blue;    Maximize( min.blue,    0.0 );
-            min.alpha -= max.alpha; Maximize( min.alpha, 0.0 );
             min.black   -= max.black;   Maximize( min.black,   0.0 );
+            min.alpha -= max.alpha; Maximize( min.alpha, 0.0 );
             break;
 
         case ErodeIntensityMorphology:
@@ -3099,14 +3182,21 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
               for (u=0; u < (ssize_t) kernel->width; u++, k++) {
                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
                 if ( result.red == 0.0 ||
-                     GetPixelIntensity(image,&(k_pixels[u])) < GetPixelIntensity(morphology_image,q) ) {
+                     GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) < GetPixelIntensity(morphology_image,q) ) {
                   /* copy the whole pixel - no channel selection */
-                  *q = k_pixels[u];
+                  SetPixelRed(morphology_image,GetPixelRed(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelGreen(morphology_image,GetPixelGreen(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelBlue(morphology_image,GetPixelBlue(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelAlpha(morphology_image,GetPixelAlpha(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
                   if ( result.red > 0.0 ) changed++;
                   result.red = 1.0;
                 }
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             break;
 
@@ -3127,51 +3217,69 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) || (*k) < 0.5 ) continue; /* boolean kernel */
                 if ( result.red == 0.0 ||
-                     GetPixelIntensity(image,&(k_pixels[u])) > GetPixelIntensity(morphology_image,q) ) {
+                     GetPixelIntensity(image,k_pixels+u*GetPixelChannels(image)) > GetPixelIntensity(morphology_image,q) ) {
                   /* copy the whole pixel - no channel selection */
-                  *q = k_pixels[u];
+                  SetPixelRed(morphology_image,GetPixelRed(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelGreen(morphology_image,GetPixelGreen(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelBlue(morphology_image,GetPixelBlue(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
+                  SetPixelAlpha(morphology_image,GetPixelAlpha(image,
+                    k_pixels+u*GetPixelChannels(image)),q);
                   if ( result.red > 0.0 ) changed++;
                   result.red = 1.0;
                 }
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             break;
-#if 0
-  This code has been obsoleted by the MorphologyPrimitiveDirect() function.
-  However it is still (almost) correct coding for Grayscale Morphology.
-  That is...
 
-  GrayErode    is equivalent but with kernel values subtracted from pixels
-               without the kernel rotation
-  GreyDilate   is equivalent but using Maximum() instead of Minimum()
-               useing kernel rotation
-
-        case DistanceMorphology:
-            /* Add kernel Value and select the minimum value found.
-            ** The result is a iterative distance from edge of image shape.
+        case IterativeDistanceMorphology:
+            /* Work out an iterative distance from black edge of a white image
+            ** shape.  Essentually white values are decreased to the smallest
+            ** 'distance from edge' it can find.
             **
-            ** All Distance Kernels are symetrical, but that may not always
-            ** be the case. For example how about a distance from left edges?
-            ** To work correctly with asymetrical kernels the reflected kernel
-            ** needs to be applied.
+            ** It works by adding kernel values to the neighbourhood, and and
+            ** select the minimum value found. The kernel is rotated before
+            ** use, so kernel distances match resulting distances, when a user
+            ** provided asymmetric kernel is applied.
+            **
+            **
+            ** This code is almost identical to True GrayScale Morphology But
+            ** not quite.
+            **
+            ** GreyDilate  Kernel values added, maximum value found Kernel is
+            ** rotated before use.
+            **
+            ** GrayErode:  Kernel values subtracted and minimum value found No
+            ** kernel rotation used.
+            **
+            ** Note the the Iterative Distance method is essentially a
+            ** GrayErode, but with negative kernel values, and kernel
+            ** rotation applied.
             */
             k = &kernel->values[ kernel->width*kernel->height-1 ];
             k_pixels = p;
             for (v=0; v < (ssize_t) kernel->height; v++) {
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) ) continue;
-                Minimize(result.red,     (*k)+k_pixels[u].red);
-                Minimize(result.green,   (*k)+k_pixels[u].green);
-                Minimize(result.blue,    (*k)+k_pixels[u].blue);
-                Minimize(result.alpha, (*k)+k_pixels[u].alpha);
+                Minimize(result.red,     (*k)+(double)
+                     GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.green,   (*k)+(double)
+                     GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.blue,    (*k)+(double)
+                     GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.alpha,   (*k)+(double)
+                     GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
                 if ( image->colorspace == CMYKColorspace)
-                  Minimize(result.black,(*k)+GetPixelBlack(p_image,k_indexes+u));
+                  Maximize(result.black, (*k)+(double)
+                      GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             break;
-#endif
+
         case UndefinedMorphology:
         default:
             break; /* Do nothing */
@@ -3196,16 +3304,16 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
           result.red     -= min.red;
           result.green   -= min.green;
           result.blue    -= min.blue;
-          result.alpha -= min.alpha;
           result.black   -= min.black;
+          result.alpha   -= min.alpha;
           break;
         case ThickenMorphology:
           /* Add the pattern matchs to the original */
           result.red     += min.red;
           result.green   += min.green;
           result.blue    += min.blue;
-          result.alpha += min.alpha;
           result.black   += min.black;
+          result.alpha   += min.alpha;
           break;
         default:
           /* result directly calculated or assigned */
@@ -3219,30 +3327,30 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
         case ErodeIntensityMorphology:
           break;  /* full pixel was directly assigned - not a channel method */
         default:
-          if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
             SetPixelRed(morphology_image,ClampToQuantum(result.red),q);
-          if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
             SetPixelGreen(morphology_image,ClampToQuantum(result.green),q);
-          if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
             SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q);
-          if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
               (image->colorspace == CMYKColorspace))
             SetPixelBlack(morphology_image,ClampToQuantum(result.black),q);
-          if (((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0) &&
-              (image->matte == MagickTrue))
+          if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
+              (image->alpha_trait == BlendPixelTrait))
             SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
           break;
       }
       /* Count up changed pixels */
-      if ((GetPixelRed(image,p+r) != GetPixelRed(morphology_image,q)) ||
-          (GetPixelGreen(image,p+r) != GetPixelGreen(morphology_image,q)) ||
-          (GetPixelBlue(image,p+r) != GetPixelBlue(morphology_image,q)) ||
-          (GetPixelAlpha(image,p+r) != GetPixelAlpha(morphology_image,q)) ||
+      if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(morphology_image,q)) ||
+          (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(morphology_image,q)) ||
+          (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(morphology_image,q)) ||
+          (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(morphology_image,q)) ||
           ((image->colorspace == CMYKColorspace) &&
-           (GetPixelBlack(image,p+r) != GetPixelBlack(morphology_image,q))))
+           (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(morphology_image,q))))
         changed++;  /* The pixel was changed in some way! */
-      p+=GetPixelComponents(image);
-      q+=GetPixelComponents(morphology_image);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(morphology_image);
     } /* x */
     if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
       status=MagickFalse;
@@ -3252,7 +3360,7 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_MorphologyImage)
+        #pragma omp critical (MagickCore_MorphologyImage)
 #endif
         proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows);
         if (proceed == MagickFalse)
@@ -3265,13 +3373,15 @@ static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
 }
 
 /* This is almost identical to the MorphologyPrimative() function above,
-** but will apply the primitive directly to the image in two passes.
+** but will apply the primitive directly to the actual image using two
+** passes, once in each direction, with the results of the previous (and
+** current) row being re-used.
 **
 ** That is after each row is 'Sync'ed' into the image, the next row will
 ** make use of those values as part of the calculation of the next row.
 ** It then repeats, but going in the oppisite (bottom-up) direction.
 **
-** Because of this 'iterative' handling this function can not make use
+** Because of this 're-use of results' this function can not make use
 ** of multi-threaded, parellel processing.
 */
 static ssize_t MorphologyPrimitiveDirect(Image *image,
@@ -3330,8 +3440,8 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
 
   /* DO NOT THREAD THIS CODE! */
   /* two views into same image (virtual, and actual) */
-  virt_view=AcquireCacheView(image);
-  auth_view=AcquireCacheView(image);
+  virt_view=AcquireVirtualCacheView(image,exception);
+  auth_view=AcquireAuthenticCacheView(image,exception);
   virt_width=image->columns+kernel->width-1;
 
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -3371,24 +3481,24 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
 
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      ssize_t
-        v;
-
-      register ssize_t
-        u;
+      PixelInfo
+        result;
 
-      register const double
+      register const MagickRealType
         *restrict k;
 
       register const Quantum
         *restrict k_pixels;
 
-      PixelInfo
-        result;
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
 
       /* Starting Defaults */
       GetPixelInfo(image,&result);
-      SetPixelInfo(image,q,&result);
+      GetPixelInfoPixel(image,q,&result);
       if ( method != VoronoiMorphology )
         result.alpha = QuantumRange - result.alpha;
 
@@ -3401,67 +3511,69 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) ) continue;
                 Minimize(result.red,     (*k)+
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.green,   (*k)+
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.blue,    (*k)+
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
                 if (image->colorspace == CMYKColorspace)
                   Minimize(result.black,(*k)+
-                    GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.alpha, (*k)+
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             /* repeat with the just processed pixels of this row */
             k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
-            k_pixels = q-offx;
+            k_pixels = q-offx*GetPixelChannels(image);
               for (u=0; u < (ssize_t) offx; u++, k--) {
                 if ( x+u-offx < 0 ) continue;  /* off the edge! */
                 if ( IsNan(*k) ) continue;
                 Minimize(result.red,     (*k)+
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.green,   (*k)+
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.blue,    (*k)+
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
                 if (image->colorspace == CMYKColorspace)
                   Minimize(result.black,(*k)+
-                    GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.alpha,(*k)+
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
               }
             break;
         case VoronoiMorphology:
-            /* Apply Distance to 'Matte' channel, coping the closest color.
+            /* Apply Distance to 'Matte' channel, while coping the color
+            ** values of the closest pixel.
             **
             ** This is experimental, and realy the 'alpha' component should
-            ** be completely separate 'masking' channel.
+            ** be completely separate 'masking' channel so that alpha can
+            ** also be used as part of the results.
             */
             k = &kernel->values[ kernel->width*kernel->height-1 ];
             k_pixels = p;
             for (v=0; v <= (ssize_t) offy; v++) {
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) ) continue;
-                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)) )
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
                   {
-                    SetPixelInfo(image,k_pixels+u*GetPixelComponents(image),
+                    GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image),
                       &result);
                     result.alpha += *k;
                   }
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             /* repeat with the just processed pixels of this row */
             k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
-            k_pixels = q-offx;
+            k_pixels = q-offx*GetPixelChannels(image);
               for (u=0; u < (ssize_t) offx; u++, k--) {
                 if ( x+u-offx < 0 ) continue;  /* off the edge! */
                 if ( IsNan(*k) ) continue;
-                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)) )
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
                   {
-                    SetPixelInfo(image,k_pixels+u*GetPixelComponents(image),
+                    GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image),
                       &result);
                     result.alpha += *k;
                   }
@@ -3474,34 +3586,34 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
       /* Assign the resulting pixel values - Clamping Result */
       switch ( method ) {
         case VoronoiMorphology:
-          SetPixelPixelInfo(image,&result,q);
+          SetPixelInfoPixel(image,&result,q);
           break;
         default:
-          if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
             SetPixelRed(image,ClampToQuantum(result.red),q);
-          if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
             SetPixelGreen(image,ClampToQuantum(result.green),q);
-          if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
             SetPixelBlue(image,ClampToQuantum(result.blue),q);
-          if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
               (image->colorspace == CMYKColorspace))
             SetPixelBlack(image,ClampToQuantum(result.black),q);
-          if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0 &&
-              (image->matte == MagickTrue))
+          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 &&
+              (image->alpha_trait == BlendPixelTrait))
             SetPixelAlpha(image,ClampToQuantum(result.alpha),q);
           break;
       }
       /* Count up changed pixels */
-      if ((GetPixelRed(image,p+r) != GetPixelRed(image,q)) ||
-          (GetPixelGreen(image,p+r) != GetPixelGreen(image,q)) ||
-          (GetPixelBlue(image,p+r) != GetPixelBlue(image,q)) ||
-          (GetPixelAlpha(image,p+r) != GetPixelAlpha(image,q)) ||
+      if ((GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q)) ||
+          (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q)) ||
+          (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q)) ||
+          (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q)) ||
           ((image->colorspace == CMYKColorspace) &&
-           (GetPixelBlack(image,p+r) != GetPixelBlack(image,q))))
+           (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q))))
         changed++;  /* The pixel was changed in some way! */
 
-      p+=GetPixelComponents(image); /* increment pixel buffers */
-      q+=GetPixelComponents(image);
+      p+=GetPixelChannels(image); /* increment pixel buffers */
+      q+=GetPixelChannels(image);
     } /* x */
 
     if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
@@ -3547,32 +3659,32 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
       break;
 
     /* adjust positions to end of row */
-    p += image->columns-1;
-    q += image->columns-1;
+    p += (image->columns-1)*GetPixelChannels(image);
+    q += (image->columns-1)*GetPixelChannels(image);
 
     /* offset to origin in 'p'. while 'q' points to it directly */
     r = offx;
 
     for (x=(ssize_t)image->columns-1; x >= 0; x--)
     {
-      ssize_t
-        v;
-
-      register ssize_t
-        u;
+      PixelInfo
+        result;
 
-      register const double
+      register const MagickRealType
         *restrict k;
 
       register const Quantum
         *restrict k_pixels;
 
-      PixelInfo
-        result;
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
 
       /* Default - previously modified pixel */
       GetPixelInfo(image,&result);
-      SetPixelInfo(image,q,&result);
+      GetPixelInfoPixel(image,q,&result);
       if ( method != VoronoiMorphology )
         result.alpha = QuantumRange - result.alpha;
 
@@ -3585,36 +3697,36 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) ) continue;
                 Minimize(result.red,     (*k)+
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.green,   (*k)+
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.blue,    (*k)+
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
                 if ( image->colorspace == CMYKColorspace)
                   Minimize(result.black,(*k)+
-                    GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.alpha, (*k)+
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             /* repeat with the just processed pixels of this row */
             k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
-            k_pixels = q-offx;
+            k_pixels = q-offx*GetPixelChannels(image);
               for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
                 if ( (x+u-offx) >= (ssize_t)image->columns ) continue;
                 if ( IsNan(*k) ) continue;
                 Minimize(result.red,     (*k)+
-                  GetPixelRed(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.green,   (*k)+
-                  GetPixelGreen(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.blue,    (*k)+
-                  GetPixelBlue(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
                 if ( image->colorspace == CMYKColorspace)
                   Minimize(result.black,   (*k)+
-                    GetPixelBlack(image,k_pixels+u*GetPixelComponents(image)));
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
                 Minimize(result.alpha, (*k)+
-                  GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)));
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
               }
             break;
         case VoronoiMorphology:
@@ -3628,24 +3740,24 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
             for (v=offy; v < (ssize_t) kernel->height; v++) {
               for (u=0; u < (ssize_t) kernel->width; u++, k--) {
                 if ( IsNan(*k) ) continue;
-                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)) )
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
                   {
-                    SetPixelInfo(image,k_pixels+u*GetPixelComponents(image),
+                    GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image),
                       &result);
                     result.alpha += *k;
                   }
               }
-              k_pixels += virt_width*GetPixelComponents(image);
+              k_pixels += virt_width*GetPixelChannels(image);
             }
             /* repeat with the just processed pixels of this row */
             k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
-            k_pixels = q-offx;
+            k_pixels = q-offx*GetPixelChannels(image);
               for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
                 if ( (x+u-offx) >= (ssize_t)image->columns ) continue;
                 if ( IsNan(*k) ) continue;
-                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelComponents(image)) )
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
                   {
-                    SetPixelInfo(image,k_pixels+u*GetPixelComponents(image),
+                    GetPixelInfoPixel(image,k_pixels+u*GetPixelChannels(image),
                       &result);
                     result.alpha += *k;
                   }
@@ -3658,34 +3770,34 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
       /* Assign the resulting pixel values - Clamping Result */
       switch ( method ) {
         case VoronoiMorphology:
-          SetPixelPixelInfo(image,&result,q);
+          SetPixelInfoPixel(image,&result,q);
           break;
         default:
-          if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
             SetPixelRed(image,ClampToQuantum(result.red),q);
-          if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
             SetPixelGreen(image,ClampToQuantum(result.green),q);
-          if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
+          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
             SetPixelBlue(image,ClampToQuantum(result.blue),q);
-          if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
+          if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
               (image->colorspace == CMYKColorspace))
             SetPixelBlack(image,ClampToQuantum(result.black),q);
-          if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0 &&
-              (image->matte == MagickTrue))
+          if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0 &&
+              (image->alpha_trait == BlendPixelTrait))
             SetPixelAlpha(image,ClampToQuantum(result.alpha),q);
           break;
       }
       /* Count up changed pixels */
-      if (   (GetPixelRed(image,p+r) != GetPixelRed(image,q))
-          || (GetPixelGreen(image,p+r) != GetPixelGreen(image,q))
-          || (GetPixelBlue(image,p+r) != GetPixelBlue(image,q))
-          || (GetPixelAlpha(image,p+r) != GetPixelAlpha(image,q))
+      if (   (GetPixelRed(image,p+r*GetPixelChannels(image)) != GetPixelRed(image,q))
+          || (GetPixelGreen(image,p+r*GetPixelChannels(image)) != GetPixelGreen(image,q))
+          || (GetPixelBlue(image,p+r*GetPixelChannels(image)) != GetPixelBlue(image,q))
+          || (GetPixelAlpha(image,p+r*GetPixelChannels(image)) != GetPixelAlpha(image,q))
           || ((image->colorspace == CMYKColorspace) &&
-              (GetPixelBlack(image,p+r) != GetPixelBlack(image,q))))
+              (GetPixelBlack(image,p+r*GetPixelChannels(image)) != GetPixelBlack(image,q))))
         changed++;  /* The pixel was changed in some way! */
 
-      p--; /* go backward through pixel buffers */
-      q--;
+      p-=GetPixelChannels(image); /* go backward through pixel buffers */
+      q-=GetPixelChannels(image);
     } /* x */
     if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
       status=MagickFalse;
@@ -3701,15 +3813,15 @@ static ssize_t MorphologyPrimitiveDirect(Image *image,
   return(status ? (ssize_t) changed : -1);
 }
 
-/* Apply a Morphology by calling theabove low level primitive application
-** functions.  This function handles any iteration loops, composition or
-** re-iteration of results, and compound morphology methods that is based
-** on multiple low-level (staged) morphology methods.
+/* Apply a Morphology by calling one of the above low level primitive
+** application functions.  This function handles any iteration loops,
+** composition or re-iteration of results, and compound morphology methods
+** that is based on multiple low-level (staged) morphology methods.
 **
-** Basically this provides the complex grue between the requested morphology
+** Basically this provides the complex glue between the requested morphology
 ** method and raw low-level implementation (above).
 */
-MagickExport Image *MorphologyApply(const Image *image,
+MagickPrivate Image *MorphologyApply(const Image *image,
   const MorphologyMethod method, const ssize_t iterations,
   const KernelInfo *kernel, const CompositeOperator compose,const double bias,
   ExceptionInfo *exception)
@@ -3772,7 +3884,7 @@ MagickExport Image *MorphologyApply(const Image *image,
   if ( iterations < 0 )  /* negative interations = infinite (well alomst) */
      kernel_limit = image->columns>image->rows ? image->columns : image->rows;
 
-  verbose = IsMagickTrue(GetImageArtifact(image,"verbose"));
+  verbose = IsStringTrue(GetImageArtifact(image,"verbose"));
 
   /* initialise for cleanup */
   curr_image = (Image *) image;
@@ -3813,7 +3925,7 @@ MagickExport Image *MorphologyApply(const Image *image,
       break;
     case DistanceMorphology:
     case VoronoiMorphology:
-      special = MagickTrue;
+      special = MagickTrue;         /* use special direct primative */
       break;
     default:
       break;
@@ -3827,16 +3939,13 @@ MagickExport Image *MorphologyApply(const Image *image,
       rslt_image=CloneImage(image,0,0,MagickTrue,exception);
       if (rslt_image == (Image *) NULL)
         goto error_cleanup;
-      if (SetImageStorageClass(rslt_image,DirectClass) == MagickFalse)
-        {
-          InheritException(exception,&rslt_image->exception);
-          goto error_cleanup;
-        }
+      if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse)
+        goto error_cleanup;
 
       changed = MorphologyPrimitiveDirect(rslt_image, method,
          kernel, exception);
 
-      if ( verbose == MagickTrue )
+      if ( IfMagickTrue(verbose) )
         (void) (void) FormatLocaleFile(stderr,
           "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
           CommandOptionToMnemonic(MagickMorphologyOptions, method),
@@ -3847,9 +3956,12 @@ MagickExport Image *MorphologyApply(const Image *image,
 
       if ( method == VoronoiMorphology ) {
         /* Preserve the alpha channel of input image - but turned off */
-        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
-        (void) CompositeImage(rslt_image, CopyOpacityCompositeOp, image, 0, 0);
-        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
+        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
+          exception);
+        (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp,
+          MagickTrue,0,0,exception);
+        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
+          exception);
       }
       goto exit_cleanup;
     }
@@ -3981,7 +4093,7 @@ MagickExport Image *MorphologyApply(const Image *image,
         assert( this_kernel != (KernelInfo *) NULL );
 
         /* Extra information for debugging compound operations */
-        if ( verbose == MagickTrue ) {
+        if ( IfMagickTrue(verbose) ) {
           if ( stage_limit > 1 )
             (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ",
              CommandOptionToMnemonic(MagickMorphologyOptions,method),(double)
@@ -4007,11 +4119,8 @@ MagickExport Image *MorphologyApply(const Image *image,
               work_image=CloneImage(image,0,0,MagickTrue,exception);
               if (work_image == (Image *) NULL)
                 goto error_cleanup;
-              if (SetImageStorageClass(work_image,DirectClass) == MagickFalse)
-                {
-                  InheritException(exception,&work_image->exception);
-                  goto error_cleanup;
-                }
+              if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse)
+                goto error_cleanup;
               /* work_image->type=image->type; ??? */
             }
 
@@ -4020,7 +4129,7 @@ MagickExport Image *MorphologyApply(const Image *image,
           changed = MorphologyPrimitive(curr_image, work_image, primitive,
                        this_kernel, bias, exception);
 
-          if ( verbose == MagickTrue ) {
+          if ( IfMagickTrue(verbose) ) {
             if ( kernel_loop > 1 )
               (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */
             (void) (void) FormatLocaleFile(stderr,
@@ -4045,9 +4154,9 @@ MagickExport Image *MorphologyApply(const Image *image,
 
         } /* End Loop 4: Iterate the kernel with primitive */
 
-        if ( verbose == MagickTrue && kernel_changed != (size_t)changed )
+        if ( IfMagickTrue(verbose) && kernel_changed != (size_t)changed )
           (void) FormatLocaleFile(stderr, "   Total %.20g",(double) kernel_changed);
-        if ( verbose == MagickTrue && stage_loop < stage_limit )
+        if ( IfMagickTrue(verbose) && stage_loop < stage_limit )
           (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */
 
 #if 0
@@ -4072,19 +4181,20 @@ MagickExport Image *MorphologyApply(const Image *image,
         case EdgeInMorphology:
         case TopHatMorphology:
         case BottomHatMorphology:
-          if ( verbose == MagickTrue )
-            (void) FormatLocaleFile(stderr, "\n%s: Difference with original image",
-                 CommandOptionToMnemonic(MagickMorphologyOptions, method) );
-          curr_image->sync=MagickFalse;
-          (void) CompositeImage(curr_image,DifferenceCompositeOp,image,0,0);
+          if ( IfMagickTrue(verbose) )
+            (void) FormatLocaleFile(stderr,
+              "\n%s: Difference with original image",CommandOptionToMnemonic(
+              MagickMorphologyOptions, method) );
+          (void) CompositeImage(curr_image,image,DifferenceCompositeOp,
+            MagickTrue,0,0,exception);
           break;
         case EdgeMorphology:
-          if ( verbose == MagickTrue )
-            (void) FormatLocaleFile(stderr, "\n%s: Difference of Dilate and Erode",
-                 CommandOptionToMnemonic(MagickMorphologyOptions, method) );
-          curr_image->sync=MagickFalse;
-          (void) CompositeImage(curr_image,DifferenceCompositeOp,save_image,0,
-            0);
+          if ( IfMagickTrue(verbose) )
+            (void) FormatLocaleFile(stderr,
+              "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic(
+              MagickMorphologyOptions, method) );
+          (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp,
+            MagickTrue,0,0,exception);
           save_image = DestroyImage(save_image); /* finished with save image */
           break;
         default:
@@ -4095,7 +4205,7 @@ MagickExport Image *MorphologyApply(const Image *image,
       if ( kernel->next == (KernelInfo *) NULL )
         rslt_image = curr_image;   /* just return the resulting image */
       else if ( rslt_compose == NoCompositeOp )
-        { if ( verbose == MagickTrue ) {
+        { if ( IfMagickTrue(verbose) ) {
             if ( this_kernel->next != (KernelInfo *) NULL )
               (void) FormatLocaleFile(stderr, " (re-iterate)");
             else
@@ -4104,7 +4214,7 @@ MagickExport Image *MorphologyApply(const Image *image,
           rslt_image = curr_image; /* return result, and re-iterate */
         }
       else if ( rslt_image == (Image *) NULL)
-        { if ( verbose == MagickTrue )
+        { if ( IfMagickTrue(verbose) )
             (void) FormatLocaleFile(stderr, " (save for compose)");
           rslt_image = curr_image;
           curr_image = (Image *) image;  /* continue with original image */
@@ -4117,15 +4227,15 @@ MagickExport Image *MorphologyApply(const Image *image,
           ** purely mathematical way, and only to the selected channels.
           ** IE: Turn off SVG composition 'alpha blending'.
           */
-          if ( verbose == MagickTrue )
+          if ( IfMagickTrue(verbose) )
             (void) FormatLocaleFile(stderr, " (compose \"%s\")",
-                 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
-          rslt_image->sync=MagickFalse;
-          (void) CompositeImage(rslt_image, rslt_compose, curr_image, 0, 0);
+              CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
+          (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue,
+            0,0,exception);
           curr_image = DestroyImage(curr_image);
           curr_image = (Image *) image;  /* continue with original image */
         }
-      if ( verbose == MagickTrue )
+      if ( IfMagickTrue(verbose) )
         (void) FormatLocaleFile(stderr, "\n");
 
       /* loop to the next kernel in a multi-kernel list */
@@ -4178,20 +4288,20 @@ exit_cleanup:
 %  the above internal function MorphologyApply().
 %
 %  User defined settings include...
-%    * Output Bias for Convolution and correlation   ("-bias")
-%    * Kernel Scale/normalize settings     ("-set 'option:convolve:scale'")
+%    * Output Bias for Convolution and correlation ("-define convolve:bias=??")
+%    * Kernel Scale/normalize settings             ("-define convolve:scale=??")
 %      This can also includes the addition of a scaled unity kernel.
-%    * Show Kernel being applied           ("-set option:showkernel 1")
+%    * Show Kernel being applied                   ("-define showkernel=1")
+%
+%  Other operators that do not want user supplied options interfering,
+%  especially "convolve:bias" and "showkernel" should use MorphologyApply()
+%  directly.
 %
 %  The format of the MorphologyImage method is:
 %
 %      Image *MorphologyImage(const Image *image,MorphologyMethod method,
 %        const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception)
 %
-%      Image *MorphologyImage(const Image *image, const ChannelType
-%        channel,MorphologyMethod method,const ssize_t iterations,
-%        KernelInfo *kernel,ExceptionInfo *exception)
-%
 %  A description of each parameter follows:
 %
 %    o image: the image.
@@ -4222,32 +4332,53 @@ MagickExport Image *MorphologyImage(const Image *image,
   Image
     *morphology_image;
 
+  double
+    bias;
+
+  curr_kernel = (KernelInfo *) kernel;
+  bias=0.0;
+  compose = UndefinedCompositeOp;  /* use default for method */
 
   /* Apply Convolve/Correlate Normalization and Scaling Factors.
    * This is done BEFORE the ShowKernelInfo() function is called so that
    * users can see the results of the 'option:convolve:scale' option.
    */
-  curr_kernel = (KernelInfo *) kernel;
-  if ( method == ConvolveMorphology ||  method == CorrelateMorphology )
-    {
+  if ( method == ConvolveMorphology || method == CorrelateMorphology ) {
       const char
         *artifact;
+
+      /* Get the bias value as it will be needed */
+      artifact = GetImageArtifact(image,"convolve:bias");
+      if ( artifact != (const char *) NULL) {
+        if (IfMagickFalse(IsGeometry(artifact)))
+          (void) ThrowMagickException(exception,GetMagickModule(),
+               OptionWarning,"InvalidSetting","'%s' '%s'",
+               "convolve:bias",artifact);
+        else
+          bias=StringToDoubleInterval(artifact,(double) QuantumRange+1.0);
+      }
+
+      /* Scale kernel according to user wishes */
       artifact = GetImageArtifact(image,"convolve:scale");
       if ( artifact != (const char *)NULL ) {
-        if ( curr_kernel == kernel )
-          curr_kernel = CloneKernelInfo(kernel);
-        if (curr_kernel == (KernelInfo *) NULL) {
-          curr_kernel=DestroyKernelInfo(curr_kernel);
-          return((Image *) NULL);
+        if (IfMagickFalse(IsGeometry(artifact)))
+          (void) ThrowMagickException(exception,GetMagickModule(),
+               OptionWarning,"InvalidSetting","'%s' '%s'",
+               "convolve:scale",artifact);
+        else {
+          if ( curr_kernel == kernel )
+            curr_kernel = CloneKernelInfo(kernel);
+          if (curr_kernel == (KernelInfo *) NULL)
+            return((Image *) NULL);
+          ScaleGeometryKernelInfo(curr_kernel, artifact);
         }
-        ScaleGeometryKernelInfo(curr_kernel, artifact);
       }
     }
 
   /* display the (normalized) kernel via stderr */
-  if ( IsMagickTrue(GetImageArtifact(image,"showkernel"))
-    || IsMagickTrue(GetImageArtifact(image,"convolve:showkernel"))
-    || IsMagickTrue(GetImageArtifact(image,"morphology:showkernel")) )
+  if ( IfStringTrue(GetImageArtifact(image,"showkernel"))
+    || IfStringTrue(GetImageArtifact(image,"convolve:showkernel"))
+    || IfStringTrue(GetImageArtifact(image,"morphology:showkernel")) )
     ShowKernelInfo(curr_kernel);
 
   /* Override the default handling of multi-kernel morphology results
@@ -4258,15 +4389,24 @@ MagickExport Image *MorphologyImage(const Image *image,
    */
   { const char
       *artifact;
+    ssize_t
+      parse;
+
     artifact = GetImageArtifact(image,"morphology:compose");
-    compose = UndefinedCompositeOp;  /* use default for method */
-    if ( artifact != (const char *) NULL)
-      compose = (CompositeOperator) ParseCommandOption(
-                             MagickComposeOptions,MagickFalse,artifact);
+    if ( artifact != (const char *) NULL) {
+      parse=ParseCommandOption(MagickComposeOptions,
+        MagickFalse,artifact);
+      if ( parse < 0 )
+        (void) ThrowMagickException(exception,GetMagickModule(),
+             OptionWarning,"UnrecognizedComposeOperator","'%s' '%s'",
+             "morphology:compose",artifact);
+      else
+        compose=(CompositeOperator)parse;
+    }
   }
   /* Apply the Morphology */
-  morphology_image = MorphologyApply(image, method, iterations,
-    curr_kernel, compose, image->bias, exception);
+  morphology_image = MorphologyApply(image,method,iterations,
+    curr_kernel,compose,bias,exception);
 
   /* Cleanup and Exit */
   if ( curr_kernel != kernel )
@@ -4348,7 +4488,6 @@ static void RotateKernelInfo(KernelInfo *kernel, double angle)
     /* These only allows a +/-90 degree rotation (by transpose) */
     /* A 180 degree rotation is useless */
     case BlurKernel:
-    case RectangleKernel:
       if ( 135.0 < angle && angle <= 225.0 )
         return;
       if ( 225.0 < angle && angle <= 315.0 )
@@ -4358,12 +4497,12 @@ static void RotateKernelInfo(KernelInfo *kernel, double angle)
     default:
       break;
   }
-  /* Attempt rotations by 45 degrees */
+  /* Attempt rotations by 45 degrees  -- 3x3 kernels only */
   if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
     {
       if ( kernel->width == 3 && kernel->height == 3 )
         { /* Rotate a 3x3 square by 45 degree angle */
-          MagickRealType t  = kernel->values[0];
+          double t  = kernel->values[0];
           kernel->values[0] = kernel->values[3];
           kernel->values[3] = kernel->values[6];
           kernel->values[6] = kernel->values[7];
@@ -4414,13 +4553,15 @@ static void RotateKernelInfo(KernelInfo *kernel, double angle)
         }
       else if ( kernel->width == kernel->height )
         { /* Rotate a square array of values by 90 degrees */
-          { register size_t
+          { register ssize_t
               i,j,x,y;
+
             register MagickRealType
               *k,t;
+
             k=kernel->values;
-            for( i=0, x=kernel->width-1;  i<=x;   i++, x--)
-              for( j=0, y=kernel->height-1;  j<y;   j++, y--)
+            for( i=0, x=(ssize_t) kernel->width-1;  i<=x;   i++, x--)
+              for( j=0, y=(ssize_t) kernel->height-1;  j<y;   j++, y--)
                 { t                    = k[i+j*kernel->width];
                   k[i+j*kernel->width] = k[j+x*kernel->width];
                   k[j+x*kernel->width] = k[x+y*kernel->width];
@@ -4448,13 +4589,19 @@ static void RotateKernelInfo(KernelInfo *kernel, double angle)
        * Basically all that is needed is a reversal of the kernel data!
        * And a reflection of the origon
        */
-      size_t
-        i,j;
-      register double
-        *k,t;
+      double
+        t;
+
+      register MagickRealType
+        *k;
+
+      ssize_t
+        i,
+        j;
 
       k=kernel->values;
-      for ( i=0, j=kernel->width*kernel->height-1;  i<j;  i++, j--)
+      j=(ssize_t) (kernel->width*kernel->height-1);
+      for (i=0;  i < j;  i++, j--)
         t=k[i],  k[i]=k[j],  k[j]=t;
 
       kernel->x = (ssize_t) kernel->width  - kernel->x - 1;
@@ -4507,13 +4654,15 @@ static void RotateKernelInfo(KernelInfo *kernel, double angle)
 MagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel,
      const char *geometry)
 {
-  GeometryFlags
+  //GeometryFlags
+  MagickStatusType
     flags;
+
   GeometryInfo
     args;
 
   SetGeometryInfo(&args);
-  flags = (GeometryFlags) ParseGeometry(geometry, &args);
+  flags = ParseGeometry(geometry, &args);
 
 #if 0
   /* For Debugging Geometry Input */
@@ -4530,7 +4679,7 @@ MagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel,
     args.sigma = 0.0;
 
   /* Scale/Normalize the input kernel */
-  ScaleKernelInfo(kernel, args.rho, flags);
+  ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags);
 
   /* Add Unity Kernel, for blending with original */
   if ( (flags & SigmaValue) != 0 )
@@ -4626,7 +4775,7 @@ MagickExport void ScaleKernelInfo(KernelInfo *kernel,
   /* Normalization of Kernel */
   pos_scale = 1.0;
   if ( (normalize_flags&NormalizeValue) != 0 ) {
-    if ( fabs(kernel->positive_range + kernel->negative_range) > MagickEpsilon )
+    if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
       /* non-zero-summing kernel (generally positive) */
       pos_scale = fabs(kernel->positive_range + kernel->negative_range);
     else
@@ -4635,9 +4784,9 @@ MagickExport void ScaleKernelInfo(KernelInfo *kernel,
   }
   /* Force kernel into a normalized zero-summing kernel */
   if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
-    pos_scale = ( fabs(kernel->positive_range) > MagickEpsilon )
+    pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
                  ? kernel->positive_range : 1.0;
-    neg_scale = ( fabs(kernel->negative_range) > MagickEpsilon )
+    neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
                  ? -kernel->negative_range : 1.0;
   }
   else
@@ -4688,16 +4837,16 @@ MagickExport void ScaleKernelInfo(KernelInfo *kernel,
 %
 %  The format of the ShowKernel method is:
 %
-%      void ShowKernelInfo(KernelInfo *kernel)
+%      void ShowKernelInfo(const KernelInfo *kernel)
 %
 %  A description of each parameter follows:
 %
 %    o kernel: the Morphology/Convolution kernel
 %
 */
-MagickExport void ShowKernelInfo(KernelInfo *kernel)
+MagickPrivate void ShowKernelInfo(const KernelInfo *kernel)
 {
-  KernelInfo
+  const KernelInfo
     *k;
 
   size_t
@@ -4710,7 +4859,7 @@ MagickExport void ShowKernelInfo(KernelInfo *kernel)
       (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c );
     (void) FormatLocaleFile(stderr, " \"%s",
           CommandOptionToMnemonic(MagickKernelOptions, k->type) );
-    if ( fabs(k->angle) > MagickEpsilon )
+    if ( fabs(k->angle) >= MagickEpsilon )
       (void) FormatLocaleFile(stderr, "@%lg", k->angle);
     (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long)
       k->width,(unsigned long) k->height,(long) k->x,(long) k->y);
@@ -4735,7 +4884,7 @@ MagickExport void ShowKernelInfo(KernelInfo *kernel)
           (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan");
         else
           (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3,
-              GetMagickPrecision(), k->values[i]);
+              GetMagickPrecision(), (double) k->values[i]);
       (void) FormatLocaleFile(stderr,"\n");
     }
   }
@@ -4813,7 +4962,7 @@ MagickExport void UnityAddKernelInfo(KernelInfo *kernel,
 %    o kernel: the Morphology/Convolution kernel
 %
 */
-MagickExport void ZeroKernelNans(KernelInfo *kernel)
+MagickPrivate void ZeroKernelNans(KernelInfo *kernel)
 {
   register size_t
     i;