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