]> granicus.if.org Git - imagemagick/blob - magick/morphology.c
Expanded Laplacian Kernel Types (5 choices)
[imagemagick] / magick / morphology.c
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-2010 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 \f
49 /*
50   Include declarations.
51 */
52 #include "magick/studio.h"
53 #include "magick/artifact.h"
54 #include "magick/cache-view.h"
55 #include "magick/color-private.h"
56 #include "magick/enhance.h"
57 #include "magick/exception.h"
58 #include "magick/exception-private.h"
59 #include "magick/gem.h"
60 #include "magick/hashmap.h"
61 #include "magick/image.h"
62 #include "magick/image-private.h"
63 #include "magick/list.h"
64 #include "magick/magick.h"
65 #include "magick/memory_.h"
66 #include "magick/monitor-private.h"
67 #include "magick/morphology.h"
68 #include "magick/option.h"
69 #include "magick/pixel-private.h"
70 #include "magick/prepress.h"
71 #include "magick/quantize.h"
72 #include "magick/registry.h"
73 #include "magick/semaphore.h"
74 #include "magick/splay-tree.h"
75 #include "magick/statistic.h"
76 #include "magick/string_.h"
77 #include "magick/string-private.h"
78 #include "magick/token.h"
79 \f
80 /*
81   The following test is for special floating point numbers of value NaN (not
82   a number), that may be used within a Kernel Definition.  NaN's are defined
83   as part of the IEEE standard for floating point number representation.
84
85   These are used a Kernel value of NaN means that that kernel position is not
86   part of the normal convolution or morphology process, and thus allowing the
87   use of 'shaped' kernels.
88
89   Special properities two NaN's are never equal, even if they are from the
90   same variable That is the IsNaN() macro is only true if the value is NaN.
91 */
92 #define IsNan(a)   ((a)!=(a))
93
94 /*
95   Other global definitions used by module.
96 */
97 static inline double MagickMin(const double x,const double y)
98 {
99   return( x < y ? x : y);
100 }
101 static inline double MagickMax(const double x,const double y)
102 {
103   return( x > y ? x : y);
104 }
105 #define Minimize(assign,value) assign=MagickMin(assign,value)
106 #define Maximize(assign,value) assign=MagickMax(assign,value)
107
108 /* Currently these are only internal to this module */
109 static void
110   ExpandKernelInfo(KernelInfo *, double),
111   RotateKernelInfo(KernelInfo *, double);
112 \f
113 /*
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %                                                                             %
116 %                                                                             %
117 %                                                                             %
118 %     A c q u i r e K e r n e l I n f o                                       %
119 %                                                                             %
120 %                                                                             %
121 %                                                                             %
122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123 %
124 %  AcquireKernelInfo() takes the given string (generally supplied by the
125 %  user) and converts it into a Morphology/Convolution Kernel.  This allows
126 %  users to specify a kernel from a number of pre-defined kernels, or to fully
127 %  specify their own kernel for a specific Convolution or Morphology
128 %  Operation.
129 %
130 %  The kernel so generated can be any rectangular array of floating point
131 %  values (doubles) with the 'control point' or 'pixel being affected'
132 %  anywhere within that array of values.
133 %
134 %  Previously IM was restricted to a square of odd size using the exact
135 %  center as origin, this is no longer the case, and any rectangular kernel
136 %  with any value being declared the origin. This in turn allows the use of
137 %  highly asymmetrical kernels.
138 %
139 %  The floating point values in the kernel can also include a special value
140 %  known as 'nan' or 'not a number' to indicate that this value is not part
141 %  of the kernel array. This allows you to shaped the kernel within its
142 %  rectangular area. That is 'nan' values provide a 'mask' for the kernel
143 %  shape.  However at least one non-nan value must be provided for correct
144 %  working of a kernel.
145 %
146 %  The returned kernel should be freed using the DestroyKernelInfo() when you
147 %  are finished with it.  Do not free this memory yourself.
148 %
149 %  Input kernel defintion strings can consist of any of three types.
150 %
151 %    "name:args"
152 %         Select from one of the built in kernels, using the name and
153 %         geometry arguments supplied.  See AcquireKernelBuiltIn()
154 %
155 %    "WxH[+X+Y]:num, num, num ..."
156 %         a kernel of size W by H, with W*H floating point numbers following.
157 %         the 'center' can be optionally be defined at +X+Y (such that +0+0
158 %         is top left corner). If not defined the pixel in the center, for
159 %         odd sizes, or to the immediate top or left of center for even sizes
160 %         is automatically selected.
161 %
162 %    "num, num, num, num, ..."
163 %         list of floating point numbers defining an 'old style' odd sized
164 %         square kernel.  At least 9 values should be provided for a 3x3
165 %         square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc.
166 %         Values can be space or comma separated.  This is not recommended.
167 %
168 %  Note that 'name' kernels will start with an alphabetic character while the
169 %  new kernel specification has a ':' character in its specification string.
170 %  If neither is the case, it is assumed an old style of a simple list of
171 %  numbers generating a odd-sized square kernel has been given.
172 %
173 %  You can define a 'list of kernels' which can be used by some morphology
174 %  operators A list is defined as a semi-colon seperated list kernels.
175 %
176 %     " kernel ; kernel ; kernel ; "
177 %
178 %  Extra ';' characters are simply ignored.
179 %
180 %  The format of the AcquireKernal method is:
181 %
182 %      KernelInfo *AcquireKernelInfo(const char *kernel_string)
183 %
184 %  A description of each parameter follows:
185 %
186 %    o kernel_string: the Morphology/Convolution kernel wanted.
187 %
188 */
189
190 /* This was separated so that it could be used as a separate
191 ** array input handling function, such as for -color-matrix
192 */
193 static KernelInfo *ParseKernelArray(const char *kernel_string)
194 {
195   KernelInfo
196     *kernel;
197
198   char
199     token[MaxTextExtent];
200
201   const char
202     *p,
203     *end;
204
205   register long
206     i;
207
208   double
209     nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
210
211   kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
212   if (kernel == (KernelInfo *)NULL)
213     return(kernel);
214   (void) ResetMagickMemory(kernel,0,sizeof(*kernel));
215   kernel->minimum = kernel->maximum = 0.0;
216   kernel->negative_range = kernel->positive_range = 0.0;
217   kernel->type = UserDefinedKernel;
218   kernel->next = (KernelInfo *) NULL;
219   kernel->signature = MagickSignature;
220
221   /* find end of this specific kernel definition string */
222   end = strchr(kernel_string, ';');
223   if ( end == (char *) NULL )
224     end = strchr(kernel_string, '\0');
225
226   /* Has a ':' in argument - New user kernel specification */
227   p = strchr(kernel_string, ':');
228   if ( p != (char *) NULL && p < end)
229     {
230       MagickStatusType
231         flags;
232
233       GeometryInfo
234         args;
235
236       /* ParseGeometry() needs the geometry separated! -- Arrgghh */
237       memcpy(token, kernel_string, (size_t) (p-kernel_string));
238       token[p-kernel_string] = '\0';
239       SetGeometryInfo(&args);
240       flags = ParseGeometry(token, &args);
241
242       /* Size handling and checks of geometry settings */
243       if ( (flags & WidthValue) == 0 ) /* if no width then */
244         args.rho = args.sigma;         /* then  width = height */
245       if ( args.rho < 1.0 )            /* if width too small */
246          args.rho = 1.0;               /* then  width = 1 */
247       if ( args.sigma < 1.0 )          /* if height too small */
248         args.sigma = args.rho;         /* then  height = width */
249       kernel->width = (unsigned long)args.rho;
250       kernel->height = (unsigned long)args.sigma;
251
252       /* Offset Handling and Checks */
253       if ( args.xi  < 0.0 || args.psi < 0.0 )
254         return(DestroyKernelInfo(kernel));
255       kernel->x = ((flags & XValue)!=0) ? (long)args.xi
256                                                : (long) (kernel->width-1)/2;
257       kernel->y = ((flags & YValue)!=0) ? (long)args.psi
258                                                : (long) (kernel->height-1)/2;
259       if ( kernel->x >= (long) kernel->width ||
260            kernel->y >= (long) kernel->height )
261         return(DestroyKernelInfo(kernel));
262
263       p++; /* advance beyond the ':' */
264     }
265   else
266     { /* ELSE - Old old specification, forming odd-square kernel */
267       /* count up number of values given */
268       p=(const char *) kernel_string;
269       while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
270         p++;  /* ignore "'" chars for convolve filter usage - Cristy */
271       for (i=0; p < end; i++)
272       {
273         GetMagickToken(p,&p,token);
274         if (*token == ',')
275           GetMagickToken(p,&p,token);
276       }
277       /* set the size of the kernel - old sized square */
278       kernel->width = kernel->height= (unsigned long) sqrt((double) i+1.0);
279       kernel->x = kernel->y = (long) (kernel->width-1)/2;
280       p=(const char *) kernel_string;
281       while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
282         p++;  /* ignore "'" chars for convolve filter usage - Cristy */
283     }
284
285   /* Read in the kernel values from rest of input string argument */
286   kernel->values=(double *) AcquireQuantumMemory(kernel->width,
287                         kernel->height*sizeof(double));
288   if (kernel->values == (double *) NULL)
289     return(DestroyKernelInfo(kernel));
290
291   kernel->minimum = +MagickHuge;
292   kernel->maximum = -MagickHuge;
293   kernel->negative_range = kernel->positive_range = 0.0;
294
295   for (i=0; (i < (long) (kernel->width*kernel->height)) && (p < end); i++)
296   {
297     GetMagickToken(p,&p,token);
298     if (*token == ',')
299       GetMagickToken(p,&p,token);
300     if (    LocaleCompare("nan",token) == 0
301         || LocaleCompare("-",token) == 0 ) {
302       kernel->values[i] = nan; /* do not include this value in kernel */
303     }
304     else {
305       kernel->values[i] = StringToDouble(token);
306       ( kernel->values[i] < 0)
307           ?  ( kernel->negative_range += kernel->values[i] )
308           :  ( kernel->positive_range += kernel->values[i] );
309       Minimize(kernel->minimum, kernel->values[i]);
310       Maximize(kernel->maximum, kernel->values[i]);
311     }
312   }
313
314   /* sanity check -- no more values in kernel definition */
315   GetMagickToken(p,&p,token);
316   if ( *token != '\0' && *token != ';' && *token != '\'' )
317     return(DestroyKernelInfo(kernel));
318
319 #if 0
320   /* this was the old method of handling a incomplete kernel */
321   if ( i < (long) (kernel->width*kernel->height) ) {
322     Minimize(kernel->minimum, kernel->values[i]);
323     Maximize(kernel->maximum, kernel->values[i]);
324     for ( ; i < (long) (kernel->width*kernel->height); i++)
325       kernel->values[i]=0.0;
326   }
327 #else
328   /* Number of values for kernel was not enough - Report Error */
329   if ( i < (long) (kernel->width*kernel->height) )
330     return(DestroyKernelInfo(kernel));
331 #endif
332
333   /* check that we recieved at least one real (non-nan) value! */
334   if ( kernel->minimum == MagickHuge )
335     return(DestroyKernelInfo(kernel));
336
337   return(kernel);
338 }
339
340 static KernelInfo *ParseNamedKernel(const char *kernel_string)
341 {
342   char
343     token[MaxTextExtent];
344
345   long
346     type;
347
348   const char
349     *p,
350     *end;
351
352   MagickStatusType
353     flags;
354
355   GeometryInfo
356     args;
357
358   /* Parse special 'named' kernel */
359   GetMagickToken(kernel_string,&p,token);
360   type=ParseMagickOption(MagickKernelOptions,MagickFalse,token);
361   if ( type < 0 || type == UserDefinedKernel )
362     return((KernelInfo *)NULL);  /* not a valid named kernel */
363
364   while (((isspace((int) ((unsigned char) *p)) != 0) ||
365           (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';'))
366     p++;
367
368   end = strchr(p, ';'); /* end of this kernel defintion */
369   if ( end == (char *) NULL )
370     end = strchr(p, '\0');
371
372   /* ParseGeometry() needs the geometry separated! -- Arrgghh */
373   memcpy(token, p, (size_t) (end-p));
374   token[end-p] = '\0';
375   SetGeometryInfo(&args);
376   flags = ParseGeometry(token, &args);
377
378 #if 0
379   /* For Debugging Geometry Input */
380   fprintf(stderr, "Geometry = %04x : %lf x %lf %+lf %+lf\n",
381        flags, args.rho, args.sigma, args.xi, args.psi );
382 #endif
383
384   /* special handling of missing values in input string */
385   switch( type ) {
386     case RectangleKernel:
387       if ( (flags & WidthValue) == 0 ) /* if no width then */
388         args.rho = args.sigma;         /* then  width = height */
389       if ( args.rho < 1.0 )            /* if width too small */
390           args.rho = 3;                 /* then  width = 3 */
391       if ( args.sigma < 1.0 )          /* if height too small */
392         args.sigma = args.rho;         /* then  height = width */
393       if ( (flags & XValue) == 0 )     /* center offset if not defined */
394         args.xi = (double)(((long)args.rho-1)/2);
395       if ( (flags & YValue) == 0 )
396         args.psi = (double)(((long)args.sigma-1)/2);
397       break;
398     case SquareKernel:
399     case DiamondKernel:
400     case DiskKernel:
401     case PlusKernel:
402       /* If no scale given (a 0 scale is valid! - set it to 1.0 */
403       if ( (flags & HeightValue) == 0 )
404         args.sigma = 1.0;
405       break;
406     case ChebyshevKernel:
407     case ManhattenKernel:
408     case EuclideanKernel:
409       if ( (flags & HeightValue) == 0 )
410         args.sigma = 100.0;                    /* default distance scaling */
411       else if ( (flags & AspectValue ) != 0 )  /* '!' flag */
412         args.sigma = QuantumRange/args.sigma;  /* maximum pixel distance */
413       else if ( (flags & PercentValue ) != 0 ) /* '%' flag */
414         args.sigma *= QuantumRange/100.0;      /* percentage of color range */
415       break;
416     default:
417       break;
418   }
419
420   return(AcquireKernelBuiltIn((KernelInfoType)type, &args));
421 }
422
423 MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string)
424 {
425
426   KernelInfo
427     *kernel,
428     *new_kernel,
429     *last_kernel;
430
431   char
432     token[MaxTextExtent];
433
434   const char
435     *p;
436
437   unsigned long
438     kernel_number;
439
440   p = kernel_string;
441   kernel = last_kernel = NULL;
442   kernel_number = 0;
443
444   while ( GetMagickToken(p,NULL,token),  *token != '\0' ) {
445
446     /* ignore multiple ';' following each other */
447     if ( *token != ';' ) {
448
449       /* tokens starting with alpha is a Named kernel */
450       if (isalpha((int) *token) == 0)
451         new_kernel = ParseKernelArray(p);
452       else /* otherwise a user defined kernel array */
453         new_kernel = ParseNamedKernel(p);
454
455       /* Error handling -- this is not proper error handling! */
456       if ( new_kernel == (KernelInfo *) NULL ) {
457         fprintf(stderr, "Failed to parse kernel number #%lu\n", kernel_number);
458         if ( kernel != (KernelInfo *) NULL )
459           kernel=DestroyKernelInfo(kernel);
460         return((KernelInfo *) NULL);
461       }
462
463       /* initialise or append the kernel list */
464       if ( last_kernel == (KernelInfo *) NULL )
465         kernel = last_kernel = new_kernel;
466       else {
467         last_kernel->next = new_kernel;
468         last_kernel = new_kernel;
469       }
470     }
471
472     /* look for the next kernel in list */
473     p = strchr(p, ';');
474     if ( p == (char *) NULL )
475       break;
476     p++;
477
478   }
479   return(kernel);
480 }
481
482 \f
483 /*
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %                                                                             %
486 %                                                                             %
487 %                                                                             %
488 %     A c q u i r e K e r n e l B u i l t I n                                 %
489 %                                                                             %
490 %                                                                             %
491 %                                                                             %
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 %
494 %  AcquireKernelBuiltIn() returned one of the 'named' built-in types of
495 %  kernels used for special purposes such as gaussian blurring, skeleton
496 %  pruning, and edge distance determination.
497 %
498 %  They take a KernelType, and a set of geometry style arguments, which were
499 %  typically decoded from a user supplied string, or from a more complex
500 %  Morphology Method that was requested.
501 %
502 %  The format of the AcquireKernalBuiltIn method is:
503 %
504 %      KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
505 %           const GeometryInfo args)
506 %
507 %  A description of each parameter follows:
508 %
509 %    o type: the pre-defined type of kernel wanted
510 %
511 %    o args: arguments defining or modifying the kernel
512 %
513 %  Convolution Kernels
514 %
515 %    Gaussian:{radius},{sigma}
516 %       Generate a two-dimentional gaussian kernel, as used by -gaussian.
517 %       A sigma is required.
518 %
519 %       NOTE: that the 'radius' is optional, but if provided can limit (clip)
520 %       the final size of the resulting kernel to a square 2*radius+1 in size.
521 %       The radius should be at least 2 times that of the sigma value, or
522 %       sever clipping and aliasing may result.  If not given or set to 0 the
523 %       radius will be determined so as to produce the best minimal error
524 %       result, which is usally much larger than is normally needed.
525 %
526 %    Blur:{radius},{sigma},{angle}
527 %       As per Gaussian, but generates a 1 dimensional or linear gaussian
528 %       blur, at the angle given (current restricted to orthogonal angles).
529 %       If a 'radius' is given the kernel is clipped to a width of 2*radius+1.
530 %       Angle can be rotated in multiples of 90 degrees.
531 %
532 %       Note that two such blurs perpendicular to each other is equivelent to
533 %       the far large "Gaussian" kernel, but much faster to apply. This is how
534 %       the -blur operator works.
535 %
536 %    Comet:{width},{sigma},{angle}
537 %       Blur in one direction only, much like how a bright object leaves
538 %       a comet like trail.  The Kernel is actually half a gaussian curve,
539 %       Adding two such blurs in opposite directions produces a Blur Kernel.
540 %       Angle can be rotated in multiples of 90 degrees.
541 %
542 %       Note that the first argument is the width of the kernel and not the
543 %       radius of the kernel.
544 %
545 %    # Still to be implemented...
546 %    #
547 %    # Sharpen:{radius},{sigma}
548 %    #    Negated Gaussian (center zeroed and re-normalized),
549 %    #    with a 2 unit positive peak.   -- Check On line documentation
550 %    #
551 %    # LOG:{radius},{sigma1},{sigma2}
552 %    #    Laplacian of Gaussian
553 %    #
554 %    # DOG:{radius},{sigma1},{sigma2}
555 %    #    Difference of two Gaussians
556 %    #
557 %    # Filter2D
558 %    # Filter1D
559 %    #    Set kernel values using a resize filter, and given scale (sigma)
560 %    #    Cylindrical or Linear.   Is this posible with an image?
561 %    #
562 %
563 %  Named Constant Convolution Kernels
564 %
565 %    Sobel:[angle]
566 %      The 3x3 sobel convolution kernel. Angle may be given in multiples
567 %      of 45 degrees.  Kernel is unscaled by default so some normalization
568 %      may be required to ensure results are not clipped.
569 %      Default kernel is   -1,0,1
570 %                          -2,0,2
571 %                          -1,0,1
572 %
573 %    Laplacian:{type}
574 %      Generate Lapacian kernel of the type specified. (1 is the default)
575 %        Type 0 default square laplacian  3x3: all -1's with central 8
576 %        Type 1            3x3: central 4 edge -1 corner 0
577 %        Type 2            3x3: central 4 edge 1 corner -2
578 %        Type 3   a  5x5 laplacian
579 %        Type 5   a  7x7 laplacian
580 %
581 %  Boolean Kernels
582 %
583 %    Rectangle:{geometry}
584 %       Simply generate a rectangle of 1's with the size given. You can also
585 %       specify the location of the 'control point', otherwise the closest
586 %       pixel to the center of the rectangle is selected.
587 %
588 %       Properly centered and odd sized rectangles work the best.
589 %
590 %    Diamond:[{radius}[,{scale}]]
591 %       Generate a diamond shaped kernel with given radius to the points.
592 %       Kernel size will again be radius*2+1 square and defaults to radius 1,
593 %       generating a 3x3 kernel that is slightly larger than a square.
594 %
595 %    Square:[{radius}[,{scale}]]
596 %       Generate a square shaped kernel of size radius*2+1, and defaulting
597 %       to a 3x3 (radius 1).
598 %
599 %       Note that using a larger radius for the "Square" or the "Diamond"
600 %       is also equivelent to iterating the basic morphological method
601 %       that many times. However However iterating with the smaller radius 1
602 %       default is actually faster than using a larger kernel radius.
603 %
604 %    Disk:[{radius}[,{scale}]]
605 %       Generate a binary disk of the radius given, radius may be a float.
606 %       Kernel size will be ceil(radius)*2+1 square.
607 %       NOTE: Here are some disk shapes of specific interest
608 %          "disk:1"    => "diamond" or "cross:1"
609 %          "disk:1.5"  => "square"
610 %          "disk:2"    => "diamond:2"
611 %          "disk:2.5"  => a general disk shape of radius 2
612 %          "disk:2.9"  => "square:2"
613 %          "disk:3.5"  => default - octagonal/disk shape of radius 3
614 %          "disk:4.2"  => roughly octagonal shape of radius 4
615 %          "disk:4.3"  => a general disk shape of radius 4
616 %       After this all the kernel shape becomes more and more circular.
617 %
618 %       Because a "disk" is more circular when using a larger radius, using a
619 %       larger radius is preferred over iterating the morphological operation.
620 %
621 %    Plus:[{radius}[,{scale}]]
622 %       Generate a kernel in the shape of a 'plus' sign. The length of each
623 %       arm is also the radius, which defaults to 2.
624 %
625 %       This kernel is not a good general morphological kernel, but is used
626 %       more for highlighting and marking any single pixels in an image using,
627 %       a "Dilate" or "Erode" method as appropriate.
628 %
629 %       NOTE: "plus:1" is equivelent to a "Diamond" kernel.
630 %
631 %       Note that unlike other kernels iterating a plus does not produce the
632 %       same result as using a larger radius for the cross.
633 %
634 %  Distance Measuring Kernels
635 %
636 %    Chebyshev "[{radius}][x{scale}[%!]]"
637 %    Manhatten "[{radius}][x{scale}[%!]]"
638 %    Euclidean "[{radius}][x{scale}[%!]]"
639 %
640 %       Different types of distance measuring methods, which are used with the
641 %       a 'Distance' morphology method for generating a gradient based on
642 %       distance from an edge of a binary shape, though there is a technique
643 %       for handling a anti-aliased shape.
644 %
645 %       Chebyshev Distance (also known as Tchebychev Distance) is a value of
646 %       one to any neighbour, orthogonal or diagonal. One why of thinking of
647 %       it is the number of squares a 'King' or 'Queen' in chess needs to
648 %       traverse reach any other position on a chess board.  It results in a
649 %       'square' like distance function, but one where diagonals are closer
650 %       than expected.
651 %
652 %       Manhatten Distance (also known as Rectilinear Distance, or the Taxi
653 %       Cab metric), is the distance needed when you can only travel in
654 %       orthogonal (horizontal or vertical) only.  It is the distance a 'Rook'
655 %       in chess would travel. It results in a diamond like distances, where
656 %       diagonals are further than expected.
657 %
658 %       Euclidean Distance is the 'direct' or 'as the crow flys distance.
659 %       However by default the kernel size only has a radius of 1, which
660 %       limits the distance to 'Knight' like moves, with only orthogonal and
661 %       diagonal measurements being correct.  As such for the default kernel
662 %       you will get octagonal like distance function, which is reasonally
663 %       accurate.
664 %
665 %       However if you use a larger radius such as "Euclidean:4" you will
666 %       get a much smoother distance gradient from the edge of the shape.
667 %       Of course a larger kernel is slower to use, and generally not needed.
668 %
669 %       To allow the use of fractional distances that you get with diagonals
670 %       the actual distance is scaled by a fixed value which the user can
671 %       provide.  This is not actually nessary for either ""Chebyshev" or
672 %       "Manhatten" distance kernels, but is done for all three distance
673 %       kernels.  If no scale is provided it is set to a value of 100,
674 %       allowing for a maximum distance measurement of 655 pixels using a Q16
675 %       version of IM, from any edge.  However for small images this can
676 %       result in quite a dark gradient.
677 %
678 %       See the 'Distance' Morphological Method, for information of how it is
679 %       applied.
680 %
681 %  # Hit-n-Miss Kernel-Lists -- Still to be implemented
682 %  #
683 %  # specifically for   Pruning,  Thinning,  Thickening
684 %  #
685 */
686
687 MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
688    const GeometryInfo *args)
689 {
690   KernelInfo
691     *kernel;
692
693   register long
694     i;
695
696   register long
697     u,
698     v;
699
700   double
701     nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
702
703   kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
704   if (kernel == (KernelInfo *) NULL)
705     return(kernel);
706   (void) ResetMagickMemory(kernel,0,sizeof(*kernel));
707   kernel->minimum = kernel->maximum = 0.0;
708   kernel->negative_range = kernel->positive_range = 0.0;
709   kernel->type = type;
710   kernel->next = (KernelInfo *) NULL;
711   kernel->signature = MagickSignature;
712
713   switch(type) {
714     /* Convolution Kernels */
715     case GaussianKernel:
716       { double
717           sigma = fabs(args->sigma);
718
719         sigma = (sigma <= MagickEpsilon) ? 1.0 : sigma;
720
721         kernel->width = kernel->height =
722                             GetOptimalKernelWidth2D(args->rho,sigma);
723         kernel->x = kernel->y = (long) (kernel->width-1)/2;
724         kernel->negative_range = kernel->positive_range = 0.0;
725         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
726                               kernel->height*sizeof(double));
727         if (kernel->values == (double *) NULL)
728           return(DestroyKernelInfo(kernel));
729
730         sigma = 2.0*sigma*sigma; /* simplify the expression */
731         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
732           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
733             kernel->positive_range += (
734               kernel->values[i] =
735                  exp(-((double)(u*u+v*v))/sigma)
736                        /*  / (MagickPI*sigma)  */ );
737         kernel->minimum = 0;
738         kernel->maximum = kernel->values[
739                          kernel->y*kernel->width+kernel->x ];
740
741         ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */
742
743         break;
744       }
745     case BlurKernel:
746       { double
747           sigma = fabs(args->sigma);
748
749         sigma = (sigma <= MagickEpsilon) ? 1.0 : sigma;
750
751         kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
752         kernel->x = (long) (kernel->width-1)/2;
753         kernel->height = 1;
754         kernel->y = 0;
755         kernel->negative_range = kernel->positive_range = 0.0;
756         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
757                               kernel->height*sizeof(double));
758         if (kernel->values == (double *) NULL)
759           return(DestroyKernelInfo(kernel));
760
761 #if 1
762 #define KernelRank 3
763         /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix).
764         ** It generates a gaussian 3 times the width, and compresses it into
765         ** the expected range.  This produces a closer normalization of the
766         ** resulting kernel, especially for very low sigma values.
767         ** As such while wierd it is prefered.
768         **
769         ** I am told this method originally came from Photoshop.
770         */
771         sigma *= KernelRank;                /* simplify expanded curve */
772         v = (long) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */
773         (void) ResetMagickMemory(kernel->values,0, (size_t)
774                        kernel->width*sizeof(double));
775         for ( u=-v; u <= v; u++) {
776           kernel->values[(u+v)/KernelRank] +=
777                 exp(-((double)(u*u))/(2.0*sigma*sigma))
778                        /*   / (MagickSQ2PI*sigma/KernelRank)  */ ;
779         }
780         for (i=0; i < (long) kernel->width; i++)
781           kernel->positive_range += kernel->values[i];
782 #else
783         for ( i=0, u=-kernel->x; i < kernel->width; i++, u++)
784           kernel->positive_range += (
785               kernel->values[i] =
786                 exp(-((double)(u*u))/(2.0*sigma*sigma))
787                        /*  / (MagickSQ2PI*sigma)  */ );
788 #endif
789         kernel->minimum = 0;
790         kernel->maximum = kernel->values[ kernel->x ];
791         /* Note that neither methods above generate a normalized kernel,
792         ** though it gets close. The kernel may be 'clipped' by a user defined
793         ** radius, producing a smaller (darker) kernel.  Also for very small
794         ** sigma's (> 0.1) the central value becomes larger than one, and thus
795         ** producing a very bright kernel.
796         */
797
798         /* Normalize the 1D Gaussian Kernel
799         **
800         ** Because of this the divisor in the above kernel generator is
801         ** not needed, so is not done above.
802         */
803         ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */
804
805         /* rotate the kernel by given angle */
806         RotateKernelInfo(kernel, args->xi);
807         break;
808       }
809     case CometKernel:
810       { double
811           sigma = fabs(args->sigma);
812
813         sigma = (sigma <= MagickEpsilon) ? 1.0 : sigma;
814
815         if ( args->rho < 1.0 )
816           kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
817         else
818           kernel->width = (unsigned long)args->rho;
819         kernel->x = kernel->y = 0;
820         kernel->height = 1;
821         kernel->negative_range = kernel->positive_range = 0.0;
822         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
823                               kernel->height*sizeof(double));
824         if (kernel->values == (double *) NULL)
825           return(DestroyKernelInfo(kernel));
826
827         /* A comet blur is half a gaussian curve, so that the object is
828         ** blurred in one direction only.  This may not be quite the right
829         ** curve so may change in the future. The function must be normalised.
830         */
831 #if 1
832 #define KernelRank 3
833         sigma *= KernelRank;                /* simplify expanded curve */
834         v = (long) kernel->width*KernelRank; /* start/end points to fit range */
835         (void) ResetMagickMemory(kernel->values,0, (size_t)
836                        kernel->width*sizeof(double));
837         for ( u=0; u < v; u++) {
838           kernel->values[u/KernelRank] +=
839                exp(-((double)(u*u))/(2.0*sigma*sigma))
840                        /*   / (MagickSQ2PI*sigma/KernelRank)  */ ;
841         }
842         for (i=0; i < (long) kernel->width; i++)
843           kernel->positive_range += kernel->values[i];
844 #else
845         for ( i=0; i < (long) kernel->width; i++)
846           kernel->positive_range += (
847             kernel->values[i] =
848                exp(-((double)(i*i))/(2.0*sigma*sigma))
849                        /*  / (MagickSQ2PI*sigma)  */ );
850 #endif
851         kernel->minimum = 0;
852         kernel->maximum = kernel->values[0];
853
854         ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */
855         RotateKernelInfo(kernel, args->xi); /* Rotate by angle */
856         break;
857       }
858     /* Convolution Kernels - Well Known Constants */
859     case SobelKernel:
860       { kernel=DestroyKernelInfo(kernel); /* default kernel is not needed */
861         kernel=ParseKernelArray("3x3:-1,0,1 -2,0,2 -1,0,1");
862         if (kernel == (KernelInfo *) NULL)
863           return(kernel);
864         kernel->type = type;
865         RotateKernelInfo(kernel, args->rho); /* Rotate by angle */
866         break;
867       }
868     case LaplacianKernel:
869       { kernel=DestroyKernelInfo(kernel); /* default kernel is not needed */
870         switch ( (int) args->rho ) {
871           case 1:
872             kernel=ParseKernelArray("3x3:  0,-1,0  -1,4,-1  0,-1,0");
873             break;
874           case 2:
875             kernel=ParseKernelArray("3x3: -2,1,-2  1,4,1  -2,1,-2");
876             break;
877           case 3:
878           default: /* default laplacian 'edge' filter */
879             kernel=ParseKernelArray("3x3: -1,-1,-1  -1,8,-1  -1,-1,-1");
880             break;
881           case 4:   /* a 5x5 laplacian */
882             kernel=ParseKernelArray(
883               "5x5: -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");
884             break;
885           case 5:   /* a 7x7 laplacian */
886             kernel=ParseKernelArray(
887               "7x7:-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" );
888             break;
889         }
890         if (kernel == (KernelInfo *) NULL)
891           return(kernel);
892         kernel->type = type;
893         break;
894       }
895     /* Boolean Kernels */
896     case RectangleKernel:
897     case SquareKernel:
898       {
899         double scale;
900         if ( type == SquareKernel )
901           {
902             if (args->rho < 1.0)
903               kernel->width = kernel->height = 3;  /* default radius = 1 */
904             else
905               kernel->width = kernel->height = (unsigned long) (2*args->rho+1);
906             kernel->x = kernel->y = (long) (kernel->width-1)/2;
907             scale = args->sigma;
908           }
909         else {
910             /* NOTE: user defaults set in "AcquireKernelInfo()" */
911             if ( args->rho < 1.0 || args->sigma < 1.0 )
912               return(DestroyKernelInfo(kernel));    /* invalid args given */
913             kernel->width = (unsigned long)args->rho;
914             kernel->height = (unsigned long)args->sigma;
915             if ( args->xi  < 0.0 || args->xi  > (double)kernel->width ||
916                  args->psi < 0.0 || args->psi > (double)kernel->height )
917               return(DestroyKernelInfo(kernel));    /* invalid args given */
918             kernel->x = (long) args->xi;
919             kernel->y = (long) args->psi;
920             scale = 1.0;
921           }
922         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
923                               kernel->height*sizeof(double));
924         if (kernel->values == (double *) NULL)
925           return(DestroyKernelInfo(kernel));
926
927         /* set all kernel values to 1.0 */
928         u=(long) kernel->width*kernel->height;
929         for ( i=0; i < u; i++)
930             kernel->values[i] = scale;
931         kernel->minimum = kernel->maximum = scale;   /* a flat shape */
932         kernel->positive_range = scale*u;
933         break;
934       }
935     case DiamondKernel:
936       {
937         if (args->rho < 1.0)
938           kernel->width = kernel->height = 3;  /* default radius = 1 */
939         else
940           kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
941         kernel->x = kernel->y = (long) (kernel->width-1)/2;
942
943         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
944                               kernel->height*sizeof(double));
945         if (kernel->values == (double *) NULL)
946           return(DestroyKernelInfo(kernel));
947
948         /* set all kernel values within diamond area to scale given */
949         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
950           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
951             if ((labs(u)+labs(v)) <= (long)kernel->x)
952               kernel->positive_range += kernel->values[i] = args->sigma;
953             else
954               kernel->values[i] = nan;
955         kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
956         break;
957       }
958     case DiskKernel:
959       {
960         long
961           limit;
962
963         limit = (long)(args->rho*args->rho);
964         if (args->rho < 0.1)             /* default radius approx 3.5 */
965           kernel->width = kernel->height = 7L, limit = 10L;
966         else
967            kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
968         kernel->x = kernel->y = (long) (kernel->width-1)/2;
969
970         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
971                               kernel->height*sizeof(double));
972         if (kernel->values == (double *) NULL)
973           return(DestroyKernelInfo(kernel));
974
975         /* set all kernel values within disk area to 1.0 */
976         for ( i=0, v= -kernel->y; v <= (long)kernel->y; v++)
977           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
978             if ((u*u+v*v) <= limit)
979               kernel->positive_range += kernel->values[i] = args->sigma;
980             else
981               kernel->values[i] = nan;
982         kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
983         break;
984       }
985     case PlusKernel:
986       {
987         if (args->rho < 1.0)
988           kernel->width = kernel->height = 5;  /* default radius 2 */
989         else
990            kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
991         kernel->x = kernel->y = (long) (kernel->width-1)/2;
992
993         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
994                               kernel->height*sizeof(double));
995         if (kernel->values == (double *) NULL)
996           return(DestroyKernelInfo(kernel));
997
998         /* set all kernel values along axises to 1.0 */
999         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
1000           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
1001             kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
1002         kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
1003         kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
1004         break;
1005       }
1006     /* Distance Measuring Kernels */
1007     case ChebyshevKernel:
1008       {
1009         if (args->rho < 1.0)
1010           kernel->width = kernel->height = 3;  /* default radius = 1 */
1011         else
1012           kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
1013         kernel->x = kernel->y = (long) (kernel->width-1)/2;
1014
1015         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
1016                               kernel->height*sizeof(double));
1017         if (kernel->values == (double *) NULL)
1018           return(DestroyKernelInfo(kernel));
1019
1020         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
1021           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
1022             kernel->positive_range += ( kernel->values[i] =
1023                  args->sigma*((labs(u)>labs(v)) ? labs(u) : labs(v)) );
1024         kernel->maximum = kernel->values[0];
1025         break;
1026       }
1027     case ManhattenKernel:
1028       {
1029         if (args->rho < 1.0)
1030           kernel->width = kernel->height = 3;  /* default radius = 1 */
1031         else
1032            kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
1033         kernel->x = kernel->y = (long) (kernel->width-1)/2;
1034
1035         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
1036                               kernel->height*sizeof(double));
1037         if (kernel->values == (double *) NULL)
1038           return(DestroyKernelInfo(kernel));
1039
1040         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
1041           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
1042             kernel->positive_range += ( kernel->values[i] =
1043                  args->sigma*(labs(u)+labs(v)) );
1044         kernel->maximum = kernel->values[0];
1045         break;
1046       }
1047     case EuclideanKernel:
1048       {
1049         if (args->rho < 1.0)
1050           kernel->width = kernel->height = 3;  /* default radius = 1 */
1051         else
1052            kernel->width = kernel->height = ((unsigned long)args->rho)*2+1;
1053         kernel->x = kernel->y = (long) (kernel->width-1)/2;
1054
1055         kernel->values=(double *) AcquireQuantumMemory(kernel->width,
1056                               kernel->height*sizeof(double));
1057         if (kernel->values == (double *) NULL)
1058           return(DestroyKernelInfo(kernel));
1059
1060         for ( i=0, v=-kernel->y; v <= (long)kernel->y; v++)
1061           for ( u=-kernel->x; u <= (long)kernel->x; u++, i++)
1062             kernel->positive_range += ( kernel->values[i] =
1063                  args->sigma*sqrt((double)(u*u+v*v)) );
1064         kernel->maximum = kernel->values[0];
1065         break;
1066       }
1067     /* Undefined Kernels */
1068     case LOGKernel:
1069     case DOGKernel:
1070       perror("Kernel Type has not been defined yet\n");
1071       /* FALL THRU */
1072     default:
1073       /* Generate a No-Op minimal kernel - 1x1 pixel */
1074       kernel->values=(double *)AcquireQuantumMemory((size_t)1,sizeof(double));
1075       if (kernel->values == (double *) NULL)
1076         return(DestroyKernelInfo(kernel));
1077       kernel->width = kernel->height = 1;
1078       kernel->x = kernel->x = 0;
1079       kernel->type = UndefinedKernel;
1080       kernel->maximum =
1081         kernel->positive_range =
1082           kernel->values[0] = 1.0;  /* a flat single-point no-op kernel! */
1083       break;
1084   }
1085
1086   return(kernel);
1087 }
1088 \f
1089 /*
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091 %                                                                             %
1092 %                                                                             %
1093 %                                                                             %
1094 %     C l o n e K e r n e l I n f o                                           %
1095 %                                                                             %
1096 %                                                                             %
1097 %                                                                             %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 %
1100 %  CloneKernelInfo() creates a new clone of the given Kernel List so that its
1101 %  can be modified without effecting the original.  The cloned kernel should
1102 %  be destroyed using DestoryKernelInfo() when no longer needed.
1103 %
1104 %  The format of the CloneKernelInfo method is:
1105 %
1106 %      KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
1107 %
1108 %  A description of each parameter follows:
1109 %
1110 %    o kernel: the Morphology/Convolution kernel to be cloned
1111 %
1112 */
1113 MagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
1114 {
1115   register long
1116     i;
1117
1118   KernelInfo
1119     *new_kernel;
1120
1121   assert(kernel != (KernelInfo *) NULL);
1122   new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
1123   if (new_kernel == (KernelInfo *) NULL)
1124     return(new_kernel);
1125   *new_kernel=(*kernel); /* copy values in structure */
1126
1127   /* replace the values with a copy of the values */
1128   new_kernel->values=(double *) AcquireQuantumMemory(kernel->width,
1129     kernel->height*sizeof(double));
1130   if (new_kernel->values == (double *) NULL)
1131     return(DestroyKernelInfo(new_kernel));
1132   for (i=0; i < (long) (kernel->width*kernel->height); i++)
1133     new_kernel->values[i]=kernel->values[i];
1134
1135   /* Also clone the next kernel in the kernel list */
1136   if ( kernel->next != (KernelInfo *) NULL ) {
1137     new_kernel->next = CloneKernelInfo(kernel->next);
1138     if ( new_kernel->next == (KernelInfo *) NULL )
1139       return(DestroyKernelInfo(new_kernel));
1140   }
1141
1142   return(new_kernel);
1143 }
1144 \f
1145 /*
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147 %                                                                             %
1148 %                                                                             %
1149 %                                                                             %
1150 %     D e s t r o y K e r n e l I n f o                                       %
1151 %                                                                             %
1152 %                                                                             %
1153 %                                                                             %
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155 %
1156 %  DestroyKernelInfo() frees the memory used by a Convolution/Morphology
1157 %  kernel.
1158 %
1159 %  The format of the DestroyKernelInfo method is:
1160 %
1161 %      KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
1162 %
1163 %  A description of each parameter follows:
1164 %
1165 %    o kernel: the Morphology/Convolution kernel to be destroyed
1166 %
1167 */
1168
1169 MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
1170 {
1171   assert(kernel != (KernelInfo *) NULL);
1172
1173   if ( kernel->next != (KernelInfo *) NULL )
1174     kernel->next = DestroyKernelInfo(kernel->next);
1175
1176   kernel->values = (double *)RelinquishMagickMemory(kernel->values);
1177   kernel = (KernelInfo *) RelinquishMagickMemory(kernel);
1178   return(kernel);
1179 }
1180 \f
1181 /*
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1183 %                                                                             %
1184 %                                                                             %
1185 %                                                                             %
1186 %     E x p a n d K e r n e l I n f o                                         %
1187 %                                                                             %
1188 %                                                                             %
1189 %                                                                             %
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 %
1192 %  ExpandKernelInfo() takes a single kernel, and expands it into a list
1193 %  of kernels each incrementally rotated the angle given.
1194 %
1195 %  WARNING: 45 degree rotations only works for 3x3 kernels.
1196 %  While 90 degree roatations only works for linear and square kernels
1197 %
1198 %  The format of the RotateKernelInfo method is:
1199 %
1200 %      void ExpandKernelInfo(KernelInfo *kernel, double angle)
1201 %
1202 %  A description of each parameter follows:
1203 %
1204 %    o kernel: the Morphology/Convolution kernel
1205 %
1206 %    o angle: angle to rotate in degrees
1207 %
1208 % This function is only internel to this module, as it is not finalized,
1209 % especially with regard to non-orthogonal angles, and rotation of larger
1210 % 2D kernels.
1211 */
1212 static void ExpandKernelInfo(KernelInfo *kernel, double angle)
1213 {
1214   KernelInfo
1215     *new,
1216     *last;
1217   double
1218     a;
1219
1220   last = kernel;
1221   for (a=angle; a<355.0; a+=angle) {
1222     new = CloneKernelInfo(last);
1223     RotateKernelInfo(new, angle);
1224     last->next = new;
1225     last = new;
1226   }
1227 }
1228 \f
1229 /*
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1231 %                                                                             %
1232 %                                                                             %
1233 %                                                                             %
1234 %     M o r p h o l o g y I m a g e C h a n n e l                             %
1235 %                                                                             %
1236 %                                                                             %
1237 %                                                                             %
1238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239 %
1240 %  MorphologyImageChannel() applies a user supplied kernel to the image
1241 %  according to the given mophology method.
1242 %
1243 %  The given kernel is assumed to have been pre-scaled appropriatally, usally
1244 %  by the kernel generator.
1245 %
1246 %  The format of the MorphologyImage method is:
1247 %
1248 %      Image *MorphologyImage(const Image *image,MorphologyMethod method,
1249 %        const long iterations,KernelInfo *kernel,ExceptionInfo *exception)
1250 %      Image *MorphologyImageChannel(const Image *image, const ChannelType
1251 %        channel,MorphologyMethod method,const long iterations,
1252 %        KernelInfo *kernel,ExceptionInfo *exception)
1253 %
1254 %  A description of each parameter follows:
1255 %
1256 %    o image: the image.
1257 %
1258 %    o method: the morphology method to be applied.
1259 %
1260 %    o iterations: apply the operation this many times (or no change).
1261 %                  A value of -1 means loop until no change found.
1262 %                  How this is applied may depend on the morphology method.
1263 %                  Typically this is a value of 1.
1264 %
1265 %    o channel: the channel type.
1266 %
1267 %    o kernel: An array of double representing the morphology kernel.
1268 %              Warning: kernel may be normalized for the Convolve method.
1269 %
1270 %    o exception: return any errors or warnings in this structure.
1271 %
1272 %
1273 % TODO: bias and auto-scale handling of the kernel for convolution
1274 %     The given kernel is assumed to have been pre-scaled appropriatally, usally
1275 %     by the kernel generator.
1276 %
1277 */
1278
1279
1280 /* Internal function
1281  * Apply the low-level Morphology Method Primatives using the given Kernel
1282  * Returning the number of pixels that changed.
1283  * Two pre-created images must be provided, no image is created.
1284  */
1285 static unsigned long MorphologyPrimative(const Image *image, Image
1286      *result_image, const MorphologyMethod method, const ChannelType channel,
1287      const KernelInfo *kernel, ExceptionInfo *exception)
1288 {
1289 #define MorphologyTag  "Morphology/Image"
1290
1291   long
1292     progress,
1293     y, offx, offy,
1294     changed;
1295
1296   MagickBooleanType
1297     status;
1298
1299   MagickPixelPacket
1300     bias;
1301
1302   CacheView
1303     *p_view,
1304     *q_view;
1305
1306   /* Only the most basic morphology is actually performed by this routine */
1307
1308   /*
1309     Apply Basic Morphology to Image.
1310   */
1311   status=MagickTrue;
1312   changed=0;
1313   progress=0;
1314
1315   GetMagickPixelPacket(image,&bias);
1316   SetMagickPixelPacketBias(image,&bias);
1317   /* Future: handle auto-bias from user, based on kernel input */
1318
1319   p_view=AcquireCacheView(image);
1320   q_view=AcquireCacheView(result_image);
1321
1322   /* Some methods (including convolve) needs use a reflected kernel.
1323    * Adjust 'origin' offsets for this reflected kernel.
1324    */
1325   offx = kernel->x;
1326   offy = kernel->y;
1327   switch(method) {
1328     case ConvolveMorphology:
1329     case DilateMorphology:
1330     case DilateIntensityMorphology:
1331     case DistanceMorphology:
1332       /* kernel needs to used with reflection about origin */
1333       offx = (long) kernel->width-offx-1;
1334       offy = (long) kernel->height-offy-1;
1335       break;
1336     case ErodeMorphology:
1337     case ErodeIntensityMorphology:
1338     case HitAndMissMorphology:
1339     case ThinningMorphology:
1340     case ThickenMorphology:
1341       /* kernel is user as is, without reflection */
1342       break;
1343     default:
1344       perror("Not a low level Morphology Method");
1345       break;
1346   }
1347
1348 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1349   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1350 #endif
1351   for (y=0; y < (long) image->rows; y++)
1352   {
1353     MagickBooleanType
1354       sync;
1355
1356     register const PixelPacket
1357       *restrict p;
1358
1359     register const IndexPacket
1360       *restrict p_indexes;
1361
1362     register PixelPacket
1363       *restrict q;
1364
1365     register IndexPacket
1366       *restrict q_indexes;
1367
1368     register long
1369       x;
1370
1371     unsigned long
1372       r;
1373
1374     if (status == MagickFalse)
1375       continue;
1376     p=GetCacheViewVirtualPixels(p_view, -offx,  y-offy,
1377          image->columns+kernel->width,  kernel->height,  exception);
1378     q=GetCacheViewAuthenticPixels(q_view,0,y,result_image->columns,1,
1379          exception);
1380     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
1381       {
1382         status=MagickFalse;
1383         continue;
1384       }
1385     p_indexes=GetCacheViewVirtualIndexQueue(p_view);
1386     q_indexes=GetCacheViewAuthenticIndexQueue(q_view);
1387     r = (image->columns+kernel->width)*offy+offx; /* constant */
1388
1389     for (x=0; x < (long) image->columns; x++)
1390     {
1391        long
1392         v;
1393
1394       register long
1395         u;
1396
1397       register const double
1398         *restrict k;
1399
1400       register const PixelPacket
1401         *restrict k_pixels;
1402
1403       register const IndexPacket
1404         *restrict k_indexes;
1405
1406       MagickPixelPacket
1407         result,
1408         min,
1409         max;
1410
1411       /* Copy input to ouput image for unused channels
1412        * This removes need for 'cloning' a new image every iteration
1413        */
1414       *q = p[r];
1415       if (image->colorspace == CMYKColorspace)
1416         q_indexes[x] = p_indexes[r];
1417
1418       /* Defaults */
1419       min.red     =
1420       min.green   =
1421       min.blue    =
1422       min.opacity =
1423       min.index   = (MagickRealType) QuantumRange;
1424       max.red     =
1425       max.green   =
1426       max.blue    =
1427       max.opacity =
1428       max.index   = (MagickRealType) 0;
1429       /* original pixel value */
1430       result.red     = (MagickRealType) p[r].red;
1431       result.green   = (MagickRealType) p[r].green;
1432       result.blue    = (MagickRealType) p[r].blue;
1433       result.opacity = QuantumRange - (MagickRealType) p[r].opacity;
1434       if ( image->colorspace == CMYKColorspace)
1435          result.index   = (MagickRealType) p_indexes[r];
1436
1437       switch (method) {
1438         case ConvolveMorphology:
1439           /* Set the user defined bias of the weighted average output
1440           **
1441           ** FUTURE: provide some way for internal functions to disable
1442           ** user provided bias and scaling effects.
1443           */
1444           result=bias;
1445           break;
1446         case DilateIntensityMorphology:
1447         case ErodeIntensityMorphology:
1448           result.red = 0.0;  /* flag indicating when first match found */
1449           break;
1450         default:
1451           break;
1452       }
1453
1454       switch ( method ) {
1455         case ConvolveMorphology:
1456             /* Weighted Average of pixels using reflected kernel
1457             **
1458             ** NOTE for correct working of this operation for asymetrical
1459             ** kernels, the kernel needs to be applied in its reflected form.
1460             ** That is its values needs to be reversed.
1461             **
1462             ** Correlation is actually the same as this but without reflecting
1463             ** the kernel, and thus 'lower-level' that Convolution.  However
1464             ** as Convolution is the more common method used, and it does not
1465             ** really cost us much in terms of processing to use a reflected
1466             ** kernel, so it is Convolution that is implemented.
1467             **
1468             ** Correlation will have its kernel reflected before calling
1469             ** this function to do a Convolve.
1470             **
1471             ** For more details of Correlation vs Convolution see
1472             **   http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf
1473             */
1474             if (((channel & SyncChannels) != 0 ) &&
1475                       (image->matte == MagickTrue))
1476               { /* Channel has a 'Sync' Flag, and Alpha Channel enabled.
1477                 ** Weight the color channels with Alpha Channel so that
1478                 ** transparent pixels are not part of the results.
1479                 */
1480                 MagickRealType
1481                   alpha,  /* color channel weighting : kernel*alpha  */
1482                   gamma;  /* divisor, sum of weighting values */
1483
1484                 gamma=0.0;
1485                 k = &kernel->values[ kernel->width*kernel->height-1 ];
1486                 k_pixels = p;
1487                 k_indexes = p_indexes;
1488                 for (v=0; v < (long) kernel->height; v++) {
1489                   for (u=0; u < (long) kernel->width; u++, k--) {
1490                     if ( IsNan(*k) ) continue;
1491                     alpha=(*k)*(QuantumScale*(QuantumRange-
1492                                           k_pixels[u].opacity));
1493                     gamma += alpha;
1494                     result.red     += alpha*k_pixels[u].red;
1495                     result.green   += alpha*k_pixels[u].green;
1496                     result.blue    += alpha*k_pixels[u].blue;
1497                     result.opacity += (*k)*(QuantumRange-k_pixels[u].opacity);
1498                     if ( image->colorspace == CMYKColorspace)
1499                       result.index   += alpha*k_indexes[u];
1500                   }
1501                   k_pixels += image->columns+kernel->width;
1502                   k_indexes += image->columns+kernel->width;
1503                 }
1504                 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
1505                 result.red *= gamma;
1506                 result.green *= gamma;
1507                 result.blue *= gamma;
1508                 result.opacity *= gamma;
1509                 result.index *= gamma;
1510               }
1511             else
1512               {
1513                 /* No 'Sync' flag, or no Alpha involved.
1514                 ** Convolution is simple individual channel weigthed sum.
1515                 */
1516                 k = &kernel->values[ kernel->width*kernel->height-1 ];
1517                 k_pixels = p;
1518                 k_indexes = p_indexes;
1519                 for (v=0; v < (long) kernel->height; v++) {
1520                   for (u=0; u < (long) kernel->width; u++, k--) {
1521                     if ( IsNan(*k) ) continue;
1522                     result.red     += (*k)*k_pixels[u].red;
1523                     result.green   += (*k)*k_pixels[u].green;
1524                     result.blue    += (*k)*k_pixels[u].blue;
1525                     result.opacity += (*k)*(QuantumRange-k_pixels[u].opacity);
1526                     if ( image->colorspace == CMYKColorspace)
1527                       result.index   += (*k)*k_indexes[u];
1528                   }
1529                   k_pixels += image->columns+kernel->width;
1530                   k_indexes += image->columns+kernel->width;
1531                 }
1532               }
1533             break;
1534
1535         case ErodeMorphology:
1536             /* Minimum Value within kernel neighbourhood
1537             **
1538             ** NOTE that the kernel is not reflected for this operation!
1539             **
1540             ** NOTE: in normal Greyscale Morphology, the kernel value should
1541             ** be added to the real value, this is currently not done, due to
1542             ** the nature of the boolean kernels being used.
1543             */
1544             k = kernel->values;
1545             k_pixels = p;
1546             k_indexes = p_indexes;
1547             for (v=0; v < (long) kernel->height; v++) {
1548               for (u=0; u < (long) kernel->width; u++, k++) {
1549                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
1550                 Minimize(min.red,     (double) k_pixels[u].red);
1551                 Minimize(min.green,   (double) k_pixels[u].green);
1552                 Minimize(min.blue,    (double) k_pixels[u].blue);
1553                 Minimize(min.opacity,
1554                             QuantumRange-(double) k_pixels[u].opacity);
1555                 if ( image->colorspace == CMYKColorspace)
1556                   Minimize(min.index,   (double) k_indexes[u]);
1557               }
1558               k_pixels += image->columns+kernel->width;
1559               k_indexes += image->columns+kernel->width;
1560             }
1561             break;
1562
1563
1564         case DilateMorphology:
1565             /* Maximum Value within kernel neighbourhood
1566             **
1567             ** NOTE for correct working of this operation for asymetrical
1568             ** kernels, the kernel needs to be applied in its reflected form.
1569             ** That is its values needs to be reversed.
1570             **
1571             ** NOTE: in normal Greyscale Morphology, the kernel value should
1572             ** be added to the real value, this is currently not done, due to
1573             ** the nature of the boolean kernels being used.
1574             **
1575             */
1576             k = &kernel->values[ kernel->width*kernel->height-1 ];
1577             k_pixels = p;
1578             k_indexes = p_indexes;
1579             for (v=0; v < (long) kernel->height; v++) {
1580               for (u=0; u < (long) kernel->width; u++, k--) {
1581                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
1582                 Maximize(max.red,     (double) k_pixels[u].red);
1583                 Maximize(max.green,   (double) k_pixels[u].green);
1584                 Maximize(max.blue,    (double) k_pixels[u].blue);
1585                 Maximize(max.opacity,
1586                             QuantumRange-(double) k_pixels[u].opacity);
1587                 if ( image->colorspace == CMYKColorspace)
1588                   Maximize(max.index,   (double) k_indexes[u]);
1589               }
1590               k_pixels += image->columns+kernel->width;
1591               k_indexes += image->columns+kernel->width;
1592             }
1593             break;
1594
1595         case HitAndMissMorphology:
1596         case ThinningMorphology:
1597         case ThickenMorphology:
1598             /* Minimum of Foreground Pixel minus Maxumum of Background Pixels
1599             **
1600             ** NOTE that the kernel is not reflected for this operation,
1601             ** and consists of both foreground and background pixel
1602             ** neighbourhoods, 0.0 for background, and 1.0 for foreground
1603             ** with either Nan or 0.5 values for don't care.
1604             **
1605             ** Note that this can produce negative results, though really
1606             ** only a positive match has any real value.
1607             */
1608             k = kernel->values;
1609             k_pixels = p;
1610             k_indexes = p_indexes;
1611             for (v=0; v < (long) kernel->height; v++) {
1612               for (u=0; u < (long) kernel->width; u++, k++) {
1613                 if ( IsNan(*k) ) continue;
1614                 if ( (*k) > 0.7 )
1615                 { /* minimim of foreground pixels */
1616                   Minimize(min.red,     (double) k_pixels[u].red);
1617                   Minimize(min.green,   (double) k_pixels[u].green);
1618                   Minimize(min.blue,    (double) k_pixels[u].blue);
1619                   Minimize(min.opacity,
1620                               QuantumRange-(double) k_pixels[u].opacity);
1621                   if ( image->colorspace == CMYKColorspace)
1622                     Minimize(min.index,   (double) k_indexes[u]);
1623                 }
1624                 else if ( (*k) < 0.3 )
1625                 { /* maximum of background pixels */
1626                   Maximize(max.red,     (double) k_pixels[u].red);
1627                   Maximize(max.green,   (double) k_pixels[u].green);
1628                   Maximize(max.blue,    (double) k_pixels[u].blue);
1629                   Maximize(max.opacity,
1630                               QuantumRange-(double) k_pixels[u].opacity);
1631                   if ( image->colorspace == CMYKColorspace)
1632                     Maximize(max.index,   (double) k_indexes[u]);
1633                 }
1634               }
1635               k_pixels += image->columns+kernel->width;
1636               k_indexes += image->columns+kernel->width;
1637             }
1638             /* Pattern Match  only if min fg larger than min bg pixels */
1639             min.red     -= max.red;     Maximize( min.red,     0.0 );
1640             min.green   -= max.green;   Maximize( min.green,   0.0 );
1641             min.blue    -= max.blue;    Maximize( min.blue,    0.0 );
1642             min.opacity -= max.opacity; Maximize( min.opacity, 0.0 );
1643             min.index   -= max.index;   Maximize( min.index,   0.0 );
1644             break;
1645
1646         case ErodeIntensityMorphology:
1647             /* Select Pixel with Minimum Intensity within kernel neighbourhood
1648             **
1649             ** WARNING: the intensity test fails for CMYK and does not
1650             ** take into account the moderating effect of teh alpha channel
1651             ** on the intensity.
1652             **
1653             ** NOTE that the kernel is not reflected for this operation!
1654             */
1655             k = kernel->values;
1656             k_pixels = p;
1657             k_indexes = p_indexes;
1658             for (v=0; v < (long) kernel->height; v++) {
1659               for (u=0; u < (long) kernel->width; u++, k++) {
1660                 if ( IsNan(*k) || (*k) < 0.5 ) continue;
1661                 if ( result.red == 0.0 ||
1662                      PixelIntensity(&(k_pixels[u])) < PixelIntensity(q) ) {
1663                   /* copy the whole pixel - no channel selection */
1664                   *q = k_pixels[u];
1665                   if ( result.red > 0.0 ) changed++;
1666                   result.red = 1.0;
1667                 }
1668               }
1669               k_pixels += image->columns+kernel->width;
1670               k_indexes += image->columns+kernel->width;
1671             }
1672             break;
1673
1674         case DilateIntensityMorphology:
1675             /* Select Pixel with Maximum Intensity within kernel neighbourhood
1676             **
1677             ** WARNING: the intensity test fails for CMYK and does not
1678             ** take into account the moderating effect of teh alpha channel
1679             ** on the intensity.
1680             **
1681             ** NOTE for correct working of this operation for asymetrical
1682             ** kernels, the kernel needs to be applied in its reflected form.
1683             ** That is its values needs to be reversed.
1684             */
1685             k = &kernel->values[ kernel->width*kernel->height-1 ];
1686             k_pixels = p;
1687             k_indexes = p_indexes;
1688             for (v=0; v < (long) kernel->height; v++) {
1689               for (u=0; u < (long) kernel->width; u++, k--) {
1690                 if ( IsNan(*k) || (*k) < 0.5 ) continue; /* boolean kernel */
1691                 if ( result.red == 0.0 ||
1692                      PixelIntensity(&(k_pixels[u])) > PixelIntensity(q) ) {
1693                   /* copy the whole pixel - no channel selection */
1694                   *q = k_pixels[u];
1695                   if ( result.red > 0.0 ) changed++;
1696                   result.red = 1.0;
1697                 }
1698               }
1699               k_pixels += image->columns+kernel->width;
1700               k_indexes += image->columns+kernel->width;
1701             }
1702             break;
1703
1704
1705         case DistanceMorphology:
1706             /* Add kernel Value and select the minimum value found.
1707             ** The result is a iterative distance from edge of image shape.
1708             **
1709             ** All Distance Kernels are symetrical, but that may not always
1710             ** be the case. For example how about a distance from left edges?
1711             ** To work correctly with asymetrical kernels the reflected kernel
1712             ** needs to be applied.
1713             **
1714             ** Actually this is really a GreyErode with a negative kernel!
1715             **
1716             */
1717             k = &kernel->values[ kernel->width*kernel->height-1 ];
1718             k_pixels = p;
1719             k_indexes = p_indexes;
1720             for (v=0; v < (long) kernel->height; v++) {
1721               for (u=0; u < (long) kernel->width; u++, k--) {
1722                 if ( IsNan(*k) ) continue;
1723                 Minimize(result.red,     (*k)+k_pixels[u].red);
1724                 Minimize(result.green,   (*k)+k_pixels[u].green);
1725                 Minimize(result.blue,    (*k)+k_pixels[u].blue);
1726                 Minimize(result.opacity, (*k)+QuantumRange-k_pixels[u].opacity);
1727                 if ( image->colorspace == CMYKColorspace)
1728                   Minimize(result.index,   (*k)+k_indexes[u]);
1729               }
1730               k_pixels += image->columns+kernel->width;
1731               k_indexes += image->columns+kernel->width;
1732             }
1733             break;
1734
1735         case UndefinedMorphology:
1736         default:
1737             break; /* Do nothing */
1738       }
1739       /* Final mathematics of results (combine with original image?)
1740       **
1741       ** NOTE: Difference Morphology operators Edge* and *Hat could also
1742       ** be done here but works better with iteration as a image difference
1743       ** in the controling function (below).  Thicken and Thinning however
1744       ** should be done here so thay can be iterated correctly.
1745       */
1746       switch ( method ) {
1747         case HitAndMissMorphology:
1748         case ErodeMorphology:
1749           result = min;    /* minimum of neighbourhood */
1750           break;
1751         case DilateMorphology:
1752           result = max;    /* maximum of neighbourhood */
1753           break;
1754         case ThinningMorphology:
1755           /* subtract pattern match from original */
1756           result.red     -= min.red;
1757           result.green   -= min.green;
1758           result.blue    -= min.blue;
1759           result.opacity -= min.opacity;
1760           result.index   -= min.index;
1761           break;
1762         case ThickenMorphology:
1763           /* Union with original image (maximize) - or should this be + */
1764           Maximize( result.red,     min.red );
1765           Maximize( result.green,   min.green );
1766           Maximize( result.blue,    min.blue );
1767           Maximize( result.opacity, min.opacity );
1768           Maximize( result.index,   min.index );
1769           break;
1770         default:
1771           /* result directly calculated or assigned */
1772           break;
1773       }
1774       /* Assign the resulting pixel values - Clamping Result */
1775       switch ( method ) {
1776         case UndefinedMorphology:
1777         case DilateIntensityMorphology:
1778         case ErodeIntensityMorphology:
1779           break;  /* full pixel was directly assigned - not a channel method */
1780         default:
1781           if ((channel & RedChannel) != 0)
1782             q->red = ClampToQuantum(result.red);
1783           if ((channel & GreenChannel) != 0)
1784             q->green = ClampToQuantum(result.green);
1785           if ((channel & BlueChannel) != 0)
1786             q->blue = ClampToQuantum(result.blue);
1787           if ((channel & OpacityChannel) != 0
1788               && image->matte == MagickTrue )
1789             q->opacity = ClampToQuantum(QuantumRange-result.opacity);
1790           if ((channel & IndexChannel) != 0
1791               && image->colorspace == CMYKColorspace)
1792             q_indexes[x] = ClampToQuantum(result.index);
1793           break;
1794       }
1795       /* Count up changed pixels */
1796       if (   ( p[r].red != q->red )
1797           || ( p[r].green != q->green )
1798           || ( p[r].blue != q->blue )
1799           || ( p[r].opacity != q->opacity )
1800           || ( image->colorspace == CMYKColorspace &&
1801                   p_indexes[r] != q_indexes[x] ) )
1802         changed++;  /* The pixel had some value changed! */
1803       p++;
1804       q++;
1805     } /* x */
1806     sync=SyncCacheViewAuthenticPixels(q_view,exception);
1807     if (sync == MagickFalse)
1808       status=MagickFalse;
1809     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1810       {
1811         MagickBooleanType
1812           proceed;
1813
1814 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1815   #pragma omp critical (MagickCore_MorphologyImage)
1816 #endif
1817         proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows);
1818         if (proceed == MagickFalse)
1819           status=MagickFalse;
1820       }
1821   } /* y */
1822   result_image->type=image->type;
1823   q_view=DestroyCacheView(q_view);
1824   p_view=DestroyCacheView(p_view);
1825   return(status ? (unsigned long) changed : 0);
1826 }
1827
1828
1829 MagickExport Image *MorphologyImage(const Image *image, const MorphologyMethod
1830   method, const long iterations,const KernelInfo *kernel, ExceptionInfo
1831   *exception)
1832 {
1833   Image
1834     *morphology_image;
1835
1836   morphology_image=MorphologyImageChannel(image,DefaultChannels,method,
1837     iterations,kernel,exception);
1838   return(morphology_image);
1839 }
1840
1841
1842 MagickExport Image *MorphologyImageChannel(const Image *image,
1843   const ChannelType channel,const MorphologyMethod method,
1844   const long iterations,const KernelInfo *kernel,ExceptionInfo *exception)
1845 {
1846   Image
1847     *new_image,
1848     *old_image,
1849     *grad_image;
1850
1851   KernelInfo
1852     *curr_kernel,
1853     *this_kernel;
1854
1855   MorphologyMethod
1856     curr_method;
1857
1858   unsigned long
1859     count,
1860     limit,
1861     changed,
1862     total_changed,
1863     kernel_number;
1864
1865   assert(image != (Image *) NULL);
1866   assert(image->signature == MagickSignature);
1867   assert(kernel != (KernelInfo *) NULL);
1868   assert(kernel->signature == MagickSignature);
1869   assert(exception != (ExceptionInfo *) NULL);
1870   assert(exception->signature == MagickSignature);
1871
1872   if ( iterations == 0 )
1873     return((Image *)NULL); /* null operation - nothing to do! */
1874
1875   /* kernel must be valid at this point
1876    * (except maybe for posible future morphology methods like "Prune"
1877    */
1878   assert(kernel != (KernelInfo *)NULL);
1879
1880   new_image  = (Image *) NULL;          /* for cleanup */
1881   old_image  = (Image *) NULL;
1882   grad_image = (Image *) NULL;
1883   curr_kernel = (KernelInfo *) NULL;
1884   count = 0;                           /* interation count */
1885   changed = 1;                         /* was last run succesfull */
1886   curr_kernel = (KernelInfo *)kernel;  /* allow kernel and method */
1887   curr_method = method;                /* to be changed as nessary */
1888
1889   limit = (unsigned long) iterations;
1890   if ( iterations < 0 )
1891     limit = image->columns > image->rows ? image->columns : image->rows;
1892
1893   /* Third-level morphology methods */
1894   switch( curr_method ) {
1895     case EdgeMorphology:
1896       grad_image = MorphologyImageChannel(image, channel,
1897             DilateMorphology, iterations, curr_kernel, exception);
1898       if ( grad_image == (Image *) NULL )
1899         goto error_cleanup;
1900       /* FALL-THRU */
1901     case EdgeInMorphology:
1902       curr_method = ErodeMorphology;
1903       break;
1904     case EdgeOutMorphology:
1905       curr_method = DilateMorphology;
1906       break;
1907     case TopHatMorphology:
1908       curr_method = OpenMorphology;
1909       break;
1910     case BottomHatMorphology:
1911       curr_method = CloseMorphology;
1912       break;
1913     default:
1914       break; /* not a third-level method */
1915   }
1916
1917   /* Second-level morphology methods */
1918   switch( curr_method ) {
1919     case OpenMorphology:
1920       /* Open is a Erode then a Dilate without reflection */
1921       new_image = MorphologyImageChannel(image, channel,
1922             ErodeMorphology, iterations, curr_kernel, exception);
1923       if (new_image == (Image *) NULL)
1924         goto error_cleanup;
1925       curr_method = DilateMorphology;
1926       break;
1927     case OpenIntensityMorphology:
1928       new_image = MorphologyImageChannel(image, channel,
1929             ErodeIntensityMorphology, iterations, curr_kernel, exception);
1930       if (new_image == (Image *) NULL)
1931         goto error_cleanup;
1932       curr_method = DilateIntensityMorphology;
1933       break;
1934
1935     case CloseMorphology:
1936       /* Close is a Dilate then Erode using reflected kernel */
1937       /* A reflected kernel is needed for a Close */
1938       if ( curr_kernel == kernel )
1939         curr_kernel = CloneKernelInfo(kernel);
1940       if (curr_kernel == (KernelInfo *) NULL)
1941         goto error_cleanup;
1942       RotateKernelInfo(curr_kernel,180);
1943       new_image = MorphologyImageChannel(image, channel,
1944             DilateMorphology, iterations, curr_kernel, exception);
1945       if (new_image == (Image *) NULL)
1946         goto error_cleanup;
1947       curr_method = ErodeMorphology;
1948       break;
1949     case CloseIntensityMorphology:
1950       /* A reflected kernel is needed for a Close */
1951       if ( curr_kernel == kernel )
1952         curr_kernel = CloneKernelInfo(kernel);
1953       if (curr_kernel == (KernelInfo *) NULL)
1954         goto error_cleanup;
1955       RotateKernelInfo(curr_kernel,180);
1956       new_image = MorphologyImageChannel(image, channel,
1957             DilateIntensityMorphology, iterations, curr_kernel, exception);
1958       if (new_image == (Image *) NULL)
1959         goto error_cleanup;
1960       curr_method = ErodeIntensityMorphology;
1961       break;
1962
1963     case CorrelateMorphology:
1964       /* A Correlation is actually a Convolution with a reflected kernel.
1965       ** However a Convolution is a weighted sum with a reflected kernel.
1966       ** It may seem stange to convert a Correlation into a Convolution
1967       ** as the Correleation is the simplier method, but Convolution is
1968       ** much more commonly used, and it makes sense to implement it directly
1969       ** so as to avoid the need to duplicate the kernel when it is not
1970       ** required (which is typically the default).
1971       */
1972       if ( curr_kernel == kernel )
1973         curr_kernel = CloneKernelInfo(kernel);
1974       if (curr_kernel == (KernelInfo *) NULL)
1975         goto error_cleanup;
1976       RotateKernelInfo(curr_kernel,180);
1977       curr_method = ConvolveMorphology;
1978       /* FALL-THRU into Correlate (weigthed sum without reflection) */
1979
1980     case ConvolveMorphology:
1981       { /* Scale or Normalize kernel, according to user wishes
1982         ** before using it for the Convolve/Correlate method.
1983         **
1984         ** FUTURE: provide some way for internal functions to disable
1985         ** user bias and scaling effects.
1986         */
1987         const char
1988           *artifact = GetImageArtifact(image,"convolve:scale");
1989         if ( artifact != (char *)NULL ) {
1990           GeometryFlags
1991             flags;
1992           GeometryInfo
1993             args;
1994
1995           if ( curr_kernel == kernel )
1996             curr_kernel = CloneKernelInfo(kernel);
1997           if (curr_kernel == (KernelInfo *) NULL)
1998             goto error_cleanup;
1999           args.rho = 1.0;
2000           flags = (GeometryFlags) ParseGeometry(artifact, &args);
2001           ScaleKernelInfo(curr_kernel, args.rho, flags);
2002         }
2003       }
2004       /* FALL-THRU to do the first, and typically the only iteration */
2005
2006     default:
2007       /* Do a single iteration using the Low-Level Morphology method!
2008       ** This ensures a "new_image" has been generated, but allows us to skip
2009       ** the creation of 'old_image' if no more iterations are needed.
2010       **
2011       ** The "curr_method" should also be set to a low-level method that is
2012       ** understood by the MorphologyPrimative() internal function.
2013       */
2014       new_image=CloneImage(image,0,0,MagickTrue,exception);
2015       if (new_image == (Image *) NULL)
2016         goto error_cleanup;
2017       if (SetImageStorageClass(new_image,DirectClass) == MagickFalse)
2018         {
2019           InheritException(exception,&new_image->exception);
2020           goto exit_cleanup;
2021         }
2022       count++;  /* iteration count */
2023       changed = MorphologyPrimative(image,new_image,curr_method,channel,
2024            curr_kernel, exception);
2025       if ( GetImageArtifact(image,"verbose") != (const char *) NULL )
2026         fprintf(stderr, "Morphology %s:%lu.%lu => Changed %lu\n",
2027               MagickOptionToMnemonic(MagickMorphologyOptions, curr_method),
2028               count, 0L, changed);
2029       break;
2030   }
2031   /* At this point
2032    *   + "curr_method" should be set to a low-level morphology method
2033    *   + "count=1" if the first iteration of the first kernel has been done.
2034    *   + "new_image" is defined and contains the current resulting image
2035    */
2036
2037   /* The Hit-And-Miss Morphology is not 'iterated' against the resulting
2038   ** image from the previous morphology step.  It must always be applied
2039   ** to the original image, with the results collected into a union (maximimum
2040   ** or lighten) of all the results.  Multiple kernels may be applied but
2041   ** an iteration of the morphology does nothing, so is ignored.
2042   **
2043   ** The first kernel is guranteed to have been done, so lets continue the
2044   ** process, with the other kernels in the kernel list.
2045   */
2046   if ( method == HitAndMissMorphology )
2047   {
2048     if ( curr_kernel->next != (KernelInfo *) NULL ) {
2049       /* create a second working image */
2050       old_image = CloneImage(image,0,0,MagickTrue,exception);
2051       if (old_image == (Image *) NULL)
2052         goto error_cleanup;
2053       if (SetImageStorageClass(old_image,DirectClass) == MagickFalse)
2054         {
2055           InheritException(exception,&old_image->exception);
2056           goto exit_cleanup;
2057         }
2058
2059       /* loop through rest of the kernels */
2060       this_kernel=curr_kernel->next;
2061       kernel_number=1;
2062       while( this_kernel != (KernelInfo *) NULL )
2063         {
2064           changed = MorphologyPrimative(image,old_image,curr_method,channel,
2065               this_kernel,exception);
2066           (void) CompositeImageChannel(new_image,
2067             (ChannelType) (channel & ~SyncChannels), LightenCompositeOp,
2068             old_image, 0, 0);
2069           if ( GetImageArtifact(image,"verbose") != (const char *) NULL )
2070             fprintf(stderr, "Morphology %s:%lu.%lu => Changed %lu\n",
2071                   MagickOptionToMnemonic(MagickMorphologyOptions, curr_method),
2072                   count, kernel_number, changed);
2073           this_kernel = this_kernel->next;
2074           kernel_number++;
2075         }
2076       old_image=DestroyImage(old_image);
2077     }
2078     goto exit_cleanup;
2079   }
2080
2081   /* Repeat the low-level morphology over all kernels
2082      until iteration count limit or no change from any kernel is found */
2083   if ( ( count < limit && changed > 0 ) ||
2084        curr_kernel->next != (KernelInfo *) NULL ) {
2085
2086     /* create a second working image */
2087     old_image = CloneImage(image,0,0,MagickTrue,exception);
2088     if (old_image == (Image *) NULL)
2089       goto error_cleanup;
2090     if (SetImageStorageClass(old_image,DirectClass) == MagickFalse)
2091       {
2092         InheritException(exception,&old_image->exception);
2093         goto exit_cleanup;
2094       }
2095
2096     /* reset variables for the first/next iteration, or next kernel) */
2097     kernel_number = 0;
2098     this_kernel = curr_kernel;
2099     total_changed = count != 0 ? changed : 0;
2100     if ( count != 0 && this_kernel != (KernelInfo *) NULL ) {
2101       count = 0;  /* first iteration is not yet finished! */
2102       this_kernel = curr_kernel->next;
2103       kernel_number = 1;
2104       total_changed = changed;
2105     }
2106
2107     while ( count < limit ) {
2108       count++;
2109       while ( this_kernel != (KernelInfo *) NULL ) {
2110         Image *tmp = old_image;
2111         old_image = new_image;
2112         new_image = tmp;
2113         changed = MorphologyPrimative(old_image,new_image,curr_method,channel,
2114                           this_kernel,exception);
2115         if ( GetImageArtifact(image,"verbose") != (const char *) NULL )
2116           fprintf(stderr, "Morphology %s:%lu.%lu => Changed %lu\n",
2117                 MagickOptionToMnemonic(MagickMorphologyOptions, curr_method),
2118                 count, kernel_number, changed);
2119         total_changed += changed;
2120         this_kernel = this_kernel->next;
2121         kernel_number++;
2122       }
2123       if ( total_changed == 0 )
2124         break;  /* no changes after processing all kernels - ABORT */
2125       /* prepare for next loop */
2126       total_changed = 0;
2127       kernel_number = 0;
2128       this_kernel = curr_kernel;
2129     }
2130     old_image=DestroyImage(old_image);
2131   }
2132
2133   /* finished with kernel - destary any copy that was made */
2134   if ( curr_kernel != kernel )
2135     curr_kernel=DestroyKernelInfo(curr_kernel);
2136
2137   /* Third-level Subtractive methods post-processing
2138   **
2139   ** The removal of any 'Sync' channel flag in the Image Compositon below
2140   ** ensures the compose method is applied in a purely mathematical way, only
2141   ** the selected channels, without any normal 'alpha blending' normally
2142   ** associated with the compose method.
2143   **
2144   ** Note "method" here is the 'original' morphological method, and not the
2145   ** 'current' morphological method used above to generate "new_image".
2146   */
2147   switch( method ) {
2148     case EdgeOutMorphology:
2149     case EdgeInMorphology:
2150     case TopHatMorphology:
2151     case BottomHatMorphology:
2152       /* Get Difference relative to the original image */
2153       (void) CompositeImageChannel(new_image, (ChannelType) (channel & ~SyncChannels),
2154            DifferenceCompositeOp, image, 0, 0);
2155       break;
2156     case EdgeMorphology:
2157       /* Difference the Eroded image from the saved Dilated image */
2158       (void) CompositeImageChannel(new_image, (ChannelType) (channel & ~SyncChannels),
2159            DifferenceCompositeOp, grad_image, 0, 0);
2160       grad_image=DestroyImage(grad_image);
2161       break;
2162     default:
2163       break;
2164   }
2165
2166   return(new_image);
2167
2168   /* Yes goto's are bad, but in this case it makes cleanup lot more efficient */
2169 error_cleanup:
2170   if ( new_image != (Image *) NULL )
2171     DestroyImage(new_image);
2172 exit_cleanup:
2173   if ( old_image != (Image *) NULL )
2174     DestroyImage(old_image);
2175   if ( curr_kernel != (KernelInfo *) NULL &&  curr_kernel != kernel )
2176     curr_kernel=DestroyKernelInfo(curr_kernel);
2177   return(new_image);
2178 }
2179 \f
2180 /*
2181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2182 %                                                                             %
2183 %                                                                             %
2184 %                                                                             %
2185 +     R o t a t e K e r n e l I n f o                                         %
2186 %                                                                             %
2187 %                                                                             %
2188 %                                                                             %
2189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 %
2191 %  RotateKernelInfo() rotates the kernel by the angle given.  Currently it is
2192 %  restricted to 90 degree angles, but this may be improved in the future.
2193 %
2194 %  The format of the RotateKernelInfo method is:
2195 %
2196 %      void RotateKernelInfo(KernelInfo *kernel, double angle)
2197 %
2198 %  A description of each parameter follows:
2199 %
2200 %    o kernel: the Morphology/Convolution kernel
2201 %
2202 %    o angle: angle to rotate in degrees
2203 %
2204 % This function is only internel to this module, as it is not finalized,
2205 % especially with regard to non-orthogonal angles, and rotation of larger
2206 % 2D kernels.
2207 */
2208 static void RotateKernelInfo(KernelInfo *kernel, double angle)
2209 {
2210   /* angle the lower kernels first */
2211   if ( kernel->next != (KernelInfo *) NULL)
2212     RotateKernelInfo(kernel->next, angle);
2213
2214   /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical
2215   **
2216   ** TODO: expand beyond simple 90 degree rotates, flips and flops
2217   */
2218
2219   /* Modulus the angle */
2220   angle = fmod(angle, 360.0);
2221   if ( angle < 0 )
2222     angle += 360.0;
2223
2224   if ( 337.5 < angle || angle <= 22.5 )
2225     return;   /* no change! - At least at this time */
2226
2227   switch (kernel->type) {
2228     /* These built-in kernels are cylindrical kernels, rotating is useless */
2229     case GaussianKernel:
2230     case LaplacianKernel:
2231     case LOGKernel:
2232     case DOGKernel:
2233     case DiskKernel:
2234     case ChebyshevKernel:
2235     case ManhattenKernel:
2236     case EuclideanKernel:
2237       return;
2238
2239     /* These may be rotatable at non-90 angles in the future */
2240     /* but simply rotating them in multiples of 90 degrees is useless */
2241     case SquareKernel:
2242     case DiamondKernel:
2243     case PlusKernel:
2244       return;
2245
2246     /* These only allows a +/-90 degree rotation (by transpose) */
2247     /* A 180 degree rotation is useless */
2248     case BlurKernel:
2249     case RectangleKernel:
2250       if ( 135.0 < angle && angle <= 225.0 )
2251         return;
2252       if ( 225.0 < angle && angle <= 315.0 )
2253         angle -= 180;
2254       break;
2255
2256     /* these are freely rotatable in 90 degree units */
2257     case SobelKernel:
2258     case CometKernel:
2259     case UndefinedKernel:
2260     case UserDefinedKernel:
2261       break;
2262   }
2263   /* Attempt rotations by 45 degrees */
2264   if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
2265     {
2266       if ( kernel->width == 3 && kernel->height == 3 )
2267         { /* Rotate a 3x3 square by 45 degree angle */
2268           MagickRealType t  = kernel->values[0];
2269           kernel->values[0] = kernel->values[1];
2270           kernel->values[1] = kernel->values[2];
2271           kernel->values[2] = kernel->values[5];
2272           kernel->values[5] = kernel->values[8];
2273           kernel->values[8] = kernel->values[7];
2274           kernel->values[7] = kernel->values[6];
2275           kernel->values[6] = kernel->values[3];
2276           kernel->values[3] = t;
2277           angle = fmod(angle+45.0, 360.0);
2278         }
2279       else
2280         perror("Unable to rotate non-3x3 kernel by 45 degrees");
2281     }
2282   if ( 45.0 < fmod(angle, 180.0)  && fmod(angle,180.0) <= 135.0 )
2283     {
2284       if ( kernel->width == 1 || kernel->height == 1 )
2285         { /* Do a transpose of the image, which results in a 90
2286           ** degree rotation of a 1 dimentional kernel
2287           */
2288           long
2289             t;
2290           t = (long) kernel->width;
2291           kernel->width = kernel->height;
2292           kernel->height = (unsigned long) t;
2293           t = kernel->x;
2294           kernel->x = kernel->y;
2295           kernel->y = t;
2296           if ( kernel->width == 1 )
2297             angle = fmod(angle+270.0, 360.0);  /* angle -90 degrees */
2298           else
2299             angle = fmod(angle+90.0, 360.0);   /* angle +90 degrees */
2300         }
2301       else if ( kernel->width == kernel->height )
2302         { /* Rotate a square array of values by 90 degrees */
2303           register unsigned long
2304             i,j,x,y;
2305           register MagickRealType
2306             *k,t;
2307           k=kernel->values;
2308           for( i=0, x=kernel->width-1;  i<=x;   i++, x--)
2309             for( j=0, y=kernel->height-1;  j<y;   j++, y--)
2310               { t                    = k[i+j*kernel->width];
2311                 k[i+j*kernel->width] = k[y+i*kernel->width];
2312                 k[y+i*kernel->width] = k[x+y*kernel->width];
2313                 k[x+y*kernel->width] = k[j+x*kernel->width];
2314                 k[j+x*kernel->width] = t;
2315               }
2316           angle = fmod(angle+90.0, 360.0);  /* angle +90 degrees */
2317         }
2318       else
2319         perror("Unable to rotate a non-square, non-linear kernel 90 degrees");
2320     }
2321   if ( 135.0 < angle && angle <= 225.0 )
2322     {
2323       /* For a 180 degree rotation - also know as a reflection */
2324       /* This is actually a very very common operation! */
2325       /* Basically all that is needed is a reversal of the kernel data! */
2326       unsigned long
2327         i,j;
2328       register double
2329         *k,t;
2330
2331       k=kernel->values;
2332       for ( i=0, j=kernel->width*kernel->height-1;  i<j;  i++, j--)
2333         t=k[i],  k[i]=k[j],  k[j]=t;
2334
2335       kernel->x = (long) kernel->width  - kernel->x - 1;
2336       kernel->y = (long) kernel->height - kernel->y - 1;
2337       angle = fmod(angle+180.0, 360.0);   /* angle+180 degrees */
2338     }
2339   /* At this point angle should at least between -45 (315) and +45 degrees
2340    * In the future some form of non-orthogonal angled rotates could be
2341    * performed here, posibily with a linear kernel restriction.
2342    */
2343
2344 #if 0
2345     { /* Do a Flop by reversing each row.
2346        */
2347       unsigned long
2348         y;
2349       register long
2350         x,r;
2351       register double
2352         *k,t;
2353
2354       for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
2355         for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
2356           t=k[x],  k[x]=k[r],  k[r]=t;
2357
2358       kernel->x = kernel->width - kernel->x - 1;
2359       angle = fmod(angle+180.0, 360.0);
2360     }
2361 #endif
2362   return;
2363 }
2364 \f
2365 /*
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 %                                                                             %
2368 %                                                                             %
2369 %                                                                             %
2370 %     S c a l e K e r n e l I n f o                                           %
2371 %                                                                             %
2372 %                                                                             %
2373 %                                                                             %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375 %
2376 %  ScaleKernelInfo() scales the given kernel list by the given amount, with or
2377 %  without normalization of the sum of the kernel values (as per given flags).
2378 %
2379 %  By default (no flags given) the values within the kernel is scaled
2380 %  directly using given scaling factor without change.
2381 %
2382 %  If any 'normalize_flags' are given the kernel will first be normalized and
2383 %  then further scaled by the scaling factor value given.  A 'PercentValue'
2384 %  flag will cause the given scaling factor to be divided by one hundred
2385 %  percent.
2386 %
2387 %  Kernel normalization ('normalize_flags' given) is designed to ensure that
2388 %  any use of the kernel scaling factor with 'Convolve' or 'Correlate'
2389 %  morphology methods will fall into -1.0 to +1.0 range.  Note that for
2390 %  non-HDRI versions of IM this may cause images to have any negative results
2391 %  clipped, unless some 'bias' is used.
2392 %
2393 %  More specifically.  Kernels which only contain positive values (such as a
2394 %  'Gaussian' kernel) will be scaled so that those values sum to +1.0,
2395 %  ensuring a 0.0 to +1.0 output range for non-HDRI images.
2396 %
2397 %  For Kernels that contain some negative values, (such as 'Sharpen' kernels)
2398 %  the kernel will be scaled by the absolute of the sum of kernel values, so
2399 %  that it will generally fall within the +/- 1.0 range.
2400 %
2401 %  For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel
2402 %  will be scaled by just the sum of the postive values, so that its output
2403 %  range will again fall into the  +/- 1.0 range.
2404 %
2405 %  For special kernels designed for locating shapes using 'Correlate', (often
2406 %  only containing +1 and -1 values, representing foreground/brackground
2407 %  matching) a special normalization method is provided to scale the positive
2408 %  values seperatally to those of the negative values, so the kernel will be
2409 %  forced to become a zero-sum kernel better suited to such searches.
2410 %
2411 %  WARNING: Correct normalization of the kernel assumes that the '*_range'
2412 %  attributes within the kernel structure have been correctly set during the
2413 %  kernels creation.
2414 %
2415 %  NOTE: The values used for 'normalize_flags' have been selected specifically
2416 %  to match the use of geometry options, so that '!' means NormalizeValue,
2417 %  '^' means CorrelateNormalizeValue, and '%' means PercentValue.  All other
2418 %  GeometryFlags values are ignored.
2419 %
2420 %  The format of the ScaleKernelInfo method is:
2421 %
2422 %      void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor,
2423 %               const MagickStatusType normalize_flags )
2424 %
2425 %  A description of each parameter follows:
2426 %
2427 %    o kernel: the Morphology/Convolution kernel
2428 %
2429 %    o scaling_factor:
2430 %             multiply all values (after normalization) by this factor if not
2431 %             zero.  If the kernel is normalized regardless of any flags.
2432 %
2433 %    o normalize_flags:
2434 %             GeometryFlags defining normalization method to use.
2435 %             specifically: NormalizeValue, CorrelateNormalizeValue,
2436 %                           and/or PercentValue
2437 %
2438 % This function is internal to this module only at this time, but can be
2439 % exported to other modules if needed.
2440 */
2441 MagickExport void ScaleKernelInfo(KernelInfo *kernel,
2442   const double scaling_factor,const GeometryFlags normalize_flags)
2443 {
2444   register long
2445     i;
2446
2447   register double
2448     pos_scale,
2449     neg_scale;
2450
2451   /* scale the lower kernels first */
2452   if ( kernel->next != (KernelInfo *) NULL)
2453     ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
2454
2455   pos_scale = 1.0;
2456   if ( (normalize_flags&NormalizeValue) != 0 ) {
2457     /* normalize kernel appropriately */
2458     if ( fabs(kernel->positive_range + kernel->negative_range) > MagickEpsilon )
2459       pos_scale = fabs(kernel->positive_range + kernel->negative_range);
2460     else
2461       pos_scale = kernel->positive_range; /* special zero-summing kernel */
2462   }
2463   /* force kernel into being a normalized zero-summing kernel */
2464   if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
2465     pos_scale = ( fabs(kernel->positive_range) > MagickEpsilon )
2466                  ? kernel->positive_range : 1.0;
2467     neg_scale = ( fabs(kernel->negative_range) > MagickEpsilon )
2468                  ? -kernel->negative_range : 1.0;
2469   }
2470   else
2471     neg_scale = pos_scale;
2472
2473   /* finialize scaling_factor for positive and negative components */
2474   pos_scale = scaling_factor/pos_scale;
2475   neg_scale = scaling_factor/neg_scale;
2476   if ( (normalize_flags&PercentValue) != 0 ) {
2477     pos_scale /= 100.0;
2478     neg_scale /= 100.0;
2479   }
2480
2481   for (i=0; i < (long) (kernel->width*kernel->height); i++)
2482     if ( ! IsNan(kernel->values[i]) )
2483       kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
2484
2485   /* convolution output range */
2486   kernel->positive_range *= pos_scale;
2487   kernel->negative_range *= neg_scale;
2488   /* maximum and minimum values in kernel */
2489   kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
2490   kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
2491
2492   /* swap kernel settings if user scaling factor is negative */
2493   if ( scaling_factor < MagickEpsilon ) {
2494     double t;
2495     t = kernel->positive_range;
2496     kernel->positive_range = kernel->negative_range;
2497     kernel->negative_range = t;
2498     t = kernel->maximum;
2499     kernel->maximum = kernel->minimum;
2500     kernel->minimum = 1;
2501   }
2502
2503   return;
2504 }
2505 \f
2506 /*
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508 %                                                                             %
2509 %                                                                             %
2510 %                                                                             %
2511 +     S h o w K e r n e l I n f o                                             %
2512 %                                                                             %
2513 %                                                                             %
2514 %                                                                             %
2515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516 %
2517 %  ShowKernelInfo() outputs the details of the given kernel defination to
2518 %  standard error, generally due to a users 'showkernel' option request.
2519 %
2520 %  The format of the ShowKernel method is:
2521 %
2522 %      void ShowKernelInfo(KernelInfo *kernel)
2523 %
2524 %  A description of each parameter follows:
2525 %
2526 %    o kernel: the Morphology/Convolution kernel
2527 %
2528 % This function is internal to this module only at this time. That may change
2529 % in the future.
2530 */
2531 MagickExport void ShowKernelInfo(KernelInfo *kernel)
2532 {
2533   KernelInfo
2534     *k;
2535
2536   long
2537     c, i, u, v;
2538
2539   for (c=0, k=kernel;  k != (KernelInfo *) NULL;  c++, k=k->next ) {
2540
2541     fprintf(stderr, "Kernel ");
2542     if ( kernel->next != (KernelInfo *) NULL )
2543       fprintf(stderr, " #%ld", c );
2544     fprintf(stderr, " \"%s\" of size %lux%lu%+ld%+ld ",
2545           MagickOptionToMnemonic(MagickKernelOptions, k->type),
2546           kernel->width, k->height,
2547           kernel->x, kernel->y );
2548     fprintf(stderr,
2549           " with values from %.*lg to %.*lg\n",
2550           GetMagickPrecision(), k->minimum,
2551           GetMagickPrecision(), k->maximum);
2552     fprintf(stderr, "Forming convolution output range from %.*lg to %.*lg%s\n",
2553           GetMagickPrecision(), k->negative_range,
2554           GetMagickPrecision(), k->positive_range,
2555           /*kernel->normalized == MagickTrue ? " (normalized)" : */ "" );
2556     for (i=v=0; v < (long) k->height; v++) {
2557       fprintf(stderr,"%2ld:",v);
2558       for (u=0; u < (long) k->width; u++, i++)
2559         if ( IsNan(k->values[i]) )
2560           fprintf(stderr," %*s", GetMagickPrecision()+2, "nan");
2561         else
2562           fprintf(stderr," %*.*lg", GetMagickPrecision()+2,
2563               GetMagickPrecision(), k->values[i]);
2564       fprintf(stderr,"\n");
2565     }
2566   }
2567 }
2568 \f
2569 /*
2570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571 %                                                                             %
2572 %                                                                             %
2573 %                                                                             %
2574 +     Z e r o K e r n e l N a n s                                             %
2575 %                                                                             %
2576 %                                                                             %
2577 %                                                                             %
2578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2579 %
2580 %  ZeroKernelNans() replaces any special 'nan' value that may be present in
2581 %  the kernel with a zero value.  This is typically done when the kernel will
2582 %  be used in special hardware (GPU) convolution processors, to simply
2583 %  matters.
2584 %
2585 %  The format of the ZeroKernelNans method is:
2586 %
2587 %      voidZeroKernelNans (KernelInfo *kernel)
2588 %
2589 %  A description of each parameter follows:
2590 %
2591 %    o kernel: the Morphology/Convolution kernel
2592 %
2593 % FUTURE: return the information in a string for API usage.
2594 */
2595 MagickExport void ZeroKernelNans(KernelInfo *kernel)
2596 {
2597   register long
2598     i;
2599
2600   /* scale the lower kernels first */
2601   if ( kernel->next != (KernelInfo *) NULL)
2602     ZeroKernelNans(kernel->next);
2603
2604   for (i=0; i < (long) (kernel->width*kernel->height); i++)
2605     if ( IsNan(kernel->values[i]) )
2606       kernel->values[i] = 0.0;
2607
2608   return;
2609 }