Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %    M   M    OOO    RRRR   PPPP   H   H   OOO   L       OOO    GGGG  Y   Y   %
      7 %    MM MM   O   O   R   R  P   P  H   H  O   O  L      O   O  G       Y Y    %
      8 %    M M M   O   O   RRRR   PPPP   HHHHH  O   O  L      O   O  G GGG    Y     %
      9 %    M   M   O   O   R R    P      H   H  O   O  L      O   O  G   G    Y     %
     10 %    M   M    OOO    R  R   P      H   H   OOO   LLLLL   OOO    GGG     Y     %
     11 %                                                                             %
     12 %                                                                             %
     13 %                        MagickCore Morphology Methods                        %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                              Anthony Thyssen                                %
     17 %                               January 2010                                  %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    https://imagemagick.org/script/license.php                               %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 % Morphology is the application of various kernels, of any size or shape, to an
     37 % image in various ways (typically binary, but not always).
     38 %
     39 % Convolution (weighted sum or average) is just one specific type of
     40 % morphology. Just one that is very common for image bluring and sharpening
     41 % effects.  Not only 2D Gaussian blurring, but also 2-pass 1D Blurring.
     42 %
     43 % This module provides not only a general morphology function, and the ability
     44 % to apply more advanced or iterative morphologies, but also functions for the
     45 % generation of many different types of kernel arrays from user supplied
     46 % arguments. Prehaps even the generation of a kernel from a small image.
     47 */
     48 
     49 /*
     51   Include declarations.
     52 */
     53 #include "MagickCore/studio.h"
     54 #include "MagickCore/artifact.h"
     55 #include "MagickCore/cache-view.h"
     56 #include "MagickCore/channel.h"
     57 #include "MagickCore/color-private.h"
     58 #include "MagickCore/enhance.h"
     59 #include "MagickCore/exception.h"
     60 #include "MagickCore/exception-private.h"
     61 #include "MagickCore/gem.h"
     62 #include "MagickCore/gem-private.h"
     63 #include "MagickCore/image.h"
     64 #include "MagickCore/image-private.h"
     65 #include "MagickCore/linked-list.h"
     66 #include "MagickCore/list.h"
     67 #include "MagickCore/magick.h"
     68 #include "MagickCore/memory_.h"
     69 #include "MagickCore/memory-private.h"
     70 #include "MagickCore/monitor-private.h"
     71 #include "MagickCore/morphology.h"
     72 #include "MagickCore/morphology-private.h"
     73 #include "MagickCore/option.h"
     74 #include "MagickCore/pixel-accessor.h"
     75 #include "MagickCore/pixel-private.h"
     76 #include "MagickCore/prepress.h"
     77 #include "MagickCore/quantize.h"
     78 #include "MagickCore/resource_.h"
     79 #include "MagickCore/registry.h"
     80 #include "MagickCore/semaphore.h"
     81 #include "MagickCore/splay-tree.h"
     82 #include "MagickCore/statistic.h"
     83 #include "MagickCore/string_.h"
     84 #include "MagickCore/string-private.h"
     85 #include "MagickCore/thread-private.h"
     86 #include "MagickCore/token.h"
     87 #include "MagickCore/utility.h"
     88 #include "MagickCore/utility-private.h"
     89 
     90 /*
     92   Other global definitions used by module.
     93 */
     94 #define Minimize(assign,value) assign=MagickMin(assign,value)
     95 #define Maximize(assign,value) assign=MagickMax(assign,value)
     96 
     97 /* Integer Factorial Function - for a Binomial kernel */
     98 #if 1
     99 static inline size_t fact(size_t n)
    100 {
    101   size_t f,l;
    102   for(f=1, l=2; l <= n; f=f*l, l++);
    103   return(f);
    104 }
    105 #elif 1 /* glibc floating point alternatives */
    106 #define fact(n) ((size_t)tgamma((double)n+1))
    107 #else
    108 #define fact(n) ((size_t)lgamma((double)n+1))
    109 #endif
    110 
    111 
    112 /* Currently these are only internal to this module */
    113 static void
    114   CalcKernelMetaData(KernelInfo *),
    115   ExpandMirrorKernelInfo(KernelInfo *),
    116   ExpandRotateKernelInfo(KernelInfo *, const double),
    117   RotateKernelInfo(KernelInfo *, double);
    118 
    119 
    121 /* Quick function to find last kernel in a kernel list */
    122 static inline KernelInfo *LastKernelInfo(KernelInfo *kernel)
    123 {
    124   while (kernel->next != (KernelInfo *) NULL)
    125     kernel=kernel->next;
    126   return(kernel);
    127 }
    128 
    129 /*
    130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    131 %                                                                             %
    132 %                                                                             %
    133 %                                                                             %
    134 %     A c q u i r e K e r n e l I n f o                                       %
    135 %                                                                             %
    136 %                                                                             %
    137 %                                                                             %
    138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    139 %
    140 %  AcquireKernelInfo() takes the given string (generally supplied by the
    141 %  user) and converts it into a Morphology/Convolution Kernel.  This allows
    142 %  users to specify a kernel from a number of pre-defined kernels, or to fully
    143 %  specify their own kernel for a specific Convolution or Morphology
    144 %  Operation.
    145 %
    146 %  The kernel so generated can be any rectangular array of floating point
    147 %  values (doubles) with the 'control point' or 'pixel being affected'
    148 %  anywhere within that array of values.
    149 %
    150 %  Previously IM was restricted to a square of odd size using the exact
    151 %  center as origin, this is no longer the case, and any rectangular kernel
    152 %  with any value being declared the origin. This in turn allows the use of
    153 %  highly asymmetrical kernels.
    154 %
    155 %  The floating point values in the kernel can also include a special value
    156 %  known as 'nan' or 'not a number' to indicate that this value is not part
    157 %  of the kernel array. This allows you to shaped the kernel within its
    158 %  rectangular area. That is 'nan' values provide a 'mask' for the kernel
    159 %  shape.  However at least one non-nan value must be provided for correct
    160 %  working of a kernel.
    161 %
    162 %  The returned kernel should be freed using the DestroyKernelInfo() when you
    163 %  are finished with it.  Do not free this memory yourself.
    164 %
    165 %  Input kernel defintion strings can consist of any of three types.
    166 %
    167 %    "name:args[[@><]"
    168 %         Select from one of the built in kernels, using the name and
    169 %         geometry arguments supplied.  See AcquireKernelBuiltIn()
    170 %
    171 %    "WxH[+X+Y][@><]:num, num, num ..."
    172 %         a kernel of size W by H, with W*H floating point numbers following.
    173 %         the 'center' can be optionally be defined at +X+Y (such that +0+0
    174 %         is top left corner). If not defined the pixel in the center, for
    175 %         odd sizes, or to the immediate top or left of center for even sizes
    176 %         is automatically selected.
    177 %
    178 %    "num, num, num, num, ..."
    179 %         list of floating point numbers defining an 'old style' odd sized
    180 %         square kernel.  At least 9 values should be provided for a 3x3
    181 %         square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc.
    182 %         Values can be space or comma separated.  This is not recommended.
    183 %
    184 %  You can define a 'list of kernels' which can be used by some morphology
    185 %  operators A list is defined as a semi-colon separated list kernels.
    186 %
    187 %     " kernel ; kernel ; kernel ; "
    188 %
    189 %  Any extra ';' characters, at start, end or between kernel defintions are
    190 %  simply ignored.
    191 %
    192 %  The special flags will expand a single kernel, into a list of rotated
    193 %  kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree
    194 %  cyclic rotations, while a '>' will generate a list of 90-degree rotations.
    195 %  The '<' also exands using 90-degree rotates, but giving a 180-degree
    196 %  reflected kernel before the +/- 90-degree rotations, which can be important
    197 %  for Thinning operations.
    198 %
    199 %  Note that 'name' kernels will start with an alphabetic character while the
    200 %  new kernel specification has a ':' character in its specification string.
    201 %  If neither is the case, it is assumed an old style of a simple list of
    202 %  numbers generating a odd-sized square kernel has been given.
    203 %
    204 %  The format of the AcquireKernal method is:
    205 %
    206 %      KernelInfo *AcquireKernelInfo(const char *kernel_string)
    207 %
    208 %  A description of each parameter follows:
    209 %
    210 %    o kernel_string: the Morphology/Convolution kernel wanted.
    211 %
    212 */
    213 
    214 /* This was separated so that it could be used as a separate
    215 ** array input handling function, such as for -color-matrix
    216 */
    217 static KernelInfo *ParseKernelArray(const char *kernel_string)
    218 {
    219   KernelInfo
    220     *kernel;
    221 
    222   char
    223     token[MagickPathExtent];
    224 
    225   const char
    226     *p,
    227     *end;
    228 
    229   register ssize_t
    230     i;
    231 
    232   double
    233     nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
    234 
    235   MagickStatusType
    236     flags;
    237 
    238   GeometryInfo
    239     args;
    240 
    241   kernel=(KernelInfo *) AcquireQuantumMemory(1,sizeof(*kernel));
    242   if (kernel == (KernelInfo *) NULL)
    243     return(kernel);
    244   (void) memset(kernel,0,sizeof(*kernel));
    245   kernel->minimum = kernel->maximum = kernel->angle = 0.0;
    246   kernel->negative_range = kernel->positive_range = 0.0;
    247   kernel->type = UserDefinedKernel;
    248   kernel->next = (KernelInfo *) NULL;
    249   kernel->signature=MagickCoreSignature;
    250   if (kernel_string == (const char *) NULL)
    251     return(kernel);
    252 
    253   /* find end of this specific kernel definition string */
    254   end = strchr(kernel_string, ';');
    255   if ( end == (char *) NULL )
    256     end = strchr(kernel_string, '\0');
    257 
    258   /* clear flags - for Expanding kernel lists thorugh rotations */
    259    flags = NoValue;
    260 
    261   /* Has a ':' in argument - New user kernel specification
    262      FUTURE: this split on ':' could be done by StringToken()
    263    */
    264   p = strchr(kernel_string, ':');
    265   if ( p != (char *) NULL && p < end)
    266     {
    267       /* ParseGeometry() needs the geometry separated! -- Arrgghh */
    268       memcpy(token, kernel_string, (size_t) (p-kernel_string));
    269       token[p-kernel_string] = '\0';
    270       SetGeometryInfo(&args);
    271       flags = ParseGeometry(token, &args);
    272 
    273       /* Size handling and checks of geometry settings */
    274       if ( (flags & WidthValue) == 0 ) /* if no width then */
    275         args.rho = args.sigma;         /* then  width = height */
    276       if ( args.rho < 1.0 )            /* if width too small */
    277          args.rho = 1.0;               /* then  width = 1 */
    278       if ( args.sigma < 1.0 )          /* if height too small */
    279         args.sigma = args.rho;         /* then  height = width */
    280       kernel->width = (size_t)args.rho;
    281       kernel->height = (size_t)args.sigma;
    282 
    283       /* Offset Handling and Checks */
    284       if ( args.xi  < 0.0 || args.psi < 0.0 )
    285         return(DestroyKernelInfo(kernel));
    286       kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
    287                                         : (ssize_t) (kernel->width-1)/2;
    288       kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
    289                                         : (ssize_t) (kernel->height-1)/2;
    290       if ( kernel->x >= (ssize_t) kernel->width ||
    291            kernel->y >= (ssize_t) kernel->height )
    292         return(DestroyKernelInfo(kernel));
    293 
    294       p++; /* advance beyond the ':' */
    295     }
    296   else
    297     { /* ELSE - Old old specification, forming odd-square kernel */
    298       /* count up number of values given */
    299       p=(const char *) kernel_string;
    300       while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
    301         p++;  /* ignore "'" chars for convolve filter usage - Cristy */
    302       for (i=0; p < end; i++)
    303       {
    304         GetNextToken(p,&p,MagickPathExtent,token);
    305         if (*token == ',')
    306           GetNextToken(p,&p,MagickPathExtent,token);
    307       }
    308       /* set the size of the kernel - old sized square */
    309       kernel->width = kernel->height= (size_t) sqrt((double) i+1.0);
    310       kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
    311       p=(const char *) kernel_string;
    312       while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
    313         p++;  /* ignore "'" chars for convolve filter usage - Cristy */
    314     }
    315 
    316   /* Read in the kernel values from rest of input string argument */
    317   kernel->values=(MagickRealType *) MagickAssumeAligned(AcquireAlignedMemory(
    318     kernel->width,kernel->height*sizeof(*kernel->values)));
    319   if (kernel->values == (MagickRealType *) NULL)
    320     return(DestroyKernelInfo(kernel));
    321   kernel->minimum=MagickMaximumValue;
    322   kernel->maximum=(-MagickMaximumValue);
    323   kernel->negative_range = kernel->positive_range = 0.0;
    324   for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
    325   {
    326     GetNextToken(p,&p,MagickPathExtent,token);
    327     if (*token == ',')
    328       GetNextToken(p,&p,MagickPathExtent,token);
    329     if (    LocaleCompare("nan",token) == 0
    330         || LocaleCompare("-",token) == 0 ) {
    331       kernel->values[i] = nan; /* this value is not part of neighbourhood */
    332     }
    333     else {
    334       kernel->values[i] = StringToDouble(token,(char **) NULL);
    335       ( kernel->values[i] < 0)
    336           ?  ( kernel->negative_range += kernel->values[i] )
    337           :  ( kernel->positive_range += kernel->values[i] );
    338       Minimize(kernel->minimum, kernel->values[i]);
    339       Maximize(kernel->maximum, kernel->values[i]);
    340     }
    341   }
    342 
    343   /* sanity check -- no more values in kernel definition */
    344   GetNextToken(p,&p,MagickPathExtent,token);
    345   if ( *token != '\0' && *token != ';' && *token != '\'' )
    346     return(DestroyKernelInfo(kernel));
    347 
    348 #if 0
    349   /* this was the old method of handling a incomplete kernel */
    350   if ( i < (ssize_t) (kernel->width*kernel->height) ) {
    351     Minimize(kernel->minimum, kernel->values[i]);
    352     Maximize(kernel->maximum, kernel->values[i]);
    353     for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
    354       kernel->values[i]=0.0;
    355   }
    356 #else
    357   /* Number of values for kernel was not enough - Report Error */
    358   if ( i < (ssize_t) (kernel->width*kernel->height) )
    359     return(DestroyKernelInfo(kernel));
    360 #endif
    361 
    362   /* check that we recieved at least one real (non-nan) value! */
    363   if (kernel->minimum == MagickMaximumValue)
    364     return(DestroyKernelInfo(kernel));
    365 
    366   if ( (flags & AreaValue) != 0 )         /* '@' symbol in kernel size */
    367     ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */
    368   else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */
    369     ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */
    370   else if ( (flags & LessValue) != 0 )    /* '<' symbol in kernel args */
    371     ExpandMirrorKernelInfo(kernel);       /* 90 degree mirror rotate */
    372 
    373   return(kernel);
    374 }
    375 
    376 static KernelInfo *ParseKernelName(const char *kernel_string,
    377   ExceptionInfo *exception)
    378 {
    379   char
    380     token[MagickPathExtent];
    381 
    382   const char
    383     *p,
    384     *end;
    385 
    386   GeometryInfo
    387     args;
    388 
    389   KernelInfo
    390     *kernel;
    391 
    392   MagickStatusType
    393     flags;
    394 
    395   ssize_t
    396     type;
    397 
    398   /* Parse special 'named' kernel */
    399   GetNextToken(kernel_string,&p,MagickPathExtent,token);
    400   type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
    401   if ( type < 0 || type == UserDefinedKernel )
    402     return((KernelInfo *) NULL);  /* not a valid named kernel */
    403 
    404   while (((isspace((int) ((unsigned char) *p)) != 0) ||
    405           (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';'))
    406     p++;
    407 
    408   end = strchr(p, ';'); /* end of this kernel defintion */
    409   if ( end == (char *) NULL )
    410     end = strchr(p, '\0');
    411 
    412   /* ParseGeometry() needs the geometry separated! -- Arrgghh */
    413   memcpy(token, p, (size_t) (end-p));
    414   token[end-p] = '\0';
    415   SetGeometryInfo(&args);
    416   flags = ParseGeometry(token, &args);
    417 
    418 #if 0
    419   /* For Debugging Geometry Input */
    420   (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
    421     flags, args.rho, args.sigma, args.xi, args.psi );
    422 #endif
    423 
    424   /* special handling of missing values in input string */
    425   switch( type ) {
    426     /* Shape Kernel Defaults */
    427     case UnityKernel:
    428       if ( (flags & WidthValue) == 0 )
    429         args.rho = 1.0;    /* Default scale = 1.0, zero is valid */
    430       break;
    431     case SquareKernel:
    432     case DiamondKernel:
    433     case OctagonKernel:
    434     case DiskKernel:
    435     case PlusKernel:
    436     case CrossKernel:
    437       if ( (flags & HeightValue) == 0 )
    438         args.sigma = 1.0;    /* Default scale = 1.0, zero is valid */
    439       break;
    440     case RingKernel:
    441       if ( (flags & XValue) == 0 )
    442         args.xi = 1.0;       /* Default scale = 1.0, zero is valid */
    443       break;
    444     case RectangleKernel:    /* Rectangle - set size defaults */
    445       if ( (flags & WidthValue) == 0 ) /* if no width then */
    446         args.rho = args.sigma;         /* then  width = height */
    447       if ( args.rho < 1.0 )            /* if width too small */
    448           args.rho = 3;                /* then  width = 3 */
    449       if ( args.sigma < 1.0 )          /* if height too small */
    450         args.sigma = args.rho;         /* then  height = width */
    451       if ( (flags & XValue) == 0 )     /* center offset if not defined */
    452         args.xi = (double)(((ssize_t)args.rho-1)/2);
    453       if ( (flags & YValue) == 0 )
    454         args.psi = (double)(((ssize_t)args.sigma-1)/2);
    455       break;
    456     /* Distance Kernel Defaults */
    457     case ChebyshevKernel:
    458     case ManhattanKernel:
    459     case OctagonalKernel:
    460     case EuclideanKernel:
    461       if ( (flags & HeightValue) == 0 )           /* no distance scale */
    462         args.sigma = 100.0;                       /* default distance scaling */
    463       else if ( (flags & AspectValue ) != 0 )     /* '!' flag */
    464         args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */
    465       else if ( (flags & PercentValue ) != 0 )    /* '%' flag */
    466         args.sigma *= QuantumRange/100.0;         /* percentage of color range */
    467       break;
    468     default:
    469       break;
    470   }
    471 
    472   kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args, exception);
    473   if ( kernel == (KernelInfo *) NULL )
    474     return(kernel);
    475 
    476   /* global expand to rotated kernel list - only for single kernels */
    477   if ( kernel->next == (KernelInfo *) NULL ) {
    478     if ( (flags & AreaValue) != 0 )         /* '@' symbol in kernel args */
    479       ExpandRotateKernelInfo(kernel, 45.0);
    480     else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */
    481       ExpandRotateKernelInfo(kernel, 90.0);
    482     else if ( (flags & LessValue) != 0 )    /* '<' symbol in kernel args */
    483       ExpandMirrorKernelInfo(kernel);
    484   }
    485 
    486   return(kernel);
    487 }
    488 
    489 MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string,
    490   ExceptionInfo *exception)
    491 {
    492   KernelInfo
    493     *kernel,
    494     *new_kernel;
    495 
    496   char
    497     *kernel_cache,
    498     token[MagickPathExtent];
    499 
    500   const char
    501     *p;
    502 
    503   if (kernel_string == (const char *) NULL)
    504     return(ParseKernelArray(kernel_string));
    505   p=kernel_string;
    506   kernel_cache=(char *) NULL;
    507   if (*kernel_string == '@')
    508     {
    509       kernel_cache=FileToString(kernel_string+1,~0UL,exception);
    510       if (kernel_cache == (char *) NULL)
    511         return((KernelInfo *) NULL);
    512       p=(const char *) kernel_cache;
    513     }
    514   kernel=NULL;
    515   while (GetNextToken(p,(const char **) NULL,MagickPathExtent,token), *token != '\0')
    516   {
    517     /* ignore extra or multiple ';' kernel separators */
    518     if (*token != ';')
    519       {
    520         /* tokens starting with alpha is a Named kernel */
    521         if (isalpha((int) ((unsigned char) *token)) != 0)
    522           new_kernel=ParseKernelName(p,exception);
    523         else /* otherwise a user defined kernel array */
    524           new_kernel=ParseKernelArray(p);
    525 
    526         /* Error handling -- this is not proper error handling! */
    527         if (new_kernel == (KernelInfo *) NULL)
    528           {
    529             if (kernel != (KernelInfo *) NULL)
    530               kernel=DestroyKernelInfo(kernel);
    531             return((KernelInfo *) NULL);
    532           }
    533 
    534         /* initialise or append the kernel list */
    535         if (kernel == (KernelInfo *) NULL)
    536           kernel=new_kernel;
    537         else
    538           LastKernelInfo(kernel)->next=new_kernel;
    539       }
    540 
    541     /* look for the next kernel in list */
    542     p=strchr(p,';');
    543     if (p == (char *) NULL)
    544       break;
    545     p++;
    546   }
    547   if (kernel_cache != (char *) NULL)
    548     kernel_cache=DestroyString(kernel_cache);
    549   return(kernel);
    550 }
    551 
    552 /*
    554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    555 %                                                                             %
    556 %                                                                             %
    557 %                                                                             %
    558 %     A c q u i r e K e r n e l B u i l t I n                                 %
    559 %                                                                             %
    560 %                                                                             %
    561 %                                                                             %
    562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    563 %
    564 %  AcquireKernelBuiltIn() returned one of the 'named' built-in types of
    565 %  kernels used for special purposes such as gaussian blurring, skeleton
    566 %  pruning, and edge distance determination.
    567 %
    568 %  They take a KernelType, and a set of geometry style arguments, which were
    569 %  typically decoded from a user supplied string, or from a more complex
    570 %  Morphology Method that was requested.
    571 %
    572 %  The format of the AcquireKernalBuiltIn method is:
    573 %
    574 %      KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
    575 %           const GeometryInfo args)
    576 %
    577 %  A description of each parameter follows:
    578 %
    579 %    o type: the pre-defined type of kernel wanted
    580 %
    581 %    o args: arguments defining or modifying the kernel
    582 %
    583 %  Convolution Kernels
    584 %
    585 %    Unity
    586 %       The a No-Op or Scaling single element kernel.
    587 %
    588 %    Gaussian:{radius},{sigma}
    589 %       Generate a two-dimensional gaussian kernel, as used by -gaussian.
    590 %       The sigma for the curve is required.  The resulting kernel is
    591 %       normalized,
    592 %
    593 %       If 'sigma' is zero, you get a single pixel on a field of zeros.
    594 %
    595 %       NOTE: that the 'radius' is optional, but if provided can limit (clip)
    596 %       the final size of the resulting kernel to a square 2*radius+1 in size.
    597 %       The radius should be at least 2 times that of the sigma value, or
    598 %       sever clipping and aliasing may result.  If not given or set to 0 the
    599 %       radius will be determined so as to produce the best minimal error
    600 %       result, which is usally much larger than is normally needed.
    601 %
    602 %    LoG:{radius},{sigma}
    603 %        "Laplacian of a Gaussian" or "Mexician Hat" Kernel.
    604 %        The supposed ideal edge detection, zero-summing kernel.
    605 %
    606 %        An alturnative to this kernel is to use a "DoG" with a sigma ratio of
    607 %        approx 1.6 (according to wikipedia).
    608 %
    609 %    DoG:{radius},{sigma1},{sigma2}
    610 %        "Difference of Gaussians" Kernel.
    611 %        As "Gaussian" but with a gaussian produced by 'sigma2' subtracted
    612 %        from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1.
    613 %        The result is a zero-summing kernel.
    614 %
    615 %    Blur:{radius},{sigma}[,{angle}]
    616 %       Generates a 1 dimensional or linear gaussian blur, at the angle given
    617 %       (current restricted to orthogonal angles).  If a 'radius' is given the
    618 %       kernel is clipped to a width of 2*radius+1.  Kernel can be rotated
    619 %       by a 90 degree angle.
    620 %
    621 %       If 'sigma' is zero, you get a single pixel on a field of zeros.
    622 %
    623 %       Note that two convolutions with two "Blur" kernels perpendicular to
    624 %       each other, is equivalent to a far larger "Gaussian" kernel with the
    625 %       same sigma value, However it is much faster to apply. This is how the
    626 %       "-blur" operator actually works.
    627 %
    628 %    Comet:{width},{sigma},{angle}
    629 %       Blur in one direction only, much like how a bright object leaves
    630 %       a comet like trail.  The Kernel is actually half a gaussian curve,
    631 %       Adding two such blurs in opposite directions produces a Blur Kernel.
    632 %       Angle can be rotated in multiples of 90 degrees.
    633 %
    634 %       Note that the first argument is the width of the kernel and not the
    635 %       radius of the kernel.
    636 %
    637 %    Binomial:[{radius}]
    638 %       Generate a discrete kernel using a 2 dimentional Pascel's Triangle
    639 %       of values. Used for special forma of image filters.
    640 %
    641 %    # Still to be implemented...
    642 %    #
    643 %    # Filter2D
    644 %    # Filter1D
    645 %    #    Set kernel values using a resize filter, and given scale (sigma)
    646 %    #    Cylindrical or Linear.   Is this possible with an image?
    647 %    #
    648 %
    649 %  Named Constant Convolution Kernels
    650 %
    651 %  All these are unscaled, zero-summing kernels by default. As such for
    652 %  non-HDRI version of ImageMagick some form of normalization, user scaling,
    653 %  and biasing the results is recommended, to prevent the resulting image
    654 %  being 'clipped'.
    655 %
    656 %  The 3x3 kernels (most of these) can be circularly rotated in multiples of
    657 %  45 degrees to generate the 8 angled varients of each of the kernels.
    658 %
    659 %    Laplacian:{type}
    660 %      Discrete Lapacian Kernels, (without normalization)
    661 %        Type 0 :  3x3 with center:8 surounded by -1  (8 neighbourhood)
    662 %        Type 1 :  3x3 with center:4 edge:-1 corner:0 (4 neighbourhood)
    663 %        Type 2 :  3x3 with center:4 edge:1 corner:-2
    664 %        Type 3 :  3x3 with center:4 edge:-2 corner:1
    665 %        Type 5 :  5x5 laplacian
    666 %        Type 7 :  7x7 laplacian
    667 %        Type 15 : 5x5 LoG (sigma approx 1.4)
    668 %        Type 19 : 9x9 LoG (sigma approx 1.4)
    669 %
    670 %    Sobel:{angle}
    671 %      Sobel 'Edge' convolution kernel (3x3)
    672 %          | -1, 0, 1 |
    673 %          | -2, 0,-2 |
    674 %          | -1, 0, 1 |
    675 %
    676 %    Roberts:{angle}
    677 %      Roberts convolution kernel (3x3)
    678 %          |  0, 0, 0 |
    679 %          | -1, 1, 0 |
    680 %          |  0, 0, 0 |
    681 %
    682 %    Prewitt:{angle}
    683 %      Prewitt Edge convolution kernel (3x3)
    684 %          | -1, 0, 1 |
    685 %          | -1, 0, 1 |
    686 %          | -1, 0, 1 |
    687 %
    688 %    Compass:{angle}
    689 %      Prewitt's "Compass" convolution kernel (3x3)
    690 %          | -1, 1, 1 |
    691 %          | -1,-2, 1 |
    692 %          | -1, 1, 1 |
    693 %
    694 %    Kirsch:{angle}
    695 %      Kirsch's "Compass" convolution kernel (3x3)
    696 %          | -3,-3, 5 |
    697 %          | -3, 0, 5 |
    698 %          | -3,-3, 5 |
    699 %
    700 %    FreiChen:{angle}
    701 %      Frei-Chen Edge Detector is based on a kernel that is similar to
    702 %      the Sobel Kernel, but is designed to be isotropic. That is it takes
    703 %      into account the distance of the diagonal in the kernel.
    704 %
    705 %          |   1,     0,   -1     |
    706 %          | sqrt(2), 0, -sqrt(2) |
    707 %          |   1,     0,   -1     |
    708 %
    709 %    FreiChen:{type},{angle}
    710 %
    711 %      Frei-Chen Pre-weighted kernels...
    712 %
    713 %        Type 0:  default un-nomalized version shown above.
    714 %
    715 %        Type 1: Orthogonal Kernel (same as type 11 below)
    716 %          |   1,     0,   -1     |
    717 %          | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2)
    718 %          |   1,     0,   -1     |
    719 %
    720 %        Type 2: Diagonal form of Kernel...
    721 %          |   1,     sqrt(2),    0     |
    722 %          | sqrt(2),   0,     -sqrt(2) | / 2*sqrt(2)
    723 %          |   0,    -sqrt(2)    -1     |
    724 %
    725 %      However this kernel is als at the heart of the FreiChen Edge Detection
    726 %      Process which uses a set of 9 specially weighted kernel.  These 9
    727 %      kernels not be normalized, but directly applied to the image. The
    728 %      results is then added together, to produce the intensity of an edge in
    729 %      a specific direction.  The square root of the pixel value can then be
    730 %      taken as the cosine of the edge, and at least 2 such runs at 90 degrees
    731 %      from each other, both the direction and the strength of the edge can be
    732 %      determined.
    733 %
    734 %        Type 10: All 9 of the following pre-weighted kernels...
    735 %
    736 %        Type 11: |   1,     0,   -1     |
    737 %                 | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2)
    738 %                 |   1,     0,   -1     |
    739 %
    740 %        Type 12: | 1, sqrt(2), 1 |
    741 %                 | 0,   0,     0 | / 2*sqrt(2)
    742 %                 | 1, sqrt(2), 1 |
    743 %
    744 %        Type 13: | sqrt(2), -1,    0     |
    745 %                 |  -1,      0,    1     | / 2*sqrt(2)
    746 %                 |   0,      1, -sqrt(2) |
    747 %
    748 %        Type 14: |    0,     1, -sqrt(2) |
    749 %                 |   -1,     0,     1    | / 2*sqrt(2)
    750 %                 | sqrt(2), -1,     0    |
    751 %
    752 %        Type 15: | 0, -1, 0 |
    753 %                 | 1,  0, 1 | / 2
    754 %                 | 0, -1, 0 |
    755 %
    756 %        Type 16: |  1, 0, -1 |
    757 %                 |  0, 0,  0 | / 2
    758 %                 | -1, 0,  1 |
    759 %
    760 %        Type 17: |  1, -2,  1 |
    761 %                 | -2,  4, -2 | / 6
    762 %                 | -1, -2,  1 |
    763 %
    764 %        Type 18: | -2, 1, -2 |
    765 %                 |  1, 4,  1 | / 6
    766 %                 | -2, 1, -2 |
    767 %
    768 %        Type 19: | 1, 1, 1 |
    769 %                 | 1, 1, 1 | / 3
    770 %                 | 1, 1, 1 |
    771 %
    772 %      The first 4 are for edge detection, the next 4 are for line detection
    773 %      and the last is to add a average component to the results.
    774 %
    775 %      Using a special type of '-1' will return all 9 pre-weighted kernels
    776 %      as a multi-kernel list, so that you can use them directly (without
    777 %      normalization) with the special "-set option:morphology:compose Plus"
    778 %      setting to apply the full FreiChen Edge Detection Technique.
    779 %
    780 %      If 'type' is large it will be taken to be an actual rotation angle for
    781 %      the default FreiChen (type 0) kernel.  As such  FreiChen:45  will look
    782 %      like a  Sobel:45  but with 'sqrt(2)' instead of '2' values.
    783 %
    784 %      WARNING: The above was layed out as per
    785 %          http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf
    786 %      But rotated 90 degrees so direction is from left rather than the top.
    787 %      I have yet to find any secondary confirmation of the above. The only
    788 %      other source found was actual source code at
    789 %          http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf
    790 %      Neigher paper defineds the kernels in a way that looks locical or
    791 %      correct when taken as a whole.
    792 %
    793 %  Boolean Kernels
    794 %
    795 %    Diamond:[{radius}[,{scale}]]
    796 %       Generate a diamond shaped kernel with given radius to the points.
    797 %       Kernel size will again be radius*2+1 square and defaults to radius 1,
    798 %       generating a 3x3 kernel that is slightly larger than a square.
    799 %
    800 %    Square:[{radius}[,{scale}]]
    801 %       Generate a square shaped kernel of size radius*2+1, and defaulting
    802 %       to a 3x3 (radius 1).
    803 %
    804 %    Octagon:[{radius}[,{scale}]]
    805 %       Generate octagonal shaped kernel of given radius and constant scale.
    806 %       Default radius is 3 producing a 7x7 kernel. A radius of 1 will result
    807 %       in "Diamond" kernel.
    808 %
    809 %    Disk:[{radius}[,{scale}]]
    810 %       Generate a binary disk, thresholded at the radius given, the radius
    811 %       may be a float-point value. Final Kernel size is floor(radius)*2+1
    812 %       square. A radius of 5.3 is the default.
    813 %
    814 %       NOTE: That a low radii Disk kernels produce the same results as
    815 %       many of the previously defined kernels, but differ greatly at larger
    816 %       radii.  Here is a table of equivalences...
    817 %          "Disk:1"    => "Diamond", "Octagon:1", or "Cross:1"
    818 %          "Disk:1.5"  => "Square"
    819 %          "Disk:2"    => "Diamond:2"
    820 %          "Disk:2.5"  => "Octagon"
    821 %          "Disk:2.9"  => "Square:2"
    822 %          "Disk:3.5"  => "Octagon:3"
    823 %          "Disk:4.5"  => "Octagon:4"
    824 %          "Disk:5.4"  => "Octagon:5"
    825 %          "Disk:6.4"  => "Octagon:6"
    826 %       All other Disk shapes are unique to this kernel, but because a "Disk"
    827 %       is more circular when using a larger radius, using a larger radius is
    828 %       preferred over iterating the morphological operation.
    829 %
    830 %    Rectangle:{geometry}
    831 %       Simply generate a rectangle of 1's with the size given. You can also
    832 %       specify the location of the 'control point', otherwise the closest
    833 %       pixel to the center of the rectangle is selected.
    834 %
    835 %       Properly centered and odd sized rectangles work the best.
    836 %
    837 %  Symbol Dilation Kernels
    838 %
    839 %    These kernel is not a good general morphological kernel, but is used
    840 %    more for highlighting and marking any single pixels in an image using,
    841 %    a "Dilate" method as appropriate.
    842 %
    843 %    For the same reasons iterating these kernels does not produce the
    844 %    same result as using a larger radius for the symbol.
    845 %
    846 %    Plus:[{radius}[,{scale}]]
    847 %    Cross:[{radius}[,{scale}]]
    848 %       Generate a kernel in the shape of a 'plus' or a 'cross' with
    849 %       a each arm the length of the given radius (default 2).
    850 %
    851 %       NOTE: "plus:1" is equivalent to a "Diamond" kernel.
    852 %
    853 %    Ring:{radius1},{radius2}[,{scale}]
    854 %       A ring of the values given that falls between the two radii.
    855 %       Defaults to a ring of approximataly 3 radius in a 7x7 kernel.
    856 %       This is the 'edge' pixels of the default "Disk" kernel,
    857 %       More specifically, "Ring" -> "Ring:2.5,3.5,1.0"
    858 %
    859 %  Hit and Miss Kernels
    860 %
    861 %    Peak:radius1,radius2
    862 %       Find any peak larger than the pixels the fall between the two radii.
    863 %       The default ring of pixels is as per "Ring".
    864 %    Edges
    865 %       Find flat orthogonal edges of a binary shape
    866 %    Corners
    867 %       Find 90 degree corners of a binary shape
    868 %    Diagonals:type
    869 %       A special kernel to thin the 'outside' of diagonals
    870 %    LineEnds:type
    871 %       Find end points of lines (for pruning a skeletion)
    872 %       Two types of lines ends (default to both) can be searched for
    873 %         Type 0: All line ends
    874 %         Type 1: single kernel for 4-conneected line ends
    875 %         Type 2: single kernel for simple line ends
    876 %    LineJunctions
    877 %       Find three line junctions (within a skeletion)
    878 %         Type 0: all line junctions
    879 %         Type 1: Y Junction kernel
    880 %         Type 2: Diagonal T Junction kernel
    881 %         Type 3: Orthogonal T Junction kernel
    882 %         Type 4: Diagonal X Junction kernel
    883 %         Type 5: Orthogonal + Junction kernel
    884 %    Ridges:type
    885 %       Find single pixel ridges or thin lines
    886 %         Type 1: Fine single pixel thick lines and ridges
    887 %         Type 2: Find two pixel thick lines and ridges
    888 %    ConvexHull
    889 %       Octagonal Thickening Kernel, to generate convex hulls of 45 degrees
    890 %    Skeleton:type
    891 %       Traditional skeleton generating kernels.
    892 %         Type 1: Tradional Skeleton kernel (4 connected skeleton)
    893 %         Type 2: HIPR2 Skeleton kernel (8 connected skeleton)
    894 %         Type 3: Thinning skeleton based on a ressearch paper by
    895 %                 Dan S. Bloomberg (Default Type)
    896 %    ThinSE:type
    897 %       A huge variety of Thinning Kernels designed to preserve conectivity.
    898 %       many other kernel sets use these kernels as source definitions.
    899 %       Type numbers are 41-49, 81-89, 481, and 482 which are based on
    900 %       the super and sub notations used in the source research paper.
    901 %
    902 %  Distance Measuring Kernels
    903 %
    904 %    Different types of distance measuring methods, which are used with the
    905 %    a 'Distance' morphology method for generating a gradient based on
    906 %    distance from an edge of a binary shape, though there is a technique
    907 %    for handling a anti-aliased shape.
    908 %
    909 %    See the 'Distance' Morphological Method, for information of how it is
    910 %    applied.
    911 %
    912 %    Chebyshev:[{radius}][x{scale}[%!]]
    913 %       Chebyshev Distance (also known as Tchebychev or Chessboard distance)
    914 %       is a value of one to any neighbour, orthogonal or diagonal. One why
    915 %       of thinking of it is the number of squares a 'King' or 'Queen' in
    916 %       chess needs to traverse reach any other position on a chess board.
    917 %       It results in a 'square' like distance function, but one where
    918 %       diagonals are given a value that is closer than expected.
    919 %
    920 %    Manhattan:[{radius}][x{scale}[%!]]
    921 %       Manhattan Distance (also known as Rectilinear, City Block, or the Taxi
    922 %       Cab distance metric), it is the distance needed when you can only
    923 %       travel in horizontal or vertical directions only.  It is the
    924 %       distance a 'Rook' in chess would have to travel, and results in a
    925 %       diamond like distances, where diagonals are further than expected.
    926 %
    927 %    Octagonal:[{radius}][x{scale}[%!]]
    928 %       An interleving of Manhatten and Chebyshev metrics producing an
    929 %       increasing octagonally shaped distance.  Distances matches those of
    930 %       the "Octagon" shaped kernel of the same radius.  The minimum radius
    931 %       and default is 2, producing a 5x5 kernel.
    932 %
    933 %    Euclidean:[{radius}][x{scale}[%!]]
    934 %       Euclidean distance is the 'direct' or 'as the crow flys' distance.
    935 %       However by default the kernel size only has a radius of 1, which
    936 %       limits the distance to 'Knight' like moves, with only orthogonal and
    937 %       diagonal measurements being correct.  As such for the default kernel
    938 %       you will get octagonal like distance function.
    939 %
    940 %       However using a larger radius such as "Euclidean:4" you will get a
    941 %       much smoother distance gradient from the edge of the shape. Especially
    942 %       if the image is pre-processed to include any anti-aliasing pixels.
    943 %       Of course a larger kernel is slower to use, and not always needed.
    944 %
    945 %    The first three Distance Measuring Kernels will only generate distances
    946 %    of exact multiples of {scale} in binary images. As such you can use a
    947 %    scale of 1 without loosing any information.  However you also need some
    948 %    scaling when handling non-binary anti-aliased shapes.
    949 %
    950 %    The "Euclidean" Distance Kernel however does generate a non-integer
    951 %    fractional results, and as such scaling is vital even for binary shapes.
    952 %
    953 */
    954 
    955 MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
    956   const GeometryInfo *args,ExceptionInfo *exception)
    957 {
    958   KernelInfo
    959     *kernel;
    960 
    961   register ssize_t
    962     i;
    963 
    964   register ssize_t
    965     u,
    966     v;
    967 
    968   double
    969     nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
    970 
    971   /* Generate a new empty kernel if needed */
    972   kernel=(KernelInfo *) NULL;
    973   switch(type) {
    974     case UndefinedKernel:    /* These should not call this function */
    975     case UserDefinedKernel:
    976       assert("Should not call this function" != (char *) NULL);
    977       break;
    978     case LaplacianKernel:   /* Named Descrete Convolution Kernels */
    979     case SobelKernel:       /* these are defined using other kernels */
    980     case RobertsKernel:
    981     case PrewittKernel:
    982     case CompassKernel:
    983     case KirschKernel:
    984     case FreiChenKernel:
    985     case EdgesKernel:       /* Hit and Miss kernels */
    986     case CornersKernel:
    987     case DiagonalsKernel:
    988     case LineEndsKernel:
    989     case LineJunctionsKernel:
    990     case RidgesKernel:
    991     case ConvexHullKernel:
    992     case SkeletonKernel:
    993     case ThinSEKernel:
    994       break;               /* A pre-generated kernel is not needed */
    995 #if 0
    996     /* set to 1 to do a compile-time check that we haven't missed anything */
    997     case UnityKernel:
    998     case GaussianKernel:
    999     case DoGKernel:
   1000     case LoGKernel:
   1001     case BlurKernel:
   1002     case CometKernel:
   1003     case BinomialKernel:
   1004     case DiamondKernel:
   1005     case SquareKernel:
   1006     case RectangleKernel:
   1007     case OctagonKernel:
   1008     case DiskKernel:
   1009     case PlusKernel:
   1010     case CrossKernel:
   1011     case RingKernel:
   1012     case PeaksKernel:
   1013     case ChebyshevKernel:
   1014     case ManhattanKernel:
   1015     case OctangonalKernel:
   1016     case EuclideanKernel:
   1017 #else
   1018     default:
   1019 #endif
   1020       /* Generate the base Kernel Structure */
   1021       kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
   1022       if (kernel == (KernelInfo *) NULL)
   1023         return(kernel);
   1024       (void) memset(kernel,0,sizeof(*kernel));
   1025       kernel->minimum = kernel->maximum = kernel->angle = 0.0;
   1026       kernel->negative_range = kernel->positive_range = 0.0;
   1027       kernel->type = type;
   1028       kernel->next = (KernelInfo *) NULL;
   1029       kernel->signature=MagickCoreSignature;
   1030       break;
   1031   }
   1032 
   1033   switch(type) {
   1034     /*
   1035       Convolution Kernels
   1036     */
   1037     case UnityKernel:
   1038       {
   1039         kernel->height = kernel->width = (size_t) 1;
   1040         kernel->x = kernel->y = (ssize_t) 0;
   1041         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1042           AcquireAlignedMemory(1,sizeof(*kernel->values)));
   1043         if (kernel->values == (MagickRealType *) NULL)
   1044           return(DestroyKernelInfo(kernel));
   1045         kernel->maximum = kernel->values[0] = args->rho;
   1046         break;
   1047       }
   1048       break;
   1049     case GaussianKernel:
   1050     case DoGKernel:
   1051     case LoGKernel:
   1052       { double
   1053           sigma = fabs(args->sigma),
   1054           sigma2 = fabs(args->xi),
   1055           A, B, R;
   1056 
   1057         if ( args->rho >= 1.0 )
   1058           kernel->width = (size_t)args->rho*2+1;
   1059         else if ( (type != DoGKernel) || (sigma >= sigma2) )
   1060           kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
   1061         else
   1062           kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
   1063         kernel->height = kernel->width;
   1064         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1065         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1066           AcquireAlignedMemory(kernel->width,kernel->height*
   1067           sizeof(*kernel->values)));
   1068         if (kernel->values == (MagickRealType *) NULL)
   1069           return(DestroyKernelInfo(kernel));
   1070 
   1071         /* WARNING: The following generates a 'sampled gaussian' kernel.
   1072          * What we really want is a 'discrete gaussian' kernel.
   1073          *
   1074          * How to do this is I don't know, but appears to be basied on the
   1075          * Error Function 'erf()' (intergral of a gaussian)
   1076          */
   1077 
   1078         if ( type == GaussianKernel || type == DoGKernel )
   1079           { /* Calculate a Gaussian,  OR positive half of a DoG */
   1080             if ( sigma > MagickEpsilon )
   1081               { A = 1.0/(2.0*sigma*sigma);  /* simplify loop expressions */
   1082                 B = (double) (1.0/(Magick2PI*sigma*sigma));
   1083                 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1084                   for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1085                       kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B;
   1086               }
   1087             else /* limiting case - a unity (normalized Dirac) kernel */
   1088               { (void) memset(kernel->values,0, (size_t)
   1089                   kernel->width*kernel->height*sizeof(*kernel->values));
   1090                 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1091               }
   1092           }
   1093 
   1094         if ( type == DoGKernel )
   1095           { /* Subtract a Negative Gaussian for "Difference of Gaussian" */
   1096             if ( sigma2 > MagickEpsilon )
   1097               { sigma = sigma2;                /* simplify loop expressions */
   1098                 A = 1.0/(2.0*sigma*sigma);
   1099                 B = (double) (1.0/(Magick2PI*sigma*sigma));
   1100                 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1101                   for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1102                     kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B;
   1103               }
   1104             else /* limiting case - a unity (normalized Dirac) kernel */
   1105               kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0;
   1106           }
   1107 
   1108         if ( type == LoGKernel )
   1109           { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */
   1110             if ( sigma > MagickEpsilon )
   1111               { A = 1.0/(2.0*sigma*sigma);  /* simplify loop expressions */
   1112                 B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
   1113                 for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1114                   for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1115                     { R = ((double)(u*u+v*v))*A;
   1116                       kernel->values[i] = (1-R)*exp(-R)*B;
   1117                     }
   1118               }
   1119             else /* special case - generate a unity kernel */
   1120               { (void) memset(kernel->values,0, (size_t)
   1121                   kernel->width*kernel->height*sizeof(*kernel->values));
   1122                 kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1123               }
   1124           }
   1125 
   1126         /* Note the above kernels may have been 'clipped' by a user defined
   1127         ** radius, producing a smaller (darker) kernel.  Also for very small
   1128         ** sigma's (> 0.1) the central value becomes larger than one, and thus
   1129         ** producing a very bright kernel.
   1130         **
   1131         ** Normalization will still be needed.
   1132         */
   1133 
   1134         /* Normalize the 2D Gaussian Kernel
   1135         **
   1136         ** NB: a CorrelateNormalize performs a normal Normalize if
   1137         ** there are no negative values.
   1138         */
   1139         CalcKernelMetaData(kernel);  /* the other kernel meta-data */
   1140         ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
   1141 
   1142         break;
   1143       }
   1144     case BlurKernel:
   1145       { double
   1146           sigma = fabs(args->sigma),
   1147           alpha, beta;
   1148 
   1149         if ( args->rho >= 1.0 )
   1150           kernel->width = (size_t)args->rho*2+1;
   1151         else
   1152           kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
   1153         kernel->height = 1;
   1154         kernel->x = (ssize_t) (kernel->width-1)/2;
   1155         kernel->y = 0;
   1156         kernel->negative_range = kernel->positive_range = 0.0;
   1157         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1158           AcquireAlignedMemory(kernel->width,kernel->height*
   1159           sizeof(*kernel->values)));
   1160         if (kernel->values == (MagickRealType *) NULL)
   1161           return(DestroyKernelInfo(kernel));
   1162 
   1163 #if 1
   1164 #define KernelRank 3
   1165         /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix).
   1166         ** It generates a gaussian 3 times the width, and compresses it into
   1167         ** the expected range.  This produces a closer normalization of the
   1168         ** resulting kernel, especially for very low sigma values.
   1169         ** As such while wierd it is prefered.
   1170         **
   1171         ** I am told this method originally came from Photoshop.
   1172         **
   1173         ** A properly normalized curve is generated (apart from edge clipping)
   1174         ** even though we later normalize the result (for edge clipping)
   1175         ** to allow the correct generation of a "Difference of Blurs".
   1176         */
   1177 
   1178         /* initialize */
   1179         v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */
   1180         (void) memset(kernel->values,0, (size_t)
   1181           kernel->width*kernel->height*sizeof(*kernel->values));
   1182         /* Calculate a Positive 1D Gaussian */
   1183         if ( sigma > MagickEpsilon )
   1184           { sigma *= KernelRank;               /* simplify loop expressions */
   1185             alpha = 1.0/(2.0*sigma*sigma);
   1186             beta= (double) (1.0/(MagickSQ2PI*sigma ));
   1187             for ( u=-v; u <= v; u++) {
   1188               kernel->values[(u+v)/KernelRank] +=
   1189                               exp(-((double)(u*u))*alpha)*beta;
   1190             }
   1191           }
   1192         else /* special case - generate a unity kernel */
   1193           kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1194 #else
   1195         /* Direct calculation without curve averaging
   1196            This is equivelent to a KernelRank of 1 */
   1197 
   1198         /* Calculate a Positive Gaussian */
   1199         if ( sigma > MagickEpsilon )
   1200           { alpha = 1.0/(2.0*sigma*sigma);    /* simplify loop expressions */
   1201             beta = 1.0/(MagickSQ2PI*sigma);
   1202             for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1203               kernel->values[i] = exp(-((double)(u*u))*alpha)*beta;
   1204           }
   1205         else /* special case - generate a unity kernel */
   1206           { (void) memset(kernel->values,0, (size_t)
   1207               kernel->width*kernel->height*sizeof(*kernel->values));
   1208             kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1209           }
   1210 #endif
   1211         /* Note the above kernel may have been 'clipped' by a user defined
   1212         ** radius, producing a smaller (darker) kernel.  Also for very small
   1213         ** sigma's (> 0.1) the central value becomes larger than one, as a
   1214         ** result of not generating a actual 'discrete' kernel, and thus
   1215         ** producing a very bright 'impulse'.
   1216         **
   1217         ** Becuase of these two factors Normalization is required!
   1218         */
   1219 
   1220         /* Normalize the 1D Gaussian Kernel
   1221         **
   1222         ** NB: a CorrelateNormalize performs a normal Normalize if
   1223         ** there are no negative values.
   1224         */
   1225         CalcKernelMetaData(kernel);  /* the other kernel meta-data */
   1226         ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
   1227 
   1228         /* rotate the 1D kernel by given angle */
   1229         RotateKernelInfo(kernel, args->xi );
   1230         break;
   1231       }
   1232     case CometKernel:
   1233       { double
   1234           sigma = fabs(args->sigma),
   1235           A;
   1236 
   1237         if ( args->rho < 1.0 )
   1238           kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
   1239         else
   1240           kernel->width = (size_t)args->rho;
   1241         kernel->x = kernel->y = 0;
   1242         kernel->height = 1;
   1243         kernel->negative_range = kernel->positive_range = 0.0;
   1244         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1245           AcquireAlignedMemory(kernel->width,kernel->height*
   1246           sizeof(*kernel->values)));
   1247         if (kernel->values == (MagickRealType *) NULL)
   1248           return(DestroyKernelInfo(kernel));
   1249 
   1250         /* A comet blur is half a 1D gaussian curve, so that the object is
   1251         ** blurred in one direction only.  This may not be quite the right
   1252         ** curve to use so may change in the future. The function must be
   1253         ** normalised after generation, which also resolves any clipping.
   1254         **
   1255         ** As we are normalizing and not subtracting gaussians,
   1256         ** there is no need for a divisor in the gaussian formula
   1257         **
   1258         ** It is less comples
   1259         */
   1260         if ( sigma > MagickEpsilon )
   1261           {
   1262 #if 1
   1263 #define KernelRank 3
   1264             v = (ssize_t) kernel->width*KernelRank; /* start/end points */
   1265             (void) memset(kernel->values,0, (size_t)
   1266               kernel->width*sizeof(*kernel->values));
   1267             sigma *= KernelRank;            /* simplify the loop expression */
   1268             A = 1.0/(2.0*sigma*sigma);
   1269             /* B = 1.0/(MagickSQ2PI*sigma); */
   1270             for ( u=0; u < v; u++) {
   1271               kernel->values[u/KernelRank] +=
   1272                   exp(-((double)(u*u))*A);
   1273               /*  exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */
   1274             }
   1275             for (i=0; i < (ssize_t) kernel->width; i++)
   1276               kernel->positive_range += kernel->values[i];
   1277 #else
   1278             A = 1.0/(2.0*sigma*sigma);     /* simplify the loop expression */
   1279             /* B = 1.0/(MagickSQ2PI*sigma); */
   1280             for ( i=0; i < (ssize_t) kernel->width; i++)
   1281               kernel->positive_range +=
   1282                 kernel->values[i] = exp(-((double)(i*i))*A);
   1283                 /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */
   1284 #endif
   1285           }
   1286         else /* special case - generate a unity kernel */
   1287           { (void) memset(kernel->values,0, (size_t)
   1288               kernel->width*kernel->height*sizeof(*kernel->values));
   1289             kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1290             kernel->positive_range = 1.0;
   1291           }
   1292 
   1293         kernel->minimum = 0.0;
   1294         kernel->maximum = kernel->values[0];
   1295         kernel->negative_range = 0.0;
   1296 
   1297         ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */
   1298         RotateKernelInfo(kernel, args->xi); /* Rotate by angle */
   1299         break;
   1300       }
   1301     case BinomialKernel:
   1302       {
   1303         size_t
   1304           order_f;
   1305 
   1306         if (args->rho < 1.0)
   1307           kernel->width = kernel->height = 3;  /* default radius = 1 */
   1308         else
   1309           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   1310         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1311 
   1312         order_f = fact(kernel->width-1);
   1313 
   1314         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1315           AcquireAlignedMemory(kernel->width,kernel->height*
   1316           sizeof(*kernel->values)));
   1317         if (kernel->values == (MagickRealType *) NULL)
   1318           return(DestroyKernelInfo(kernel));
   1319 
   1320         /* set all kernel values within diamond area to scale given */
   1321         for ( i=0, v=0; v < (ssize_t)kernel->height; v++)
   1322           { size_t
   1323               alpha = order_f / ( fact((size_t) v) * fact(kernel->height-v-1) );
   1324             for ( u=0; u < (ssize_t)kernel->width; u++, i++)
   1325               kernel->positive_range += kernel->values[i] = (double)
   1326                 (alpha * order_f / ( fact((size_t) u) * fact(kernel->height-u-1) ));
   1327           }
   1328         kernel->minimum = 1.0;
   1329         kernel->maximum = kernel->values[kernel->x+kernel->y*kernel->width];
   1330         kernel->negative_range = 0.0;
   1331         break;
   1332       }
   1333 
   1334     /*
   1335       Convolution Kernels - Well Known Named Constant Kernels
   1336     */
   1337     case LaplacianKernel:
   1338       { switch ( (int) args->rho ) {
   1339           case 0:
   1340           default: /* laplacian square filter -- default */
   1341             kernel=ParseKernelArray("3: -1,-1,-1  -1,8,-1  -1,-1,-1");
   1342             break;
   1343           case 1:  /* laplacian diamond filter */
   1344             kernel=ParseKernelArray("3: 0,-1,0  -1,4,-1  0,-1,0");
   1345             break;
   1346           case 2:
   1347             kernel=ParseKernelArray("3: -2,1,-2  1,4,1  -2,1,-2");
   1348             break;
   1349           case 3:
   1350             kernel=ParseKernelArray("3: 1,-2,1  -2,4,-2  1,-2,1");
   1351             break;
   1352           case 5:   /* a 5x5 laplacian */
   1353             kernel=ParseKernelArray(
   1354               "5: -4,-1,0,-1,-4  -1,2,3,2,-1  0,3,4,3,0  -1,2,3,2,-1  -4,-1,0,-1,-4");
   1355             break;
   1356           case 7:   /* a 7x7 laplacian */
   1357             kernel=ParseKernelArray(
   1358               "7:-10,-5,-2,-1,-2,-5,-10 -5,0,3,4,3,0,-5 -2,3,6,7,6,3,-2 -1,4,7,8,7,4,-1 -2,3,6,7,6,3,-2 -5,0,3,4,3,0,-5 -10,-5,-2,-1,-2,-5,-10" );
   1359             break;
   1360           case 15:  /* a 5x5 LoG (sigma approx 1.4) */
   1361             kernel=ParseKernelArray(
   1362               "5: 0,0,-1,0,0  0,-1,-2,-1,0  -1,-2,16,-2,-1  0,-1,-2,-1,0  0,0,-1,0,0");
   1363             break;
   1364           case 19:  /* a 9x9 LoG (sigma approx 1.4) */
   1365             /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */
   1366             kernel=ParseKernelArray(
   1367               "9: 0,-1,-1,-2,-2,-2,-1,-1,0  -1,-2,-4,-5,-5,-5,-4,-2,-1  -1,-4,-5,-3,-0,-3,-5,-4,-1  -2,-5,-3,12,24,12,-3,-5,-2  -2,-5,-0,24,40,24,-0,-5,-2  -2,-5,-3,12,24,12,-3,-5,-2  -1,-4,-5,-3,-0,-3,-5,-4,-1  -1,-2,-4,-5,-5,-5,-4,-2,-1  0,-1,-1,-2,-2,-2,-1,-1,0");
   1368             break;
   1369         }
   1370         if (kernel == (KernelInfo *) NULL)
   1371           return(kernel);
   1372         kernel->type = type;
   1373         break;
   1374       }
   1375     case SobelKernel:
   1376       { /* Simple Sobel Kernel */
   1377         kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
   1378         if (kernel == (KernelInfo *) NULL)
   1379           return(kernel);
   1380         kernel->type = type;
   1381         RotateKernelInfo(kernel, args->rho);
   1382         break;
   1383       }
   1384     case RobertsKernel:
   1385       {
   1386         kernel=ParseKernelArray("3: 0,0,0  1,-1,0  0,0,0");
   1387         if (kernel == (KernelInfo *) NULL)
   1388           return(kernel);
   1389         kernel->type = type;
   1390         RotateKernelInfo(kernel, args->rho);
   1391         break;
   1392       }
   1393     case PrewittKernel:
   1394       {
   1395         kernel=ParseKernelArray("3: 1,0,-1  1,0,-1  1,0,-1");
   1396         if (kernel == (KernelInfo *) NULL)
   1397           return(kernel);
   1398         kernel->type = type;
   1399         RotateKernelInfo(kernel, args->rho);
   1400         break;
   1401       }
   1402     case CompassKernel:
   1403       {
   1404         kernel=ParseKernelArray("3: 1,1,-1  1,-2,-1  1,1,-1");
   1405         if (kernel == (KernelInfo *) NULL)
   1406           return(kernel);
   1407         kernel->type = type;
   1408         RotateKernelInfo(kernel, args->rho);
   1409         break;
   1410       }
   1411     case KirschKernel:
   1412       {
   1413         kernel=ParseKernelArray("3: 5,-3,-3  5,0,-3  5,-3,-3");
   1414         if (kernel == (KernelInfo *) NULL)
   1415           return(kernel);
   1416         kernel->type = type;
   1417         RotateKernelInfo(kernel, args->rho);
   1418         break;
   1419       }
   1420     case FreiChenKernel:
   1421       /* Direction is set to be left to right positive */
   1422       /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */
   1423       /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */
   1424       { switch ( (int) args->rho ) {
   1425           default:
   1426           case 0:
   1427             kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
   1428             if (kernel == (KernelInfo *) NULL)
   1429               return(kernel);
   1430             kernel->type = type;
   1431             kernel->values[3] = +(MagickRealType) MagickSQ2;
   1432             kernel->values[5] = -(MagickRealType) MagickSQ2;
   1433             CalcKernelMetaData(kernel);     /* recalculate meta-data */
   1434             break;
   1435           case 2:
   1436             kernel=ParseKernelArray("3: 1,2,0  2,0,-2  0,-2,-1");
   1437             if (kernel == (KernelInfo *) NULL)
   1438               return(kernel);
   1439             kernel->type = type;
   1440             kernel->values[1] = kernel->values[3]= +(MagickRealType) MagickSQ2;
   1441             kernel->values[5] = kernel->values[7]= -(MagickRealType) MagickSQ2;
   1442             CalcKernelMetaData(kernel);     /* recalculate meta-data */
   1443             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
   1444             break;
   1445           case 10:
   1446           {
   1447             kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19",exception);
   1448             if (kernel == (KernelInfo *) NULL)
   1449               return(kernel);
   1450             break;
   1451           }
   1452           case 1:
   1453           case 11:
   1454             kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
   1455             if (kernel == (KernelInfo *) NULL)
   1456               return(kernel);
   1457             kernel->type = type;
   1458             kernel->values[3] = +(MagickRealType) MagickSQ2;
   1459             kernel->values[5] = -(MagickRealType) MagickSQ2;
   1460             CalcKernelMetaData(kernel);     /* recalculate meta-data */
   1461             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
   1462             break;
   1463           case 12:
   1464             kernel=ParseKernelArray("3: 1,2,1  0,0,0  1,2,1");
   1465             if (kernel == (KernelInfo *) NULL)
   1466               return(kernel);
   1467             kernel->type = type;
   1468             kernel->values[1] = +(MagickRealType) MagickSQ2;
   1469             kernel->values[7] = +(MagickRealType) MagickSQ2;
   1470             CalcKernelMetaData(kernel);
   1471             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
   1472             break;
   1473           case 13:
   1474             kernel=ParseKernelArray("3: 2,-1,0  -1,0,1  0,1,-2");
   1475             if (kernel == (KernelInfo *) NULL)
   1476               return(kernel);
   1477             kernel->type = type;
   1478             kernel->values[0] = +(MagickRealType) MagickSQ2;
   1479             kernel->values[8] = -(MagickRealType) MagickSQ2;
   1480             CalcKernelMetaData(kernel);
   1481             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
   1482             break;
   1483           case 14:
   1484             kernel=ParseKernelArray("3: 0,1,-2  -1,0,1  2,-1,0");
   1485             if (kernel == (KernelInfo *) NULL)
   1486               return(kernel);
   1487             kernel->type = type;
   1488             kernel->values[2] = -(MagickRealType) MagickSQ2;
   1489             kernel->values[6] = +(MagickRealType) MagickSQ2;
   1490             CalcKernelMetaData(kernel);
   1491             ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
   1492             break;
   1493           case 15:
   1494             kernel=ParseKernelArray("3: 0,-1,0  1,0,1  0,-1,0");
   1495             if (kernel == (KernelInfo *) NULL)
   1496               return(kernel);
   1497             kernel->type = type;
   1498             ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
   1499             break;
   1500           case 16:
   1501             kernel=ParseKernelArray("3: 1,0,-1  0,0,0  -1,0,1");
   1502             if (kernel == (KernelInfo *) NULL)
   1503               return(kernel);
   1504             kernel->type = type;
   1505             ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
   1506             break;
   1507           case 17:
   1508             kernel=ParseKernelArray("3: 1,-2,1  -2,4,-2  -1,-2,1");
   1509             if (kernel == (KernelInfo *) NULL)
   1510               return(kernel);
   1511             kernel->type = type;
   1512             ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
   1513             break;
   1514           case 18:
   1515             kernel=ParseKernelArray("3: -2,1,-2  1,4,1  -2,1,-2");
   1516             if (kernel == (KernelInfo *) NULL)
   1517               return(kernel);
   1518             kernel->type = type;
   1519             ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
   1520             break;
   1521           case 19:
   1522             kernel=ParseKernelArray("3: 1,1,1  1,1,1  1,1,1");
   1523             if (kernel == (KernelInfo *) NULL)
   1524               return(kernel);
   1525             kernel->type = type;
   1526             ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
   1527             break;
   1528         }
   1529         if ( fabs(args->sigma) >= MagickEpsilon )
   1530           /* Rotate by correctly supplied 'angle' */
   1531           RotateKernelInfo(kernel, args->sigma);
   1532         else if ( args->rho > 30.0 || args->rho < -30.0 )
   1533           /* Rotate by out of bounds 'type' */
   1534           RotateKernelInfo(kernel, args->rho);
   1535         break;
   1536       }
   1537 
   1538     /*
   1539       Boolean or Shaped Kernels
   1540     */
   1541     case DiamondKernel:
   1542       {
   1543         if (args->rho < 1.0)
   1544           kernel->width = kernel->height = 3;  /* default radius = 1 */
   1545         else
   1546           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   1547         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1548 
   1549         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1550           AcquireAlignedMemory(kernel->width,kernel->height*
   1551           sizeof(*kernel->values)));
   1552         if (kernel->values == (MagickRealType *) NULL)
   1553           return(DestroyKernelInfo(kernel));
   1554 
   1555         /* set all kernel values within diamond area to scale given */
   1556         for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1557           for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1558             if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x)
   1559               kernel->positive_range += kernel->values[i] = args->sigma;
   1560             else
   1561               kernel->values[i] = nan;
   1562         kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
   1563         break;
   1564       }
   1565     case SquareKernel:
   1566     case RectangleKernel:
   1567       { double
   1568           scale;
   1569         if ( type == SquareKernel )
   1570           {
   1571             if (args->rho < 1.0)
   1572               kernel->width = kernel->height = 3;  /* default radius = 1 */
   1573             else
   1574               kernel->width = kernel->height = (size_t) (2*args->rho+1);
   1575             kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1576             scale = args->sigma;
   1577           }
   1578         else {
   1579             /* NOTE: user defaults set in "AcquireKernelInfo()" */
   1580             if ( args->rho < 1.0 || args->sigma < 1.0 )
   1581               return(DestroyKernelInfo(kernel));    /* invalid args given */
   1582             kernel->width = (size_t)args->rho;
   1583             kernel->height = (size_t)args->sigma;
   1584             if ( args->xi  < 0.0 || args->xi  > (double)kernel->width ||
   1585                  args->psi < 0.0 || args->psi > (double)kernel->height )
   1586               return(DestroyKernelInfo(kernel));    /* invalid args given */
   1587             kernel->x = (ssize_t) args->xi;
   1588             kernel->y = (ssize_t) args->psi;
   1589             scale = 1.0;
   1590           }
   1591         kernel->values=(MagickRealType *) MagickAssumeAligned(
   1592           AcquireAlignedMemory(kernel->width,kernel->height*
   1593           sizeof(*kernel->values)));
   1594         if (kernel->values == (MagickRealType *) NULL)
   1595           return(DestroyKernelInfo(kernel));
   1596 
   1597         /* set all kernel values to scale given */
   1598         u=(ssize_t) (kernel->width*kernel->height);
   1599         for ( i=0; i < u; i++)
   1600             kernel->values[i] = scale;
   1601         kernel->minimum = kernel->maximum = scale;   /* a flat shape */
   1602         kernel->positive_range = scale*u;
   1603         break;
   1604       }
   1605       case OctagonKernel:
   1606         {
   1607           if (args->rho < 1.0)
   1608             kernel->width = kernel->height = 5;  /* default radius = 2 */
   1609           else
   1610             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   1611           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1612 
   1613           kernel->values=(MagickRealType *) MagickAssumeAligned(
   1614             AcquireAlignedMemory(kernel->width,kernel->height*
   1615             sizeof(*kernel->values)));
   1616           if (kernel->values == (MagickRealType *) NULL)
   1617             return(DestroyKernelInfo(kernel));
   1618 
   1619           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1620             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1621               if ( (labs((long) u)+labs((long) v)) <=
   1622                         ((long)kernel->x + (long)(kernel->x/2)) )
   1623                 kernel->positive_range += kernel->values[i] = args->sigma;
   1624               else
   1625                 kernel->values[i] = nan;
   1626           kernel->minimum = kernel->maximum = args->sigma;  /* a flat shape */
   1627           break;
   1628         }
   1629       case DiskKernel:
   1630         {
   1631           ssize_t
   1632             limit = (ssize_t)(args->rho*args->rho);
   1633 
   1634           if (args->rho < 0.4)           /* default radius approx 4.3 */
   1635             kernel->width = kernel->height = 9L, limit = 18L;
   1636           else
   1637             kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1;
   1638           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1639 
   1640           kernel->values=(MagickRealType *) MagickAssumeAligned(
   1641             AcquireAlignedMemory(kernel->width,kernel->height*
   1642             sizeof(*kernel->values)));
   1643           if (kernel->values == (MagickRealType *) NULL)
   1644             return(DestroyKernelInfo(kernel));
   1645 
   1646           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1647             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1648               if ((u*u+v*v) <= limit)
   1649                 kernel->positive_range += kernel->values[i] = args->sigma;
   1650               else
   1651                 kernel->values[i] = nan;
   1652           kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
   1653           break;
   1654         }
   1655       case PlusKernel:
   1656         {
   1657           if (args->rho < 1.0)
   1658             kernel->width = kernel->height = 5;  /* default radius 2 */
   1659           else
   1660             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   1661           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1662 
   1663           kernel->values=(MagickRealType *) MagickAssumeAligned(
   1664             AcquireAlignedMemory(kernel->width,kernel->height*
   1665             sizeof(*kernel->values)));
   1666           if (kernel->values == (MagickRealType *) NULL)
   1667             return(DestroyKernelInfo(kernel));
   1668 
   1669           /* set all kernel values along axises to given scale */
   1670           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1671             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1672               kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
   1673           kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
   1674           kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
   1675           break;
   1676         }
   1677       case CrossKernel:
   1678         {
   1679           if (args->rho < 1.0)
   1680             kernel->width = kernel->height = 5;  /* default radius 2 */
   1681           else
   1682             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   1683           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1684 
   1685           kernel->values=(MagickRealType *) MagickAssumeAligned(
   1686             AcquireAlignedMemory(kernel->width,kernel->height*
   1687             sizeof(*kernel->values)));
   1688           if (kernel->values == (MagickRealType *) NULL)
   1689             return(DestroyKernelInfo(kernel));
   1690 
   1691           /* set all kernel values along axises to given scale */
   1692           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   1693             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1694               kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
   1695           kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
   1696           kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
   1697           break;
   1698         }
   1699       /*
   1700         HitAndMiss Kernels
   1701       */
   1702       case RingKernel:
   1703       case PeaksKernel:
   1704         {
   1705           ssize_t
   1706             limit1,
   1707             limit2,
   1708             scale;
   1709 
   1710           if (args->rho < args->sigma)
   1711             {
   1712               kernel->width = ((size_t)args->sigma)*2+1;
   1713               limit1 = (ssize_t)(args->rho*args->rho);
   1714               limit2 = (ssize_t)(args->sigma*args->sigma);
   1715             }
   1716           else
   1717             {
   1718               kernel->width = ((size_t)args->rho)*2+1;
   1719               limit1 = (ssize_t)(args->sigma*args->sigma);
   1720               limit2 = (ssize_t)(args->rho*args->rho);
   1721             }
   1722           if ( limit2 <= 0 )
   1723             kernel->width = 7L, limit1 = 7L, limit2 = 11L;
   1724 
   1725           kernel->height = kernel->width;
   1726           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   1727           kernel->values=(MagickRealType *) MagickAssumeAligned(
   1728             AcquireAlignedMemory(kernel->width,kernel->height*
   1729             sizeof(*kernel->values)));
   1730           if (kernel->values == (MagickRealType *) NULL)
   1731             return(DestroyKernelInfo(kernel));
   1732 
   1733           /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */
   1734           scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
   1735           for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
   1736             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   1737               { ssize_t radius=u*u+v*v;
   1738                 if (limit1 < radius && radius <= limit2)
   1739                   kernel->positive_range += kernel->values[i] = (double) scale;
   1740                 else
   1741                   kernel->values[i] = nan;
   1742               }
   1743           kernel->minimum = kernel->maximum = (double) scale;
   1744           if ( type == PeaksKernel ) {
   1745             /* set the central point in the middle */
   1746             kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
   1747             kernel->positive_range = 1.0;
   1748             kernel->maximum = 1.0;
   1749           }
   1750           break;
   1751         }
   1752       case EdgesKernel:
   1753         {
   1754           kernel=AcquireKernelInfo("ThinSE:482",exception);
   1755           if (kernel == (KernelInfo *) NULL)
   1756             return(kernel);
   1757           kernel->type = type;
   1758           ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */
   1759           break;
   1760         }
   1761       case CornersKernel:
   1762         {
   1763           kernel=AcquireKernelInfo("ThinSE:87",exception);
   1764           if (kernel == (KernelInfo *) NULL)
   1765             return(kernel);
   1766           kernel->type = type;
   1767           ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */
   1768           break;
   1769         }
   1770       case DiagonalsKernel:
   1771         {
   1772           switch ( (int) args->rho ) {
   1773             case 0:
   1774             default:
   1775               { KernelInfo
   1776                   *new_kernel;
   1777                 kernel=ParseKernelArray("3: 0,0,0  0,-,1  1,1,-");
   1778                 if (kernel == (KernelInfo *) NULL)
   1779                   return(kernel);
   1780                 kernel->type = type;
   1781                 new_kernel=ParseKernelArray("3: 0,0,1  0,-,1  0,1,-");
   1782                 if (new_kernel == (KernelInfo *) NULL)
   1783                   return(DestroyKernelInfo(kernel));
   1784                 new_kernel->type = type;
   1785                 LastKernelInfo(kernel)->next = new_kernel;
   1786                 ExpandMirrorKernelInfo(kernel);
   1787                 return(kernel);
   1788               }
   1789             case 1:
   1790               kernel=ParseKernelArray("3: 0,0,0  0,-,1  1,1,-");
   1791               break;
   1792             case 2:
   1793               kernel=ParseKernelArray("3: 0,0,1  0,-,1  0,1,-");
   1794               break;
   1795           }
   1796           if (kernel == (KernelInfo *) NULL)
   1797             return(kernel);
   1798           kernel->type = type;
   1799           RotateKernelInfo(kernel, args->sigma);
   1800           break;
   1801         }
   1802       case LineEndsKernel:
   1803         { /* Kernels for finding the end of thin lines */
   1804           switch ( (int) args->rho ) {
   1805             case 0:
   1806             default:
   1807               /* set of kernels to find all end of lines */
   1808               return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>",exception));
   1809             case 1:
   1810               /* kernel for 4-connected line ends - no rotation */
   1811               kernel=ParseKernelArray("3: 0,0,-  0,1,1  0,0,-");
   1812               break;
   1813           case 2:
   1814               /* kernel to add for 8-connected lines - no rotation */
   1815               kernel=ParseKernelArray("3: 0,0,0  0,1,0  0,0,1");
   1816               break;
   1817           case 3:
   1818               /* kernel to add for orthogonal line ends - does not find corners */
   1819               kernel=ParseKernelArray("3: 0,0,0  0,1,1  0,0,0");
   1820               break;
   1821           case 4:
   1822               /* traditional line end - fails on last T end */
   1823               kernel=ParseKernelArray("3: 0,0,0  0,1,-  0,0,-");
   1824               break;
   1825           }
   1826           if (kernel == (KernelInfo *) NULL)
   1827             return(kernel);
   1828           kernel->type = type;
   1829           RotateKernelInfo(kernel, args->sigma);
   1830           break;
   1831         }
   1832       case LineJunctionsKernel:
   1833         { /* kernels for finding the junctions of multiple lines */
   1834           switch ( (int) args->rho ) {
   1835             case 0:
   1836             default:
   1837               /* set of kernels to find all line junctions */
   1838               return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>",exception));
   1839             case 1:
   1840               /* Y Junction */
   1841               kernel=ParseKernelArray("3: 1,-,1  -,1,-  -,1,-");
   1842               break;
   1843             case 2:
   1844               /* Diagonal T Junctions */
   1845               kernel=ParseKernelArray("3: 1,-,-  -,1,-  1,-,1");
   1846               break;
   1847             case 3:
   1848               /* Orthogonal T Junctions */
   1849               kernel=ParseKernelArray("3: -,-,-  1,1,1  -,1,-");
   1850               break;
   1851             case 4:
   1852               /* Diagonal X Junctions */
   1853               kernel=ParseKernelArray("3: 1,-,1  -,1,-  1,-,1");
   1854               break;
   1855             case 5:
   1856               /* Orthogonal X Junctions - minimal diamond kernel */
   1857               kernel=ParseKernelArray("3: -,1,-  1,1,1  -,1,-");
   1858               break;
   1859           }
   1860           if (kernel == (KernelInfo *) NULL)
   1861             return(kernel);
   1862           kernel->type = type;
   1863           RotateKernelInfo(kernel, args->sigma);
   1864           break;
   1865         }
   1866       case RidgesKernel:
   1867         { /* Ridges - Ridge finding kernels */
   1868           KernelInfo
   1869             *new_kernel;
   1870           switch ( (int) args->rho ) {
   1871             case 1:
   1872             default:
   1873               kernel=ParseKernelArray("3x1:0,1,0");
   1874               if (kernel == (KernelInfo *) NULL)
   1875                 return(kernel);
   1876               kernel->type = type;
   1877               ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */
   1878               break;
   1879             case 2:
   1880               kernel=ParseKernelArray("4x1:0,1,1,0");
   1881               if (kernel == (KernelInfo *) NULL)
   1882                 return(kernel);
   1883               kernel->type = type;
   1884               ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */
   1885 
   1886               /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */
   1887               /* Unfortunatally we can not yet rotate a non-square kernel */
   1888               /* But then we can't flip a non-symetrical kernel either */
   1889               new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0");
   1890               if (new_kernel == (KernelInfo *) NULL)
   1891                 return(DestroyKernelInfo(kernel));
   1892               new_kernel->type = type;
   1893               LastKernelInfo(kernel)->next = new_kernel;
   1894               new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0");
   1895               if (new_kernel == (KernelInfo *) NULL)
   1896                 return(DestroyKernelInfo(kernel));
   1897               new_kernel->type = type;
   1898               LastKernelInfo(kernel)->next = new_kernel;
   1899               new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
   1900               if (new_kernel == (KernelInfo *) NULL)
   1901                 return(DestroyKernelInfo(kernel));
   1902               new_kernel->type = type;
   1903               LastKernelInfo(kernel)->next = new_kernel;
   1904               new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
   1905               if (new_kernel == (KernelInfo *) NULL)
   1906                 return(DestroyKernelInfo(kernel));
   1907               new_kernel->type = type;
   1908               LastKernelInfo(kernel)->next = new_kernel;
   1909               new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
   1910               if (new_kernel == (KernelInfo *) NULL)
   1911                 return(DestroyKernelInfo(kernel));
   1912               new_kernel->type = type;
   1913               LastKernelInfo(kernel)->next = new_kernel;
   1914               new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
   1915               if (new_kernel == (KernelInfo *) NULL)
   1916                 return(DestroyKernelInfo(kernel));
   1917               new_kernel->type = type;
   1918               LastKernelInfo(kernel)->next = new_kernel;
   1919               new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
   1920               if (new_kernel == (KernelInfo *) NULL)
   1921                 return(DestroyKernelInfo(kernel));
   1922               new_kernel->type = type;
   1923               LastKernelInfo(kernel)->next = new_kernel;
   1924               new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
   1925               if (new_kernel == (KernelInfo *) NULL)
   1926                 return(DestroyKernelInfo(kernel));
   1927               new_kernel->type = type;
   1928               LastKernelInfo(kernel)->next = new_kernel;
   1929               break;
   1930           }
   1931           break;
   1932         }
   1933       case ConvexHullKernel:
   1934         {
   1935           KernelInfo
   1936             *new_kernel;
   1937           /* first set of 8 kernels */
   1938           kernel=ParseKernelArray("3: 1,1,-  1,0,-  1,-,0");
   1939           if (kernel == (KernelInfo *) NULL)
   1940             return(kernel);
   1941           kernel->type = type;
   1942           ExpandRotateKernelInfo(kernel, 90.0);
   1943           /* append the mirror versions too - no flip function yet */
   1944           new_kernel=ParseKernelArray("3: 1,1,1  1,0,-  -,-,0");
   1945           if (new_kernel == (KernelInfo *) NULL)
   1946             return(DestroyKernelInfo(kernel));
   1947           new_kernel->type = type;
   1948           ExpandRotateKernelInfo(new_kernel, 90.0);
   1949           LastKernelInfo(kernel)->next = new_kernel;
   1950           break;
   1951         }
   1952       case SkeletonKernel:
   1953         {
   1954           switch ( (int) args->rho ) {
   1955             case 1:
   1956             default:
   1957               /* Traditional Skeleton...
   1958               ** A cyclically rotated single kernel
   1959               */
   1960               kernel=AcquireKernelInfo("ThinSE:482",exception);
   1961               if (kernel == (KernelInfo *) NULL)
   1962                 return(kernel);
   1963               kernel->type = type;
   1964               ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */
   1965               break;
   1966             case 2:
   1967               /* HIPR Variation of the cyclic skeleton
   1968               ** Corners of the traditional method made more forgiving,
   1969               ** but the retain the same cyclic order.
   1970               */
   1971               kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;",exception);
   1972               if (kernel == (KernelInfo *) NULL)
   1973                 return(kernel);
   1974               if (kernel->next == (KernelInfo *) NULL)
   1975                 return(DestroyKernelInfo(kernel));
   1976               kernel->type = type;
   1977               kernel->next->type = type;
   1978               ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */
   1979               break;
   1980             case 3:
   1981               /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's
   1982               ** "Connectivity-Preserving Morphological Image Thransformations"
   1983               ** by Dan S. Bloomberg, available on Leptonica, Selected Papers,
   1984               **   http://www.leptonica.com/papers/conn.pdf
   1985               */
   1986               kernel=AcquireKernelInfo("ThinSE:41; ThinSE:42; ThinSE:43",
   1987                 exception);
   1988               if (kernel == (KernelInfo *) NULL)
   1989                 return(kernel);
   1990               kernel->type = type;
   1991               kernel->next->type = type;
   1992               kernel->next->next->type = type;
   1993               ExpandMirrorKernelInfo(kernel); /* 12 kernels total */
   1994               break;
   1995            }
   1996           break;
   1997         }
   1998       case ThinSEKernel:
   1999         { /* Special kernels for general thinning, while preserving connections
   2000           ** "Connectivity-Preserving Morphological Image Thransformations"
   2001           ** by Dan S. Bloomberg, available on Leptonica, Selected Papers,
   2002           **   http://www.leptonica.com/papers/conn.pdf
   2003           ** And
   2004           **   http://tpgit.github.com/Leptonica/ccthin_8c_source.html
   2005           **
   2006           ** Note kernels do not specify the origin pixel, allowing them
   2007           ** to be used for both thickening and thinning operations.
   2008           */
   2009           switch ( (int) args->rho ) {
   2010             /* SE for 4-connected thinning */
   2011             case 41: /* SE_4_1 */
   2012               kernel=ParseKernelArray("3: -,-,1  0,-,1  -,-,1");
   2013               break;
   2014             case 42: /* SE_4_2 */
   2015               kernel=ParseKernelArray("3: -,-,1  0,-,1  -,0,-");
   2016               break;
   2017             case 43: /* SE_4_3 */
   2018               kernel=ParseKernelArray("3: -,0,-  0,-,1  -,-,1");
   2019               break;
   2020             case 44: /* SE_4_4 */
   2021               kernel=ParseKernelArray("3: -,0,-  0,-,1  -,0,-");
   2022               break;
   2023             case 45: /* SE_4_5 */
   2024               kernel=ParseKernelArray("3: -,0,1  0,-,1  -,0,-");
   2025               break;
   2026             case 46: /* SE_4_6 */
   2027               kernel=ParseKernelArray("3: -,0,-  0,-,1  -,0,1");
   2028               break;
   2029             case 47: /* SE_4_7 */
   2030               kernel=ParseKernelArray("3: -,1,1  0,-,1  -,0,-");
   2031               break;
   2032             case 48: /* SE_4_8 */
   2033               kernel=ParseKernelArray("3: -,-,1  0,-,1  0,-,1");
   2034               break;
   2035             case 49: /* SE_4_9 */
   2036               kernel=ParseKernelArray("3: 0,-,1  0,-,1  -,-,1");
   2037               break;
   2038             /* SE for 8-connected thinning - negatives of the above */
   2039             case 81: /* SE_8_0 */
   2040               kernel=ParseKernelArray("3: -,1,-  0,-,1  -,1,-");
   2041               break;
   2042             case 82: /* SE_8_2 */
   2043               kernel=ParseKernelArray("3: -,1,-  0,-,1  0,-,-");
   2044               break;
   2045             case 83: /* SE_8_3 */
   2046               kernel=ParseKernelArray("3: 0,-,-  0,-,1  -,1,-");
   2047               break;
   2048             case 84: /* SE_8_4 */
   2049               kernel=ParseKernelArray("3: 0,-,-  0,-,1  0,-,-");
   2050               break;
   2051             case 85: /* SE_8_5 */
   2052               kernel=ParseKernelArray("3: 0,-,1  0,-,1  0,-,-");
   2053               break;
   2054             case 86: /* SE_8_6 */
   2055               kernel=ParseKernelArray("3: 0,-,-  0,-,1  0,-,1");
   2056               break;
   2057             case 87: /* SE_8_7 */
   2058               kernel=ParseKernelArray("3: -,1,-  0,-,1  0,0,-");
   2059               break;
   2060             case 88: /* SE_8_8 */
   2061               kernel=ParseKernelArray("3: -,1,-  0,-,1  0,1,-");
   2062               break;
   2063             case 89: /* SE_8_9 */
   2064               kernel=ParseKernelArray("3: 0,1,-  0,-,1  -,1,-");
   2065               break;
   2066             /* Special combined SE kernels */
   2067             case 423: /* SE_4_2 , SE_4_3 Combined Kernel */
   2068               kernel=ParseKernelArray("3: -,-,1  0,-,-  -,0,-");
   2069               break;
   2070             case 823: /* SE_8_2 , SE_8_3 Combined Kernel */
   2071               kernel=ParseKernelArray("3: -,1,-  -,-,1  0,-,-");
   2072               break;
   2073             case 481: /* SE_48_1 - General Connected Corner Kernel */
   2074               kernel=ParseKernelArray("3: -,1,1  0,-,1  0,0,-");
   2075               break;
   2076             default:
   2077             case 482: /* SE_48_2 - General Edge Kernel */
   2078               kernel=ParseKernelArray("3: 0,-,1  0,-,1  0,-,1");
   2079               break;
   2080           }
   2081           if (kernel == (KernelInfo *) NULL)
   2082             return(kernel);
   2083           kernel->type = type;
   2084           RotateKernelInfo(kernel, args->sigma);
   2085           break;
   2086         }
   2087       /*
   2088         Distance Measuring Kernels
   2089       */
   2090       case ChebyshevKernel:
   2091         {
   2092           if (args->rho < 1.0)
   2093             kernel->width = kernel->height = 3;  /* default radius = 1 */
   2094           else
   2095             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   2096           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   2097 
   2098           kernel->values=(MagickRealType *) MagickAssumeAligned(
   2099             AcquireAlignedMemory(kernel->width,kernel->height*
   2100             sizeof(*kernel->values)));
   2101           if (kernel->values == (MagickRealType *) NULL)
   2102             return(DestroyKernelInfo(kernel));
   2103 
   2104           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   2105             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   2106               kernel->positive_range += ( kernel->values[i] =
   2107                   args->sigma*MagickMax(fabs((double)u),fabs((double)v)) );
   2108           kernel->maximum = kernel->values[0];
   2109           break;
   2110         }
   2111       case ManhattanKernel:
   2112         {
   2113           if (args->rho < 1.0)
   2114             kernel->width = kernel->height = 3;  /* default radius = 1 */
   2115           else
   2116             kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   2117           kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   2118 
   2119           kernel->values=(MagickRealType *) MagickAssumeAligned(
   2120             AcquireAlignedMemory(kernel->width,kernel->height*
   2121             sizeof(*kernel->values)));
   2122           if (kernel->values == (MagickRealType *) NULL)
   2123             return(DestroyKernelInfo(kernel));
   2124 
   2125           for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   2126             for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   2127               kernel->positive_range += ( kernel->values[i] =
   2128                   args->sigma*(labs((long) u)+labs((long) v)) );
   2129           kernel->maximum = kernel->values[0];
   2130           break;
   2131         }
   2132       case OctagonalKernel:
   2133       {
   2134         if (args->rho < 2.0)
   2135           kernel->width = kernel->height = 5;  /* default/minimum radius = 2 */
   2136         else
   2137           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   2138         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   2139 
   2140         kernel->values=(MagickRealType *) MagickAssumeAligned(
   2141           AcquireAlignedMemory(kernel->width,kernel->height*
   2142           sizeof(*kernel->values)));
   2143         if (kernel->values == (MagickRealType *) NULL)
   2144           return(DestroyKernelInfo(kernel));
   2145 
   2146         for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   2147           for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   2148             {
   2149               double
   2150                 r1 = MagickMax(fabs((double)u),fabs((double)v)),
   2151                 r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5);
   2152               kernel->positive_range += kernel->values[i] =
   2153                         args->sigma*MagickMax(r1,r2);
   2154             }
   2155         kernel->maximum = kernel->values[0];
   2156         break;
   2157       }
   2158     case EuclideanKernel:
   2159       {
   2160         if (args->rho < 1.0)
   2161           kernel->width = kernel->height = 3;  /* default radius = 1 */
   2162         else
   2163           kernel->width = kernel->height = ((size_t)args->rho)*2+1;
   2164         kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
   2165 
   2166         kernel->values=(MagickRealType *) MagickAssumeAligned(
   2167           AcquireAlignedMemory(kernel->width,kernel->height*
   2168           sizeof(*kernel->values)));
   2169         if (kernel->values == (MagickRealType *) NULL)
   2170           return(DestroyKernelInfo(kernel));
   2171 
   2172         for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
   2173           for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
   2174             kernel->positive_range += ( kernel->values[i] =
   2175               args->sigma*sqrt((double)(u*u+v*v)) );
   2176         kernel->maximum = kernel->values[0];
   2177         break;
   2178       }
   2179     default:
   2180       {
   2181         /* No-Op Kernel - Basically just a single pixel on its own */
   2182         kernel=ParseKernelArray("1:1");
   2183         if (kernel == (KernelInfo *) NULL)
   2184           return(kernel);
   2185         kernel->type = UndefinedKernel;
   2186         break;
   2187       }
   2188       break;
   2189   }
   2190   return(kernel);
   2191 }
   2192 
   2193 /*
   2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2196 %                                                                             %
   2197 %                                                                             %
   2198 %                                                                             %
   2199 %     C l o n e K e r n e l I n f o                                           %
   2200 %                                                                             %
   2201 %                                                                             %
   2202 %                                                                             %
   2203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2204 %
   2205 %  CloneKernelInfo() creates a new clone of the given Kernel List so that its
   2206 %  can be modified without effecting the original.  The cloned kernel should
   2207 %  be destroyed using DestoryKernelInfo() when no longer needed.
   2208 %
   2209 %  The format of the CloneKernelInfo method is:
   2210 %
   2211 %      KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
   2212 %
   2213 %  A description of each parameter follows:
   2214 %
   2215 %    o kernel: the Morphology/Convolution kernel to be cloned
   2216 %
   2217 */
   2218 MagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
   2219 {
   2220   register ssize_t
   2221     i;
   2222 
   2223   KernelInfo
   2224     *new_kernel;
   2225 
   2226   assert(kernel != (KernelInfo *) NULL);
   2227   new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
   2228   if (new_kernel == (KernelInfo *) NULL)
   2229     return(new_kernel);
   2230   *new_kernel=(*kernel); /* copy values in structure */
   2231 
   2232   /* replace the values with a copy of the values */
   2233   new_kernel->values=(MagickRealType *) MagickAssumeAligned(
   2234     AcquireAlignedMemory(kernel->width,kernel->height*sizeof(*kernel->values)));
   2235   if (new_kernel->values == (MagickRealType *) NULL)
   2236     return(DestroyKernelInfo(new_kernel));
   2237   for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
   2238     new_kernel->values[i]=kernel->values[i];
   2239 
   2240   /* Also clone the next kernel in the kernel list */
   2241   if ( kernel->next != (KernelInfo *) NULL ) {
   2242     new_kernel->next = CloneKernelInfo(kernel->next);
   2243     if ( new_kernel->next == (KernelInfo *) NULL )
   2244       return(DestroyKernelInfo(new_kernel));
   2245   }
   2246 
   2247   return(new_kernel);
   2248 }
   2249 
   2250 /*
   2252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2253 %                                                                             %
   2254 %                                                                             %
   2255 %                                                                             %
   2256 %     D e s t r o y K e r n e l I n f o                                       %
   2257 %                                                                             %
   2258 %                                                                             %
   2259 %                                                                             %
   2260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2261 %
   2262 %  DestroyKernelInfo() frees the memory used by a Convolution/Morphology
   2263 %  kernel.
   2264 %
   2265 %  The format of the DestroyKernelInfo method is:
   2266 %
   2267 %      KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
   2268 %
   2269 %  A description of each parameter follows:
   2270 %
   2271 %    o kernel: the Morphology/Convolution kernel to be destroyed
   2272 %
   2273 */
   2274 MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
   2275 {
   2276   assert(kernel != (KernelInfo *) NULL);
   2277   if (kernel->next != (KernelInfo *) NULL)
   2278     kernel->next=DestroyKernelInfo(kernel->next);
   2279   kernel->values=(MagickRealType *) RelinquishAlignedMemory(kernel->values);
   2280   kernel=(KernelInfo *) RelinquishMagickMemory(kernel);
   2281   return(kernel);
   2282 }
   2283 
   2284 /*
   2286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2287 %                                                                             %
   2288 %                                                                             %
   2289 %                                                                             %
   2290 +     E x p a n d M i r r o r K e r n e l I n f o                             %
   2291 %                                                                             %
   2292 %                                                                             %
   2293 %                                                                             %
   2294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2295 %
   2296 %  ExpandMirrorKernelInfo() takes a single kernel, and expands it into a
   2297 %  sequence of 90-degree rotated kernels but providing a reflected 180
   2298 %  rotatation, before the -/+ 90-degree rotations.
   2299 %
   2300 %  This special rotation order produces a better, more symetrical thinning of
   2301 %  objects.
   2302 %
   2303 %  The format of the ExpandMirrorKernelInfo method is:
   2304 %
   2305 %      void ExpandMirrorKernelInfo(KernelInfo *kernel)
   2306 %
   2307 %  A description of each parameter follows:
   2308 %
   2309 %    o kernel: the Morphology/Convolution kernel
   2310 %
   2311 % This function is only internel to this module, as it is not finalized,
   2312 % especially with regard to non-orthogonal angles, and rotation of larger
   2313 % 2D kernels.
   2314 */
   2315 
   2316 #if 0
   2317 static void FlopKernelInfo(KernelInfo *kernel)
   2318     { /* Do a Flop by reversing each row. */
   2319       size_t
   2320         y;
   2321       register ssize_t
   2322         x,r;
   2323       register double
   2324         *k,t;
   2325 
   2326       for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
   2327         for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
   2328           t=k[x],  k[x]=k[r],  k[r]=t;
   2329 
   2330       kernel->x = kernel->width - kernel->x - 1;
   2331       angle = fmod(angle+180.0, 360.0);
   2332     }
   2333 #endif
   2334 
   2335 static void ExpandMirrorKernelInfo(KernelInfo *kernel)
   2336 {
   2337   KernelInfo
   2338     *clone,
   2339     *last;
   2340 
   2341   last = kernel;
   2342 
   2343   clone = CloneKernelInfo(last);
   2344   if (clone == (KernelInfo *) NULL)
   2345     return;
   2346   RotateKernelInfo(clone, 180);   /* flip */
   2347   LastKernelInfo(last)->next = clone;
   2348   last = clone;
   2349 
   2350   clone = CloneKernelInfo(last);
   2351   if (clone == (KernelInfo *) NULL)
   2352     return;
   2353   RotateKernelInfo(clone, 90);   /* transpose */
   2354   LastKernelInfo(last)->next = clone;
   2355   last = clone;
   2356 
   2357   clone = CloneKernelInfo(last);
   2358   if (clone == (KernelInfo *) NULL)
   2359     return;
   2360   RotateKernelInfo(clone, 180);  /* flop */
   2361   LastKernelInfo(last)->next = clone;
   2362 
   2363   return;
   2364 }
   2365 
   2366 /*
   2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2369 %                                                                             %
   2370 %                                                                             %
   2371 %                                                                             %
   2372 +     E x p a n d R o t a t e K e r n e l I n f o                             %
   2373 %                                                                             %
   2374 %                                                                             %
   2375 %                                                                             %
   2376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2377 %
   2378 %  ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating
   2379 %  incrementally by the angle given, until the kernel repeats.
   2380 %
   2381 %  WARNING: 45 degree rotations only works for 3x3 kernels.
   2382 %  While 90 degree roatations only works for linear and square kernels
   2383 %
   2384 %  The format of the ExpandRotateKernelInfo method is:
   2385 %
   2386 %      void ExpandRotateKernelInfo(KernelInfo *kernel, double angle)
   2387 %
   2388 %  A description of each parameter follows:
   2389 %
   2390 %    o kernel: the Morphology/Convolution kernel
   2391 %
   2392 %    o angle: angle to rotate in degrees
   2393 %
   2394 % This function is only internel to this module, as it is not finalized,
   2395 % especially with regard to non-orthogonal angles, and rotation of larger
   2396 % 2D kernels.
   2397 */
   2398 
   2399 /* Internal Routine - Return true if two kernels are the same */
   2400 static MagickBooleanType SameKernelInfo(const KernelInfo *kernel1,
   2401      const KernelInfo *kernel2)
   2402 {
   2403   register size_t
   2404     i;
   2405 
   2406   /* check size and origin location */
   2407   if (    kernel1->width != kernel2->width
   2408        || kernel1->height != kernel2->height
   2409        || kernel1->x != kernel2->x
   2410        || kernel1->y != kernel2->y )
   2411     return MagickFalse;
   2412 
   2413   /* check actual kernel values */
   2414   for (i=0; i < (kernel1->width*kernel1->height); i++) {
   2415     /* Test for Nan equivalence */
   2416     if ( IsNaN(kernel1->values[i]) && !IsNaN(kernel2->values[i]) )
   2417       return MagickFalse;
   2418     if ( IsNaN(kernel2->values[i]) && !IsNaN(kernel1->values[i]) )
   2419       return MagickFalse;
   2420     /* Test actual values are equivalent */
   2421     if ( fabs(kernel1->values[i] - kernel2->values[i]) >= MagickEpsilon )
   2422       return MagickFalse;
   2423   }
   2424 
   2425   return MagickTrue;
   2426 }
   2427 
   2428 static void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle)
   2429 {
   2430   KernelInfo
   2431     *clone_info,
   2432     *last;
   2433 
   2434   last=kernel;
   2435 DisableMSCWarning(4127)
   2436   while (1) {
   2437 RestoreMSCWarning
   2438     clone_info=CloneKernelInfo(last);
   2439     if (clone_info == (KernelInfo *) NULL)
   2440       break;
   2441     RotateKernelInfo(clone_info,angle);
   2442     if (SameKernelInfo(kernel,clone_info) != MagickFalse)
   2443       break;
   2444     LastKernelInfo(last)->next=clone_info;
   2445     last=clone_info;
   2446   }
   2447   if (clone_info != (KernelInfo *) NULL)
   2448     clone_info=DestroyKernelInfo(clone_info);  /* kernel repeated - junk */
   2449   return;
   2450 }
   2451 
   2452 /*
   2454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2455 %                                                                             %
   2456 %                                                                             %
   2457 %                                                                             %
   2458 +     C a l c M e t a K e r n a l I n f o                                     %
   2459 %                                                                             %
   2460 %                                                                             %
   2461 %                                                                             %
   2462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2463 %
   2464 %  CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only,
   2465 %  using the kernel values.  This should only ne used if it is not possible to
   2466 %  calculate that meta-data in some easier way.
   2467 %
   2468 %  It is important that the meta-data is correct before ScaleKernelInfo() is
   2469 %  used to perform kernel normalization.
   2470 %
   2471 %  The format of the CalcKernelMetaData method is:
   2472 %
   2473 %      void CalcKernelMetaData(KernelInfo *kernel, const double scale )
   2474 %
   2475 %  A description of each parameter follows:
   2476 %
   2477 %    o kernel: the Morphology/Convolution kernel to modify
   2478 %
   2479 %  WARNING: Minimum and Maximum values are assumed to include zero, even if
   2480 %  zero is not part of the kernel (as in Gaussian Derived kernels). This
   2481 %  however is not true for flat-shaped morphological kernels.
   2482 %
   2483 %  WARNING: Only the specific kernel pointed to is modified, not a list of
   2484 %  multiple kernels.
   2485 %
   2486 % This is an internal function and not expected to be useful outside this
   2487 % module.  This could change however.
   2488 */
   2489 static void CalcKernelMetaData(KernelInfo *kernel)
   2490 {
   2491   register size_t
   2492     i;
   2493 
   2494   kernel->minimum = kernel->maximum = 0.0;
   2495   kernel->negative_range = kernel->positive_range = 0.0;
   2496   for (i=0; i < (kernel->width*kernel->height); i++)
   2497     {
   2498       if ( fabs(kernel->values[i]) < MagickEpsilon )
   2499         kernel->values[i] = 0.0;
   2500       ( kernel->values[i] < 0)
   2501           ?  ( kernel->negative_range += kernel->values[i] )
   2502           :  ( kernel->positive_range += kernel->values[i] );
   2503       Minimize(kernel->minimum, kernel->values[i]);
   2504       Maximize(kernel->maximum, kernel->values[i]);
   2505     }
   2506 
   2507   return;
   2508 }
   2509 
   2510 /*
   2512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2513 %                                                                             %
   2514 %                                                                             %
   2515 %                                                                             %
   2516 %     M o r p h o l o g y A p p l y                                           %
   2517 %                                                                             %
   2518 %                                                                             %
   2519 %                                                                             %
   2520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   2521 %
   2522 %  MorphologyApply() applies a morphological method, multiple times using
   2523 %  a list of multiple kernels.  This is the method that should be called by
   2524 %  other 'operators' that internally use morphology operations as part of
   2525 %  their processing.
   2526 %
   2527 %  It is basically equivalent to as MorphologyImage() (see below) but without
   2528 %  any user controls.  This allows internel programs to use this method to
   2529 %  perform a specific task without possible interference by any API user
   2530 %  supplied settings.
   2531 %
   2532 %  It is MorphologyImage() task to extract any such user controls, and
   2533 %  pass them to this function for processing.
   2534 %
   2535 %  More specifically all given kernels should already be scaled, normalised,
   2536 %  and blended appropriatally before being parred to this routine. The
   2537 %  appropriate bias, and compose (typically 'UndefinedComposeOp') given.
   2538 %
   2539 %  The format of the MorphologyApply method is:
   2540 %
   2541 %      Image *MorphologyApply(const Image *image,MorphologyMethod method,
   2542 %        const ssize_t iterations,const KernelInfo *kernel,
   2543 %        const CompositeMethod compose,const double bias,
   2544 %        ExceptionInfo *exception)
   2545 %
   2546 %  A description of each parameter follows:
   2547 %
   2548 %    o image: the source image
   2549 %
   2550 %    o method: the morphology method to be applied.
   2551 %
   2552 %    o iterations: apply the operation this many times (or no change).
   2553 %                  A value of -1 means loop until no change found.
   2554 %                  How this is applied may depend on the morphology method.
   2555 %                  Typically this is a value of 1.
   2556 %
   2557 %    o channel: the channel type.
   2558 %
   2559 %    o kernel: An array of double representing the morphology kernel.
   2560 %
   2561 %    o compose: How to handle or merge multi-kernel results.
   2562 %          If 'UndefinedCompositeOp' use default for the Morphology method.
   2563 %          If 'NoCompositeOp' force image to be re-iterated by each kernel.
   2564 %          Otherwise merge the results using the compose method given.
   2565 %
   2566 %    o bias: Convolution Output Bias.
   2567 %
   2568 %    o exception: return any errors or warnings in this structure.
   2569 %
   2570 */
   2571 static ssize_t MorphologyPrimitive(const Image *image,Image *morphology_image,
   2572   const MorphologyMethod method,const KernelInfo *kernel,const double bias,
   2573   ExceptionInfo *exception)
   2574 {
   2575 #define MorphologyTag  "Morphology/Image"
   2576 
   2577   CacheView
   2578     *image_view,
   2579     *morphology_view;
   2580 
   2581   OffsetInfo
   2582     offset;
   2583 
   2584   register ssize_t
   2585     j,
   2586     y;
   2587 
   2588   size_t
   2589     *changes,
   2590     changed,
   2591     width;
   2592 
   2593   MagickBooleanType
   2594     status;
   2595 
   2596   MagickOffsetType
   2597     progress;
   2598 
   2599   assert(image != (Image *) NULL);
   2600   assert(image->signature == MagickCoreSignature);
   2601   assert(morphology_image != (Image *) NULL);
   2602   assert(morphology_image->signature == MagickCoreSignature);
   2603   assert(kernel != (KernelInfo *) NULL);
   2604   assert(kernel->signature == MagickCoreSignature);
   2605   assert(exception != (ExceptionInfo *) NULL);
   2606   assert(exception->signature == MagickCoreSignature);
   2607   status=MagickTrue;
   2608   progress=0;
   2609   image_view=AcquireVirtualCacheView(image,exception);
   2610   morphology_view=AcquireAuthenticCacheView(morphology_image,exception);
   2611   width=image->columns+kernel->width-1;
   2612   offset.x=0;
   2613   offset.y=0;
   2614   switch (method)
   2615   {
   2616     case ConvolveMorphology:
   2617     case DilateMorphology:
   2618     case DilateIntensityMorphology:
   2619     case IterativeDistanceMorphology:
   2620     {
   2621       /*
   2622         Kernel needs to used with reflection about origin.
   2623       */
   2624       offset.x=(ssize_t) kernel->width-kernel->x-1;
   2625       offset.y=(ssize_t) kernel->height-kernel->y-1;
   2626       break;
   2627     }
   2628     case ErodeMorphology:
   2629     case ErodeIntensityMorphology:
   2630     case HitAndMissMorphology:
   2631     case ThinningMorphology:
   2632     case ThickenMorphology:
   2633     {
   2634       offset.x=kernel->x;
   2635       offset.y=kernel->y;
   2636       break;
   2637     }
   2638     default:
   2639     {
   2640       assert("Not a Primitive Morphology Method" != (char *) NULL);
   2641       break;
   2642     }
   2643   }
   2644   changed=0;
   2645   changes=(size_t *) AcquireQuantumMemory(GetOpenMPMaximumThreads(),
   2646     sizeof(*changes));
   2647   if (changes == (size_t *) NULL)
   2648     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   2649   for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
   2650     changes[j]=0;
   2651 
   2652   if ((method == ConvolveMorphology) && (kernel->width == 1))
   2653     {
   2654       register ssize_t
   2655         x;
   2656 
   2657       /*
   2658         Special handling (for speed) of vertical (blur) kernels.  This performs
   2659         its handling in columns rather than in rows.  This is only done
   2660         for convolve as it is the only method that generates very large 1-D
   2661         vertical kernels (such as a 'BlurKernel')
   2662      */
   2663 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2664      #pragma omp parallel for schedule(static) shared(progress,status) \
   2665        magick_number_threads(image,morphology_image,image->columns,1)
   2666 #endif
   2667       for (x=0; x < (ssize_t) image->columns; x++)
   2668       {
   2669         const int
   2670           id = GetOpenMPThreadId();
   2671 
   2672         register const Quantum
   2673           *magick_restrict p;
   2674 
   2675         register Quantum
   2676           *magick_restrict q;
   2677 
   2678         register ssize_t
   2679           r;
   2680 
   2681         ssize_t
   2682           center;
   2683 
   2684         if (status == MagickFalse)
   2685           continue;
   2686         p=GetCacheViewVirtualPixels(image_view,x,-offset.y,1,image->rows+
   2687           kernel->height-1,exception);
   2688         q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,
   2689           morphology_image->rows,exception);
   2690         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   2691           {
   2692             status=MagickFalse;
   2693             continue;
   2694           }
   2695         center=(ssize_t) GetPixelChannels(image)*offset.y;
   2696         for (r=0; r < (ssize_t) image->rows; r++)
   2697         {
   2698           register ssize_t
   2699             i;
   2700 
   2701           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   2702           {
   2703             double
   2704               alpha,
   2705               gamma,
   2706               pixel;
   2707 
   2708             PixelChannel
   2709               channel;
   2710 
   2711             PixelTrait
   2712               morphology_traits,
   2713               traits;
   2714 
   2715             register const MagickRealType
   2716               *magick_restrict k;
   2717 
   2718             register const Quantum
   2719               *magick_restrict pixels;
   2720 
   2721             register ssize_t
   2722               v;
   2723 
   2724             size_t
   2725               count;
   2726 
   2727             channel=GetPixelChannelChannel(image,i);
   2728             traits=GetPixelChannelTraits(image,channel);
   2729             morphology_traits=GetPixelChannelTraits(morphology_image,channel);
   2730             if ((traits == UndefinedPixelTrait) ||
   2731                 (morphology_traits == UndefinedPixelTrait))
   2732               continue;
   2733             if ((traits & CopyPixelTrait) != 0)
   2734               {
   2735                 SetPixelChannel(morphology_image,channel,p[center+i],q);
   2736                 continue;
   2737               }
   2738             k=(&kernel->values[kernel->height-1]);
   2739             pixels=p;
   2740             pixel=bias;
   2741             gamma=0.0;
   2742             count=0;
   2743             if ((morphology_traits & BlendPixelTrait) == 0)
   2744               for (v=0; v < (ssize_t) kernel->height; v++)
   2745               {
   2746                 if (!IsNaN(*k))
   2747                   {
   2748                     pixel+=(*k)*pixels[i];
   2749                     gamma+=(*k);
   2750                     count++;
   2751                   }
   2752                 k--;
   2753                 pixels+=GetPixelChannels(image);
   2754               }
   2755             else
   2756               for (v=0; v < (ssize_t) kernel->height; v++)
   2757               {
   2758                 if (!IsNaN(*k))
   2759                   {
   2760                     alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
   2761                     pixel+=alpha*(*k)*pixels[i];
   2762                     gamma+=alpha*(*k);
   2763                     count++;
   2764                   }
   2765                 k--;
   2766                 pixels+=GetPixelChannels(image);
   2767               }
   2768             if (fabs(pixel-p[center+i]) > MagickEpsilon)
   2769               changes[id]++;
   2770             gamma=PerceptibleReciprocal(gamma);
   2771             if (count != 0)
   2772               gamma*=(double) kernel->height/count;
   2773             SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*
   2774               pixel),q);
   2775           }
   2776           p+=GetPixelChannels(image);
   2777           q+=GetPixelChannels(morphology_image);
   2778         }
   2779         if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
   2780           status=MagickFalse;
   2781         if (image->progress_monitor != (MagickProgressMonitor) NULL)
   2782           {
   2783             MagickBooleanType
   2784               proceed;
   2785 
   2786 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2787             #pragma omp atomic
   2788 #endif
   2789             progress++;
   2790             proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
   2791             if (proceed == MagickFalse)
   2792               status=MagickFalse;
   2793           }
   2794       }
   2795       morphology_image->type=image->type;
   2796       morphology_view=DestroyCacheView(morphology_view);
   2797       image_view=DestroyCacheView(image_view);
   2798       for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
   2799         changed+=changes[j];
   2800       changes=(size_t *) RelinquishMagickMemory(changes);
   2801       return(status ? (ssize_t) changed : 0);
   2802     }
   2803   /*
   2804     Normal handling of horizontal or rectangular kernels (row by row).
   2805   */
   2806 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   2807   #pragma omp parallel for schedule(static) shared(progress,status) \
   2808     magick_number_threads(image,morphology_image,image->rows,1)
   2809 #endif
   2810   for (y=0; y < (ssize_t) image->rows; y++)
   2811   {
   2812     const int
   2813       id = GetOpenMPThreadId();
   2814 
   2815     register const Quantum
   2816       *magick_restrict p;
   2817 
   2818     register Quantum
   2819       *magick_restrict q;
   2820 
   2821     register ssize_t
   2822       x;
   2823 
   2824     ssize_t
   2825       center;
   2826 
   2827     if (status == MagickFalse)
   2828       continue;
   2829     p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,
   2830       kernel->height,exception);
   2831     q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,
   2832       1,exception);
   2833     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   2834       {
   2835         status=MagickFalse;
   2836         continue;
   2837       }
   2838     center=(ssize_t) (GetPixelChannels(image)*width*offset.y+
   2839       GetPixelChannels(image)*offset.x);
   2840     for (x=0; x < (ssize_t) image->columns; x++)
   2841     {
   2842       register ssize_t
   2843         i;
   2844 
   2845       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   2846       {
   2847         double
   2848           alpha,
   2849           gamma,
   2850           intensity,
   2851           maximum,
   2852           minimum,
   2853           pixel;
   2854 
   2855         PixelChannel
   2856           channel;
   2857 
   2858         PixelTrait
   2859           morphology_traits,
   2860           traits;
   2861 
   2862         register const MagickRealType
   2863           *magick_restrict k;
   2864 
   2865         register const Quantum
   2866           *magick_restrict pixels;
   2867 
   2868         register ssize_t
   2869           u;
   2870 
   2871         size_t
   2872           count;
   2873 
   2874         ssize_t
   2875           v;
   2876 
   2877         channel=GetPixelChannelChannel(image,i);
   2878         traits=GetPixelChannelTraits(image,channel);
   2879         morphology_traits=GetPixelChannelTraits(morphology_image,channel);
   2880         if ((traits == UndefinedPixelTrait) ||
   2881             (morphology_traits == UndefinedPixelTrait))
   2882           continue;
   2883         if ((traits & CopyPixelTrait) != 0)
   2884           {
   2885             SetPixelChannel(morphology_image,channel,p[center+i],q);
   2886             continue;
   2887           }
   2888         pixels=p;
   2889         maximum=0.0;
   2890         minimum=(double) QuantumRange;
   2891         switch (method)
   2892         {
   2893           case ConvolveMorphology:
   2894           {
   2895             pixel=bias;
   2896             break;
   2897           }
   2898           case DilateMorphology:
   2899           case ErodeIntensityMorphology:
   2900           {
   2901             pixel=0.0;
   2902             break;
   2903           }
   2904           case HitAndMissMorphology:
   2905           case ErodeMorphology:
   2906           {
   2907             pixel=QuantumRange;
   2908             break;
   2909           }
   2910           default:
   2911           {
   2912             pixel=(double) p[center+i];
   2913             break;
   2914           }
   2915         }
   2916         count=0;
   2917         gamma=1.0;
   2918         switch (method)
   2919         {
   2920           case ConvolveMorphology:
   2921           {
   2922             /*
   2923                Weighted Average of pixels using reflected kernel
   2924 
   2925                For correct working of this operation for asymetrical kernels,
   2926                the kernel needs to be applied in its reflected form.  That is
   2927                its values needs to be reversed.
   2928 
   2929                Correlation is actually the same as this but without reflecting
   2930                the kernel, and thus 'lower-level' that Convolution.  However as
   2931                Convolution is the more common method used, and it does not
   2932                really cost us much in terms of processing to use a reflected
   2933                kernel, so it is Convolution that is implemented.
   2934 
   2935                Correlation will have its kernel reflected before calling this
   2936                function to do a Convolve.
   2937 
   2938                For more details of Correlation vs Convolution see
   2939                  http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf
   2940             */
   2941             k=(&kernel->values[kernel->width*kernel->height-1]);
   2942             if ((morphology_traits & BlendPixelTrait) == 0)
   2943               {
   2944                 /*
   2945                   No alpha blending.
   2946                 */
   2947                 for (v=0; v < (ssize_t) kernel->height; v++)
   2948                 {
   2949                   for (u=0; u < (ssize_t) kernel->width; u++)
   2950                   {
   2951                     if (!IsNaN(*k))
   2952                       {
   2953                         pixel+=(*k)*pixels[i];
   2954                         count++;
   2955                       }
   2956                     k--;
   2957                     pixels+=GetPixelChannels(image);
   2958                   }
   2959                   pixels+=(image->columns-1)*GetPixelChannels(image);
   2960                 }
   2961                 break;
   2962               }
   2963             /*
   2964               Alpha blending.
   2965             */
   2966             gamma=0.0;
   2967             for (v=0; v < (ssize_t) kernel->height; v++)
   2968             {
   2969               for (u=0; u < (ssize_t) kernel->width; u++)
   2970               {
   2971                 if (!IsNaN(*k))
   2972                   {
   2973                     alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
   2974                     pixel+=alpha*(*k)*pixels[i];
   2975                     gamma+=alpha*(*k);
   2976                     count++;
   2977                   }
   2978                 k--;
   2979                 pixels+=GetPixelChannels(image);
   2980               }
   2981               pixels+=(image->columns-1)*GetPixelChannels(image);
   2982             }
   2983             break;
   2984           }
   2985           case ErodeMorphology:
   2986           {
   2987             /*
   2988               Minimum value within kernel neighbourhood.
   2989 
   2990               The kernel is not reflected for this operation.  In normal
   2991               Greyscale Morphology, the kernel value should be added
   2992               to the real value, this is currently not done, due to the
   2993               nature of the boolean kernels being used.
   2994             */
   2995             k=kernel->values;
   2996             for (v=0; v < (ssize_t) kernel->height; v++)
   2997             {
   2998               for (u=0; u < (ssize_t) kernel->width; u++)
   2999               {
   3000                 if (!IsNaN(*k) && (*k >= 0.5))
   3001                   {
   3002                     if ((double) pixels[i] < pixel)
   3003                       pixel=(double) pixels[i];
   3004                   }
   3005                 k++;
   3006                 pixels+=GetPixelChannels(image);
   3007               }
   3008               pixels+=(image->columns-1)*GetPixelChannels(image);
   3009             }
   3010             break;
   3011           }
   3012           case DilateMorphology:
   3013           {
   3014             /*
   3015                Maximum value within kernel neighbourhood.
   3016 
   3017                For correct working of this operation for asymetrical kernels,
   3018                the kernel needs to be applied in its reflected form.  That is
   3019                its values needs to be reversed.
   3020 
   3021                In normal Greyscale Morphology, the kernel value should be
   3022                added to the real value, this is currently not done, due to the
   3023                nature of the boolean kernels being used.
   3024             */
   3025             k=(&kernel->values[kernel->width*kernel->height-1]);
   3026             for (v=0; v < (ssize_t) kernel->height; v++)
   3027             {
   3028               for (u=0; u < (ssize_t) kernel->width; u++)
   3029               {
   3030                 if (!IsNaN(*k) && (*k > 0.5))
   3031                   {
   3032                     if ((double) pixels[i] > pixel)
   3033                       pixel=(double) pixels[i];
   3034                   }
   3035                 k--;
   3036                 pixels+=GetPixelChannels(image);
   3037               }
   3038               pixels+=(image->columns-1)*GetPixelChannels(image);
   3039             }
   3040             break;
   3041           }
   3042           case HitAndMissMorphology:
   3043           case ThinningMorphology:
   3044           case ThickenMorphology:
   3045           {
   3046             /*
   3047                Minimum of foreground pixel minus maxumum of background pixels.
   3048 
   3049                The kernel is not reflected for this operation, and consists
   3050                of both foreground and background pixel neighbourhoods, 0.0 for
   3051                background, and 1.0 for foreground with either Nan or 0.5 values
   3052                for don't care.
   3053 
   3054                This never produces a meaningless negative result.  Such results
   3055                cause Thinning/Thicken to not work correctly when used against a
   3056                greyscale image.
   3057             */
   3058             k=kernel->values;
   3059             for (v=0; v < (ssize_t) kernel->height; v++)
   3060             {
   3061               for (u=0; u < (ssize_t) kernel->width; u++)
   3062               {
   3063                 if (!IsNaN(*k))
   3064                   {
   3065                     if (*k > 0.7)
   3066                       {
   3067                         if ((double) pixels[i] < pixel)
   3068                           pixel=(double) pixels[i];
   3069                       }
   3070                     else
   3071                       if (*k < 0.3)
   3072                         {
   3073                           if ((double) pixels[i] > maximum)
   3074                             maximum=(double) pixels[i];
   3075                         }
   3076                     count++;
   3077                   }
   3078                 k++;
   3079                 pixels+=GetPixelChannels(image);
   3080               }
   3081               pixels+=(image->columns-1)*GetPixelChannels(image);
   3082             }
   3083             pixel-=maximum;
   3084             if (pixel < 0.0)
   3085               pixel=0.0;
   3086             if (method ==  ThinningMorphology)
   3087               pixel=(double) p[center+i]-pixel;
   3088             else
   3089               if (method ==  ThickenMorphology)
   3090                 pixel+=(double) p[center+i]+pixel;
   3091             break;
   3092           }
   3093           case ErodeIntensityMorphology:
   3094           {
   3095             /*
   3096               Select pixel with minimum intensity within kernel neighbourhood.
   3097 
   3098               The kernel is not reflected for this operation.
   3099             */
   3100             k=kernel->values;
   3101             for (v=0; v < (ssize_t) kernel->height; v++)
   3102             {
   3103               for (u=0; u < (ssize_t) kernel->width; u++)
   3104               {
   3105                 if (!IsNaN(*k) && (*k >= 0.5))
   3106                   {
   3107                     intensity=(double) GetPixelIntensity(image,pixels);
   3108                     if (intensity < minimum)
   3109                       {
   3110                         pixel=(double) pixels[i];
   3111                         minimum=intensity;
   3112                       }
   3113                     count++;
   3114                   }
   3115                 k++;
   3116                 pixels+=GetPixelChannels(image);
   3117               }
   3118               pixels+=(image->columns-1)*GetPixelChannels(image);
   3119             }
   3120             break;
   3121           }
   3122           case DilateIntensityMorphology:
   3123           {
   3124             /*
   3125               Select pixel with maximum intensity within kernel neighbourhood.
   3126 
   3127               The kernel is not reflected for this operation.
   3128             */
   3129             k=(&kernel->values[kernel->width*kernel->height-1]);
   3130             for (v=0; v < (ssize_t) kernel->height; v++)
   3131             {
   3132               for (u=0; u < (ssize_t) kernel->width; u++)
   3133               {
   3134                 if (!IsNaN(*k) && (*k >= 0.5))
   3135                   {
   3136                     intensity=(double) GetPixelIntensity(image,pixels);
   3137                     if (intensity > maximum)
   3138                       {
   3139                         pixel=(double) pixels[i];
   3140                         maximum=intensity;
   3141                       }
   3142                     count++;
   3143                   }
   3144                 k--;
   3145                 pixels+=GetPixelChannels(image);
   3146               }
   3147               pixels+=(image->columns-1)*GetPixelChannels(image);
   3148             }
   3149             break;
   3150           }
   3151           case IterativeDistanceMorphology:
   3152           {
   3153             /*
   3154                Compute th iterative distance from black edge of a white image
   3155                shape.  Essentually white values are decreased to the smallest
   3156                'distance from edge' it can find.
   3157 
   3158                It works by adding kernel values to the neighbourhood, and and
   3159                select the minimum value found. The kernel is rotated before
   3160                use, so kernel distances match resulting distances, when a user
   3161                provided asymmetric kernel is applied.
   3162 
   3163                This code is nearly identical to True GrayScale Morphology but
   3164                not quite.
   3165 
   3166                GreyDilate Kernel values added, maximum value found Kernel is
   3167                rotated before use.
   3168 
   3169                GrayErode:  Kernel values subtracted and minimum value found No
   3170                kernel rotation used.
   3171 
   3172                Note the the Iterative Distance method is essentially a
   3173                GrayErode, but with negative kernel values, and kernel rotation
   3174                applied.
   3175             */
   3176             k=(&kernel->values[kernel->width*kernel->height-1]);
   3177             for (v=0; v < (ssize_t) kernel->height; v++)
   3178             {
   3179               for (u=0; u < (ssize_t) kernel->width; u++)
   3180               {
   3181                 if (!IsNaN(*k))
   3182                   {
   3183                     if ((pixels[i]+(*k)) < pixel)
   3184                       pixel=(double) pixels[i]+(*k);
   3185                     count++;
   3186                   }
   3187                 k--;
   3188                 pixels+=GetPixelChannels(image);
   3189               }
   3190               pixels+=(image->columns-1)*GetPixelChannels(image);
   3191             }
   3192             break;
   3193           }
   3194           case UndefinedMorphology:
   3195           default:
   3196             break;
   3197         }
   3198         if (fabs(pixel-p[center+i]) > MagickEpsilon)
   3199           changes[id]++;
   3200         gamma=PerceptibleReciprocal(gamma);
   3201         if (count != 0)
   3202           gamma*=(double) kernel->height*kernel->width/count;
   3203         SetPixelChannel(morphology_image,channel,ClampToQuantum(gamma*pixel),q);
   3204       }
   3205       p+=GetPixelChannels(image);
   3206       q+=GetPixelChannels(morphology_image);
   3207     }
   3208     if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
   3209       status=MagickFalse;
   3210     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   3211       {
   3212         MagickBooleanType
   3213           proceed;
   3214 
   3215 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   3216         #pragma omp atomic
   3217 #endif
   3218         progress++;
   3219         proceed=SetImageProgress(image,MorphologyTag,progress,image->rows);
   3220         if (proceed == MagickFalse)
   3221           status=MagickFalse;
   3222       }
   3223   }
   3224   morphology_view=DestroyCacheView(morphology_view);
   3225   image_view=DestroyCacheView(image_view);
   3226   for (j=0; j < (ssize_t) GetOpenMPMaximumThreads(); j++)
   3227     changed+=changes[j];
   3228   changes=(size_t *) RelinquishMagickMemory(changes);
   3229   return(status ? (ssize_t) changed : -1);
   3230 }
   3231 
   3232 /*
   3233   This is almost identical to the MorphologyPrimative() function above, but
   3234   applies the primitive directly to the actual image using two passes, once in
   3235   each direction, with the results of the previous (and current) row being
   3236   re-used.
   3237 
   3238   That is after each row is 'Sync'ed' into the image, the next row makes use of
   3239   those values as part of the calculation of the next row.  It repeats, but
   3240   going in the oppisite (bottom-up) direction.
   3241 
   3242   Because of this 're-use of results' this function can not make use of multi-
   3243   threaded, parellel processing.
   3244 */
   3245 static ssize_t MorphologyPrimitiveDirect(Image *image,
   3246   const MorphologyMethod method,const KernelInfo *kernel,
   3247   ExceptionInfo *exception)
   3248 {
   3249   CacheView
   3250     *morphology_view,
   3251     *image_view;
   3252 
   3253   MagickBooleanType
   3254     status;
   3255 
   3256   MagickOffsetType
   3257     progress;
   3258 
   3259   OffsetInfo
   3260     offset;
   3261 
   3262   size_t
   3263     width,
   3264     changed;
   3265 
   3266   ssize_t
   3267     y;
   3268 
   3269   assert(image != (Image *) NULL);
   3270   assert(image->signature == MagickCoreSignature);
   3271   assert(kernel != (KernelInfo *) NULL);
   3272   assert(kernel->signature == MagickCoreSignature);
   3273   assert(exception != (ExceptionInfo *) NULL);
   3274   assert(exception->signature == MagickCoreSignature);
   3275   status=MagickTrue;
   3276   changed=0;
   3277   progress=0;
   3278   switch(method)
   3279   {
   3280     case DistanceMorphology:
   3281     case VoronoiMorphology:
   3282     {
   3283       /*
   3284         Kernel reflected about origin.
   3285       */
   3286       offset.x=(ssize_t) kernel->width-kernel->x-1;
   3287       offset.y=(ssize_t) kernel->height-kernel->y-1;
   3288       break;
   3289     }
   3290     default:
   3291     {
   3292       offset.x=kernel->x;
   3293       offset.y=kernel->y;
   3294       break;
   3295     }
   3296   }
   3297   /*
   3298     Two views into same image, do not thread.
   3299   */
   3300   image_view=AcquireVirtualCacheView(image,exception);
   3301   morphology_view=AcquireAuthenticCacheView(image,exception);
   3302   width=image->columns+kernel->width-1;
   3303   for (y=0; y < (ssize_t) image->rows; y++)
   3304   {
   3305     register const Quantum
   3306       *magick_restrict p;
   3307 
   3308     register Quantum
   3309       *magick_restrict q;
   3310 
   3311     register ssize_t
   3312       x;
   3313 
   3314     /*
   3315       Read virtual pixels, and authentic pixels, from the same image!  We read
   3316       using virtual to get virtual pixel handling, but write back into the same
   3317       image.
   3318 
   3319       Only top half of kernel is processed as we do a single pass downward
   3320       through the image iterating the distance function as we go.
   3321     */
   3322     if (status == MagickFalse)
   3323       continue;
   3324     p=GetCacheViewVirtualPixels(image_view,-offset.x,y-offset.y,width,(size_t)
   3325       offset.y+1,exception);
   3326     q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
   3327       exception);
   3328     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   3329       {
   3330         status=MagickFalse;
   3331         continue;
   3332       }
   3333     for (x=0; x < (ssize_t) image->columns; x++)
   3334     {
   3335       register ssize_t
   3336         i;
   3337 
   3338       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   3339       {
   3340         double
   3341           pixel;
   3342 
   3343         PixelChannel
   3344           channel;
   3345 
   3346         PixelTrait
   3347           traits;
   3348 
   3349         register const MagickRealType
   3350           *magick_restrict k;
   3351 
   3352         register const Quantum
   3353           *magick_restrict pixels;
   3354 
   3355         register ssize_t
   3356           u;
   3357 
   3358         ssize_t
   3359           v;
   3360 
   3361         channel=GetPixelChannelChannel(image,i);
   3362         traits=GetPixelChannelTraits(image,channel);
   3363         if (traits == UndefinedPixelTrait)
   3364           continue;
   3365         if ((traits & CopyPixelTrait) != 0)
   3366           continue;
   3367         pixels=p;
   3368         pixel=(double) QuantumRange;
   3369         switch (method)
   3370         {
   3371           case DistanceMorphology:
   3372           {
   3373             k=(&kernel->values[kernel->width*kernel->height-1]);
   3374             for (v=0; v <= offset.y; v++)
   3375             {
   3376               for (u=0; u < (ssize_t) kernel->width; u++)
   3377               {
   3378                 if (!IsNaN(*k))
   3379                   {
   3380                     if ((pixels[i]+(*k)) < pixel)
   3381                       pixel=(double) pixels[i]+(*k);
   3382                   }
   3383                 k--;
   3384                 pixels+=GetPixelChannels(image);
   3385               }
   3386               pixels+=(image->columns-1)*GetPixelChannels(image);
   3387             }
   3388             k=(&kernel->values[kernel->width*(kernel->y+1)-1]);
   3389             pixels=q-offset.x*GetPixelChannels(image);
   3390             for (u=0; u < offset.x; u++)
   3391             {
   3392               if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
   3393                 {
   3394                   if ((pixels[i]+(*k)) < pixel)
   3395                     pixel=(double) pixels[i]+(*k);
   3396                 }
   3397               k--;
   3398               pixels+=GetPixelChannels(image);
   3399             }
   3400             break;
   3401           }
   3402           case VoronoiMorphology:
   3403           {
   3404             k=(&kernel->values[kernel->width*kernel->height-1]);
   3405             for (v=0; v < offset.y; v++)
   3406             {
   3407               for (u=0; u < (ssize_t) kernel->width; u++)
   3408               {
   3409                 if (!IsNaN(*k))
   3410                   {
   3411                     if ((pixels[i]+(*k)) < pixel)
   3412                       pixel=(double) pixels[i]+(*k);
   3413                   }
   3414                 k--;
   3415                 pixels+=GetPixelChannels(image);
   3416               }
   3417               pixels+=(image->columns-1)*GetPixelChannels(image);
   3418             }
   3419             k=(&kernel->values[kernel->width*(kernel->y+1)-1]);
   3420             pixels=q-offset.x*GetPixelChannels(image);
   3421             for (u=0; u < offset.x; u++)
   3422             {
   3423               if (!IsNaN(*k) && ((x+u-offset.x) >= 0))
   3424                 {
   3425                   if ((pixels[i]+(*k)) < pixel)
   3426                     pixel=(double) pixels[i]+(*k);
   3427                 }
   3428               k--;
   3429               pixels+=GetPixelChannels(image);
   3430             }
   3431             break;
   3432           }
   3433           default:
   3434             break;
   3435         }
   3436         if (fabs(pixel-q[i]) > MagickEpsilon)
   3437           changed++;
   3438         q[i]=ClampToQuantum(pixel);
   3439       }
   3440       p+=GetPixelChannels(image);
   3441       q+=GetPixelChannels(image);
   3442     }
   3443     if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
   3444       status=MagickFalse;
   3445     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   3446       {
   3447         MagickBooleanType
   3448           proceed;
   3449 
   3450 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   3451         #pragma omp atomic
   3452 #endif
   3453         progress++;
   3454         proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
   3455         if (proceed == MagickFalse)
   3456           status=MagickFalse;
   3457       }
   3458   }
   3459   morphology_view=DestroyCacheView(morphology_view);
   3460   image_view=DestroyCacheView(image_view);
   3461   /*
   3462     Do the reverse pass through the image.
   3463   */
   3464   image_view=AcquireVirtualCacheView(image,exception);
   3465   morphology_view=AcquireAuthenticCacheView(image,exception);
   3466   for (y=(ssize_t) image->rows-1; y >= 0; y--)
   3467   {
   3468     register const Quantum
   3469       *magick_restrict p;
   3470 
   3471     register Quantum
   3472       *magick_restrict q;
   3473 
   3474     register ssize_t
   3475       x;
   3476 
   3477     /*
   3478        Read virtual pixels, and authentic pixels, from the same image.  We
   3479        read using virtual to get virtual pixel handling, but write back
   3480        into the same image.
   3481 
   3482        Only the bottom half of the kernel is processed as we up the image.
   3483     */
   3484     if (status == MagickFalse)
   3485       continue;
   3486     p=GetCacheViewVirtualPixels(image_view,-offset.x,y,width,(size_t)
   3487       kernel->y+1,exception);
   3488     q=GetCacheViewAuthenticPixels(morphology_view,0,y,image->columns,1,
   3489       exception);
   3490     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
   3491       {
   3492         status=MagickFalse;
   3493         continue;
   3494       }
   3495     p+=(image->columns-1)*GetPixelChannels(image);
   3496     q+=(image->columns-1)*GetPixelChannels(image);
   3497     for (x=(ssize_t) image->columns-1; x >= 0; x--)
   3498     {
   3499       register ssize_t
   3500         i;
   3501 
   3502       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   3503       {
   3504         double
   3505           pixel;
   3506 
   3507         PixelChannel
   3508           channel;
   3509 
   3510         PixelTrait
   3511           traits;
   3512 
   3513         register const MagickRealType
   3514           *magick_restrict k;
   3515 
   3516         register const Quantum
   3517           *magick_restrict pixels;
   3518 
   3519         register ssize_t
   3520           u;
   3521 
   3522         ssize_t
   3523           v;
   3524 
   3525         channel=GetPixelChannelChannel(image,i);
   3526         traits=GetPixelChannelTraits(image,channel);
   3527         if (traits == UndefinedPixelTrait)
   3528           continue;
   3529         if ((traits & CopyPixelTrait) != 0)
   3530           continue;
   3531         pixels=p;
   3532         pixel=(double) QuantumRange;
   3533         switch (method)
   3534         {
   3535           case DistanceMorphology:
   3536           {
   3537             k=(&kernel->values[kernel->width*(kernel->y+1)-1]);
   3538             for (v=offset.y; v < (ssize_t) kernel->height; v++)
   3539             {
   3540               for (u=0; u < (ssize_t) kernel->width; u++)
   3541               {
   3542                 if (!IsNaN(*k))
   3543                   {
   3544                     if ((pixels[i]+(*k)) < pixel)
   3545                       pixel=(double) pixels[i]+(*k);
   3546                   }
   3547                 k--;
   3548                 pixels+=GetPixelChannels(image);
   3549               }
   3550               pixels+=(image->columns-1)*GetPixelChannels(image);
   3551             }
   3552             k=(&kernel->values[kernel->width*kernel->y+kernel->x-1]);
   3553             pixels=q;
   3554             for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
   3555             {
   3556               pixels+=GetPixelChannels(image);
   3557               if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
   3558                 {
   3559                   if ((pixels[i]+(*k)) < pixel)
   3560                     pixel=(double) pixels[i]+(*k);
   3561                 }
   3562               k--;
   3563             }
   3564             break;
   3565           }
   3566           case VoronoiMorphology:
   3567           {
   3568             k=(&kernel->values[kernel->width*(kernel->y+1)-1]);
   3569             for (v=offset.y; v < (ssize_t) kernel->height; v++)
   3570             {
   3571               for (u=0; u < (ssize_t) kernel->width; u++)
   3572               {
   3573                 if (!IsNaN(*k))
   3574                   {
   3575                     if ((pixels[i]+(*k)) < pixel)
   3576                       pixel=(double) pixels[i]+(*k);
   3577                   }
   3578                 k--;
   3579                 pixels+=GetPixelChannels(image);
   3580               }
   3581               pixels+=(image->columns-1)*GetPixelChannels(image);
   3582             }
   3583             k=(&kernel->values[kernel->width*(kernel->y+1)-1]);
   3584             pixels=q;
   3585             for (u=offset.x+1; u < (ssize_t) kernel->width; u++)
   3586             {
   3587               pixels+=GetPixelChannels(image);
   3588               if (!IsNaN(*k) && ((x+u-offset.x) < (ssize_t) image->columns))
   3589                 {
   3590                   if ((pixels[i]+(*k)) < pixel)
   3591                     pixel=(double) pixels[i]+(*k);
   3592                 }
   3593               k--;
   3594             }
   3595             break;
   3596           }
   3597           default:
   3598             break;
   3599         }
   3600         if (fabs(pixel-q[i]) > MagickEpsilon)
   3601           changed++;
   3602         q[i]=ClampToQuantum(pixel);
   3603       }
   3604       p-=GetPixelChannels(image);
   3605       q-=GetPixelChannels(image);
   3606     }
   3607     if (SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
   3608       status=MagickFalse;
   3609     if (image->progress_monitor != (MagickProgressMonitor) NULL)
   3610       {
   3611         MagickBooleanType
   3612           proceed;
   3613 
   3614 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   3615         #pragma omp atomic
   3616 #endif
   3617         progress++;
   3618         proceed=SetImageProgress(image,MorphologyTag,progress,2*image->rows);
   3619         if (proceed == MagickFalse)
   3620           status=MagickFalse;
   3621       }
   3622   }
   3623   morphology_view=DestroyCacheView(morphology_view);
   3624   image_view=DestroyCacheView(image_view);
   3625   return(status ? (ssize_t) changed : -1);
   3626 }
   3627 
   3628 /*
   3629   Apply a Morphology by calling one of the above low level primitive
   3630   application functions.  This function handles any iteration loops,
   3631   composition or re-iteration of results, and compound morphology methods that
   3632   is based on multiple low-level (staged) morphology methods.
   3633 
   3634   Basically this provides the complex glue between the requested morphology
   3635   method and raw low-level implementation (above).
   3636 */
   3637 MagickPrivate Image *MorphologyApply(const Image *image,
   3638   const MorphologyMethod method, const ssize_t iterations,
   3639   const KernelInfo *kernel, const CompositeOperator compose,const double bias,
   3640   ExceptionInfo *exception)
   3641 {
   3642   CompositeOperator
   3643     curr_compose;
   3644 
   3645   Image
   3646     *curr_image,    /* Image we are working with or iterating */
   3647     *work_image,    /* secondary image for primitive iteration */
   3648     *save_image,    /* saved image - for 'edge' method only */
   3649     *rslt_image;    /* resultant image - after multi-kernel handling */
   3650 
   3651   KernelInfo
   3652     *reflected_kernel, /* A reflected copy of the kernel (if needed) */
   3653     *norm_kernel,      /* the current normal un-reflected kernel */
   3654     *rflt_kernel,      /* the current reflected kernel (if needed) */
   3655     *this_kernel;      /* the kernel being applied */
   3656 
   3657   MorphologyMethod
   3658     primitive;      /* the current morphology primitive being applied */
   3659 
   3660   CompositeOperator
   3661     rslt_compose;   /* multi-kernel compose method for results to use */
   3662 
   3663   MagickBooleanType
   3664     special,        /* do we use a direct modify function? */
   3665     verbose;        /* verbose output of results */
   3666 
   3667   size_t
   3668     method_loop,    /* Loop 1: number of compound method iterations (norm 1) */
   3669     method_limit,   /*         maximum number of compound method iterations */
   3670     kernel_number,  /* Loop 2: the kernel number being applied */
   3671     stage_loop,     /* Loop 3: primitive loop for compound morphology */
   3672     stage_limit,    /*         how many primitives are in this compound */
   3673     kernel_loop,    /* Loop 4: iterate the kernel over image */
   3674     kernel_limit,   /*         number of times to iterate kernel */
   3675     count,          /* total count of primitive steps applied */
   3676     kernel_changed, /* total count of changed using iterated kernel */
   3677     method_changed; /* total count of changed over method iteration */
   3678 
   3679   ssize_t
   3680     changed;        /* number pixels changed by last primitive operation */
   3681 
   3682   char
   3683     v_info[MagickPathExtent];
   3684 
   3685   assert(image != (Image *) NULL);
   3686   assert(image->signature == MagickCoreSignature);
   3687   assert(kernel != (KernelInfo *) NULL);
   3688   assert(kernel->signature == MagickCoreSignature);
   3689   assert(exception != (ExceptionInfo *) NULL);
   3690   assert(exception->signature == MagickCoreSignature);
   3691 
   3692   count = 0;      /* number of low-level morphology primitives performed */
   3693   if ( iterations == 0 )
   3694     return((Image *) NULL);   /* null operation - nothing to do! */
   3695 
   3696   kernel_limit = (size_t) iterations;
   3697   if ( iterations < 0 )  /* negative interations = infinite (well alomst) */
   3698      kernel_limit = image->columns>image->rows ? image->columns : image->rows;
   3699 
   3700   verbose = IsStringTrue(GetImageArtifact(image,"debug"));
   3701 
   3702   /* initialise for cleanup */
   3703   curr_image = (Image *) image;
   3704   curr_compose = image->compose;
   3705   (void) curr_compose;
   3706   work_image = save_image = rslt_image = (Image *) NULL;
   3707   reflected_kernel = (KernelInfo *) NULL;
   3708 
   3709   /* Initialize specific methods
   3710    * + which loop should use the given iteratations
   3711    * + how many primitives make up the compound morphology
   3712    * + multi-kernel compose method to use (by default)
   3713    */
   3714   method_limit = 1;       /* just do method once, unless otherwise set */
   3715   stage_limit = 1;        /* assume method is not a compound */
   3716   special = MagickFalse;   /* assume it is NOT a direct modify primitive */
   3717   rslt_compose = compose; /* and we are composing multi-kernels as given */
   3718   switch( method ) {
   3719     case SmoothMorphology:  /* 4 primitive compound morphology */
   3720       stage_limit = 4;
   3721       break;
   3722     case OpenMorphology:    /* 2 primitive compound morphology */
   3723     case OpenIntensityMorphology:
   3724     case TopHatMorphology:
   3725     case CloseMorphology:
   3726     case CloseIntensityMorphology:
   3727     case BottomHatMorphology:
   3728     case EdgeMorphology:
   3729       stage_limit = 2;
   3730       break;
   3731     case HitAndMissMorphology:
   3732       rslt_compose = LightenCompositeOp;  /* Union of multi-kernel results */
   3733       /* FALL THUR */
   3734     case ThinningMorphology:
   3735     case ThickenMorphology:
   3736       method_limit = kernel_limit;  /* iterate the whole method */
   3737       kernel_limit = 1;             /* do not do kernel iteration  */
   3738       break;
   3739     case DistanceMorphology:
   3740     case VoronoiMorphology:
   3741       special = MagickTrue;         /* use special direct primative */
   3742       break;
   3743     default:
   3744       break;
   3745   }
   3746 
   3747   /* Apply special methods with special requirments
   3748   ** For example, single run only, or post-processing requirements
   3749   */
   3750   if ( special != MagickFalse )
   3751     {
   3752       rslt_image=CloneImage(image,0,0,MagickTrue,exception);
   3753       if (rslt_image == (Image *) NULL)
   3754         goto error_cleanup;
   3755       if (SetImageStorageClass(rslt_image,DirectClass,exception) == MagickFalse)
   3756         goto error_cleanup;
   3757 
   3758       changed=MorphologyPrimitiveDirect(rslt_image,method,kernel,exception);
   3759 
   3760       if (verbose != MagickFalse)
   3761         (void) (void) FormatLocaleFile(stderr,
   3762           "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
   3763           CommandOptionToMnemonic(MagickMorphologyOptions, method),
   3764           1.0,0.0,1.0, (double) changed);
   3765 
   3766       if ( changed < 0 )
   3767         goto error_cleanup;
   3768 
   3769       if ( method == VoronoiMorphology ) {
   3770         /* Preserve the alpha channel of input image - but turned it off */
   3771         (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
   3772           exception);
   3773         (void) CompositeImage(rslt_image,image,CopyAlphaCompositeOp,
   3774           MagickTrue,0,0,exception);
   3775         (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel,
   3776           exception);
   3777       }
   3778       goto exit_cleanup;
   3779     }
   3780 
   3781   /* Handle user (caller) specified multi-kernel composition method */
   3782   if ( compose != UndefinedCompositeOp )
   3783     rslt_compose = compose;  /* override default composition for method */
   3784   if ( rslt_compose == UndefinedCompositeOp )
   3785     rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */
   3786 
   3787   /* Some methods require a reflected kernel to use with primitives.
   3788    * Create the reflected kernel for those methods. */
   3789   switch ( method ) {
   3790     case CorrelateMorphology:
   3791     case CloseMorphology:
   3792     case CloseIntensityMorphology:
   3793     case BottomHatMorphology:
   3794     case SmoothMorphology:
   3795       reflected_kernel = CloneKernelInfo(kernel);
   3796       if (reflected_kernel == (KernelInfo *) NULL)
   3797         goto error_cleanup;
   3798       RotateKernelInfo(reflected_kernel,180);
   3799       break;
   3800     default:
   3801       break;
   3802   }
   3803 
   3804   /* Loops around more primitive morpholgy methods
   3805   **  erose, dilate, open, close, smooth, edge, etc...
   3806   */
   3807   /* Loop 1:  iterate the compound method */
   3808   method_loop = 0;
   3809   method_changed = 1;
   3810   while ( method_loop < method_limit && method_changed > 0 ) {
   3811     method_loop++;
   3812     method_changed = 0;
   3813 
   3814     /* Loop 2:  iterate over each kernel in a multi-kernel list */
   3815     norm_kernel = (KernelInfo *) kernel;
   3816     this_kernel = (KernelInfo *) kernel;
   3817     rflt_kernel = reflected_kernel;
   3818 
   3819     kernel_number = 0;
   3820     while ( norm_kernel != NULL ) {
   3821 
   3822       /* Loop 3: Compound Morphology Staging - Select Primative to apply */
   3823       stage_loop = 0;          /* the compound morphology stage number */
   3824       while ( stage_loop < stage_limit ) {
   3825         stage_loop++;   /* The stage of the compound morphology */
   3826 
   3827         /* Select primitive morphology for this stage of compound method */
   3828         this_kernel = norm_kernel; /* default use unreflected kernel */
   3829         primitive = method;        /* Assume method is a primitive */
   3830         switch( method ) {
   3831           case ErodeMorphology:      /* just erode */
   3832           case EdgeInMorphology:     /* erode and image difference */
   3833             primitive = ErodeMorphology;
   3834             break;
   3835           case DilateMorphology:     /* just dilate */
   3836           case EdgeOutMorphology:    /* dilate and image difference */
   3837             primitive = DilateMorphology;
   3838             break;
   3839           case OpenMorphology:       /* erode then dialate */
   3840           case TopHatMorphology:     /* open and image difference */
   3841             primitive = ErodeMorphology;
   3842             if ( stage_loop == 2 )
   3843               primitive = DilateMorphology;
   3844             break;
   3845           case OpenIntensityMorphology:
   3846             primitive = ErodeIntensityMorphology;
   3847             if ( stage_loop == 2 )
   3848               primitive = DilateIntensityMorphology;
   3849             break;
   3850           case CloseMorphology:      /* dilate, then erode */
   3851           case BottomHatMorphology:  /* close and image difference */
   3852             this_kernel = rflt_kernel; /* use the reflected kernel */
   3853             primitive = DilateMorphology;
   3854             if ( stage_loop == 2 )
   3855               primitive = ErodeMorphology;
   3856             break;
   3857           case CloseIntensityMorphology:
   3858             this_kernel = rflt_kernel; /* use the reflected kernel */
   3859             primitive = DilateIntensityMorphology;
   3860             if ( stage_loop == 2 )
   3861               primitive = ErodeIntensityMorphology;
   3862             break;
   3863           case SmoothMorphology:         /* open, close */
   3864             switch ( stage_loop ) {
   3865               case 1: /* start an open method, which starts with Erode */
   3866                 primitive = ErodeMorphology;
   3867                 break;
   3868               case 2:  /* now Dilate the Erode */
   3869                 primitive = DilateMorphology;
   3870                 break;
   3871               case 3:  /* Reflect kernel a close */
   3872                 this_kernel = rflt_kernel; /* use the reflected kernel */
   3873                 primitive = DilateMorphology;
   3874                 break;
   3875               case 4:  /* Finish the Close */
   3876                 this_kernel = rflt_kernel; /* use the reflected kernel */
   3877                 primitive = ErodeMorphology;
   3878                 break;
   3879             }
   3880             break;
   3881           case EdgeMorphology:        /* dilate and erode difference */
   3882             primitive = DilateMorphology;
   3883             if ( stage_loop == 2 ) {
   3884               save_image = curr_image;      /* save the image difference */
   3885               curr_image = (Image *) image;
   3886               primitive = ErodeMorphology;
   3887             }
   3888             break;
   3889           case CorrelateMorphology:
   3890             /* A Correlation is a Convolution with a reflected kernel.
   3891             ** However a Convolution is a weighted sum using a reflected
   3892             ** kernel.  It may seem stange to convert a Correlation into a
   3893             ** Convolution as the Correlation is the simplier method, but
   3894             ** Convolution is much more commonly used, and it makes sense to
   3895             ** implement it directly so as to avoid the need to duplicate the
   3896             ** kernel when it is not required (which is typically the
   3897             ** default).
   3898             */
   3899             this_kernel = rflt_kernel; /* use the reflected kernel */
   3900             primitive = ConvolveMorphology;
   3901             break;
   3902           default:
   3903             break;
   3904         }
   3905         assert( this_kernel != (KernelInfo *) NULL );
   3906 
   3907         /* Extra information for debugging compound operations */
   3908         if (verbose != MagickFalse) {
   3909           if ( stage_limit > 1 )
   3910             (void) FormatLocaleString(v_info,MagickPathExtent,"%s:%.20g.%.20g -> ",
   3911              CommandOptionToMnemonic(MagickMorphologyOptions,method),(double)
   3912              method_loop,(double) stage_loop);
   3913           else if ( primitive != method )
   3914             (void) FormatLocaleString(v_info, MagickPathExtent, "%s:%.20g -> ",
   3915               CommandOptionToMnemonic(MagickMorphologyOptions, method),(double)
   3916               method_loop);
   3917           else
   3918             v_info[0] = '\0';
   3919         }
   3920 
   3921         /* Loop 4: Iterate the kernel with primitive */
   3922         kernel_loop = 0;
   3923         kernel_changed = 0;
   3924         changed = 1;
   3925         while ( kernel_loop < kernel_limit && changed > 0 ) {
   3926           kernel_loop++;     /* the iteration of this kernel */
   3927 
   3928           /* Create a clone as the destination image, if not yet defined */
   3929           if ( work_image == (Image *) NULL )
   3930             {
   3931               work_image=CloneImage(image,0,0,MagickTrue,exception);
   3932               if (work_image == (Image *) NULL)
   3933                 goto error_cleanup;
   3934               if (SetImageStorageClass(work_image,DirectClass,exception) == MagickFalse)
   3935                 goto error_cleanup;
   3936             }
   3937 
   3938           /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */
   3939           count++;
   3940           changed = MorphologyPrimitive(curr_image, work_image, primitive,
   3941                        this_kernel, bias, exception);
   3942           if (verbose != MagickFalse) {
   3943             if ( kernel_loop > 1 )
   3944               (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */
   3945             (void) (void) FormatLocaleFile(stderr,
   3946               "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
   3947               v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
   3948               primitive),(this_kernel == rflt_kernel ) ? "*" : "",
   3949               (double) (method_loop+kernel_loop-1),(double) kernel_number,
   3950               (double) count,(double) changed);
   3951           }
   3952           if ( changed < 0 )
   3953             goto error_cleanup;
   3954           kernel_changed += changed;
   3955           method_changed += changed;
   3956 
   3957           /* prepare next loop */
   3958           { Image *tmp = work_image;   /* swap images for iteration */
   3959             work_image = curr_image;
   3960             curr_image = tmp;
   3961           }
   3962           if ( work_image == image )
   3963             work_image = (Image *) NULL; /* replace input 'image' */
   3964 
   3965         } /* End Loop 4: Iterate the kernel with primitive */
   3966 
   3967         if (verbose != MagickFalse && kernel_changed != (size_t)changed)
   3968           (void) FormatLocaleFile(stderr, "   Total %.20g",(double) kernel_changed);
   3969         if (verbose != MagickFalse && stage_loop < stage_limit)
   3970           (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */
   3971 
   3972 #if 0
   3973     (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image);
   3974     (void) FormatLocaleFile(stderr, "      curr =0x%lx\n", (unsigned long)curr_image);
   3975     (void) FormatLocaleFile(stderr, "      work =0x%lx\n", (unsigned long)work_image);
   3976     (void) FormatLocaleFile(stderr, "      save =0x%lx\n", (unsigned long)save_image);
   3977     (void) FormatLocaleFile(stderr, "      union=0x%lx\n", (unsigned long)rslt_image);
   3978 #endif
   3979 
   3980       } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */
   3981 
   3982       /*  Final Post-processing for some Compound Methods
   3983       **
   3984       ** The removal of any 'Sync' channel flag in the Image Compositon
   3985       ** below ensures the methematical compose method is applied in a
   3986       ** purely mathematical way, and only to the selected channels.
   3987       ** Turn off SVG composition 'alpha blending'.
   3988       */
   3989       switch( method ) {
   3990         case EdgeOutMorphology:
   3991         case EdgeInMorphology:
   3992         case TopHatMorphology:
   3993         case BottomHatMorphology:
   3994           if (verbose != MagickFalse)
   3995             (void) FormatLocaleFile(stderr,
   3996               "\n%s: Difference with original image",CommandOptionToMnemonic(
   3997               MagickMorphologyOptions, method) );
   3998           (void) CompositeImage(curr_image,image,DifferenceCompositeOp,
   3999             MagickTrue,0,0,exception);
   4000           break;
   4001         case EdgeMorphology:
   4002           if (verbose != MagickFalse)
   4003             (void) FormatLocaleFile(stderr,
   4004               "\n%s: Difference of Dilate and Erode",CommandOptionToMnemonic(
   4005               MagickMorphologyOptions, method) );
   4006           (void) CompositeImage(curr_image,save_image,DifferenceCompositeOp,
   4007             MagickTrue,0,0,exception);
   4008           save_image = DestroyImage(save_image); /* finished with save image */
   4009           break;
   4010         default:
   4011           break;
   4012       }
   4013 
   4014       /* multi-kernel handling:  re-iterate, or compose results */
   4015       if ( kernel->next == (KernelInfo *) NULL )
   4016         rslt_image = curr_image;   /* just return the resulting image */
   4017       else if ( rslt_compose == NoCompositeOp )
   4018         { if (verbose != MagickFalse) {
   4019             if ( this_kernel->next != (KernelInfo *) NULL )
   4020               (void) FormatLocaleFile(stderr, " (re-iterate)");
   4021             else
   4022               (void) FormatLocaleFile(stderr, " (done)");
   4023           }
   4024           rslt_image = curr_image; /* return result, and re-iterate */
   4025         }
   4026       else if ( rslt_image == (Image *) NULL)
   4027         { if (verbose != MagickFalse)
   4028             (void) FormatLocaleFile(stderr, " (save for compose)");
   4029           rslt_image = curr_image;
   4030           curr_image = (Image *) image;  /* continue with original image */
   4031         }
   4032       else
   4033         { /* Add the new 'current' result to the composition
   4034           **
   4035           ** The removal of any 'Sync' channel flag in the Image Compositon
   4036           ** below ensures the methematical compose method is applied in a
   4037           ** purely mathematical way, and only to the selected channels.
   4038           ** IE: Turn off SVG composition 'alpha blending'.
   4039           */
   4040           if (verbose != MagickFalse)
   4041             (void) FormatLocaleFile(stderr, " (compose \"%s\")",
   4042               CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
   4043           (void) CompositeImage(rslt_image,curr_image,rslt_compose,MagickTrue,
   4044             0,0,exception);
   4045           curr_image = DestroyImage(curr_image);
   4046           curr_image = (Image *) image;  /* continue with original image */
   4047         }
   4048       if (verbose != MagickFalse)
   4049         (void) FormatLocaleFile(stderr, "\n");
   4050 
   4051       /* loop to the next kernel in a multi-kernel list */
   4052       norm_kernel = norm_kernel->next;
   4053       if ( rflt_kernel != (KernelInfo *) NULL )
   4054         rflt_kernel = rflt_kernel->next;
   4055       kernel_number++;
   4056     } /* End Loop 2: Loop over each kernel */
   4057 
   4058   } /* End Loop 1: compound method interation */
   4059 
   4060   goto exit_cleanup;
   4061 
   4062   /* Yes goto's are bad, but it makes cleanup lot more efficient */
   4063 error_cleanup:
   4064   if ( curr_image == rslt_image )
   4065     curr_image = (Image *) NULL;
   4066   if ( rslt_image != (Image *) NULL )
   4067     rslt_image = DestroyImage(rslt_image);
   4068 exit_cleanup:
   4069   if ( curr_image == rslt_image || curr_image == image )
   4070     curr_image = (Image *) NULL;
   4071   if ( curr_image != (Image *) NULL )
   4072     curr_image = DestroyImage(curr_image);
   4073   if ( work_image != (Image *) NULL )
   4074     work_image = DestroyImage(work_image);
   4075   if ( save_image != (Image *) NULL )
   4076     save_image = DestroyImage(save_image);
   4077   if ( reflected_kernel != (KernelInfo *) NULL )
   4078     reflected_kernel = DestroyKernelInfo(reflected_kernel);
   4079   return(rslt_image);
   4080 }
   4081 
   4082 
   4083 /*
   4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4086 %                                                                             %
   4087 %                                                                             %
   4088 %                                                                             %
   4089 %     M o r p h o l o g y I m a g e                                           %
   4090 %                                                                             %
   4091 %                                                                             %
   4092 %                                                                             %
   4093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4094 %
   4095 %  MorphologyImage() applies a user supplied kernel to the image according to
   4096 %  the given mophology method.
   4097 %
   4098 %  This function applies any and all user defined settings before calling
   4099 %  the above internal function MorphologyApply().
   4100 %
   4101 %  User defined settings include...
   4102 %    * Output Bias for Convolution and correlation ("-define convolve:bias=??")
   4103 %    * Kernel Scale/normalize settings            ("-define convolve:scale=??")
   4104 %      This can also includes the addition of a scaled unity kernel.
   4105 %    * Show Kernel being applied            ("-define morphology:showKernel=1")
   4106 %
   4107 %  Other operators that do not want user supplied options interfering,
   4108 %  especially "convolve:bias" and "morphology:showKernel" should use
   4109 %  MorphologyApply() directly.
   4110 %
   4111 %  The format of the MorphologyImage method is:
   4112 %
   4113 %      Image *MorphologyImage(const Image *image,MorphologyMethod method,
   4114 %        const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception)
   4115 %
   4116 %  A description of each parameter follows:
   4117 %
   4118 %    o image: the image.
   4119 %
   4120 %    o method: the morphology method to be applied.
   4121 %
   4122 %    o iterations: apply the operation this many times (or no change).
   4123 %                  A value of -1 means loop until no change found.
   4124 %                  How this is applied may depend on the morphology method.
   4125 %                  Typically this is a value of 1.
   4126 %
   4127 %    o kernel: An array of double representing the morphology kernel.
   4128 %              Warning: kernel may be normalized for the Convolve method.
   4129 %
   4130 %    o exception: return any errors or warnings in this structure.
   4131 %
   4132 */
   4133 MagickExport Image *MorphologyImage(const Image *image,
   4134   const MorphologyMethod method,const ssize_t iterations,
   4135   const KernelInfo *kernel,ExceptionInfo *exception)
   4136 {
   4137   const char
   4138     *artifact;
   4139 
   4140   CompositeOperator
   4141     compose;
   4142 
   4143   double
   4144     bias;
   4145 
   4146   Image
   4147     *morphology_image;
   4148 
   4149   KernelInfo
   4150     *curr_kernel;
   4151 
   4152   curr_kernel = (KernelInfo *) kernel;
   4153   bias=0.0;
   4154   compose = UndefinedCompositeOp;  /* use default for method */
   4155 
   4156   /* Apply Convolve/Correlate Normalization and Scaling Factors.
   4157    * This is done BEFORE the ShowKernelInfo() function is called so that
   4158    * users can see the results of the 'option:convolve:scale' option.
   4159    */
   4160   if ( method == ConvolveMorphology || method == CorrelateMorphology ) {
   4161       /* Get the bias value as it will be needed */
   4162       artifact = GetImageArtifact(image,"convolve:bias");
   4163       if ( artifact != (const char *) NULL) {
   4164         if (IsGeometry(artifact) == MagickFalse)
   4165           (void) ThrowMagickException(exception,GetMagickModule(),
   4166                OptionWarning,"InvalidSetting","'%s' '%s'",
   4167                "convolve:bias",artifact);
   4168         else
   4169           bias=StringToDoubleInterval(artifact,(double) QuantumRange+1.0);
   4170       }
   4171 
   4172       /* Scale kernel according to user wishes */
   4173       artifact = GetImageArtifact(image,"convolve:scale");
   4174       if ( artifact != (const char *) NULL ) {
   4175         if (IsGeometry(artifact) == MagickFalse)
   4176           (void) ThrowMagickException(exception,GetMagickModule(),
   4177                OptionWarning,"InvalidSetting","'%s' '%s'",
   4178                "convolve:scale",artifact);
   4179         else {
   4180           if ( curr_kernel == kernel )
   4181             curr_kernel = CloneKernelInfo(kernel);
   4182           if (curr_kernel == (KernelInfo *) NULL)
   4183             return((Image *) NULL);
   4184           ScaleGeometryKernelInfo(curr_kernel, artifact);
   4185         }
   4186       }
   4187     }
   4188 
   4189   /* display the (normalized) kernel via stderr */
   4190   artifact=GetImageArtifact(image,"morphology:showKernel");
   4191   if (IsStringTrue(artifact) != MagickFalse)
   4192     ShowKernelInfo(curr_kernel);
   4193 
   4194   /* Override the default handling of multi-kernel morphology results
   4195    * If 'Undefined' use the default method
   4196    * If 'None' (default for 'Convolve') re-iterate previous result
   4197    * Otherwise merge resulting images using compose method given.
   4198    * Default for 'HitAndMiss' is 'Lighten'.
   4199    */
   4200   {
   4201     ssize_t
   4202       parse;
   4203 
   4204     artifact = GetImageArtifact(image,"morphology:compose");
   4205     if ( artifact != (const char *) NULL) {
   4206       parse=ParseCommandOption(MagickComposeOptions,
   4207         MagickFalse,artifact);
   4208       if ( parse < 0 )
   4209         (void) ThrowMagickException(exception,GetMagickModule(),
   4210              OptionWarning,"UnrecognizedComposeOperator","'%s' '%s'",
   4211              "morphology:compose",artifact);
   4212       else
   4213         compose=(CompositeOperator)parse;
   4214     }
   4215   }
   4216   /* Apply the Morphology */
   4217   morphology_image = MorphologyApply(image,method,iterations,
   4218     curr_kernel,compose,bias,exception);
   4219 
   4220   /* Cleanup and Exit */
   4221   if ( curr_kernel != kernel )
   4222     curr_kernel=DestroyKernelInfo(curr_kernel);
   4223   return(morphology_image);
   4224 }
   4225 
   4226 /*
   4228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4229 %                                                                             %
   4230 %                                                                             %
   4231 %                                                                             %
   4232 +     R o t a t e K e r n e l I n f o                                         %
   4233 %                                                                             %
   4234 %                                                                             %
   4235 %                                                                             %
   4236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4237 %
   4238 %  RotateKernelInfo() rotates the kernel by the angle given.
   4239 %
   4240 %  Currently it is restricted to 90 degree angles, of either 1D kernels
   4241 %  or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels.
   4242 %  It will ignore usless rotations for specific 'named' built-in kernels.
   4243 %
   4244 %  The format of the RotateKernelInfo method is:
   4245 %
   4246 %      void RotateKernelInfo(KernelInfo *kernel, double angle)
   4247 %
   4248 %  A description of each parameter follows:
   4249 %
   4250 %    o kernel: the Morphology/Convolution kernel
   4251 %
   4252 %    o angle: angle to rotate in degrees
   4253 %
   4254 % This function is currently internal to this module only, but can be exported
   4255 % to other modules if needed.
   4256 */
   4257 static void RotateKernelInfo(KernelInfo *kernel, double angle)
   4258 {
   4259   /* angle the lower kernels first */
   4260   if ( kernel->next != (KernelInfo *) NULL)
   4261     RotateKernelInfo(kernel->next, angle);
   4262 
   4263   /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical
   4264   **
   4265   ** TODO: expand beyond simple 90 degree rotates, flips and flops
   4266   */
   4267 
   4268   /* Modulus the angle */
   4269   angle = fmod(angle, 360.0);
   4270   if ( angle < 0 )
   4271     angle += 360.0;
   4272 
   4273   if ( 337.5 < angle || angle <= 22.5 )
   4274     return;   /* Near zero angle - no change! - At least not at this time */
   4275 
   4276   /* Handle special cases */
   4277   switch (kernel->type) {
   4278     /* These built-in kernels are cylindrical kernels, rotating is useless */
   4279     case GaussianKernel:
   4280     case DoGKernel:
   4281     case LoGKernel:
   4282     case DiskKernel:
   4283     case PeaksKernel:
   4284     case LaplacianKernel:
   4285     case ChebyshevKernel:
   4286     case ManhattanKernel:
   4287     case EuclideanKernel:
   4288       return;
   4289 
   4290     /* These may be rotatable at non-90 angles in the future */
   4291     /* but simply rotating them in multiples of 90 degrees is useless */
   4292     case SquareKernel:
   4293     case DiamondKernel:
   4294     case PlusKernel:
   4295     case CrossKernel:
   4296       return;
   4297 
   4298     /* These only allows a +/-90 degree rotation (by transpose) */
   4299     /* A 180 degree rotation is useless */
   4300     case BlurKernel:
   4301       if ( 135.0 < angle && angle <= 225.0 )
   4302         return;
   4303       if ( 225.0 < angle && angle <= 315.0 )
   4304         angle -= 180;
   4305       break;
   4306 
   4307     default:
   4308       break;
   4309   }
   4310   /* Attempt rotations by 45 degrees  -- 3x3 kernels only */
   4311   if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
   4312     {
   4313       if ( kernel->width == 3 && kernel->height == 3 )
   4314         { /* Rotate a 3x3 square by 45 degree angle */
   4315           double t  = kernel->values[0];
   4316           kernel->values[0] = kernel->values[3];
   4317           kernel->values[3] = kernel->values[6];
   4318           kernel->values[6] = kernel->values[7];
   4319           kernel->values[7] = kernel->values[8];
   4320           kernel->values[8] = kernel->values[5];
   4321           kernel->values[5] = kernel->values[2];
   4322           kernel->values[2] = kernel->values[1];
   4323           kernel->values[1] = t;
   4324           /* rotate non-centered origin */
   4325           if ( kernel->x != 1 || kernel->y != 1 ) {
   4326             ssize_t x,y;
   4327             x = (ssize_t) kernel->x-1;
   4328             y = (ssize_t) kernel->y-1;
   4329                  if ( x == y  ) x = 0;
   4330             else if ( x == 0  ) x = -y;
   4331             else if ( x == -y ) y = 0;
   4332             else if ( y == 0  ) y = x;
   4333             kernel->x = (ssize_t) x+1;
   4334             kernel->y = (ssize_t) y+1;
   4335           }
   4336           angle = fmod(angle+315.0, 360.0);  /* angle reduced 45 degrees */
   4337           kernel->angle = fmod(kernel->angle+45.0, 360.0);
   4338         }
   4339       else
   4340         perror("Unable to rotate non-3x3 kernel by 45 degrees");
   4341     }
   4342   if ( 45.0 < fmod(angle, 180.0)  && fmod(angle,180.0) <= 135.0 )
   4343     {
   4344       if ( kernel->width == 1 || kernel->height == 1 )
   4345         { /* Do a transpose of a 1 dimensional kernel,
   4346           ** which results in a fast 90 degree rotation of some type.
   4347           */
   4348           ssize_t
   4349             t;
   4350           t = (ssize_t) kernel->width;
   4351           kernel->width = kernel->height;
   4352           kernel->height = (size_t) t;
   4353           t = kernel->x;
   4354           kernel->x = kernel->y;
   4355           kernel->y = t;
   4356           if ( kernel->width == 1 ) {
   4357             angle = fmod(angle+270.0, 360.0);     /* angle reduced 90 degrees */
   4358             kernel->angle = fmod(kernel->angle+90.0, 360.0);
   4359           } else {
   4360             angle = fmod(angle+90.0, 360.0);   /* angle increased 90 degrees */
   4361             kernel->angle = fmod(kernel->angle+270.0, 360.0);
   4362           }
   4363         }
   4364       else if ( kernel->width == kernel->height )
   4365         { /* Rotate a square array of values by 90 degrees */
   4366           { register ssize_t
   4367               i,j,x,y;
   4368 
   4369             register MagickRealType
   4370               *k,t;
   4371 
   4372             k=kernel->values;
   4373             for( i=0, x=(ssize_t) kernel->width-1;  i<=x;   i++, x--)
   4374               for( j=0, y=(ssize_t) kernel->height-1;  j<y;   j++, y--)
   4375                 { t                    = k[i+j*kernel->width];
   4376                   k[i+j*kernel->width] = k[j+x*kernel->width];
   4377                   k[j+x*kernel->width] = k[x+y*kernel->width];
   4378                   k[x+y*kernel->width] = k[y+i*kernel->width];
   4379                   k[y+i*kernel->width] = t;
   4380                 }
   4381           }
   4382           /* rotate the origin - relative to center of array */
   4383           { register ssize_t x,y;
   4384             x = (ssize_t) (kernel->x*2-kernel->width+1);
   4385             y = (ssize_t) (kernel->y*2-kernel->height+1);
   4386             kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
   4387             kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
   4388           }
   4389           angle = fmod(angle+270.0, 360.0);     /* angle reduced 90 degrees */
   4390           kernel->angle = fmod(kernel->angle+90.0, 360.0);
   4391         }
   4392       else
   4393         perror("Unable to rotate a non-square, non-linear kernel 90 degrees");
   4394     }
   4395   if ( 135.0 < angle && angle <= 225.0 )
   4396     {
   4397       /* For a 180 degree rotation - also know as a reflection
   4398        * This is actually a very very common operation!
   4399        * Basically all that is needed is a reversal of the kernel data!
   4400        * And a reflection of the origon
   4401        */
   4402       MagickRealType
   4403         t;
   4404 
   4405       register MagickRealType
   4406         *k;
   4407 
   4408       ssize_t
   4409         i,
   4410         j;
   4411 
   4412       k=kernel->values;
   4413       j=(ssize_t) (kernel->width*kernel->height-1);
   4414       for (i=0;  i < j;  i++, j--)
   4415         t=k[i],  k[i]=k[j],  k[j]=t;
   4416 
   4417       kernel->x = (ssize_t) kernel->width  - kernel->x - 1;
   4418       kernel->y = (ssize_t) kernel->height - kernel->y - 1;
   4419       angle = fmod(angle-180.0, 360.0);   /* angle+180 degrees */
   4420       kernel->angle = fmod(kernel->angle+180.0, 360.0);
   4421     }
   4422   /* At this point angle should at least between -45 (315) and +45 degrees
   4423    * In the future some form of non-orthogonal angled rotates could be
   4424    * performed here, posibily with a linear kernel restriction.
   4425    */
   4426 
   4427   return;
   4428 }
   4429 
   4430 /*
   4432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4433 %                                                                             %
   4434 %                                                                             %
   4435 %                                                                             %
   4436 %     S c a l e G e o m e t r y K e r n e l I n f o                           %
   4437 %                                                                             %
   4438 %                                                                             %
   4439 %                                                                             %
   4440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4441 %
   4442 %  ScaleGeometryKernelInfo() takes a geometry argument string, typically
   4443 %  provided as a  "-set option:convolve:scale {geometry}" user setting,
   4444 %  and modifies the kernel according to the parsed arguments of that setting.
   4445 %
   4446 %  The first argument (and any normalization flags) are passed to
   4447 %  ScaleKernelInfo() to scale/normalize the kernel.  The second argument
   4448 %  is then passed to UnityAddKernelInfo() to add a scled unity kernel
   4449 %  into the scaled/normalized kernel.
   4450 %
   4451 %  The format of the ScaleGeometryKernelInfo method is:
   4452 %
   4453 %      void ScaleGeometryKernelInfo(KernelInfo *kernel,
   4454 %        const double scaling_factor,const MagickStatusType normalize_flags)
   4455 %
   4456 %  A description of each parameter follows:
   4457 %
   4458 %    o kernel: the Morphology/Convolution kernel to modify
   4459 %
   4460 %    o geometry:
   4461 %             The geometry string to parse, typically from the user provided
   4462 %             "-set option:convolve:scale {geometry}" setting.
   4463 %
   4464 */
   4465 MagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel,
   4466   const char *geometry)
   4467 {
   4468   MagickStatusType
   4469     flags;
   4470 
   4471   GeometryInfo
   4472     args;
   4473 
   4474   SetGeometryInfo(&args);
   4475   flags = ParseGeometry(geometry, &args);
   4476 
   4477 #if 0
   4478   /* For Debugging Geometry Input */
   4479   (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
   4480        flags, args.rho, args.sigma, args.xi, args.psi );
   4481 #endif
   4482 
   4483   if ( (flags & PercentValue) != 0 )      /* Handle Percentage flag*/
   4484     args.rho *= 0.01,  args.sigma *= 0.01;
   4485 
   4486   if ( (flags & RhoValue) == 0 )          /* Set Defaults for missing args */
   4487     args.rho = 1.0;
   4488   if ( (flags & SigmaValue) == 0 )
   4489     args.sigma = 0.0;
   4490 
   4491   /* Scale/Normalize the input kernel */
   4492   ScaleKernelInfo(kernel, args.rho, (GeometryFlags) flags);
   4493 
   4494   /* Add Unity Kernel, for blending with original */
   4495   if ( (flags & SigmaValue) != 0 )
   4496     UnityAddKernelInfo(kernel, args.sigma);
   4497 
   4498   return;
   4499 }
   4500 /*
   4501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4502 %                                                                             %
   4503 %                                                                             %
   4504 %                                                                             %
   4505 %     S c a l e K e r n e l I n f o                                           %
   4506 %                                                                             %
   4507 %                                                                             %
   4508 %                                                                             %
   4509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4510 %
   4511 %  ScaleKernelInfo() scales the given kernel list by the given amount, with or
   4512 %  without normalization of the sum of the kernel values (as per given flags).
   4513 %
   4514 %  By default (no flags given) the values within the kernel is scaled
   4515 %  directly using given scaling factor without change.
   4516 %
   4517 %  If either of the two 'normalize_flags' are given the kernel will first be
   4518 %  normalized and then further scaled by the scaling factor value given.
   4519 %
   4520 %  Kernel normalization ('normalize_flags' given) is designed to ensure that
   4521 %  any use of the kernel scaling factor with 'Convolve' or 'Correlate'
   4522 %  morphology methods will fall into -1.0 to +1.0 range.  Note that for
   4523 %  non-HDRI versions of IM this may cause images to have any negative results
   4524 %  clipped, unless some 'bias' is used.
   4525 %
   4526 %  More specifically.  Kernels which only contain positive values (such as a
   4527 %  'Gaussian' kernel) will be scaled so that those values sum to +1.0,
   4528 %  ensuring a 0.0 to +1.0 output range for non-HDRI images.
   4529 %
   4530 %  For Kernels that contain some negative values, (such as 'Sharpen' kernels)
   4531 %  the kernel will be scaled by the absolute of the sum of kernel values, so
   4532 %  that it will generally fall within the +/- 1.0 range.
   4533 %
   4534 %  For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel
   4535 %  will be scaled by just the sum of the postive values, so that its output
   4536 %  range will again fall into the  +/- 1.0 range.
   4537 %
   4538 %  For special kernels designed for locating shapes using 'Correlate', (often
   4539 %  only containing +1 and -1 values, representing foreground/brackground
   4540 %  matching) a special normalization method is provided to scale the positive
   4541 %  values separately to those of the negative values, so the kernel will be
   4542 %  forced to become a zero-sum kernel better suited to such searches.
   4543 %
   4544 %  WARNING: Correct normalization of the kernel assumes that the '*_range'
   4545 %  attributes within the kernel structure have been correctly set during the
   4546 %  kernels creation.
   4547 %
   4548 %  NOTE: The values used for 'normalize_flags' have been selected specifically
   4549 %  to match the use of geometry options, so that '!' means NormalizeValue, '^'
   4550 %  means CorrelateNormalizeValue.  All other GeometryFlags values are ignored.
   4551 %
   4552 %  The format of the ScaleKernelInfo method is:
   4553 %
   4554 %      void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor,
   4555 %               const MagickStatusType normalize_flags )
   4556 %
   4557 %  A description of each parameter follows:
   4558 %
   4559 %    o kernel: the Morphology/Convolution kernel
   4560 %
   4561 %    o scaling_factor:
   4562 %             multiply all values (after normalization) by this factor if not
   4563 %             zero.  If the kernel is normalized regardless of any flags.
   4564 %
   4565 %    o normalize_flags:
   4566 %             GeometryFlags defining normalization method to use.
   4567 %             specifically: NormalizeValue, CorrelateNormalizeValue,
   4568 %                           and/or PercentValue
   4569 %
   4570 */
   4571 MagickExport void ScaleKernelInfo(KernelInfo *kernel,
   4572   const double scaling_factor,const GeometryFlags normalize_flags)
   4573 {
   4574   register double
   4575     pos_scale,
   4576     neg_scale;
   4577 
   4578   register ssize_t
   4579     i;
   4580 
   4581   /* do the other kernels in a multi-kernel list first */
   4582   if ( kernel->next != (KernelInfo *) NULL)
   4583     ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
   4584 
   4585   /* Normalization of Kernel */
   4586   pos_scale = 1.0;
   4587   if ( (normalize_flags&NormalizeValue) != 0 ) {
   4588     if ( fabs(kernel->positive_range + kernel->negative_range) >= MagickEpsilon )
   4589       /* non-zero-summing kernel (generally positive) */
   4590       pos_scale = fabs(kernel->positive_range + kernel->negative_range);
   4591     else
   4592       /* zero-summing kernel */
   4593       pos_scale = kernel->positive_range;
   4594   }
   4595   /* Force kernel into a normalized zero-summing kernel */
   4596   if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
   4597     pos_scale = ( fabs(kernel->positive_range) >= MagickEpsilon )
   4598                  ? kernel->positive_range : 1.0;
   4599     neg_scale = ( fabs(kernel->negative_range) >= MagickEpsilon )
   4600                  ? -kernel->negative_range : 1.0;
   4601   }
   4602   else
   4603     neg_scale = pos_scale;
   4604 
   4605   /* finialize scaling_factor for positive and negative components */
   4606   pos_scale = scaling_factor/pos_scale;
   4607   neg_scale = scaling_factor/neg_scale;
   4608 
   4609   for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
   4610     if (!IsNaN(kernel->values[i]))
   4611       kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
   4612 
   4613   /* convolution output range */
   4614   kernel->positive_range *= pos_scale;
   4615   kernel->negative_range *= neg_scale;
   4616   /* maximum and minimum values in kernel */
   4617   kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
   4618   kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
   4619 
   4620   /* swap kernel settings if user's scaling factor is negative */
   4621   if ( scaling_factor < MagickEpsilon ) {
   4622     double t;
   4623     t = kernel->positive_range;
   4624     kernel->positive_range = kernel->negative_range;
   4625     kernel->negative_range = t;
   4626     t = kernel->maximum;
   4627     kernel->maximum = kernel->minimum;
   4628     kernel->minimum = 1;
   4629   }
   4630 
   4631   return;
   4632 }
   4633 
   4634 /*
   4636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4637 %                                                                             %
   4638 %                                                                             %
   4639 %                                                                             %
   4640 %     S h o w K e r n e l I n f o                                             %
   4641 %                                                                             %
   4642 %                                                                             %
   4643 %                                                                             %
   4644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4645 %
   4646 %  ShowKernelInfo() outputs the details of the given kernel defination to
   4647 %  standard error, generally due to a users 'morphology:showKernel' option
   4648 %  request.
   4649 %
   4650 %  The format of the ShowKernel method is:
   4651 %
   4652 %      void ShowKernelInfo(const KernelInfo *kernel)
   4653 %
   4654 %  A description of each parameter follows:
   4655 %
   4656 %    o kernel: the Morphology/Convolution kernel
   4657 %
   4658 */
   4659 MagickPrivate void ShowKernelInfo(const KernelInfo *kernel)
   4660 {
   4661   const KernelInfo
   4662     *k;
   4663 
   4664   size_t
   4665     c, i, u, v;
   4666 
   4667   for (c=0, k=kernel;  k != (KernelInfo *) NULL;  c++, k=k->next ) {
   4668 
   4669     (void) FormatLocaleFile(stderr, "Kernel");
   4670     if ( kernel->next != (KernelInfo *) NULL )
   4671       (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c );
   4672     (void) FormatLocaleFile(stderr, " \"%s",
   4673           CommandOptionToMnemonic(MagickKernelOptions, k->type) );
   4674     if ( fabs(k->angle) >= MagickEpsilon )
   4675       (void) FormatLocaleFile(stderr, "@%lg", k->angle);
   4676     (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long)
   4677       k->width,(unsigned long) k->height,(long) k->x,(long) k->y);
   4678     (void) FormatLocaleFile(stderr,
   4679           " with values from %.*lg to %.*lg\n",
   4680           GetMagickPrecision(), k->minimum,
   4681           GetMagickPrecision(), k->maximum);
   4682     (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg",
   4683           GetMagickPrecision(), k->negative_range,
   4684           GetMagickPrecision(), k->positive_range);
   4685     if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
   4686       (void) FormatLocaleFile(stderr, " (Zero-Summing)\n");
   4687     else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
   4688       (void) FormatLocaleFile(stderr, " (Normalized)\n");
   4689     else
   4690       (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n",
   4691           GetMagickPrecision(), k->positive_range+k->negative_range);
   4692     for (i=v=0; v < k->height; v++) {
   4693       (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v );
   4694       for (u=0; u < k->width; u++, i++)
   4695         if (IsNaN(k->values[i]))
   4696           (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan");
   4697         else
   4698           (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3,
   4699               GetMagickPrecision(), (double) k->values[i]);
   4700       (void) FormatLocaleFile(stderr,"\n");
   4701     }
   4702   }
   4703 }
   4704 
   4705 /*
   4707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4708 %                                                                             %
   4709 %                                                                             %
   4710 %                                                                             %
   4711 %     U n i t y A d d K e r n a l I n f o                                     %
   4712 %                                                                             %
   4713 %                                                                             %
   4714 %                                                                             %
   4715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4716 %
   4717 %  UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel
   4718 %  to the given pre-scaled and normalized Kernel.  This in effect adds that
   4719 %  amount of the original image into the resulting convolution kernel.  This
   4720 %  value is usually provided by the user as a percentage value in the
   4721 %  'convolve:scale' setting.
   4722 %
   4723 %  The resulting effect is to convert the defined kernels into blended
   4724 %  soft-blurs, unsharp kernels or into sharpening kernels.
   4725 %
   4726 %  The format of the UnityAdditionKernelInfo method is:
   4727 %
   4728 %      void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale )
   4729 %
   4730 %  A description of each parameter follows:
   4731 %
   4732 %    o kernel: the Morphology/Convolution kernel
   4733 %
   4734 %    o scale:
   4735 %             scaling factor for the unity kernel to be added to
   4736 %             the given kernel.
   4737 %
   4738 */
   4739 MagickExport void UnityAddKernelInfo(KernelInfo *kernel,
   4740   const double scale)
   4741 {
   4742   /* do the other kernels in a multi-kernel list first */
   4743   if ( kernel->next != (KernelInfo *) NULL)
   4744     UnityAddKernelInfo(kernel->next, scale);
   4745 
   4746   /* Add the scaled unity kernel to the existing kernel */
   4747   kernel->values[kernel->x+kernel->y*kernel->width] += scale;
   4748   CalcKernelMetaData(kernel);  /* recalculate the meta-data */
   4749 
   4750   return;
   4751 }
   4752 
   4753 /*
   4755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4756 %                                                                             %
   4757 %                                                                             %
   4758 %                                                                             %
   4759 %     Z e r o K e r n e l N a n s                                             %
   4760 %                                                                             %
   4761 %                                                                             %
   4762 %                                                                             %
   4763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   4764 %
   4765 %  ZeroKernelNans() replaces any special 'nan' value that may be present in
   4766 %  the kernel with a zero value.  This is typically done when the kernel will
   4767 %  be used in special hardware (GPU) convolution processors, to simply
   4768 %  matters.
   4769 %
   4770 %  The format of the ZeroKernelNans method is:
   4771 %
   4772 %      void ZeroKernelNans (KernelInfo *kernel)
   4773 %
   4774 %  A description of each parameter follows:
   4775 %
   4776 %    o kernel: the Morphology/Convolution kernel
   4777 %
   4778 */
   4779 MagickPrivate void ZeroKernelNans(KernelInfo *kernel)
   4780 {
   4781   register size_t
   4782     i;
   4783 
   4784   /* do the other kernels in a multi-kernel list first */
   4785   if (kernel->next != (KernelInfo *) NULL)
   4786     ZeroKernelNans(kernel->next);
   4787 
   4788   for (i=0; i < (kernel->width*kernel->height); i++)
   4789     if (IsNaN(kernel->values[i]))
   4790       kernel->values[i]=0.0;
   4791 
   4792   return;
   4793 }
   4794