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