]> granicus.if.org Git - imagemagick/blob - MagickCore/statistic.c
(no commit message)
[imagemagick] / MagickCore / statistic.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %        SSSSS  TTTTT   AAA   TTTTT  IIIII  SSSSS  TTTTT  IIIII   CCCC        %
7 %        SS       T    A   A    T      I    SS       T      I    C            %
8 %         SSS     T    AAAAA    T      I     SSS     T      I    C            %
9 %           SS    T    A   A    T      I       SS    T      I    C            %
10 %        SSSSS    T    A   A    T    IIIII  SSSSS    T    IIIII   CCCC        %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Statistical Methods                    %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/property.h"
45 #include "MagickCore/animate.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/cache-private.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/client.h"
52 #include "MagickCore/color.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/composite.h"
57 #include "MagickCore/composite-private.h"
58 #include "MagickCore/compress.h"
59 #include "MagickCore/constitute.h"
60 #include "MagickCore/display.h"
61 #include "MagickCore/draw.h"
62 #include "MagickCore/enhance.h"
63 #include "MagickCore/exception.h"
64 #include "MagickCore/exception-private.h"
65 #include "MagickCore/gem.h"
66 #include "MagickCore/gem-private.h"
67 #include "MagickCore/geometry.h"
68 #include "MagickCore/list.h"
69 #include "MagickCore/image-private.h"
70 #include "MagickCore/magic.h"
71 #include "MagickCore/magick.h"
72 #include "MagickCore/memory_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/monitor.h"
75 #include "MagickCore/monitor-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/paint.h"
78 #include "MagickCore/pixel-accessor.h"
79 #include "MagickCore/profile.h"
80 #include "MagickCore/quantize.h"
81 #include "MagickCore/quantum-private.h"
82 #include "MagickCore/random_.h"
83 #include "MagickCore/random-private.h"
84 #include "MagickCore/resource_.h"
85 #include "MagickCore/segment.h"
86 #include "MagickCore/semaphore.h"
87 #include "MagickCore/signature-private.h"
88 #include "MagickCore/statistic.h"
89 #include "MagickCore/string_.h"
90 #include "MagickCore/thread-private.h"
91 #include "MagickCore/timer.h"
92 #include "MagickCore/utility.h"
93 #include "MagickCore/version.h"
94 \f
95 /*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %                                                                             %
98 %                                                                             %
99 %                                                                             %
100 %     E v a l u a t e I m a g e                                               %
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 %  EvaluateImage() applies a value to the image with an arithmetic, relational,
107 %  or logical operator to an image. Use these operations to lighten or darken
108 %  an image, to increase or decrease contrast in an image, or to produce the
109 %  "negative" of an image.
110 %
111 %  The format of the EvaluateImage method is:
112 %
113 %      MagickBooleanType EvaluateImage(Image *image,
114 %        const MagickEvaluateOperator op,const double value,
115 %        ExceptionInfo *exception)
116 %      MagickBooleanType EvaluateImages(Image *images,
117 %        const MagickEvaluateOperator op,const double value,
118 %        ExceptionInfo *exception)
119 %
120 %  A description of each parameter follows:
121 %
122 %    o image: the image.
123 %
124 %    o op: A channel op.
125 %
126 %    o value: A value value.
127 %
128 %    o exception: return any errors or warnings in this structure.
129 %
130 */
131
132 typedef struct _PixelChannels
133 {
134   double
135     channel[CompositePixelChannel];
136 } PixelChannels;
137
138 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
139 {
140   register ssize_t
141     i;
142
143   assert(pixels != (PixelChannels **) NULL);
144   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
145     if (pixels[i] != (PixelChannels *) NULL)
146       pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
147   pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
148   return(pixels);
149 }
150
151 static PixelChannels **AcquirePixelThreadSet(const Image *image,
152   const size_t number_images)
153 {
154   register ssize_t
155     i;
156
157   PixelChannels
158     **pixels;
159
160   size_t
161     length,
162     number_threads;
163
164   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
165   pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
166     sizeof(*pixels));
167   if (pixels == (PixelChannels **) NULL)
168     return((PixelChannels **) NULL);
169   (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
170   for (i=0; i < (ssize_t) number_threads; i++)
171   {
172     register ssize_t
173       j;
174
175     length=image->columns;
176     if (length < number_images)
177       length=number_images;
178     pixels[i]=(PixelChannels *) AcquireQuantumMemory(length,sizeof(**pixels));
179     if (pixels[i] == (PixelChannels *) NULL)
180       return(DestroyPixelThreadSet(pixels));
181     for (j=0; j < (ssize_t) length; j++)
182     {
183       register ssize_t
184         k;
185
186       for (k=0; k < MaxPixelChannels; k++)
187         pixels[i][j].channel[k]=0.0;
188     }
189   }
190   return(pixels);
191 }
192
193 static inline double EvaluateMax(const double x,const double y)
194 {
195   if (x > y)
196     return(x);
197   return(y);
198 }
199
200 #if defined(__cplusplus) || defined(c_plusplus)
201 extern "C" {
202 #endif
203
204 static int IntensityCompare(const void *x,const void *y)
205 {
206   const PixelChannels
207     *color_1,
208     *color_2;
209
210   double
211     distance;
212
213   register ssize_t
214     i;
215
216   color_1=(const PixelChannels *) x;
217   color_2=(const PixelChannels *) y;
218   distance=0.0;
219   for (i=0; i < MaxPixelChannels; i++)
220     distance+=color_1->channel[i]-(double) color_2->channel[i];
221   return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
222 }
223
224 #if defined(__cplusplus) || defined(c_plusplus)
225 }
226 #endif
227
228 static inline double MagickMin(const double x,const double y)
229 {
230   if (x < y)
231     return(x);
232   return(y);
233 }
234
235 static double ApplyEvaluateOperator(RandomInfo *random_info,const Quantum pixel,
236   const MagickEvaluateOperator op,const double value)
237 {
238   double
239     result;
240
241   result=0.0;
242   switch (op)
243   {
244     case UndefinedEvaluateOperator:
245       break;
246     case AbsEvaluateOperator:
247     {
248       result=(double) fabs((double) (pixel+value));
249       break;
250     }
251     case AddEvaluateOperator:
252     {
253       result=(double) (pixel+value);
254       break;
255     }
256     case AddModulusEvaluateOperator:
257     {
258       /*
259         This returns a 'floored modulus' of the addition which is a positive
260         result.  It differs from % or fmod() that returns a 'truncated modulus'
261         result, where floor() is replaced by trunc() and could return a
262         negative result (which is clipped).
263       */
264       result=pixel+value;
265       result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
266       break;
267     }
268     case AndEvaluateOperator:
269     {
270       result=(double) ((size_t) pixel & (size_t) (value+0.5));
271       break;
272     }
273     case CosineEvaluateOperator:
274     {
275       result=(double) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
276         QuantumScale*pixel*value))+0.5));
277       break;
278     }
279     case DivideEvaluateOperator:
280     {
281       result=pixel/(value == 0.0 ? 1.0 : value);
282       break;
283     }
284     case ExponentialEvaluateOperator:
285     {
286       result=(double) (QuantumRange*exp((double) (value*QuantumScale*pixel)));
287       break;
288     }
289     case GaussianNoiseEvaluateOperator:
290     {
291       result=(double) GenerateDifferentialNoise(random_info,pixel,
292         GaussianNoise,value);
293       break;
294     }
295     case ImpulseNoiseEvaluateOperator:
296     {
297       result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
298         value);
299       break;
300     }
301     case LaplacianNoiseEvaluateOperator:
302     {
303       result=(double) GenerateDifferentialNoise(random_info,pixel,
304         LaplacianNoise,value);
305       break;
306     }
307     case LeftShiftEvaluateOperator:
308     {
309       result=(double) ((size_t) pixel << (size_t) (value+0.5));
310       break;
311     }
312     case LogEvaluateOperator:
313     {
314       if ((QuantumScale*pixel) >= MagickEpsilon)
315         result=(double) (QuantumRange*log((double) (QuantumScale*value*pixel+
316           1.0))/log((double) (value+1.0)));
317       break;
318     }
319     case MaxEvaluateOperator:
320     {
321       result=(double) EvaluateMax((double) pixel,value);
322       break;
323     }
324     case MeanEvaluateOperator:
325     {
326       result=(double) (pixel+value);
327       break;
328     }
329     case MedianEvaluateOperator:
330     {
331       result=(double) (pixel+value);
332       break;
333     }
334     case MinEvaluateOperator:
335     {
336       result=(double) MagickMin((double) pixel,value);
337       break;
338     }
339     case MultiplicativeNoiseEvaluateOperator:
340     {
341       result=(double) GenerateDifferentialNoise(random_info,pixel,
342         MultiplicativeGaussianNoise,value);
343       break;
344     }
345     case MultiplyEvaluateOperator:
346     {
347       result=(double) (value*pixel);
348       break;
349     }
350     case OrEvaluateOperator:
351     {
352       result=(double) ((size_t) pixel | (size_t) (value+0.5));
353       break;
354     }
355     case PoissonNoiseEvaluateOperator:
356     {
357       result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
358         value);
359       break;
360     }
361     case PowEvaluateOperator:
362     {
363       result=(double) (QuantumRange*pow((double) (QuantumScale*pixel),(double)
364         value));
365       break;
366     }
367     case RightShiftEvaluateOperator:
368     {
369       result=(double) ((size_t) pixel >> (size_t) (value+0.5));
370       break;
371     }
372     case SetEvaluateOperator:
373     {
374       result=value;
375       break;
376     }
377     case SineEvaluateOperator:
378     {
379       result=(double) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
380         QuantumScale*pixel*value))+0.5));
381       break;
382     }
383     case SubtractEvaluateOperator:
384     {
385       result=(double) (pixel-value);
386       break;
387     }
388     case SumEvaluateOperator:
389     {
390       result=(double) (pixel+value);
391       break;
392     }
393     case ThresholdEvaluateOperator:
394     {
395       result=(double) (((double) pixel <= value) ? 0 : QuantumRange);
396       break;
397     }
398     case ThresholdBlackEvaluateOperator:
399     {
400       result=(double) (((double) pixel <= value) ? 0 : pixel);
401       break;
402     }
403     case ThresholdWhiteEvaluateOperator:
404     {
405       result=(double) (((double) pixel > value) ? QuantumRange : pixel);
406       break;
407     }
408     case UniformNoiseEvaluateOperator:
409     {
410       result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
411         value);
412       break;
413     }
414     case XorEvaluateOperator:
415     {
416       result=(double) ((size_t) pixel ^ (size_t) (value+0.5));
417       break;
418     }
419   }
420   return(result);
421 }
422
423 MagickExport Image *EvaluateImages(const Image *images,
424   const MagickEvaluateOperator op,ExceptionInfo *exception)
425 {
426 #define EvaluateImageTag  "Evaluate/Image"
427
428   CacheView
429     *evaluate_view;
430
431   Image
432     *image;
433
434   MagickBooleanType
435     status;
436
437   MagickOffsetType
438     progress;
439
440   PixelChannels
441     **restrict evaluate_pixels;
442
443   RandomInfo
444     **restrict random_info;
445
446   size_t
447     number_images;
448
449   ssize_t
450     y;
451
452 #if defined(MAGICKCORE_OPENMP_SUPPORT)
453   unsigned long
454     key;
455 #endif
456
457   assert(images != (Image *) NULL);
458   assert(images->signature == MagickSignature);
459   if (images->debug != MagickFalse)
460     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
461   assert(exception != (ExceptionInfo *) NULL);
462   assert(exception->signature == MagickSignature);
463   image=CloneImage(images,images->columns,images->rows,MagickTrue,
464     exception);
465   if (image == (Image *) NULL)
466     return((Image *) NULL);
467   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
468     {
469       image=DestroyImage(image);
470       return((Image *) NULL);
471     }
472   number_images=GetImageListLength(images);
473   evaluate_pixels=AcquirePixelThreadSet(images,number_images);
474   if (evaluate_pixels == (PixelChannels **) NULL)
475     {
476       image=DestroyImage(image);
477       (void) ThrowMagickException(exception,GetMagickModule(),
478         ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
479       return((Image *) NULL);
480     }
481   /*
482     Evaluate image pixels.
483   */
484   status=MagickTrue;
485   progress=0;
486   random_info=AcquireRandomInfoThreadSet();
487 #if defined(MAGICKCORE_OPENMP_SUPPORT)
488   key=GetRandomSecretKey(random_info[0]);
489 #endif
490   evaluate_view=AcquireAuthenticCacheView(image,exception);
491   if (op == MedianEvaluateOperator)
492     {
493 #if defined(MAGICKCORE_OPENMP_SUPPORT)
494       #pragma omp parallel for schedule(static,4) shared(progress,status) \
495         magick_threads(image,images,image->rows,key == ~0UL)
496 #endif
497       for (y=0; y < (ssize_t) image->rows; y++)
498       {
499         CacheView
500           *image_view;
501
502         const Image
503           *next;
504
505         const int
506           id = GetOpenMPThreadId();
507
508         register PixelChannels
509           *evaluate_pixel;
510
511         register Quantum
512           *restrict q;
513
514         register ssize_t
515           x;
516
517         if (status == MagickFalse)
518           continue;
519         q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
520           exception);
521         if (q == (Quantum *) NULL)
522           {
523             status=MagickFalse;
524             continue;
525           }
526         evaluate_pixel=evaluate_pixels[id];
527         for (x=0; x < (ssize_t) image->columns; x++)
528         {
529           register ssize_t
530             j,
531             k;
532
533           for (j=0; j < (ssize_t) number_images; j++)
534             for (k=0; k < MaxPixelChannels; k++)
535               evaluate_pixel[j].channel[k]=0.0;
536           next=images;
537           for (j=0; j < (ssize_t) number_images; j++)
538           {
539             register const Quantum
540               *p;
541
542             register ssize_t
543               i;
544
545             image_view=AcquireVirtualCacheView(next,exception);
546             p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
547             if (p == (const Quantum *) NULL)
548               {
549                 image_view=DestroyCacheView(image_view);
550                 break;
551               }
552             for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
553             {
554               PixelChannel channel=GetPixelChannelChannel(image,i);
555               PixelTrait evaluate_traits=GetPixelChannelTraits(image,channel);
556               PixelTrait traits=GetPixelChannelTraits(next,channel);
557               if ((traits == UndefinedPixelTrait) ||
558                   (evaluate_traits == UndefinedPixelTrait))
559                 continue;
560               if ((evaluate_traits & UpdatePixelTrait) == 0)
561                 continue;
562               evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
563                 random_info[id],GetPixelChannel(image,channel,p),op,
564                 evaluate_pixel[j].channel[i]);
565             }
566             image_view=DestroyCacheView(image_view);
567             next=GetNextImageInList(next);
568           }
569           qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
570             IntensityCompare);
571           for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
572             q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
573           q+=GetPixelChannels(image);
574         }
575         if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
576           status=MagickFalse;
577         if (images->progress_monitor != (MagickProgressMonitor) NULL)
578           {
579             MagickBooleanType
580               proceed;
581
582 #if   defined(MAGICKCORE_OPENMP_SUPPORT)
583             #pragma omp critical (MagickCore_EvaluateImages)
584 #endif
585             proceed=SetImageProgress(images,EvaluateImageTag,progress++,
586               image->rows);
587             if (proceed == MagickFalse)
588               status=MagickFalse;
589           }
590       }
591     }
592   else
593     {
594 #if defined(MAGICKCORE_OPENMP_SUPPORT)
595       #pragma omp parallel for schedule(static,4) shared(progress,status) \
596         magick_threads(image,images,image->rows,key == ~0UL)
597 #endif
598       for (y=0; y < (ssize_t) image->rows; y++)
599       {
600         CacheView
601           *image_view;
602
603         const Image
604           *next;
605
606         const int
607           id = GetOpenMPThreadId();
608
609         register ssize_t
610           i,
611           x;
612
613         register PixelChannels
614           *evaluate_pixel;
615
616         register Quantum
617           *restrict q;
618
619         ssize_t
620           j;
621
622         if (status == MagickFalse)
623           continue;
624         q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
625           exception);
626         if (q == (Quantum *) NULL)
627           {
628             status=MagickFalse;
629             continue;
630           }
631         evaluate_pixel=evaluate_pixels[id];
632         for (j=0; j < (ssize_t) image->columns; j++)
633           for (i=0; i < MaxPixelChannels; i++)
634             evaluate_pixel[j].channel[i]=0.0;
635         next=images;
636         for (j=0; j < (ssize_t) number_images; j++)
637         {
638           register const Quantum
639             *p;
640
641           image_view=AcquireVirtualCacheView(next,exception);
642           p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
643           if (p == (const Quantum *) NULL)
644             {
645               image_view=DestroyCacheView(image_view);
646               break;
647             }
648           for (x=0; x < (ssize_t) next->columns; x++)
649           {
650             register ssize_t
651               i;
652
653             if (GetPixelMask(next,p) != 0)
654               {
655                 p+=GetPixelChannels(next);
656                 continue;
657               }
658             for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
659             {
660               PixelChannel channel=GetPixelChannelChannel(image,i);
661               PixelTrait  traits=GetPixelChannelTraits(next,channel);
662               PixelTrait  evaluate_traits=GetPixelChannelTraits(image,channel);
663               if ((traits == UndefinedPixelTrait) ||
664                   (evaluate_traits == UndefinedPixelTrait))
665                 continue;
666               if ((traits & UpdatePixelTrait) == 0)
667                 continue;
668               evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
669                 random_info[id],GetPixelChannel(image,channel,p),j == 0 ?
670                 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
671             }
672             p+=GetPixelChannels(next);
673           }
674           image_view=DestroyCacheView(image_view);
675           next=GetNextImageInList(next);
676         }
677         for (x=0; x < (ssize_t) image->columns; x++)
678         {
679           register ssize_t
680              i;
681
682           switch (op)
683           {
684             case MeanEvaluateOperator:
685             {
686               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
687                 evaluate_pixel[x].channel[i]/=(double) number_images;
688               break;
689             }
690             case MultiplyEvaluateOperator:
691             {
692               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
693               {
694                 register ssize_t
695                   j;
696
697                 for (j=0; j < (ssize_t) (number_images-1); j++)
698                   evaluate_pixel[x].channel[i]*=QuantumScale;
699               }
700               break;
701             }
702             default:
703               break;
704           }
705         }
706         for (x=0; x < (ssize_t) image->columns; x++)
707         {
708           register ssize_t
709             i;
710
711           if (GetPixelMask(image,q) != 0)
712             {
713               q+=GetPixelChannels(image);
714               continue;
715             }
716           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
717           {
718             PixelChannel channel=GetPixelChannelChannel(image,i);
719             PixelTrait traits=GetPixelChannelTraits(image,channel);
720             if (traits == UndefinedPixelTrait)
721               continue;
722             if ((traits & UpdatePixelTrait) == 0)
723               continue;
724             q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
725           }
726           q+=GetPixelChannels(image);
727         }
728         if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
729           status=MagickFalse;
730         if (images->progress_monitor != (MagickProgressMonitor) NULL)
731           {
732             MagickBooleanType
733               proceed;
734
735 #if   defined(MAGICKCORE_OPENMP_SUPPORT)
736             #pragma omp critical (MagickCore_EvaluateImages)
737 #endif
738             proceed=SetImageProgress(images,EvaluateImageTag,progress++,
739               image->rows);
740             if (proceed == MagickFalse)
741               status=MagickFalse;
742           }
743       }
744     }
745   evaluate_view=DestroyCacheView(evaluate_view);
746   evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
747   random_info=DestroyRandomInfoThreadSet(random_info);
748   if (status == MagickFalse)
749     image=DestroyImage(image);
750   return(image);
751 }
752
753 MagickExport MagickBooleanType EvaluateImage(Image *image,
754   const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
755 {
756   CacheView
757     *image_view;
758
759   MagickBooleanType
760     status;
761
762   MagickOffsetType
763     progress;
764
765   RandomInfo
766     **restrict random_info;
767
768   ssize_t
769     y;
770
771 #if defined(MAGICKCORE_OPENMP_SUPPORT)
772   unsigned long
773     key;
774 #endif
775
776   assert(image != (Image *) NULL);
777   assert(image->signature == MagickSignature);
778   if (image->debug != MagickFalse)
779     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
780   assert(exception != (ExceptionInfo *) NULL);
781   assert(exception->signature == MagickSignature);
782   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
783     return(MagickFalse);
784   status=MagickTrue;
785   progress=0;
786   random_info=AcquireRandomInfoThreadSet();
787 #if defined(MAGICKCORE_OPENMP_SUPPORT)
788   key=GetRandomSecretKey(random_info[0]);
789 #endif
790   image_view=AcquireAuthenticCacheView(image,exception);
791 #if defined(MAGICKCORE_OPENMP_SUPPORT)
792   #pragma omp parallel for schedule(static,4) shared(progress,status) \
793     magick_threads(image,image,image->rows,key == ~0UL)
794 #endif
795   for (y=0; y < (ssize_t) image->rows; y++)
796   {
797     const int
798       id = GetOpenMPThreadId();
799
800     register Quantum
801       *restrict q;
802
803     register ssize_t
804       x;
805
806     if (status == MagickFalse)
807       continue;
808     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
809     if (q == (Quantum *) NULL)
810       {
811         status=MagickFalse;
812         continue;
813       }
814     for (x=0; x < (ssize_t) image->columns; x++)
815     {
816       register ssize_t
817         i;
818
819       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
820       {
821         PixelChannel channel=GetPixelChannelChannel(image,i);
822         PixelTrait traits=GetPixelChannelTraits(image,channel);
823         if (traits == UndefinedPixelTrait)
824           continue;
825         if (((traits & CopyPixelTrait) != 0) ||
826             (GetPixelMask(image,q) != 0))
827           continue;
828         q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
829           value));
830       }
831       q+=GetPixelChannels(image);
832     }
833     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
834       status=MagickFalse;
835     if (image->progress_monitor != (MagickProgressMonitor) NULL)
836       {
837         MagickBooleanType
838           proceed;
839
840 #if defined(MAGICKCORE_OPENMP_SUPPORT)
841         #pragma omp critical (MagickCore_EvaluateImage)
842 #endif
843         proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
844         if (proceed == MagickFalse)
845           status=MagickFalse;
846       }
847   }
848   image_view=DestroyCacheView(image_view);
849   random_info=DestroyRandomInfoThreadSet(random_info);
850   return(status);
851 }
852 \f
853 /*
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855 %                                                                             %
856 %                                                                             %
857 %                                                                             %
858 %     F u n c t i o n I m a g e                                               %
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 %
864 %  FunctionImage() applies a value to the image with an arithmetic, relational,
865 %  or logical operator to an image. Use these operations to lighten or darken
866 %  an image, to increase or decrease contrast in an image, or to produce the
867 %  "negative" of an image.
868 %
869 %  The format of the FunctionImage method is:
870 %
871 %      MagickBooleanType FunctionImage(Image *image,
872 %        const MagickFunction function,const ssize_t number_parameters,
873 %        const double *parameters,ExceptionInfo *exception)
874 %
875 %  A description of each parameter follows:
876 %
877 %    o image: the image.
878 %
879 %    o function: A channel function.
880 %
881 %    o parameters: one or more parameters.
882 %
883 %    o exception: return any errors or warnings in this structure.
884 %
885 */
886
887 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
888   const size_t number_parameters,const double *parameters,
889   ExceptionInfo *exception)
890 {
891   double
892     result;
893
894   register ssize_t
895     i;
896
897   (void) exception;
898   result=0.0;
899   switch (function)
900   {
901     case PolynomialFunction:
902     {
903       /*
904         Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
905         c1*x^2+c2*x+c3).
906       */
907       result=0.0;
908       for (i=0; i < (ssize_t) number_parameters; i++)
909         result=result*QuantumScale*pixel+parameters[i];
910       result*=QuantumRange;
911       break;
912     }
913     case SinusoidFunction:
914     {
915       double
916         amplitude,
917         bias,
918         frequency,
919         phase;
920
921       /*
922         Sinusoid: frequency, phase, amplitude, bias.
923       */
924       frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
925       phase=(number_parameters >= 2) ? parameters[1] : 0.0;
926       amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
927       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
928       result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
929         MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
930       break;
931     }
932     case ArcsinFunction:
933     {
934       double
935         bias,
936         center,
937         range,
938         width;
939
940       /*
941         Arcsin (peged at range limits for invalid results): width, center,
942         range, and bias.
943       */
944       width=(number_parameters >= 1) ? parameters[0] : 1.0;
945       center=(number_parameters >= 2) ? parameters[1] : 0.5;
946       range=(number_parameters >= 3) ? parameters[2] : 1.0;
947       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
948       result=2.0/width*(QuantumScale*pixel-center);
949       if ( result <= -1.0 )
950         result=bias-range/2.0;
951       else
952         if (result >= 1.0)
953           result=bias+range/2.0;
954         else
955           result=(double) (range/MagickPI*asin((double) result)+bias);
956       result*=QuantumRange;
957       break;
958     }
959     case ArctanFunction:
960     {
961       double
962         center,
963         bias,
964         range,
965         slope;
966
967       /*
968         Arctan: slope, center, range, and bias.
969       */
970       slope=(number_parameters >= 1) ? parameters[0] : 1.0;
971       center=(number_parameters >= 2) ? parameters[1] : 0.5;
972       range=(number_parameters >= 3) ? parameters[2] : 1.0;
973       bias=(number_parameters >= 4) ? parameters[3] : 0.5;
974       result=(double) (MagickPI*slope*(QuantumScale*pixel-center));
975       result=(double) (QuantumRange*(range/MagickPI*atan((double)
976         result)+bias));
977       break;
978     }
979     case UndefinedFunction:
980       break;
981   }
982   return(ClampToQuantum(result));
983 }
984
985 MagickExport MagickBooleanType FunctionImage(Image *image,
986   const MagickFunction function,const size_t number_parameters,
987   const double *parameters,ExceptionInfo *exception)
988 {
989 #define FunctionImageTag  "Function/Image "
990
991   CacheView
992     *image_view;
993
994   MagickBooleanType
995     status;
996
997   MagickOffsetType
998     progress;
999
1000   ssize_t
1001     y;
1002
1003   assert(image != (Image *) NULL);
1004   assert(image->signature == MagickSignature);
1005   if (image->debug != MagickFalse)
1006     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1007   assert(exception != (ExceptionInfo *) NULL);
1008   assert(exception->signature == MagickSignature);
1009   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1010     return(MagickFalse);
1011   status=MagickTrue;
1012   progress=0;
1013   image_view=AcquireAuthenticCacheView(image,exception);
1014 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1015   #pragma omp parallel for schedule(static,4) shared(progress,status) \
1016     magick_threads(image,image,image->rows,1)
1017 #endif
1018   for (y=0; y < (ssize_t) image->rows; y++)
1019   {
1020     register Quantum
1021       *restrict q;
1022
1023     register ssize_t
1024       x;
1025
1026     if (status == MagickFalse)
1027       continue;
1028     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1029     if (q == (Quantum *) NULL)
1030       {
1031         status=MagickFalse;
1032         continue;
1033       }
1034     for (x=0; x < (ssize_t) image->columns; x++)
1035     {
1036       register ssize_t
1037         i;
1038
1039       if (GetPixelMask(image,q) != 0)
1040         {
1041           q+=GetPixelChannels(image);
1042           continue;
1043         }
1044       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1045       {
1046         PixelChannel channel=GetPixelChannelChannel(image,i);
1047         PixelTrait traits=GetPixelChannelTraits(image,channel);
1048         if (traits == UndefinedPixelTrait)
1049           continue;
1050         if ((traits & UpdatePixelTrait) == 0)
1051           continue;
1052         q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1053           exception);
1054       }
1055       q+=GetPixelChannels(image);
1056     }
1057     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1058       status=MagickFalse;
1059     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1060       {
1061         MagickBooleanType
1062           proceed;
1063
1064 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1065         #pragma omp critical (MagickCore_FunctionImage)
1066 #endif
1067         proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1068         if (proceed == MagickFalse)
1069           status=MagickFalse;
1070       }
1071   }
1072   image_view=DestroyCacheView(image_view);
1073   return(status);
1074 }
1075 \f
1076 /*
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 %                                                                             %
1079 %                                                                             %
1080 %                                                                             %
1081 %   G e t I m a g e E x t r e m a                                             %
1082 %                                                                             %
1083 %                                                                             %
1084 %                                                                             %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 %
1087 %  GetImageExtrema() returns the extrema of one or more image channels.
1088 %
1089 %  The format of the GetImageExtrema method is:
1090 %
1091 %      MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1092 %        size_t *maxima,ExceptionInfo *exception)
1093 %
1094 %  A description of each parameter follows:
1095 %
1096 %    o image: the image.
1097 %
1098 %    o minima: the minimum value in the channel.
1099 %
1100 %    o maxima: the maximum value in the channel.
1101 %
1102 %    o exception: return any errors or warnings in this structure.
1103 %
1104 */
1105 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1106   size_t *minima,size_t *maxima,ExceptionInfo *exception)
1107 {
1108   double
1109     max,
1110     min;
1111
1112   MagickBooleanType
1113     status;
1114
1115   assert(image != (Image *) NULL);
1116   assert(image->signature == MagickSignature);
1117   if (image->debug != MagickFalse)
1118     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1119   status=GetImageRange(image,&min,&max,exception);
1120   *minima=(size_t) ceil(min-0.5);
1121   *maxima=(size_t) floor(max+0.5);
1122   return(status);
1123 }
1124 \f
1125 /*
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 %                                                                             %
1128 %                                                                             %
1129 %                                                                             %
1130 %   G e t I m a g e M e a n                                                   %
1131 %                                                                             %
1132 %                                                                             %
1133 %                                                                             %
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1135 %
1136 %  GetImageMean() returns the mean and standard deviation of one or more image
1137 %  channels.
1138 %
1139 %  The format of the GetImageMean method is:
1140 %
1141 %      MagickBooleanType GetImageMean(const Image *image,double *mean,
1142 %        double *standard_deviation,ExceptionInfo *exception)
1143 %
1144 %  A description of each parameter follows:
1145 %
1146 %    o image: the image.
1147 %
1148 %    o mean: the average value in the channel.
1149 %
1150 %    o standard_deviation: the standard deviation of the channel.
1151 %
1152 %    o exception: return any errors or warnings in this structure.
1153 %
1154 */
1155 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1156   double *standard_deviation,ExceptionInfo *exception)
1157 {
1158   double
1159     area;
1160
1161   ChannelStatistics
1162     *channel_statistics;
1163
1164   register ssize_t
1165     i;
1166
1167   assert(image != (Image *) NULL);
1168   assert(image->signature == MagickSignature);
1169   if (image->debug != MagickFalse)
1170     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1171   channel_statistics=GetImageStatistics(image,exception);
1172   if (channel_statistics == (ChannelStatistics *) NULL)
1173     return(MagickFalse);
1174   area=0.0;
1175   channel_statistics[CompositePixelChannel].mean=0.0;
1176   channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1177   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1178   {
1179     PixelChannel channel=GetPixelChannelChannel(image,i);
1180     PixelTrait traits=GetPixelChannelTraits(image,channel);
1181     if (traits == UndefinedPixelTrait)
1182       continue;
1183     if ((traits & UpdatePixelTrait) == 0)
1184       continue;
1185     channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1186     channel_statistics[CompositePixelChannel].standard_deviation+=
1187       channel_statistics[i].variance-channel_statistics[i].mean*
1188       channel_statistics[i].mean;
1189     area++;
1190   }
1191   channel_statistics[CompositePixelChannel].mean/=area;
1192   channel_statistics[CompositePixelChannel].standard_deviation=
1193     sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1194   *mean=channel_statistics[CompositePixelChannel].mean;
1195   *standard_deviation=
1196     channel_statistics[CompositePixelChannel].standard_deviation;
1197   channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1198     channel_statistics);
1199   return(MagickTrue);
1200 }
1201 \f
1202 /*
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204 %                                                                             %
1205 %                                                                             %
1206 %                                                                             %
1207 %   G e t I m a g e K u r t o s i s                                           %
1208 %                                                                             %
1209 %                                                                             %
1210 %                                                                             %
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 %
1213 %  GetImageKurtosis() returns the kurtosis and skewness of one or more image
1214 %  channels.
1215 %
1216 %  The format of the GetImageKurtosis method is:
1217 %
1218 %      MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1219 %        double *skewness,ExceptionInfo *exception)
1220 %
1221 %  A description of each parameter follows:
1222 %
1223 %    o image: the image.
1224 %
1225 %    o kurtosis: the kurtosis of the channel.
1226 %
1227 %    o skewness: the skewness of the channel.
1228 %
1229 %    o exception: return any errors or warnings in this structure.
1230 %
1231 */
1232 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1233   double *kurtosis,double *skewness,ExceptionInfo *exception)
1234 {
1235   CacheView
1236     *image_view;
1237
1238   double
1239     area,
1240     mean,
1241     standard_deviation,
1242     sum_squares,
1243     sum_cubes,
1244     sum_fourth_power;
1245
1246   MagickBooleanType
1247     status;
1248
1249   ssize_t
1250     y;
1251
1252   assert(image != (Image *) NULL);
1253   assert(image->signature == MagickSignature);
1254   if (image->debug != MagickFalse)
1255     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1256   status=MagickTrue;
1257   *kurtosis=0.0;
1258   *skewness=0.0;
1259   area=0.0;
1260   mean=0.0;
1261   standard_deviation=0.0;
1262   sum_squares=0.0;
1263   sum_cubes=0.0;
1264   sum_fourth_power=0.0;
1265   image_view=AcquireVirtualCacheView(image,exception);
1266 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1267   #pragma omp parallel for schedule(static,4) shared(status) \
1268     magick_threads(image,image,image->rows,1)
1269 #endif
1270   for (y=0; y < (ssize_t) image->rows; y++)
1271   {
1272     register const Quantum
1273       *restrict p;
1274
1275     register ssize_t
1276       x;
1277
1278     if (status == MagickFalse)
1279       continue;
1280     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1281     if (p == (const Quantum *) NULL)
1282       {
1283         status=MagickFalse;
1284         continue;
1285       }
1286     for (x=0; x < (ssize_t) image->columns; x++)
1287     {
1288       register ssize_t
1289         i;
1290
1291       if (GetPixelMask(image,p) != 0)
1292         {
1293           p+=GetPixelChannels(image);
1294           continue;
1295         }
1296       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1297       {
1298         PixelChannel channel=GetPixelChannelChannel(image,i);
1299         PixelTrait traits=GetPixelChannelTraits(image,channel);
1300         if (traits == UndefinedPixelTrait)
1301           continue;
1302         if ((traits & UpdatePixelTrait) == 0)
1303           continue;
1304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1305         #pragma omp critical (MagickCore_GetImageKurtosis)
1306 #endif
1307         {
1308           mean+=p[i];
1309           sum_squares+=(double) p[i]*p[i];
1310           sum_cubes+=(double) p[i]*p[i]*p[i];
1311           sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1312           area++;
1313         }
1314       }
1315       p+=GetPixelChannels(image);
1316     }
1317   }
1318   image_view=DestroyCacheView(image_view);
1319   if (area != 0.0)
1320     {
1321       mean/=area;
1322       sum_squares/=area;
1323       sum_cubes/=area;
1324       sum_fourth_power/=area;
1325     }
1326   standard_deviation=sqrt(sum_squares-(mean*mean));
1327   if (standard_deviation != 0.0)
1328     {
1329       *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1330         3.0*mean*mean*mean*mean;
1331       *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1332         standard_deviation;
1333       *kurtosis-=3.0;
1334       *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1335       *skewness/=standard_deviation*standard_deviation*standard_deviation;
1336     }
1337   return(status);
1338 }
1339 \f
1340 /*
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 %                                                                             %
1343 %                                                                             %
1344 %                                                                             %
1345 %   G e t I m a g e R a n g e                                                 %
1346 %                                                                             %
1347 %                                                                             %
1348 %                                                                             %
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350 %
1351 %  GetImageRange() returns the range of one or more image channels.
1352 %
1353 %  The format of the GetImageRange method is:
1354 %
1355 %      MagickBooleanType GetImageRange(const Image *image,double *minima,
1356 %        double *maxima,ExceptionInfo *exception)
1357 %
1358 %  A description of each parameter follows:
1359 %
1360 %    o image: the image.
1361 %
1362 %    o minima: the minimum value in the channel.
1363 %
1364 %    o maxima: the maximum value in the channel.
1365 %
1366 %    o exception: return any errors or warnings in this structure.
1367 %
1368 */
1369 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1370   double *maxima,ExceptionInfo *exception)
1371 {
1372   CacheView
1373     *image_view;
1374
1375   MagickBooleanType
1376     initialize,
1377     status;
1378
1379   ssize_t
1380     y;
1381
1382   assert(image != (Image *) NULL);
1383   assert(image->signature == MagickSignature);
1384   if (image->debug != MagickFalse)
1385     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1386   status=MagickTrue;
1387   initialize=MagickTrue;
1388   *maxima=0.0;
1389   *minima=0.0;
1390   image_view=AcquireVirtualCacheView(image,exception);
1391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1392   #pragma omp parallel for schedule(static,4) shared(status,initialize) \
1393     magick_threads(image,image,image->rows,1)
1394 #endif
1395   for (y=0; y < (ssize_t) image->rows; y++)
1396   {
1397     register const Quantum
1398       *restrict p;
1399
1400     register ssize_t
1401       x;
1402
1403     if (status == MagickFalse)
1404       continue;
1405     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1406     if (p == (const Quantum *) NULL)
1407       {
1408         status=MagickFalse;
1409         continue;
1410       }
1411     for (x=0; x < (ssize_t) image->columns; x++)
1412     {
1413       register ssize_t
1414         i;
1415
1416       if (GetPixelMask(image,p) != 0)
1417         {
1418           p+=GetPixelChannels(image);
1419           continue;
1420         }
1421       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1422       {
1423         PixelChannel channel=GetPixelChannelChannel(image,i);
1424         PixelTrait traits=GetPixelChannelTraits(image,channel);
1425         if (traits == UndefinedPixelTrait)
1426           continue;
1427         if ((traits & UpdatePixelTrait) == 0)
1428           continue;
1429 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1430         #pragma omp critical (MagickCore_GetImageRange)
1431 #endif
1432         {
1433           if (initialize != MagickFalse)
1434             {
1435               *minima=(double) p[i];
1436               *maxima=(double) p[i];
1437               initialize=MagickFalse;
1438             }
1439           else
1440             {
1441               if ((double) p[i] < *minima)
1442                 *minima=(double) p[i];
1443               if ((double) p[i] > *maxima)
1444                 *maxima=(double) p[i];
1445            }
1446         }
1447       }
1448       p+=GetPixelChannels(image);
1449     }
1450   }
1451   image_view=DestroyCacheView(image_view);
1452   return(status);
1453 }
1454 \f
1455 /*
1456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457 %                                                                             %
1458 %                                                                             %
1459 %                                                                             %
1460 %   G e t I m a g e S t a t i s t i c s                                       %
1461 %                                                                             %
1462 %                                                                             %
1463 %                                                                             %
1464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 %
1466 %  GetImageStatistics() returns statistics for each channel in the image.  The
1467 %  statistics include the channel depth, its minima, maxima, mean, standard
1468 %  deviation, kurtosis and skewness.  You can access the red channel mean, for
1469 %  example, like this:
1470 %
1471 %      channel_statistics=GetImageStatistics(image,exception);
1472 %      red_mean=channel_statistics[RedPixelChannel].mean;
1473 %
1474 %  Use MagickRelinquishMemory() to free the statistics buffer.
1475 %
1476 %  The format of the GetImageStatistics method is:
1477 %
1478 %      ChannelStatistics *GetImageStatistics(const Image *image,
1479 %        ExceptionInfo *exception)
1480 %
1481 %  A description of each parameter follows:
1482 %
1483 %    o image: the image.
1484 %
1485 %    o exception: return any errors or warnings in this structure.
1486 %
1487 */
1488
1489 static size_t GetImageChannels(const Image *image)
1490 {
1491   register ssize_t
1492     i;
1493
1494   size_t
1495     channels;
1496
1497   channels=0;
1498   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1499   {
1500     PixelChannel channel=GetPixelChannelChannel(image,i);
1501     PixelTrait traits=GetPixelChannelTraits(image,channel);
1502     if (traits != UndefinedPixelTrait)
1503       channels++;
1504   }
1505   return(channels);
1506 }
1507
1508 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1509   ExceptionInfo *exception)
1510 {
1511   ChannelStatistics
1512     *channel_statistics;
1513
1514   MagickStatusType
1515     status;
1516
1517   QuantumAny
1518     range;
1519
1520   register ssize_t
1521     i;
1522
1523   size_t
1524     channels,
1525     depth;
1526
1527   ssize_t
1528     y;
1529
1530   assert(image != (Image *) NULL);
1531   assert(image->signature == MagickSignature);
1532   if (image->debug != MagickFalse)
1533     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1534   channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1535     MaxPixelChannels+1,sizeof(*channel_statistics));
1536   if (channel_statistics == (ChannelStatistics *) NULL)
1537     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1538   (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1539     sizeof(*channel_statistics));
1540   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1541   {
1542     channel_statistics[i].depth=1;
1543     channel_statistics[i].maxima=(-MagickHuge);
1544     channel_statistics[i].minima=MagickHuge;
1545   }
1546   for (y=0; y < (ssize_t) image->rows; y++)
1547   {
1548     register const Quantum
1549       *restrict p;
1550
1551     register ssize_t
1552       x;
1553
1554     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1555     if (p == (const Quantum *) NULL)
1556       break;
1557     for (x=0; x < (ssize_t) image->columns; x++)
1558     {
1559       register ssize_t
1560         i;
1561
1562       if (GetPixelMask(image,p) != 0)
1563         {
1564           p+=GetPixelChannels(image);
1565           continue;
1566         }
1567       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1568       {
1569         PixelChannel channel=GetPixelChannelChannel(image,i);
1570         PixelTrait traits=GetPixelChannelTraits(image,channel);
1571         if (traits == UndefinedPixelTrait)
1572           continue;
1573         if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1574           {
1575             depth=channel_statistics[channel].depth;
1576             range=GetQuantumRange(depth);
1577             status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1578               range) ? MagickTrue : MagickFalse;
1579             if (status != MagickFalse)
1580               {
1581                 channel_statistics[channel].depth++;
1582                 i--;
1583                 continue;
1584               }
1585           }
1586         if ((double) p[i] < channel_statistics[channel].minima)
1587           channel_statistics[channel].minima=(double) p[i];
1588         if ((double) p[i] > channel_statistics[channel].maxima)
1589           channel_statistics[channel].maxima=(double) p[i];
1590         channel_statistics[channel].sum+=p[i];
1591         channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1592         channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1593         channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1594           p[i];
1595         channel_statistics[channel].area++;
1596       }
1597       p+=GetPixelChannels(image);
1598     }
1599   }
1600   for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1601   {
1602     double
1603       area;
1604
1605     area=PerceptibleReciprocal(channel_statistics[i].area);
1606     channel_statistics[i].sum*=area;
1607     channel_statistics[i].sum_squared*=area;
1608     channel_statistics[i].sum_cubed*=area;
1609     channel_statistics[i].sum_fourth_power*=area;
1610     channel_statistics[i].mean=channel_statistics[i].sum;
1611     channel_statistics[i].variance=channel_statistics[i].sum_squared;
1612     channel_statistics[i].standard_deviation=sqrt(
1613       channel_statistics[i].variance-(channel_statistics[i].mean*
1614       channel_statistics[i].mean));
1615   }
1616   for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1617   {
1618     channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1619       (double) channel_statistics[CompositePixelChannel].depth,(double)
1620       channel_statistics[i].depth);
1621     channel_statistics[CompositePixelChannel].minima=MagickMin(
1622       channel_statistics[CompositePixelChannel].minima,
1623       channel_statistics[i].minima);
1624     channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1625       channel_statistics[CompositePixelChannel].maxima,
1626       channel_statistics[i].maxima);
1627     channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1628     channel_statistics[CompositePixelChannel].sum_squared+=
1629       channel_statistics[i].sum_squared;
1630     channel_statistics[CompositePixelChannel].sum_cubed+=
1631       channel_statistics[i].sum_cubed;
1632     channel_statistics[CompositePixelChannel].sum_fourth_power+=
1633       channel_statistics[i].sum_fourth_power;
1634     channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1635     channel_statistics[CompositePixelChannel].variance+=
1636       channel_statistics[i].variance-channel_statistics[i].mean*
1637       channel_statistics[i].mean;
1638     channel_statistics[CompositePixelChannel].standard_deviation+=
1639       channel_statistics[i].variance-channel_statistics[i].mean*
1640       channel_statistics[i].mean;
1641   }
1642   channels=GetImageChannels(image);
1643   channel_statistics[CompositePixelChannel].sum/=channels;
1644   channel_statistics[CompositePixelChannel].sum_squared/=channels;
1645   channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1646   channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1647   channel_statistics[CompositePixelChannel].mean/=channels;
1648   channel_statistics[CompositePixelChannel].variance/=channels;
1649   channel_statistics[CompositePixelChannel].standard_deviation=
1650     sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1651   channel_statistics[CompositePixelChannel].kurtosis/=channels;
1652   channel_statistics[CompositePixelChannel].skewness/=channels;
1653   for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1654   {
1655     double
1656       standard_deviation;
1657
1658     if (channel_statistics[i].standard_deviation == 0.0)
1659       continue;
1660     standard_deviation=PerceptibleReciprocal(
1661       channel_statistics[i].standard_deviation);
1662     channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1663       channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1664       channel_statistics[i].mean*channel_statistics[i].mean*
1665       channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1666       standard_deviation);
1667     channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1668       channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1669       channel_statistics[i].mean*channel_statistics[i].mean*
1670       channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1671       channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1672       channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1673       standard_deviation*standard_deviation)-3.0;
1674   }
1675   return(channel_statistics);
1676 }
1677 \f
1678 /*
1679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1680 %                                                                             %
1681 %                                                                             %
1682 %                                                                             %
1683 %     P o l y n o m i a l I m a g e                                           %
1684 %                                                                             %
1685 %                                                                             %
1686 %                                                                             %
1687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688 %
1689 %  PolynomialImage() returns a new image where each pixel is the sum of the
1690 %  pixels in the image sequence after applying its corresponding terms
1691 %  (coefficient and degree pairs).
1692 %
1693 %  The format of the PolynomialImage method is:
1694 %
1695 %      Image *PolynomialImage(const Image *images,const size_t number_terms,
1696 %        const double *terms,ExceptionInfo *exception)
1697 %
1698 %  A description of each parameter follows:
1699 %
1700 %    o images: the image sequence.
1701 %
1702 %    o number_terms: the number of terms in the list.  The actual list length
1703 %      is 2 x number_terms + 1 (the constant).
1704 %
1705 %    o terms: the list of polynomial coefficients and degree pairs and a
1706 %      constant.
1707 %
1708 %    o exception: return any errors or warnings in this structure.
1709 %
1710 */
1711
1712 MagickExport Image *PolynomialImage(const Image *images,
1713   const size_t number_terms,const double *terms,ExceptionInfo *exception)
1714 {
1715 #define PolynomialImageTag  "Polynomial/Image"
1716
1717   CacheView
1718     *polynomial_view;
1719
1720   Image
1721     *image;
1722
1723   MagickBooleanType
1724     status;
1725
1726   MagickOffsetType
1727     progress;
1728
1729   PixelChannels
1730     **restrict polynomial_pixels;
1731
1732   size_t
1733     number_images;
1734
1735   ssize_t
1736     y;
1737
1738   assert(images != (Image *) NULL);
1739   assert(images->signature == MagickSignature);
1740   if (images->debug != MagickFalse)
1741     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1742   assert(exception != (ExceptionInfo *) NULL);
1743   assert(exception->signature == MagickSignature);
1744   image=CloneImage(images,images->columns,images->rows,MagickTrue,
1745     exception);
1746   if (image == (Image *) NULL)
1747     return((Image *) NULL);
1748   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1749     {
1750       image=DestroyImage(image);
1751       return((Image *) NULL);
1752     }
1753   number_images=GetImageListLength(images);
1754   polynomial_pixels=AcquirePixelThreadSet(images,number_images);
1755   if (polynomial_pixels == (PixelChannels **) NULL)
1756     {
1757       image=DestroyImage(image);
1758       (void) ThrowMagickException(exception,GetMagickModule(),
1759         ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
1760       return((Image *) NULL);
1761     }
1762   /*
1763     Polynomial image pixels.
1764   */
1765   status=MagickTrue;
1766   progress=0;
1767   polynomial_view=AcquireAuthenticCacheView(image,exception);
1768 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1769   #pragma omp parallel for schedule(static,4) shared(progress,status) \
1770     magick_threads(image,image,image->rows,1)
1771 #endif
1772   for (y=0; y < (ssize_t) image->rows; y++)
1773   {
1774     CacheView
1775       *image_view;
1776
1777     const Image
1778       *next;
1779
1780     const int
1781       id = GetOpenMPThreadId();
1782
1783     register ssize_t
1784       i,
1785       x;
1786
1787     register PixelChannels
1788       *polynomial_pixel;
1789
1790     register Quantum
1791       *restrict q;
1792
1793     ssize_t
1794       j;
1795
1796     if (status == MagickFalse)
1797       continue;
1798     q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
1799       exception);
1800     if (q == (Quantum *) NULL)
1801       {
1802         status=MagickFalse;
1803         continue;
1804       }
1805     polynomial_pixel=polynomial_pixels[id];
1806     for (j=0; j < (ssize_t) image->columns; j++)
1807       for (i=0; i < MaxPixelChannels; i++)
1808         polynomial_pixel[j].channel[i]=0.0;
1809     next=images;
1810     for (j=0; j < (ssize_t) number_images; j++)
1811     {
1812       register const Quantum
1813         *p;
1814
1815       if (j >= (ssize_t) number_terms)
1816         continue;
1817       image_view=AcquireVirtualCacheView(next,exception);
1818       p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1819       if (p == (const Quantum *) NULL)
1820         {
1821           image_view=DestroyCacheView(image_view);
1822           break;
1823         }
1824       for (x=0; x < (ssize_t) image->columns; x++)
1825       {
1826         register ssize_t
1827           i;
1828
1829         if (GetPixelMask(next,p) != 0)
1830           {
1831             p+=GetPixelChannels(next);
1832             continue;
1833           }
1834         for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
1835         {
1836           MagickRealType
1837             coefficient,
1838             degree;
1839
1840           PixelChannel channel=GetPixelChannelChannel(image,i);
1841           PixelTrait traits=GetPixelChannelTraits(next,channel);
1842           PixelTrait polynomial_traits=GetPixelChannelTraits(image,channel);
1843           if ((traits == UndefinedPixelTrait) ||
1844               (polynomial_traits == UndefinedPixelTrait))
1845             continue;
1846           if ((traits & UpdatePixelTrait) == 0)
1847             continue;
1848           coefficient=(MagickRealType) terms[2*i];
1849           degree=(MagickRealType) terms[(i << 1)+1];
1850           polynomial_pixel[x].channel[i]+=coefficient*
1851             pow(QuantumScale*GetPixelChannel(image,channel,p),degree);
1852         }
1853         p+=GetPixelChannels(next);
1854       }
1855       image_view=DestroyCacheView(image_view);
1856       next=GetNextImageInList(next);
1857     }
1858     for (x=0; x < (ssize_t) image->columns; x++)
1859     {
1860       register ssize_t
1861         i;
1862
1863       if (GetPixelMask(image,q) != 0)
1864         {
1865           q+=GetPixelChannels(image);
1866           continue;
1867         }
1868       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1869       {
1870         PixelChannel channel=GetPixelChannelChannel(image,i);
1871         PixelTrait traits=GetPixelChannelTraits(image,channel);
1872         if (traits == UndefinedPixelTrait)
1873           continue;
1874         if ((traits & UpdatePixelTrait) == 0)
1875           continue;
1876         q[i]=ClampToQuantum(QuantumRange*polynomial_pixel[x].channel[i]);
1877       }
1878       q+=GetPixelChannels(image);
1879     }
1880     if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
1881       status=MagickFalse;
1882     if (images->progress_monitor != (MagickProgressMonitor) NULL)
1883       {
1884         MagickBooleanType
1885           proceed;
1886
1887 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1888         #pragma omp critical (MagickCore_PolynomialImages)
1889 #endif
1890         proceed=SetImageProgress(images,PolynomialImageTag,progress++,
1891           image->rows);
1892         if (proceed == MagickFalse)
1893           status=MagickFalse;
1894       }
1895   }
1896   polynomial_view=DestroyCacheView(polynomial_view);
1897   polynomial_pixels=DestroyPixelThreadSet(polynomial_pixels);
1898   if (status == MagickFalse)
1899     image=DestroyImage(image);
1900   return(image);
1901 }
1902 \f
1903 /*
1904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905 %                                                                             %
1906 %                                                                             %
1907 %                                                                             %
1908 %     S t a t i s t i c I m a g e                                             %
1909 %                                                                             %
1910 %                                                                             %
1911 %                                                                             %
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1913 %
1914 %  StatisticImage() makes each pixel the min / max / median / mode / etc. of
1915 %  the neighborhood of the specified width and height.
1916 %
1917 %  The format of the StatisticImage method is:
1918 %
1919 %      Image *StatisticImage(const Image *image,const StatisticType type,
1920 %        const size_t width,const size_t height,ExceptionInfo *exception)
1921 %
1922 %  A description of each parameter follows:
1923 %
1924 %    o image: the image.
1925 %
1926 %    o type: the statistic type (median, mode, etc.).
1927 %
1928 %    o width: the width of the pixel neighborhood.
1929 %
1930 %    o height: the height of the pixel neighborhood.
1931 %
1932 %    o exception: return any errors or warnings in this structure.
1933 %
1934 */
1935
1936 typedef struct _SkipNode
1937 {
1938   size_t
1939     next[9],
1940     count,
1941     signature;
1942 } SkipNode;
1943
1944 typedef struct _SkipList
1945 {
1946   ssize_t
1947     level;
1948
1949   SkipNode
1950     *nodes;
1951 } SkipList;
1952
1953 typedef struct _PixelList
1954 {
1955   size_t
1956     length,
1957     seed;
1958
1959   SkipList
1960     skip_list;
1961
1962   size_t
1963     signature;
1964 } PixelList;
1965
1966 static PixelList *DestroyPixelList(PixelList *pixel_list)
1967 {
1968   if (pixel_list == (PixelList *) NULL)
1969     return((PixelList *) NULL);
1970   if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
1971     pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
1972       pixel_list->skip_list.nodes);
1973   pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
1974   return(pixel_list);
1975 }
1976
1977 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
1978 {
1979   register ssize_t
1980     i;
1981
1982   assert(pixel_list != (PixelList **) NULL);
1983   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
1984     if (pixel_list[i] != (PixelList *) NULL)
1985       pixel_list[i]=DestroyPixelList(pixel_list[i]);
1986   pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
1987   return(pixel_list);
1988 }
1989
1990 static PixelList *AcquirePixelList(const size_t width,const size_t height)
1991 {
1992   PixelList
1993     *pixel_list;
1994
1995   pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
1996   if (pixel_list == (PixelList *) NULL)
1997     return(pixel_list);
1998   (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
1999   pixel_list->length=width*height;
2000   pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
2001     sizeof(*pixel_list->skip_list.nodes));
2002   if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
2003     return(DestroyPixelList(pixel_list));
2004   (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
2005     sizeof(*pixel_list->skip_list.nodes));
2006   pixel_list->signature=MagickSignature;
2007   return(pixel_list);
2008 }
2009
2010 static PixelList **AcquirePixelListThreadSet(const size_t width,
2011   const size_t height)
2012 {
2013   PixelList
2014     **pixel_list;
2015
2016   register ssize_t
2017     i;
2018
2019   size_t
2020     number_threads;
2021
2022   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2023   pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
2024     sizeof(*pixel_list));
2025   if (pixel_list == (PixelList **) NULL)
2026     return((PixelList **) NULL);
2027   (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
2028   for (i=0; i < (ssize_t) number_threads; i++)
2029   {
2030     pixel_list[i]=AcquirePixelList(width,height);
2031     if (pixel_list[i] == (PixelList *) NULL)
2032       return(DestroyPixelListThreadSet(pixel_list));
2033   }
2034   return(pixel_list);
2035 }
2036
2037 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
2038 {
2039   register SkipList
2040     *p;
2041
2042   register ssize_t
2043     level;
2044
2045   size_t
2046     search,
2047     update[9];
2048
2049   /*
2050     Initialize the node.
2051   */
2052   p=(&pixel_list->skip_list);
2053   p->nodes[color].signature=pixel_list->signature;
2054   p->nodes[color].count=1;
2055   /*
2056     Determine where it belongs in the list.
2057   */
2058   search=65536UL;
2059   for (level=p->level; level >= 0; level--)
2060   {
2061     while (p->nodes[search].next[level] < color)
2062       search=p->nodes[search].next[level];
2063     update[level]=search;
2064   }
2065   /*
2066     Generate a pseudo-random level for this node.
2067   */
2068   for (level=0; ; level++)
2069   {
2070     pixel_list->seed=(pixel_list->seed*42893621L)+1L;
2071     if ((pixel_list->seed & 0x300) != 0x300)
2072       break;
2073   }
2074   if (level > 8)
2075     level=8;
2076   if (level > (p->level+2))
2077     level=p->level+2;
2078   /*
2079     If we're raising the list's level, link back to the root node.
2080   */
2081   while (level > p->level)
2082   {
2083     p->level++;
2084     update[p->level]=65536UL;
2085   }
2086   /*
2087     Link the node into the skip-list.
2088   */
2089   do
2090   {
2091     p->nodes[color].next[level]=p->nodes[update[level]].next[level];
2092     p->nodes[update[level]].next[level]=color;
2093   } while (level-- > 0);
2094 }
2095
2096 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
2097 {
2098   register SkipList
2099     *p;
2100
2101   size_t
2102     color,
2103     maximum;
2104
2105   ssize_t
2106     count;
2107
2108   /*
2109     Find the maximum value for each of the color.
2110   */
2111   p=(&pixel_list->skip_list);
2112   color=65536L;
2113   count=0;
2114   maximum=p->nodes[color].next[0];
2115   do
2116   {
2117     color=p->nodes[color].next[0];
2118     if (color > maximum)
2119       maximum=color;
2120     count+=p->nodes[color].count;
2121   } while (count < (ssize_t) pixel_list->length);
2122   *pixel=ScaleShortToQuantum((unsigned short) maximum);
2123 }
2124
2125 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
2126 {
2127   double
2128     sum;
2129
2130   register SkipList
2131     *p;
2132
2133   size_t
2134     color;
2135
2136   ssize_t
2137     count;
2138
2139   /*
2140     Find the mean value for each of the color.
2141   */
2142   p=(&pixel_list->skip_list);
2143   color=65536L;
2144   count=0;
2145   sum=0.0;
2146   do
2147   {
2148     color=p->nodes[color].next[0];
2149     sum+=(double) p->nodes[color].count*color;
2150     count+=p->nodes[color].count;
2151   } while (count < (ssize_t) pixel_list->length);
2152   sum/=pixel_list->length;
2153   *pixel=ScaleShortToQuantum((unsigned short) sum);
2154 }
2155
2156 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2157 {
2158   register SkipList
2159     *p;
2160
2161   size_t
2162     color;
2163
2164   ssize_t
2165     count;
2166
2167   /*
2168     Find the median value for each of the color.
2169   */
2170   p=(&pixel_list->skip_list);
2171   color=65536L;
2172   count=0;
2173   do
2174   {
2175     color=p->nodes[color].next[0];
2176     count+=p->nodes[color].count;
2177   } while (count <= (ssize_t) (pixel_list->length >> 1));
2178   *pixel=ScaleShortToQuantum((unsigned short) color);
2179 }
2180
2181 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2182 {
2183   register SkipList
2184     *p;
2185
2186   size_t
2187     color,
2188     minimum;
2189
2190   ssize_t
2191     count;
2192
2193   /*
2194     Find the minimum value for each of the color.
2195   */
2196   p=(&pixel_list->skip_list);
2197   count=0;
2198   color=65536UL;
2199   minimum=p->nodes[color].next[0];
2200   do
2201   {
2202     color=p->nodes[color].next[0];
2203     if (color < minimum)
2204       minimum=color;
2205     count+=p->nodes[color].count;
2206   } while (count < (ssize_t) pixel_list->length);
2207   *pixel=ScaleShortToQuantum((unsigned short) minimum);
2208 }
2209
2210 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2211 {
2212   register SkipList
2213     *p;
2214
2215   size_t
2216     color,
2217     max_count,
2218     mode;
2219
2220   ssize_t
2221     count;
2222
2223   /*
2224     Make each pixel the 'predominant color' of the specified neighborhood.
2225   */
2226   p=(&pixel_list->skip_list);
2227   color=65536L;
2228   mode=color;
2229   max_count=p->nodes[mode].count;
2230   count=0;
2231   do
2232   {
2233     color=p->nodes[color].next[0];
2234     if (p->nodes[color].count > max_count)
2235       {
2236         mode=color;
2237         max_count=p->nodes[mode].count;
2238       }
2239     count+=p->nodes[color].count;
2240   } while (count < (ssize_t) pixel_list->length);
2241   *pixel=ScaleShortToQuantum((unsigned short) mode);
2242 }
2243
2244 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2245 {
2246   register SkipList
2247     *p;
2248
2249   size_t
2250     color,
2251     next,
2252     previous;
2253
2254   ssize_t
2255     count;
2256
2257   /*
2258     Finds the non peak value for each of the colors.
2259   */
2260   p=(&pixel_list->skip_list);
2261   color=65536L;
2262   next=p->nodes[color].next[0];
2263   count=0;
2264   do
2265   {
2266     previous=color;
2267     color=next;
2268     next=p->nodes[color].next[0];
2269     count+=p->nodes[color].count;
2270   } while (count <= (ssize_t) (pixel_list->length >> 1));
2271   if ((previous == 65536UL) && (next != 65536UL))
2272     color=next;
2273   else
2274     if ((previous != 65536UL) && (next == 65536UL))
2275       color=previous;
2276   *pixel=ScaleShortToQuantum((unsigned short) color);
2277 }
2278
2279 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2280   Quantum *pixel)
2281 {
2282   double
2283     sum,
2284     sum_squared;
2285
2286   register SkipList
2287     *p;
2288
2289   size_t
2290     color;
2291
2292   ssize_t
2293     count;
2294
2295   /*
2296     Find the standard-deviation value for each of the color.
2297   */
2298   p=(&pixel_list->skip_list);
2299   color=65536L;
2300   count=0;
2301   sum=0.0;
2302   sum_squared=0.0;
2303   do
2304   {
2305     register ssize_t
2306       i;
2307
2308     color=p->nodes[color].next[0];
2309     sum+=(double) p->nodes[color].count*color;
2310     for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2311       sum_squared+=((double) color)*((double) color);
2312     count+=p->nodes[color].count;
2313   } while (count < (ssize_t) pixel_list->length);
2314   sum/=pixel_list->length;
2315   sum_squared/=pixel_list->length;
2316   *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2317 }
2318
2319 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2320   PixelList *pixel_list)
2321 {
2322   size_t
2323     signature;
2324
2325   unsigned short
2326     index;
2327
2328   index=ScaleQuantumToShort(pixel);
2329   signature=pixel_list->skip_list.nodes[index].signature;
2330   if (signature == pixel_list->signature)
2331     {
2332       pixel_list->skip_list.nodes[index].count++;
2333       return;
2334     }
2335   AddNodePixelList(pixel_list,index);
2336 }
2337
2338 static inline double MagickAbsoluteValue(const double x)
2339 {
2340   if (x < 0)
2341     return(-x);
2342   return(x);
2343 }
2344
2345 static inline size_t MagickMax(const size_t x,const size_t y)
2346 {
2347   if (x > y)
2348     return(x);
2349   return(y);
2350 }
2351
2352 static void ResetPixelList(PixelList *pixel_list)
2353 {
2354   int
2355     level;
2356
2357   register SkipNode
2358     *root;
2359
2360   register SkipList
2361     *p;
2362
2363   /*
2364     Reset the skip-list.
2365   */
2366   p=(&pixel_list->skip_list);
2367   root=p->nodes+65536UL;
2368   p->level=0;
2369   for (level=0; level < 9; level++)
2370     root->next[level]=65536UL;
2371   pixel_list->seed=pixel_list->signature++;
2372 }
2373
2374 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2375   const size_t width,const size_t height,ExceptionInfo *exception)
2376 {
2377 #define StatisticImageTag  "Statistic/Image"
2378
2379   CacheView
2380     *image_view,
2381     *statistic_view;
2382
2383   Image
2384     *statistic_image;
2385
2386   MagickBooleanType
2387     status;
2388
2389   MagickOffsetType
2390     progress;
2391
2392   PixelList
2393     **restrict pixel_list;
2394
2395   ssize_t
2396     center,
2397     y;
2398
2399   /*
2400     Initialize statistics image attributes.
2401   */
2402   assert(image != (Image *) NULL);
2403   assert(image->signature == MagickSignature);
2404   if (image->debug != MagickFalse)
2405     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2406   assert(exception != (ExceptionInfo *) NULL);
2407   assert(exception->signature == MagickSignature);
2408   statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2409     exception);
2410   if (statistic_image == (Image *) NULL)
2411     return((Image *) NULL);
2412   status=SetImageStorageClass(statistic_image,DirectClass,exception);
2413   if (status == MagickFalse)
2414     {
2415       statistic_image=DestroyImage(statistic_image);
2416       return((Image *) NULL);
2417     }
2418   pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2419   if (pixel_list == (PixelList **) NULL)
2420     {
2421       statistic_image=DestroyImage(statistic_image);
2422       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2423     }
2424   /*
2425     Make each pixel the min / max / median / mode / etc. of the neighborhood.
2426   */
2427   center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2428     (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2429   status=MagickTrue;
2430   progress=0;
2431   image_view=AcquireVirtualCacheView(image,exception);
2432   statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2433 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2434   #pragma omp parallel for schedule(static,4) shared(progress,status) \
2435     magick_threads(image,statistic_image,statistic_image->rows,1)
2436 #endif
2437   for (y=0; y < (ssize_t) statistic_image->rows; y++)
2438   {
2439     const int
2440       id = GetOpenMPThreadId();
2441
2442     register const Quantum
2443       *restrict p;
2444
2445     register Quantum
2446       *restrict q;
2447
2448     register ssize_t
2449       x;
2450
2451     if (status == MagickFalse)
2452       continue;
2453     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2454       (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2455       MagickMax(height,1),exception);
2456     q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns,      1,exception);
2457     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2458       {
2459         status=MagickFalse;
2460         continue;
2461       }
2462     for (x=0; x < (ssize_t) statistic_image->columns; x++)
2463     {
2464       register ssize_t
2465         i;
2466
2467       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2468       {
2469         Quantum
2470           pixel;
2471
2472         register const Quantum
2473           *restrict pixels;
2474
2475         register ssize_t
2476           u;
2477
2478         ssize_t
2479           v;
2480
2481         PixelChannel channel=GetPixelChannelChannel(image,i);
2482         PixelTrait traits=GetPixelChannelTraits(image,channel);
2483         PixelTrait statistic_traits=GetPixelChannelTraits(statistic_image,
2484           channel);
2485         if ((traits == UndefinedPixelTrait) ||
2486             (statistic_traits == UndefinedPixelTrait))
2487           continue;
2488         if (((statistic_traits & CopyPixelTrait) != 0) ||
2489             (GetPixelMask(image,p) != 0))
2490           {
2491             SetPixelChannel(statistic_image,channel,p[center+i],q);
2492             continue;
2493           }
2494         pixels=p;
2495         ResetPixelList(pixel_list[id]);
2496         for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2497         {
2498           for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2499           {
2500             InsertPixelList(image,pixels[i],pixel_list[id]);
2501             pixels+=GetPixelChannels(image);
2502           }
2503           pixels+=(image->columns-1)*GetPixelChannels(image);
2504         }
2505         switch (type)
2506         {
2507           case GradientStatistic:
2508           {
2509             double
2510               maximum,
2511               minimum;
2512
2513             GetMinimumPixelList(pixel_list[id],&pixel);
2514             minimum=(double) pixel;
2515             GetMaximumPixelList(pixel_list[id],&pixel);
2516             maximum=(double) pixel;
2517             pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2518             break;
2519           }
2520           case MaximumStatistic:
2521           {
2522             GetMaximumPixelList(pixel_list[id],&pixel);
2523             break;
2524           }
2525           case MeanStatistic:
2526           {
2527             GetMeanPixelList(pixel_list[id],&pixel);
2528             break;
2529           }
2530           case MedianStatistic:
2531           default:
2532           {
2533             GetMedianPixelList(pixel_list[id],&pixel);
2534             break;
2535           }
2536           case MinimumStatistic:
2537           {
2538             GetMinimumPixelList(pixel_list[id],&pixel);
2539             break;
2540           }
2541           case ModeStatistic:
2542           {
2543             GetModePixelList(pixel_list[id],&pixel);
2544             break;
2545           }
2546           case NonpeakStatistic:
2547           {
2548             GetNonpeakPixelList(pixel_list[id],&pixel);
2549             break;
2550           }
2551           case StandardDeviationStatistic:
2552           {
2553             GetStandardDeviationPixelList(pixel_list[id],&pixel);
2554             break;
2555           }
2556         }
2557         SetPixelChannel(statistic_image,channel,pixel,q);
2558       }
2559       p+=GetPixelChannels(image);
2560       q+=GetPixelChannels(statistic_image);
2561     }
2562     if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2563       status=MagickFalse;
2564     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2565       {
2566         MagickBooleanType
2567           proceed;
2568
2569 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2570         #pragma omp critical (MagickCore_StatisticImage)
2571 #endif
2572         proceed=SetImageProgress(image,StatisticImageTag,progress++,
2573           image->rows);
2574         if (proceed == MagickFalse)
2575           status=MagickFalse;
2576       }
2577   }
2578   statistic_view=DestroyCacheView(statistic_view);
2579   image_view=DestroyCacheView(image_view);
2580   pixel_list=DestroyPixelListThreadSet(pixel_list);
2581   if (status == MagickFalse)
2582     statistic_image=DestroyImage(statistic_image);
2583   return(statistic_image);
2584 }