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