2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Image Statistical Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % E v a l u a t e I m a g e %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
111 % The format of the EvaluateImage method is:
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)
120 % A description of each parameter follows:
122 % o image: the image.
124 % o op: A channel op.
126 % o value: A value value.
128 % o exception: return any errors or warnings in this structure.
132 typedef struct _PixelChannels
135 channel[CompositePixelChannel];
138 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
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);
151 static PixelChannels **AcquirePixelThreadSet(const Image *image,
152 const size_t number_images)
164 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
165 pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
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++)
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++)
186 for (k=0; k < MaxPixelChannels; k++)
187 pixels[i][j].channel[k]=0.0;
193 static inline double EvaluateMax(const double x,const double y)
200 #if defined(__cplusplus) || defined(c_plusplus)
204 static int IntensityCompare(const void *x,const void *y)
216 color_1=(const PixelChannels *) x;
217 color_2=(const PixelChannels *) y;
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);
224 #if defined(__cplusplus) || defined(c_plusplus)
228 static inline double MagickMin(const double x,const double y)
235 static double ApplyEvaluateOperator(RandomInfo *random_info,
236 Quantum pixel,const MagickEvaluateOperator op,const double value)
244 case UndefinedEvaluateOperator:
246 case AbsEvaluateOperator:
248 result=(double) fabs((double) (pixel+value));
251 case AddEvaluateOperator:
253 result=(double) (pixel+value);
256 case AddModulusEvaluateOperator:
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).
265 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
268 case AndEvaluateOperator:
270 result=(double) ((size_t) pixel & (size_t) (value+0.5));
273 case CosineEvaluateOperator:
275 result=(double) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
276 QuantumScale*pixel*value))+0.5));
279 case DivideEvaluateOperator:
281 result=pixel/(value == 0.0 ? 1.0 : value);
284 case ExponentialEvaluateOperator:
286 result=(double) (QuantumRange*exp((double) (value*QuantumScale*
290 case GaussianNoiseEvaluateOperator:
292 result=(double) GenerateDifferentialNoise(random_info,pixel,
293 GaussianNoise,value);
296 case ImpulseNoiseEvaluateOperator:
298 result=(double) GenerateDifferentialNoise(random_info,pixel,
302 case LaplacianNoiseEvaluateOperator:
304 result=(double) GenerateDifferentialNoise(random_info,pixel,
305 LaplacianNoise,value);
308 case LeftShiftEvaluateOperator:
310 result=(double) ((size_t) pixel << (size_t) (value+0.5));
313 case LogEvaluateOperator:
315 if ((QuantumScale*pixel) >= MagickEpsilon)
316 result=(double) (QuantumRange*log((double) (QuantumScale*value*
317 pixel+1.0))/log((double) (value+1.0)));
320 case MaxEvaluateOperator:
322 result=(double) EvaluateMax((double) pixel,value);
325 case MeanEvaluateOperator:
327 result=(double) (pixel+value);
330 case MedianEvaluateOperator:
332 result=(double) (pixel+value);
335 case MinEvaluateOperator:
337 result=(double) MagickMin((double) pixel,value);
340 case MultiplicativeNoiseEvaluateOperator:
342 result=(double) GenerateDifferentialNoise(random_info,pixel,
343 MultiplicativeGaussianNoise,value);
346 case MultiplyEvaluateOperator:
348 result=(double) (value*pixel);
351 case OrEvaluateOperator:
353 result=(double) ((size_t) pixel | (size_t) (value+0.5));
356 case PoissonNoiseEvaluateOperator:
358 result=(double) GenerateDifferentialNoise(random_info,pixel,
362 case PowEvaluateOperator:
364 result=(double) (QuantumRange*pow((double) (QuantumScale*pixel),
368 case RightShiftEvaluateOperator:
370 result=(double) ((size_t) pixel >> (size_t) (value+0.5));
373 case SetEvaluateOperator:
378 case SineEvaluateOperator:
380 result=(double) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
381 QuantumScale*pixel*value))+0.5));
384 case SubtractEvaluateOperator:
386 result=(double) (pixel-value);
389 case SumEvaluateOperator:
391 result=(double) (pixel+value);
394 case ThresholdEvaluateOperator:
396 result=(double) (((double) pixel <= value) ? 0 :
400 case ThresholdBlackEvaluateOperator:
402 result=(double) (((double) pixel <= value) ? 0 : pixel);
405 case ThresholdWhiteEvaluateOperator:
407 result=(double) (((double) pixel > value) ? QuantumRange :
411 case UniformNoiseEvaluateOperator:
413 result=(double) GenerateDifferentialNoise(random_info,pixel,
417 case XorEvaluateOperator:
419 result=(double) ((size_t) pixel ^ (size_t) (value+0.5));
426 MagickExport Image *EvaluateImages(const Image *images,
427 const MagickEvaluateOperator op,ExceptionInfo *exception)
429 #define EvaluateImageTag "Evaluate/Image"
447 **restrict evaluate_pixels;
450 **restrict random_info;
458 #if defined(MAGICKCORE_OPENMP_SUPPORT)
464 Ensure the image are the same size.
466 assert(images != (Image *) NULL);
467 assert(images->signature == MagickSignature);
468 if (images->debug != MagickFalse)
469 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
470 assert(exception != (ExceptionInfo *) NULL);
471 assert(exception->signature == MagickSignature);
472 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
473 if ((next->columns != images->columns) || (next->rows != images->rows))
475 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
476 "ImageWidthsOrHeightsDiffer","'%s'",images->filename);
477 return((Image *) NULL);
480 Initialize evaluate next attributes.
482 image=CloneImage(images,images->columns,images->rows,MagickTrue,
484 if (image == (Image *) NULL)
485 return((Image *) NULL);
486 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
488 image=DestroyImage(image);
489 return((Image *) NULL);
491 number_images=GetImageListLength(images);
492 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
493 if (evaluate_pixels == (PixelChannels **) NULL)
495 image=DestroyImage(image);
496 (void) ThrowMagickException(exception,GetMagickModule(),
497 ResourceLimitError,"MemoryAllocationFailed","'%s'",images->filename);
498 return((Image *) NULL);
501 Evaluate image pixels.
505 random_info=AcquireRandomInfoThreadSet();
506 #if defined(MAGICKCORE_OPENMP_SUPPORT)
507 key=GetRandomSecretKey(random_info[0]);
509 evaluate_view=AcquireAuthenticCacheView(image,exception);
510 if (op == MedianEvaluateOperator)
512 #if defined(MAGICKCORE_OPENMP_SUPPORT)
513 #pragma omp parallel for schedule(static,4) shared(progress,status) \
514 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
516 for (y=0; y < (ssize_t) image->rows; y++)
525 id = GetOpenMPThreadId();
527 register PixelChannels
536 if (status == MagickFalse)
538 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
539 image->columns,1,exception);
540 if (q == (Quantum *) NULL)
545 evaluate_pixel=evaluate_pixels[id];
546 for (x=0; x < (ssize_t) image->columns; x++)
552 for (j=0; j < (ssize_t) number_images; j++)
553 for (k=0; k < MaxPixelChannels; k++)
554 evaluate_pixel[j].channel[k]=0.0;
556 for (j=0; j < (ssize_t) number_images; j++)
558 register const Quantum
564 image_view=AcquireVirtualCacheView(next,exception);
565 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
566 if (p == (const Quantum *) NULL)
568 image_view=DestroyCacheView(image_view);
571 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
580 channel=GetPixelChannelChannel(image,i);
581 evaluate_traits=GetPixelChannelTraits(image,channel);
582 traits=GetPixelChannelTraits(next,channel);
583 if ((traits == UndefinedPixelTrait) ||
584 (evaluate_traits == UndefinedPixelTrait))
586 if ((evaluate_traits & UpdatePixelTrait) == 0)
588 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
589 random_info[id],GetPixelChannel(image,channel,p),op,
590 evaluate_pixel[j].channel[i]);
592 image_view=DestroyCacheView(image_view);
593 next=GetNextImageInList(next);
595 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
597 for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
598 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
599 q+=GetPixelChannels(image);
601 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
603 if (images->progress_monitor != (MagickProgressMonitor) NULL)
608 #if defined(MAGICKCORE_OPENMP_SUPPORT)
609 #pragma omp critical (MagickCore_EvaluateImages)
611 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
613 if (proceed == MagickFalse)
620 #if defined(MAGICKCORE_OPENMP_SUPPORT)
621 #pragma omp parallel for schedule(static,4) shared(progress,status) \
622 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
624 for (y=0; y < (ssize_t) image->rows; y++)
633 id = GetOpenMPThreadId();
639 register PixelChannels
648 if (status == MagickFalse)
650 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
651 image->columns,1,exception);
652 if (q == (Quantum *) NULL)
657 evaluate_pixel=evaluate_pixels[id];
658 for (j=0; j < (ssize_t) image->columns; j++)
659 for (i=0; i < MaxPixelChannels; i++)
660 evaluate_pixel[j].channel[i]=0.0;
662 for (j=0; j < (ssize_t) number_images; j++)
664 register const Quantum
667 image_view=AcquireVirtualCacheView(next,exception);
668 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
669 if (p == (const Quantum *) NULL)
671 image_view=DestroyCacheView(image_view);
674 for (x=0; x < (ssize_t) next->columns; x++)
679 if (GetPixelMask(next,p) != 0)
681 p+=GetPixelChannels(next);
684 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
693 channel=GetPixelChannelChannel(image,i);
694 traits=GetPixelChannelTraits(next,channel);
695 evaluate_traits=GetPixelChannelTraits(image,channel);
696 if ((traits == UndefinedPixelTrait) ||
697 (evaluate_traits == UndefinedPixelTrait))
699 if ((traits & UpdatePixelTrait) == 0)
701 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
702 random_info[id],GetPixelChannel(image,channel,p),j ==
703 0 ? AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
705 p+=GetPixelChannels(next);
707 image_view=DestroyCacheView(image_view);
708 next=GetNextImageInList(next);
710 for (x=0; x < (ssize_t) image->columns; x++)
717 case MeanEvaluateOperator:
719 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
720 evaluate_pixel[x].channel[i]/=(double) number_images;
723 case MultiplyEvaluateOperator:
725 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
730 for (j=0; j < (ssize_t) (number_images-1); j++)
731 evaluate_pixel[x].channel[i]*=QuantumScale;
739 for (x=0; x < (ssize_t) image->columns; x++)
744 if (GetPixelMask(image,q) != 0)
746 q+=GetPixelChannels(image);
749 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
757 channel=GetPixelChannelChannel(image,i);
758 traits=GetPixelChannelTraits(image,channel);
759 if (traits == UndefinedPixelTrait)
761 if ((traits & UpdatePixelTrait) == 0)
763 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
765 q+=GetPixelChannels(image);
767 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
769 if (images->progress_monitor != (MagickProgressMonitor) NULL)
774 #if defined(MAGICKCORE_OPENMP_SUPPORT)
775 #pragma omp critical (MagickCore_EvaluateImages)
777 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
779 if (proceed == MagickFalse)
784 evaluate_view=DestroyCacheView(evaluate_view);
785 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
786 random_info=DestroyRandomInfoThreadSet(random_info);
787 if (status == MagickFalse)
788 image=DestroyImage(image);
792 MagickExport MagickBooleanType EvaluateImage(Image *image,
793 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
805 **restrict random_info;
810 #if defined(MAGICKCORE_OPENMP_SUPPORT)
815 assert(image != (Image *) NULL);
816 assert(image->signature == MagickSignature);
817 if (image->debug != MagickFalse)
818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
819 assert(exception != (ExceptionInfo *) NULL);
820 assert(exception->signature == MagickSignature);
821 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
825 random_info=AcquireRandomInfoThreadSet();
826 #if defined(MAGICKCORE_OPENMP_SUPPORT)
827 key=GetRandomSecretKey(random_info[0]);
829 image_view=AcquireAuthenticCacheView(image,exception);
830 #if defined(MAGICKCORE_OPENMP_SUPPORT)
831 #pragma omp parallel for schedule(static,4) shared(progress,status) \
832 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
834 for (y=0; y < (ssize_t) image->rows; y++)
837 id = GetOpenMPThreadId();
845 if (status == MagickFalse)
847 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
848 if (q == (Quantum *) NULL)
853 for (x=0; x < (ssize_t) image->columns; x++)
858 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
866 channel=GetPixelChannelChannel(image,i);
867 traits=GetPixelChannelTraits(image,channel);
868 if (traits == UndefinedPixelTrait)
870 if (((traits & CopyPixelTrait) != 0) ||
871 (GetPixelMask(image,q) != 0))
873 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
876 q+=GetPixelChannels(image);
878 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
880 if (image->progress_monitor != (MagickProgressMonitor) NULL)
885 #if defined(MAGICKCORE_OPENMP_SUPPORT)
886 #pragma omp critical (MagickCore_EvaluateImage)
888 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
889 if (proceed == MagickFalse)
893 image_view=DestroyCacheView(image_view);
894 random_info=DestroyRandomInfoThreadSet(random_info);
899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903 % F u n c t i o n I m a g e %
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 % FunctionImage() applies a value to the image with an arithmetic, relational,
910 % or logical operator to an image. Use these operations to lighten or darken
911 % an image, to increase or decrease contrast in an image, or to produce the
912 % "negative" of an image.
914 % The format of the FunctionImage method is:
916 % MagickBooleanType FunctionImage(Image *image,
917 % const MagickFunction function,const ssize_t number_parameters,
918 % const double *parameters,ExceptionInfo *exception)
920 % A description of each parameter follows:
922 % o image: the image.
924 % o function: A channel function.
926 % o parameters: one or more parameters.
928 % o exception: return any errors or warnings in this structure.
932 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
933 const size_t number_parameters,const double *parameters,
934 ExceptionInfo *exception)
946 case PolynomialFunction:
949 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
953 for (i=0; i < (ssize_t) number_parameters; i++)
954 result=result*QuantumScale*pixel+parameters[i];
955 result*=QuantumRange;
958 case SinusoidFunction:
967 Sinusoid: frequency, phase, amplitude, bias.
969 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
970 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
971 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
972 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
973 result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
974 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
986 Arcsin (peged at range limits for invalid results): width, center,
989 width=(number_parameters >= 1) ? parameters[0] : 1.0;
990 center=(number_parameters >= 2) ? parameters[1] : 0.5;
991 range=(number_parameters >= 3) ? parameters[2] : 1.0;
992 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
993 result=2.0/width*(QuantumScale*pixel-center);
994 if ( result <= -1.0 )
995 result=bias-range/2.0;
998 result=bias+range/2.0;
1000 result=(double) (range/MagickPI*asin((double) result)+bias);
1001 result*=QuantumRange;
1004 case ArctanFunction:
1013 Arctan: slope, center, range, and bias.
1015 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
1016 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1017 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1018 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1019 result=(double) (MagickPI*slope*(QuantumScale*pixel-center));
1020 result=(double) (QuantumRange*(range/MagickPI*atan((double)
1024 case UndefinedFunction:
1027 return(ClampToQuantum(result));
1030 MagickExport MagickBooleanType FunctionImage(Image *image,
1031 const MagickFunction function,const size_t number_parameters,
1032 const double *parameters,ExceptionInfo *exception)
1034 #define FunctionImageTag "Function/Image "
1048 assert(image != (Image *) NULL);
1049 assert(image->signature == MagickSignature);
1050 if (image->debug != MagickFalse)
1051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1052 assert(exception != (ExceptionInfo *) NULL);
1053 assert(exception->signature == MagickSignature);
1054 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1055 return(MagickFalse);
1058 image_view=AcquireAuthenticCacheView(image,exception);
1059 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1060 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1061 dynamic_number_threads(image,image->columns,image->rows,1)
1063 for (y=0; y < (ssize_t) image->rows; y++)
1071 if (status == MagickFalse)
1073 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1074 if (q == (Quantum *) NULL)
1079 for (x=0; x < (ssize_t) image->columns; x++)
1084 if (GetPixelMask(image,q) != 0)
1086 q+=GetPixelChannels(image);
1089 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1097 channel=GetPixelChannelChannel(image,i);
1098 traits=GetPixelChannelTraits(image,channel);
1099 if (traits == UndefinedPixelTrait)
1101 if ((traits & UpdatePixelTrait) == 0)
1103 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1106 q+=GetPixelChannels(image);
1108 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1110 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1115 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1116 #pragma omp critical (MagickCore_FunctionImage)
1118 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1119 if (proceed == MagickFalse)
1123 image_view=DestroyCacheView(image_view);
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 % G e t I m a g e E x t r e m a %
1136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 % GetImageExtrema() returns the extrema of one or more image channels.
1140 % The format of the GetImageExtrema method is:
1142 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1143 % size_t *maxima,ExceptionInfo *exception)
1145 % A description of each parameter follows:
1147 % o image: the image.
1149 % o minima: the minimum value in the channel.
1151 % o maxima: the maximum value in the channel.
1153 % o exception: return any errors or warnings in this structure.
1156 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1157 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1166 assert(image != (Image *) NULL);
1167 assert(image->signature == MagickSignature);
1168 if (image->debug != MagickFalse)
1169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1170 status=GetImageRange(image,&min,&max,exception);
1171 *minima=(size_t) ceil(min-0.5);
1172 *maxima=(size_t) floor(max+0.5);
1177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 % G e t I m a g e M e a n %
1185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187 % GetImageMean() returns the mean and standard deviation of one or more image
1190 % The format of the GetImageMean method is:
1192 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1193 % double *standard_deviation,ExceptionInfo *exception)
1195 % A description of each parameter follows:
1197 % o image: the image.
1199 % o mean: the average value in the channel.
1201 % o standard_deviation: the standard deviation of the channel.
1203 % o exception: return any errors or warnings in this structure.
1206 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1207 double *standard_deviation,ExceptionInfo *exception)
1213 *channel_statistics;
1218 assert(image != (Image *) NULL);
1219 assert(image->signature == MagickSignature);
1220 if (image->debug != MagickFalse)
1221 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1222 channel_statistics=GetImageStatistics(image,exception);
1223 if (channel_statistics == (ChannelStatistics *) NULL)
1224 return(MagickFalse);
1226 channel_statistics[CompositePixelChannel].mean=0.0;
1227 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1228 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1236 channel=GetPixelChannelChannel(image,i);
1237 traits=GetPixelChannelTraits(image,channel);
1238 if (traits == UndefinedPixelTrait)
1240 if ((traits & UpdatePixelTrait) == 0)
1242 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1243 channel_statistics[CompositePixelChannel].standard_deviation+=
1244 channel_statistics[i].variance-channel_statistics[i].mean*
1245 channel_statistics[i].mean;
1248 channel_statistics[CompositePixelChannel].mean/=area;
1249 channel_statistics[CompositePixelChannel].standard_deviation=
1250 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1251 *mean=channel_statistics[CompositePixelChannel].mean;
1252 *standard_deviation=
1253 channel_statistics[CompositePixelChannel].standard_deviation;
1254 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1255 channel_statistics);
1260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 % G e t I m a g e K u r t o s i s %
1268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1270 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1273 % The format of the GetImageKurtosis method is:
1275 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1276 % double *skewness,ExceptionInfo *exception)
1278 % A description of each parameter follows:
1280 % o image: the image.
1282 % o kurtosis: the kurtosis of the channel.
1284 % o skewness: the skewness of the channel.
1286 % o exception: return any errors or warnings in this structure.
1289 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1290 double *kurtosis,double *skewness,ExceptionInfo *exception)
1309 assert(image != (Image *) NULL);
1310 assert(image->signature == MagickSignature);
1311 if (image->debug != MagickFalse)
1312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1318 standard_deviation=0.0;
1321 sum_fourth_power=0.0;
1322 image_view=AcquireVirtualCacheView(image,exception);
1323 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1324 #pragma omp parallel for schedule(static,4) shared(status) \
1325 dynamic_number_threads(image,image->columns,image->rows,1)
1327 for (y=0; y < (ssize_t) image->rows; y++)
1329 register const Quantum
1335 if (status == MagickFalse)
1337 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1338 if (p == (const Quantum *) NULL)
1343 for (x=0; x < (ssize_t) image->columns; x++)
1348 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1356 channel=GetPixelChannelChannel(image,i);
1357 traits=GetPixelChannelTraits(image,channel);
1358 if (traits == UndefinedPixelTrait)
1360 if (((traits & UpdatePixelTrait) == 0) ||
1361 (GetPixelMask(image,p) != 0))
1363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1364 #pragma omp critical (MagickCore_GetImageKurtosis)
1368 sum_squares+=(double) p[i]*p[i];
1369 sum_cubes+=(double) p[i]*p[i]*p[i];
1370 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1374 p+=GetPixelChannels(image);
1377 image_view=DestroyCacheView(image_view);
1383 sum_fourth_power/=area;
1385 standard_deviation=sqrt(sum_squares-(mean*mean));
1386 if (standard_deviation != 0.0)
1388 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1389 3.0*mean*mean*mean*mean;
1390 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1393 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1394 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 % G e t I m a g e R a n g e %
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 % GetImageRange() returns the range of one or more image channels.
1412 % The format of the GetImageRange method is:
1414 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1415 % double *maxima,ExceptionInfo *exception)
1417 % A description of each parameter follows:
1419 % o image: the image.
1421 % o minima: the minimum value in the channel.
1423 % o maxima: the maximum value in the channel.
1425 % o exception: return any errors or warnings in this structure.
1428 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1429 double *maxima,ExceptionInfo *exception)
1441 assert(image != (Image *) NULL);
1442 assert(image->signature == MagickSignature);
1443 if (image->debug != MagickFalse)
1444 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1446 initialize=MagickTrue;
1449 image_view=AcquireVirtualCacheView(image,exception);
1450 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1451 #pragma omp parallel for schedule(static,4) shared(status,initialize) \
1452 dynamic_number_threads(image,image->columns,image->rows,1)
1454 for (y=0; y < (ssize_t) image->rows; y++)
1456 register const Quantum
1462 if (status == MagickFalse)
1464 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1465 if (p == (const Quantum *) NULL)
1470 for (x=0; x < (ssize_t) image->columns; x++)
1475 if (GetPixelMask(image,p) != 0)
1477 p+=GetPixelChannels(image);
1480 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1488 channel=GetPixelChannelChannel(image,i);
1489 traits=GetPixelChannelTraits(image,channel);
1490 if (traits == UndefinedPixelTrait)
1492 if ((traits & UpdatePixelTrait) == 0)
1494 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1495 #pragma omp critical (MagickCore_GetImageRange)
1498 if (initialize != MagickFalse)
1500 *minima=(double) p[i];
1501 *maxima=(double) p[i];
1502 initialize=MagickFalse;
1506 if ((double) p[i] < *minima)
1507 *minima=(double) p[i];
1508 if ((double) p[i] > *maxima)
1509 *maxima=(double) p[i];
1513 p+=GetPixelChannels(image);
1516 image_view=DestroyCacheView(image_view);
1521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525 % G e t I m a g e S t a t i s t i c s %
1529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531 % GetImageStatistics() returns statistics for each channel in the image. The
1532 % statistics include the channel depth, its minima, maxima, mean, standard
1533 % deviation, kurtosis and skewness. You can access the red channel mean, for
1534 % example, like this:
1536 % channel_statistics=GetImageStatistics(image,exception);
1537 % red_mean=channel_statistics[RedPixelChannel].mean;
1539 % Use MagickRelinquishMemory() to free the statistics buffer.
1541 % The format of the GetImageStatistics method is:
1543 % ChannelStatistics *GetImageStatistics(const Image *image,
1544 % ExceptionInfo *exception)
1546 % A description of each parameter follows:
1548 % o image: the image.
1550 % o exception: return any errors or warnings in this structure.
1554 static size_t GetImageChannels(const Image *image)
1563 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1571 channel=GetPixelChannelChannel(image,i);
1572 traits=GetPixelChannelTraits(image,channel);
1573 if ((traits & UpdatePixelTrait) != 0)
1579 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1580 ExceptionInfo *exception)
1583 *channel_statistics;
1601 assert(image != (Image *) NULL);
1602 assert(image->signature == MagickSignature);
1603 if (image->debug != MagickFalse)
1604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1605 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1606 MaxPixelChannels+1,sizeof(*channel_statistics));
1607 if (channel_statistics == (ChannelStatistics *) NULL)
1608 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1609 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1610 sizeof(*channel_statistics));
1611 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1613 channel_statistics[i].depth=1;
1614 channel_statistics[i].maxima=(-MagickHuge);
1615 channel_statistics[i].minima=MagickHuge;
1617 for (y=0; y < (ssize_t) image->rows; y++)
1619 register const Quantum
1625 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1626 if (p == (const Quantum *) NULL)
1628 for (x=0; x < (ssize_t) image->columns; x++)
1633 if (GetPixelMask(image,p) != 0)
1635 p+=GetPixelChannels(image);
1638 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1646 channel=GetPixelChannelChannel(image,i);
1647 traits=GetPixelChannelTraits(image,channel);
1648 if (traits == UndefinedPixelTrait)
1650 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1652 depth=channel_statistics[channel].depth;
1653 range=GetQuantumRange(depth);
1654 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1655 range) ? MagickTrue : MagickFalse;
1656 if (status != MagickFalse)
1658 channel_statistics[channel].depth++;
1663 if ((double) p[i] < channel_statistics[channel].minima)
1664 channel_statistics[channel].minima=(double) p[i];
1665 if ((double) p[i] > channel_statistics[channel].maxima)
1666 channel_statistics[channel].maxima=(double) p[i];
1667 channel_statistics[channel].sum+=p[i];
1668 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1669 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1670 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1672 channel_statistics[channel].area++;
1674 p+=GetPixelChannels(image);
1677 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1682 area=MagickEpsilonReciprocal(channel_statistics[i].area);
1683 channel_statistics[i].sum*=area;
1684 channel_statistics[i].sum_squared*=area;
1685 channel_statistics[i].sum_cubed*=area;
1686 channel_statistics[i].sum_fourth_power*=area;
1687 channel_statistics[i].mean=channel_statistics[i].sum;
1688 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1689 channel_statistics[i].standard_deviation=sqrt(
1690 channel_statistics[i].variance-(channel_statistics[i].mean*
1691 channel_statistics[i].mean));
1693 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1695 channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1696 (double) channel_statistics[CompositePixelChannel].depth,(double)
1697 channel_statistics[i].depth);
1698 channel_statistics[CompositePixelChannel].minima=MagickMin(
1699 channel_statistics[CompositePixelChannel].minima,
1700 channel_statistics[i].minima);
1701 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1702 channel_statistics[CompositePixelChannel].maxima,
1703 channel_statistics[i].maxima);
1704 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1705 channel_statistics[CompositePixelChannel].sum_squared+=
1706 channel_statistics[i].sum_squared;
1707 channel_statistics[CompositePixelChannel].sum_cubed+=
1708 channel_statistics[i].sum_cubed;
1709 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1710 channel_statistics[i].sum_fourth_power;
1711 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1712 channel_statistics[CompositePixelChannel].variance+=
1713 channel_statistics[i].variance-channel_statistics[i].mean*
1714 channel_statistics[i].mean;
1715 channel_statistics[CompositePixelChannel].standard_deviation+=
1716 channel_statistics[i].variance-channel_statistics[i].mean*
1717 channel_statistics[i].mean;
1719 channels=GetImageChannels(image);
1720 channel_statistics[CompositePixelChannel].sum/=channels;
1721 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1722 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1723 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1724 channel_statistics[CompositePixelChannel].mean/=channels;
1725 channel_statistics[CompositePixelChannel].variance/=channels;
1726 channel_statistics[CompositePixelChannel].standard_deviation=
1727 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1728 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1729 channel_statistics[CompositePixelChannel].skewness/=channels;
1730 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1735 standard_deviation=MagickEpsilonReciprocal(
1736 channel_statistics[i].standard_deviation);
1737 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1738 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1739 channel_statistics[i].mean*channel_statistics[i].mean*
1740 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1741 standard_deviation);
1742 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1743 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1744 channel_statistics[i].mean*channel_statistics[i].mean*
1745 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1746 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1747 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1748 standard_deviation*standard_deviation)-3.0;
1750 return(channel_statistics);
1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758 % S t a t i s t i c I m a g e %
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
1765 % the neighborhood of the specified width and height.
1767 % The format of the StatisticImage method is:
1769 % Image *StatisticImage(const Image *image,const StatisticType type,
1770 % const size_t width,const size_t height,ExceptionInfo *exception)
1772 % A description of each parameter follows:
1774 % o image: the image.
1776 % o type: the statistic type (median, mode, etc.).
1778 % o width: the width of the pixel neighborhood.
1780 % o height: the height of the pixel neighborhood.
1782 % o exception: return any errors or warnings in this structure.
1786 typedef struct _SkipNode
1794 typedef struct _SkipList
1803 typedef struct _PixelList
1816 static PixelList *DestroyPixelList(PixelList *pixel_list)
1818 if (pixel_list == (PixelList *) NULL)
1819 return((PixelList *) NULL);
1820 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
1821 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
1822 pixel_list->skip_list.nodes);
1823 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
1827 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
1832 assert(pixel_list != (PixelList **) NULL);
1833 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
1834 if (pixel_list[i] != (PixelList *) NULL)
1835 pixel_list[i]=DestroyPixelList(pixel_list[i]);
1836 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
1840 static PixelList *AcquirePixelList(const size_t width,const size_t height)
1845 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
1846 if (pixel_list == (PixelList *) NULL)
1848 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
1849 pixel_list->length=width*height;
1850 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
1851 sizeof(*pixel_list->skip_list.nodes));
1852 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
1853 return(DestroyPixelList(pixel_list));
1854 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
1855 sizeof(*pixel_list->skip_list.nodes));
1856 pixel_list->signature=MagickSignature;
1860 static PixelList **AcquirePixelListThreadSet(const size_t width,
1861 const size_t height)
1872 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
1873 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
1874 sizeof(*pixel_list));
1875 if (pixel_list == (PixelList **) NULL)
1876 return((PixelList **) NULL);
1877 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
1878 for (i=0; i < (ssize_t) number_threads; i++)
1880 pixel_list[i]=AcquirePixelList(width,height);
1881 if (pixel_list[i] == (PixelList *) NULL)
1882 return(DestroyPixelListThreadSet(pixel_list));
1887 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
1900 Initialize the node.
1902 p=(&pixel_list->skip_list);
1903 p->nodes[color].signature=pixel_list->signature;
1904 p->nodes[color].count=1;
1906 Determine where it belongs in the list.
1909 for (level=p->level; level >= 0; level--)
1911 while (p->nodes[search].next[level] < color)
1912 search=p->nodes[search].next[level];
1913 update[level]=search;
1916 Generate a pseudo-random level for this node.
1918 for (level=0; ; level++)
1920 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
1921 if ((pixel_list->seed & 0x300) != 0x300)
1926 if (level > (p->level+2))
1929 If we're raising the list's level, link back to the root node.
1931 while (level > p->level)
1934 update[p->level]=65536UL;
1937 Link the node into the skip-list.
1941 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
1942 p->nodes[update[level]].next[level]=color;
1943 } while (level-- > 0);
1946 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
1959 Find the maximum value for each of the color.
1961 p=(&pixel_list->skip_list);
1964 maximum=p->nodes[color].next[0];
1967 color=p->nodes[color].next[0];
1968 if (color > maximum)
1970 count+=p->nodes[color].count;
1971 } while (count < (ssize_t) pixel_list->length);
1972 *pixel=ScaleShortToQuantum((unsigned short) maximum);
1975 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
1990 Find the mean value for each of the color.
1992 p=(&pixel_list->skip_list);
1998 color=p->nodes[color].next[0];
1999 sum+=(double) p->nodes[color].count*color;
2000 count+=p->nodes[color].count;
2001 } while (count < (ssize_t) pixel_list->length);
2002 sum/=pixel_list->length;
2003 *pixel=ScaleShortToQuantum((unsigned short) sum);
2006 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2018 Find the median value for each of the color.
2020 p=(&pixel_list->skip_list);
2025 color=p->nodes[color].next[0];
2026 count+=p->nodes[color].count;
2027 } while (count <= (ssize_t) (pixel_list->length >> 1));
2028 *pixel=ScaleShortToQuantum((unsigned short) color);
2031 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2044 Find the minimum value for each of the color.
2046 p=(&pixel_list->skip_list);
2049 minimum=p->nodes[color].next[0];
2052 color=p->nodes[color].next[0];
2053 if (color < minimum)
2055 count+=p->nodes[color].count;
2056 } while (count < (ssize_t) pixel_list->length);
2057 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2060 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2074 Make each pixel the 'predominant color' of the specified neighborhood.
2076 p=(&pixel_list->skip_list);
2079 max_count=p->nodes[mode].count;
2083 color=p->nodes[color].next[0];
2084 if (p->nodes[color].count > max_count)
2087 max_count=p->nodes[mode].count;
2089 count+=p->nodes[color].count;
2090 } while (count < (ssize_t) pixel_list->length);
2091 *pixel=ScaleShortToQuantum((unsigned short) mode);
2094 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2108 Finds the non peak value for each of the colors.
2110 p=(&pixel_list->skip_list);
2112 next=p->nodes[color].next[0];
2118 next=p->nodes[color].next[0];
2119 count+=p->nodes[color].count;
2120 } while (count <= (ssize_t) (pixel_list->length >> 1));
2121 if ((previous == 65536UL) && (next != 65536UL))
2124 if ((previous != 65536UL) && (next == 65536UL))
2126 *pixel=ScaleShortToQuantum((unsigned short) color);
2129 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2146 Find the standard-deviation value for each of the color.
2148 p=(&pixel_list->skip_list);
2158 color=p->nodes[color].next[0];
2159 sum+=(double) p->nodes[color].count*color;
2160 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2161 sum_squared+=((double) color)*((double) color);
2162 count+=p->nodes[color].count;
2163 } while (count < (ssize_t) pixel_list->length);
2164 sum/=pixel_list->length;
2165 sum_squared/=pixel_list->length;
2166 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2169 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2170 PixelList *pixel_list)
2178 index=ScaleQuantumToShort(pixel);
2179 signature=pixel_list->skip_list.nodes[index].signature;
2180 if (signature == pixel_list->signature)
2182 pixel_list->skip_list.nodes[index].count++;
2185 AddNodePixelList(pixel_list,index);
2188 static inline double MagickAbsoluteValue(const double x)
2195 static inline size_t MagickMax(const size_t x,const size_t y)
2202 static void ResetPixelList(PixelList *pixel_list)
2214 Reset the skip-list.
2216 p=(&pixel_list->skip_list);
2217 root=p->nodes+65536UL;
2219 for (level=0; level < 9; level++)
2220 root->next[level]=65536UL;
2221 pixel_list->seed=pixel_list->signature++;
2224 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2225 const size_t width,const size_t height,ExceptionInfo *exception)
2227 #define StatisticImageTag "Statistic/Image"
2243 **restrict pixel_list;
2250 Initialize statistics image attributes.
2252 assert(image != (Image *) NULL);
2253 assert(image->signature == MagickSignature);
2254 if (image->debug != MagickFalse)
2255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2256 assert(exception != (ExceptionInfo *) NULL);
2257 assert(exception->signature == MagickSignature);
2258 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2260 if (statistic_image == (Image *) NULL)
2261 return((Image *) NULL);
2262 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2263 if (status == MagickFalse)
2265 statistic_image=DestroyImage(statistic_image);
2266 return((Image *) NULL);
2268 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2269 if (pixel_list == (PixelList **) NULL)
2271 statistic_image=DestroyImage(statistic_image);
2272 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2275 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2277 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2278 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2281 image_view=AcquireVirtualCacheView(image,exception);
2282 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2283 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2284 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2285 dynamic_number_threads(image,image->columns,image->rows,1)
2287 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2290 id = GetOpenMPThreadId();
2292 register const Quantum
2301 if (status == MagickFalse)
2303 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2304 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2305 MagickMax(height,1),exception);
2306 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2307 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2312 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2317 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2329 register const Quantum
2338 channel=GetPixelChannelChannel(image,i);
2339 traits=GetPixelChannelTraits(image,channel);
2340 statistic_traits=GetPixelChannelTraits(statistic_image,channel);
2341 if ((traits == UndefinedPixelTrait) ||
2342 (statistic_traits == UndefinedPixelTrait))
2344 if (((statistic_traits & CopyPixelTrait) != 0) ||
2345 (GetPixelMask(image,p) != 0))
2347 SetPixelChannel(statistic_image,channel,p[center+i],q);
2351 ResetPixelList(pixel_list[id]);
2352 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2354 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2356 InsertPixelList(image,pixels[i],pixel_list[id]);
2357 pixels+=GetPixelChannels(image);
2359 pixels+=image->columns*GetPixelChannels(image);
2363 case GradientStatistic:
2369 GetMinimumPixelList(pixel_list[id],&pixel);
2370 minimum=(double) pixel;
2371 GetMaximumPixelList(pixel_list[id],&pixel);
2372 maximum=(double) pixel;
2373 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2376 case MaximumStatistic:
2378 GetMaximumPixelList(pixel_list[id],&pixel);
2383 GetMeanPixelList(pixel_list[id],&pixel);
2386 case MedianStatistic:
2389 GetMedianPixelList(pixel_list[id],&pixel);
2392 case MinimumStatistic:
2394 GetMinimumPixelList(pixel_list[id],&pixel);
2399 GetModePixelList(pixel_list[id],&pixel);
2402 case NonpeakStatistic:
2404 GetNonpeakPixelList(pixel_list[id],&pixel);
2407 case StandardDeviationStatistic:
2409 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2413 SetPixelChannel(statistic_image,channel,pixel,q);
2415 p+=GetPixelChannels(image);
2416 q+=GetPixelChannels(statistic_image);
2418 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2420 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2425 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2426 #pragma omp critical (MagickCore_StatisticImage)
2428 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2430 if (proceed == MagickFalse)
2434 statistic_view=DestroyCacheView(statistic_view);
2435 image_view=DestroyCacheView(image_view);
2436 pixel_list=DestroyPixelListThreadSet(pixel_list);
2437 return(statistic_image);