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,const Quantum pixel,
236 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*pixel)));
289 case GaussianNoiseEvaluateOperator:
291 result=(double) GenerateDifferentialNoise(random_info,pixel,
292 GaussianNoise,value);
295 case ImpulseNoiseEvaluateOperator:
297 result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
301 case LaplacianNoiseEvaluateOperator:
303 result=(double) GenerateDifferentialNoise(random_info,pixel,
304 LaplacianNoise,value);
307 case LeftShiftEvaluateOperator:
309 result=(double) ((size_t) pixel << (size_t) (value+0.5));
312 case LogEvaluateOperator:
314 if ((QuantumScale*pixel) >= MagickEpsilon)
315 result=(double) (QuantumRange*log((double) (QuantumScale*value*pixel+
316 1.0))/log((double) (value+1.0)));
319 case MaxEvaluateOperator:
321 result=(double) EvaluateMax((double) pixel,value);
324 case MeanEvaluateOperator:
326 result=(double) (pixel+value);
329 case MedianEvaluateOperator:
331 result=(double) (pixel+value);
334 case MinEvaluateOperator:
336 result=(double) MagickMin((double) pixel,value);
339 case MultiplicativeNoiseEvaluateOperator:
341 result=(double) GenerateDifferentialNoise(random_info,pixel,
342 MultiplicativeGaussianNoise,value);
345 case MultiplyEvaluateOperator:
347 result=(double) (value*pixel);
350 case OrEvaluateOperator:
352 result=(double) ((size_t) pixel | (size_t) (value+0.5));
355 case PoissonNoiseEvaluateOperator:
357 result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
361 case PowEvaluateOperator:
363 result=(double) (QuantumRange*pow((double) (QuantumScale*pixel),(double)
367 case RightShiftEvaluateOperator:
369 result=(double) ((size_t) pixel >> (size_t) (value+0.5));
372 case SetEvaluateOperator:
377 case SineEvaluateOperator:
379 result=(double) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
380 QuantumScale*pixel*value))+0.5));
383 case SubtractEvaluateOperator:
385 result=(double) (pixel-value);
388 case SumEvaluateOperator:
390 result=(double) (pixel+value);
393 case ThresholdEvaluateOperator:
395 result=(double) (((double) pixel <= value) ? 0 : QuantumRange);
398 case ThresholdBlackEvaluateOperator:
400 result=(double) (((double) pixel <= value) ? 0 : pixel);
403 case ThresholdWhiteEvaluateOperator:
405 result=(double) (((double) pixel > value) ? QuantumRange : pixel);
408 case UniformNoiseEvaluateOperator:
410 result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
414 case XorEvaluateOperator:
416 result=(double) ((size_t) pixel ^ (size_t) (value+0.5));
423 MagickExport Image *EvaluateImages(const Image *images,
424 const MagickEvaluateOperator op,ExceptionInfo *exception)
426 #define EvaluateImageTag "Evaluate/Image"
444 **restrict evaluate_pixels;
447 **restrict random_info;
455 #if defined(MAGICKCORE_OPENMP_SUPPORT)
461 Ensure the image are the same size.
463 assert(images != (Image *) NULL);
464 assert(images->signature == MagickSignature);
465 if (images->debug != MagickFalse)
466 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
467 assert(exception != (ExceptionInfo *) NULL);
468 assert(exception->signature == MagickSignature);
469 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
470 if ((next->columns != images->columns) || (next->rows != images->rows))
472 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
473 "ImageWidthsOrHeightsDiffer","'%s'",images->filename);
474 return((Image *) NULL);
477 Initialize evaluate next attributes.
479 image=CloneImage(images,images->columns,images->rows,MagickTrue,
481 if (image == (Image *) NULL)
482 return((Image *) NULL);
483 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
485 image=DestroyImage(image);
486 return((Image *) NULL);
488 number_images=GetImageListLength(images);
489 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
490 if (evaluate_pixels == (PixelChannels **) NULL)
492 image=DestroyImage(image);
493 (void) ThrowMagickException(exception,GetMagickModule(),
494 ResourceLimitError,"MemoryAllocationFailed","'%s'",images->filename);
495 return((Image *) NULL);
498 Evaluate image pixels.
502 random_info=AcquireRandomInfoThreadSet();
503 #if defined(MAGICKCORE_OPENMP_SUPPORT)
504 key=GetRandomSecretKey(random_info[0]);
506 evaluate_view=AcquireAuthenticCacheView(image,exception);
507 if (op == MedianEvaluateOperator)
509 #if defined(MAGICKCORE_OPENMP_SUPPORT)
510 #pragma omp parallel for schedule(static,4) shared(progress,status) \
511 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
513 for (y=0; y < (ssize_t) image->rows; y++)
522 id = GetOpenMPThreadId();
524 register PixelChannels
533 if (status == MagickFalse)
535 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
537 if (q == (Quantum *) NULL)
542 evaluate_pixel=evaluate_pixels[id];
543 for (x=0; x < (ssize_t) image->columns; x++)
549 for (j=0; j < (ssize_t) number_images; j++)
550 for (k=0; k < MaxPixelChannels; k++)
551 evaluate_pixel[j].channel[k]=0.0;
553 for (j=0; j < (ssize_t) number_images; j++)
555 register const Quantum
561 image_view=AcquireVirtualCacheView(next,exception);
562 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
563 if (p == (const Quantum *) NULL)
565 image_view=DestroyCacheView(image_view);
568 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
577 channel=GetPixelChannelChannel(image,i);
578 evaluate_traits=GetPixelChannelTraits(image,channel);
579 traits=GetPixelChannelTraits(next,channel);
580 if ((traits == UndefinedPixelTrait) ||
581 (evaluate_traits == UndefinedPixelTrait))
583 if ((evaluate_traits & UpdatePixelTrait) == 0)
585 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
586 random_info[id],GetPixelChannel(image,channel,p),op,
587 evaluate_pixel[j].channel[i]);
589 image_view=DestroyCacheView(image_view);
590 next=GetNextImageInList(next);
592 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
594 for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
595 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
596 q+=GetPixelChannels(image);
598 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
600 if (images->progress_monitor != (MagickProgressMonitor) NULL)
605 #if defined(MAGICKCORE_OPENMP_SUPPORT)
606 #pragma omp critical (MagickCore_EvaluateImages)
608 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
610 if (proceed == MagickFalse)
617 #if defined(MAGICKCORE_OPENMP_SUPPORT)
618 #pragma omp parallel for schedule(static,4) shared(progress,status) \
619 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
621 for (y=0; y < (ssize_t) image->rows; y++)
630 id = GetOpenMPThreadId();
636 register PixelChannels
645 if (status == MagickFalse)
647 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
648 image->columns,1,exception);
649 if (q == (Quantum *) NULL)
654 evaluate_pixel=evaluate_pixels[id];
655 for (j=0; j < (ssize_t) image->columns; j++)
656 for (i=0; i < MaxPixelChannels; i++)
657 evaluate_pixel[j].channel[i]=0.0;
659 for (j=0; j < (ssize_t) number_images; j++)
661 register const Quantum
664 image_view=AcquireVirtualCacheView(next,exception);
665 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
666 if (p == (const Quantum *) NULL)
668 image_view=DestroyCacheView(image_view);
671 for (x=0; x < (ssize_t) next->columns; x++)
676 if (GetPixelMask(next,p) != 0)
678 p+=GetPixelChannels(next);
681 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
690 channel=GetPixelChannelChannel(image,i);
691 traits=GetPixelChannelTraits(next,channel);
692 evaluate_traits=GetPixelChannelTraits(image,channel);
693 if ((traits == UndefinedPixelTrait) ||
694 (evaluate_traits == UndefinedPixelTrait))
696 if ((traits & UpdatePixelTrait) == 0)
698 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
699 random_info[id],GetPixelChannel(image,channel,p),j ==
700 0 ? AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
702 p+=GetPixelChannels(next);
704 image_view=DestroyCacheView(image_view);
705 next=GetNextImageInList(next);
707 for (x=0; x < (ssize_t) image->columns; x++)
714 case MeanEvaluateOperator:
716 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
717 evaluate_pixel[x].channel[i]/=(double) number_images;
720 case MultiplyEvaluateOperator:
722 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
727 for (j=0; j < (ssize_t) (number_images-1); j++)
728 evaluate_pixel[x].channel[i]*=QuantumScale;
736 for (x=0; x < (ssize_t) image->columns; x++)
741 if (GetPixelMask(image,q) != 0)
743 q+=GetPixelChannels(image);
746 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
754 channel=GetPixelChannelChannel(image,i);
755 traits=GetPixelChannelTraits(image,channel);
756 if (traits == UndefinedPixelTrait)
758 if ((traits & UpdatePixelTrait) == 0)
760 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
762 q+=GetPixelChannels(image);
764 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
766 if (images->progress_monitor != (MagickProgressMonitor) NULL)
771 #if defined(MAGICKCORE_OPENMP_SUPPORT)
772 #pragma omp critical (MagickCore_EvaluateImages)
774 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
776 if (proceed == MagickFalse)
781 evaluate_view=DestroyCacheView(evaluate_view);
782 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
783 random_info=DestroyRandomInfoThreadSet(random_info);
784 if (status == MagickFalse)
785 image=DestroyImage(image);
789 MagickExport MagickBooleanType EvaluateImage(Image *image,
790 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
802 **restrict random_info;
807 #if defined(MAGICKCORE_OPENMP_SUPPORT)
812 assert(image != (Image *) NULL);
813 assert(image->signature == MagickSignature);
814 if (image->debug != MagickFalse)
815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
816 assert(exception != (ExceptionInfo *) NULL);
817 assert(exception->signature == MagickSignature);
818 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
822 random_info=AcquireRandomInfoThreadSet();
823 #if defined(MAGICKCORE_OPENMP_SUPPORT)
824 key=GetRandomSecretKey(random_info[0]);
826 image_view=AcquireAuthenticCacheView(image,exception);
827 #if defined(MAGICKCORE_OPENMP_SUPPORT)
828 #pragma omp parallel for schedule(static,4) shared(progress,status) \
829 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
831 for (y=0; y < (ssize_t) image->rows; y++)
834 id = GetOpenMPThreadId();
842 if (status == MagickFalse)
844 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
845 if (q == (Quantum *) NULL)
850 for (x=0; x < (ssize_t) image->columns; x++)
855 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
863 channel=GetPixelChannelChannel(image,i);
864 traits=GetPixelChannelTraits(image,channel);
865 if (traits == UndefinedPixelTrait)
867 if (((traits & CopyPixelTrait) != 0) ||
868 (GetPixelMask(image,q) != 0))
870 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
873 q+=GetPixelChannels(image);
875 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
877 if (image->progress_monitor != (MagickProgressMonitor) NULL)
882 #if defined(MAGICKCORE_OPENMP_SUPPORT)
883 #pragma omp critical (MagickCore_EvaluateImage)
885 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
886 if (proceed == MagickFalse)
890 image_view=DestroyCacheView(image_view);
891 random_info=DestroyRandomInfoThreadSet(random_info);
896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900 % F u n c t i o n I m a g e %
904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906 % FunctionImage() applies a value to the image with an arithmetic, relational,
907 % or logical operator to an image. Use these operations to lighten or darken
908 % an image, to increase or decrease contrast in an image, or to produce the
909 % "negative" of an image.
911 % The format of the FunctionImage method is:
913 % MagickBooleanType FunctionImage(Image *image,
914 % const MagickFunction function,const ssize_t number_parameters,
915 % const double *parameters,ExceptionInfo *exception)
917 % A description of each parameter follows:
919 % o image: the image.
921 % o function: A channel function.
923 % o parameters: one or more parameters.
925 % o exception: return any errors or warnings in this structure.
929 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
930 const size_t number_parameters,const double *parameters,
931 ExceptionInfo *exception)
943 case PolynomialFunction:
946 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
950 for (i=0; i < (ssize_t) number_parameters; i++)
951 result=result*QuantumScale*pixel+parameters[i];
952 result*=QuantumRange;
955 case SinusoidFunction:
964 Sinusoid: frequency, phase, amplitude, bias.
966 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
967 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
968 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
969 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
970 result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
971 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
983 Arcsin (peged at range limits for invalid results): width, center,
986 width=(number_parameters >= 1) ? parameters[0] : 1.0;
987 center=(number_parameters >= 2) ? parameters[1] : 0.5;
988 range=(number_parameters >= 3) ? parameters[2] : 1.0;
989 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
990 result=2.0/width*(QuantumScale*pixel-center);
991 if ( result <= -1.0 )
992 result=bias-range/2.0;
995 result=bias+range/2.0;
997 result=(double) (range/MagickPI*asin((double) result)+bias);
998 result*=QuantumRange;
1001 case ArctanFunction:
1010 Arctan: slope, center, range, and bias.
1012 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
1013 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1014 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1015 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1016 result=(double) (MagickPI*slope*(QuantumScale*pixel-center));
1017 result=(double) (QuantumRange*(range/MagickPI*atan((double)
1021 case UndefinedFunction:
1024 return(ClampToQuantum(result));
1027 MagickExport MagickBooleanType FunctionImage(Image *image,
1028 const MagickFunction function,const size_t number_parameters,
1029 const double *parameters,ExceptionInfo *exception)
1031 #define FunctionImageTag "Function/Image "
1045 assert(image != (Image *) NULL);
1046 assert(image->signature == MagickSignature);
1047 if (image->debug != MagickFalse)
1048 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1049 assert(exception != (ExceptionInfo *) NULL);
1050 assert(exception->signature == MagickSignature);
1051 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1052 return(MagickFalse);
1055 image_view=AcquireAuthenticCacheView(image,exception);
1056 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1057 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1058 dynamic_number_threads(image,image->columns,image->rows,1)
1060 for (y=0; y < (ssize_t) image->rows; y++)
1068 if (status == MagickFalse)
1070 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1071 if (q == (Quantum *) NULL)
1076 for (x=0; x < (ssize_t) image->columns; x++)
1081 if (GetPixelMask(image,q) != 0)
1083 q+=GetPixelChannels(image);
1086 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1094 channel=GetPixelChannelChannel(image,i);
1095 traits=GetPixelChannelTraits(image,channel);
1096 if (traits == UndefinedPixelTrait)
1098 if ((traits & UpdatePixelTrait) == 0)
1100 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1103 q+=GetPixelChannels(image);
1105 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1107 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1112 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1113 #pragma omp critical (MagickCore_FunctionImage)
1115 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1116 if (proceed == MagickFalse)
1120 image_view=DestroyCacheView(image_view);
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129 % G e t I m a g e E x t r e m a %
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1135 % GetImageExtrema() returns the extrema of one or more image channels.
1137 % The format of the GetImageExtrema method is:
1139 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1140 % size_t *maxima,ExceptionInfo *exception)
1142 % A description of each parameter follows:
1144 % o image: the image.
1146 % o minima: the minimum value in the channel.
1148 % o maxima: the maximum value in the channel.
1150 % o exception: return any errors or warnings in this structure.
1153 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1154 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1163 assert(image != (Image *) NULL);
1164 assert(image->signature == MagickSignature);
1165 if (image->debug != MagickFalse)
1166 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1167 status=GetImageRange(image,&min,&max,exception);
1168 *minima=(size_t) ceil(min-0.5);
1169 *maxima=(size_t) floor(max+0.5);
1174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178 % G e t I m a g e M e a n %
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 % GetImageMean() returns the mean and standard deviation of one or more image
1187 % The format of the GetImageMean method is:
1189 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1190 % double *standard_deviation,ExceptionInfo *exception)
1192 % A description of each parameter follows:
1194 % o image: the image.
1196 % o mean: the average value in the channel.
1198 % o standard_deviation: the standard deviation of the channel.
1200 % o exception: return any errors or warnings in this structure.
1203 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1204 double *standard_deviation,ExceptionInfo *exception)
1210 *channel_statistics;
1215 assert(image != (Image *) NULL);
1216 assert(image->signature == MagickSignature);
1217 if (image->debug != MagickFalse)
1218 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1219 channel_statistics=GetImageStatistics(image,exception);
1220 if (channel_statistics == (ChannelStatistics *) NULL)
1221 return(MagickFalse);
1223 channel_statistics[CompositePixelChannel].mean=0.0;
1224 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1225 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1233 channel=GetPixelChannelChannel(image,i);
1234 traits=GetPixelChannelTraits(image,channel);
1235 if (traits == UndefinedPixelTrait)
1237 if ((traits & UpdatePixelTrait) == 0)
1239 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1240 channel_statistics[CompositePixelChannel].standard_deviation+=
1241 channel_statistics[i].variance-channel_statistics[i].mean*
1242 channel_statistics[i].mean;
1245 channel_statistics[CompositePixelChannel].mean/=area;
1246 channel_statistics[CompositePixelChannel].standard_deviation=
1247 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1248 *mean=channel_statistics[CompositePixelChannel].mean;
1249 *standard_deviation=
1250 channel_statistics[CompositePixelChannel].standard_deviation;
1251 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1252 channel_statistics);
1257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261 % G e t I m a g e K u r t o s i s %
1265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1270 % The format of the GetImageKurtosis method is:
1272 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1273 % double *skewness,ExceptionInfo *exception)
1275 % A description of each parameter follows:
1277 % o image: the image.
1279 % o kurtosis: the kurtosis of the channel.
1281 % o skewness: the skewness of the channel.
1283 % o exception: return any errors or warnings in this structure.
1286 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1287 double *kurtosis,double *skewness,ExceptionInfo *exception)
1306 assert(image != (Image *) NULL);
1307 assert(image->signature == MagickSignature);
1308 if (image->debug != MagickFalse)
1309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1315 standard_deviation=0.0;
1318 sum_fourth_power=0.0;
1319 image_view=AcquireVirtualCacheView(image,exception);
1320 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1321 #pragma omp parallel for schedule(static,4) shared(status) \
1322 dynamic_number_threads(image,image->columns,image->rows,1)
1324 for (y=0; y < (ssize_t) image->rows; y++)
1326 register const Quantum
1332 if (status == MagickFalse)
1334 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1335 if (p == (const Quantum *) NULL)
1340 for (x=0; x < (ssize_t) image->columns; x++)
1345 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1353 channel=GetPixelChannelChannel(image,i);
1354 traits=GetPixelChannelTraits(image,channel);
1355 if (traits == UndefinedPixelTrait)
1357 if (((traits & UpdatePixelTrait) == 0) ||
1358 (GetPixelMask(image,p) != 0))
1360 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1361 #pragma omp critical (MagickCore_GetImageKurtosis)
1365 sum_squares+=(double) p[i]*p[i];
1366 sum_cubes+=(double) p[i]*p[i]*p[i];
1367 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1371 p+=GetPixelChannels(image);
1374 image_view=DestroyCacheView(image_view);
1380 sum_fourth_power/=area;
1382 standard_deviation=sqrt(sum_squares-(mean*mean));
1383 if (standard_deviation != 0.0)
1385 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1386 3.0*mean*mean*mean*mean;
1387 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1390 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1391 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 % G e t I m a g e R a n g e %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % GetImageRange() returns the range of one or more image channels.
1409 % The format of the GetImageRange method is:
1411 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1412 % double *maxima,ExceptionInfo *exception)
1414 % A description of each parameter follows:
1416 % o image: the image.
1418 % o minima: the minimum value in the channel.
1420 % o maxima: the maximum value in the channel.
1422 % o exception: return any errors or warnings in this structure.
1425 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1426 double *maxima,ExceptionInfo *exception)
1438 assert(image != (Image *) NULL);
1439 assert(image->signature == MagickSignature);
1440 if (image->debug != MagickFalse)
1441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1443 initialize=MagickTrue;
1446 image_view=AcquireVirtualCacheView(image,exception);
1447 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1448 #pragma omp parallel for schedule(static,4) shared(status,initialize) \
1449 dynamic_number_threads(image,image->columns,image->rows,1)
1451 for (y=0; y < (ssize_t) image->rows; y++)
1453 register const Quantum
1459 if (status == MagickFalse)
1461 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1462 if (p == (const Quantum *) NULL)
1467 for (x=0; x < (ssize_t) image->columns; x++)
1472 if (GetPixelMask(image,p) != 0)
1474 p+=GetPixelChannels(image);
1477 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1485 channel=GetPixelChannelChannel(image,i);
1486 traits=GetPixelChannelTraits(image,channel);
1487 if (traits == UndefinedPixelTrait)
1489 if ((traits & UpdatePixelTrait) == 0)
1491 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1492 #pragma omp critical (MagickCore_GetImageRange)
1495 if (initialize != MagickFalse)
1497 *minima=(double) p[i];
1498 *maxima=(double) p[i];
1499 initialize=MagickFalse;
1503 if ((double) p[i] < *minima)
1504 *minima=(double) p[i];
1505 if ((double) p[i] > *maxima)
1506 *maxima=(double) p[i];
1510 p+=GetPixelChannels(image);
1513 image_view=DestroyCacheView(image_view);
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 % G e t I m a g e S t a t i s t i c s %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % GetImageStatistics() returns statistics for each channel in the image. The
1529 % statistics include the channel depth, its minima, maxima, mean, standard
1530 % deviation, kurtosis and skewness. You can access the red channel mean, for
1531 % example, like this:
1533 % channel_statistics=GetImageStatistics(image,exception);
1534 % red_mean=channel_statistics[RedPixelChannel].mean;
1536 % Use MagickRelinquishMemory() to free the statistics buffer.
1538 % The format of the GetImageStatistics method is:
1540 % ChannelStatistics *GetImageStatistics(const Image *image,
1541 % ExceptionInfo *exception)
1543 % A description of each parameter follows:
1545 % o image: the image.
1547 % o exception: return any errors or warnings in this structure.
1551 static size_t GetImageChannels(const Image *image)
1560 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1568 channel=GetPixelChannelChannel(image,i);
1569 traits=GetPixelChannelTraits(image,channel);
1570 if ((traits & UpdatePixelTrait) != 0)
1576 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1577 ExceptionInfo *exception)
1580 *channel_statistics;
1598 assert(image != (Image *) NULL);
1599 assert(image->signature == MagickSignature);
1600 if (image->debug != MagickFalse)
1601 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1602 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1603 MaxPixelChannels+1,sizeof(*channel_statistics));
1604 if (channel_statistics == (ChannelStatistics *) NULL)
1605 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1606 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1607 sizeof(*channel_statistics));
1608 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1610 channel_statistics[i].depth=1;
1611 channel_statistics[i].maxima=(-MagickHuge);
1612 channel_statistics[i].minima=MagickHuge;
1614 for (y=0; y < (ssize_t) image->rows; y++)
1616 register const Quantum
1622 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1623 if (p == (const Quantum *) NULL)
1625 for (x=0; x < (ssize_t) image->columns; x++)
1630 if (GetPixelMask(image,p) != 0)
1632 p+=GetPixelChannels(image);
1635 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1643 channel=GetPixelChannelChannel(image,i);
1644 traits=GetPixelChannelTraits(image,channel);
1645 if (traits == UndefinedPixelTrait)
1647 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1649 depth=channel_statistics[channel].depth;
1650 range=GetQuantumRange(depth);
1651 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1652 range) ? MagickTrue : MagickFalse;
1653 if (status != MagickFalse)
1655 channel_statistics[channel].depth++;
1660 if ((double) p[i] < channel_statistics[channel].minima)
1661 channel_statistics[channel].minima=(double) p[i];
1662 if ((double) p[i] > channel_statistics[channel].maxima)
1663 channel_statistics[channel].maxima=(double) p[i];
1664 channel_statistics[channel].sum+=p[i];
1665 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1666 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1667 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1669 channel_statistics[channel].area++;
1671 p+=GetPixelChannels(image);
1674 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1679 area=PerceptibleReciprocal(channel_statistics[i].area);
1680 channel_statistics[i].sum*=area;
1681 channel_statistics[i].sum_squared*=area;
1682 channel_statistics[i].sum_cubed*=area;
1683 channel_statistics[i].sum_fourth_power*=area;
1684 channel_statistics[i].mean=channel_statistics[i].sum;
1685 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1686 channel_statistics[i].standard_deviation=sqrt(
1687 channel_statistics[i].variance-(channel_statistics[i].mean*
1688 channel_statistics[i].mean));
1690 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1692 channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1693 (double) channel_statistics[CompositePixelChannel].depth,(double)
1694 channel_statistics[i].depth);
1695 channel_statistics[CompositePixelChannel].minima=MagickMin(
1696 channel_statistics[CompositePixelChannel].minima,
1697 channel_statistics[i].minima);
1698 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1699 channel_statistics[CompositePixelChannel].maxima,
1700 channel_statistics[i].maxima);
1701 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1702 channel_statistics[CompositePixelChannel].sum_squared+=
1703 channel_statistics[i].sum_squared;
1704 channel_statistics[CompositePixelChannel].sum_cubed+=
1705 channel_statistics[i].sum_cubed;
1706 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1707 channel_statistics[i].sum_fourth_power;
1708 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1709 channel_statistics[CompositePixelChannel].variance+=
1710 channel_statistics[i].variance-channel_statistics[i].mean*
1711 channel_statistics[i].mean;
1712 channel_statistics[CompositePixelChannel].standard_deviation+=
1713 channel_statistics[i].variance-channel_statistics[i].mean*
1714 channel_statistics[i].mean;
1716 channels=GetImageChannels(image);
1717 channel_statistics[CompositePixelChannel].sum/=channels;
1718 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1719 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1720 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1721 channel_statistics[CompositePixelChannel].mean/=channels;
1722 channel_statistics[CompositePixelChannel].variance/=channels;
1723 channel_statistics[CompositePixelChannel].standard_deviation=
1724 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1725 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1726 channel_statistics[CompositePixelChannel].skewness/=channels;
1727 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1732 standard_deviation=PerceptibleReciprocal(
1733 channel_statistics[i].standard_deviation);
1734 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1735 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1736 channel_statistics[i].mean*channel_statistics[i].mean*
1737 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1738 standard_deviation);
1739 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1740 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1741 channel_statistics[i].mean*channel_statistics[i].mean*
1742 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1743 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1744 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1745 standard_deviation*standard_deviation)-3.0;
1747 return(channel_statistics);
1751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755 % S t a t i s t i c I m a g e %
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
1762 % the neighborhood of the specified width and height.
1764 % The format of the StatisticImage method is:
1766 % Image *StatisticImage(const Image *image,const StatisticType type,
1767 % const size_t width,const size_t height,ExceptionInfo *exception)
1769 % A description of each parameter follows:
1771 % o image: the image.
1773 % o type: the statistic type (median, mode, etc.).
1775 % o width: the width of the pixel neighborhood.
1777 % o height: the height of the pixel neighborhood.
1779 % o exception: return any errors or warnings in this structure.
1783 typedef struct _SkipNode
1791 typedef struct _SkipList
1800 typedef struct _PixelList
1813 static PixelList *DestroyPixelList(PixelList *pixel_list)
1815 if (pixel_list == (PixelList *) NULL)
1816 return((PixelList *) NULL);
1817 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
1818 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
1819 pixel_list->skip_list.nodes);
1820 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
1824 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
1829 assert(pixel_list != (PixelList **) NULL);
1830 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
1831 if (pixel_list[i] != (PixelList *) NULL)
1832 pixel_list[i]=DestroyPixelList(pixel_list[i]);
1833 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
1837 static PixelList *AcquirePixelList(const size_t width,const size_t height)
1842 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
1843 if (pixel_list == (PixelList *) NULL)
1845 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
1846 pixel_list->length=width*height;
1847 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
1848 sizeof(*pixel_list->skip_list.nodes));
1849 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
1850 return(DestroyPixelList(pixel_list));
1851 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
1852 sizeof(*pixel_list->skip_list.nodes));
1853 pixel_list->signature=MagickSignature;
1857 static PixelList **AcquirePixelListThreadSet(const size_t width,
1858 const size_t height)
1869 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
1870 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
1871 sizeof(*pixel_list));
1872 if (pixel_list == (PixelList **) NULL)
1873 return((PixelList **) NULL);
1874 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
1875 for (i=0; i < (ssize_t) number_threads; i++)
1877 pixel_list[i]=AcquirePixelList(width,height);
1878 if (pixel_list[i] == (PixelList *) NULL)
1879 return(DestroyPixelListThreadSet(pixel_list));
1884 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
1897 Initialize the node.
1899 p=(&pixel_list->skip_list);
1900 p->nodes[color].signature=pixel_list->signature;
1901 p->nodes[color].count=1;
1903 Determine where it belongs in the list.
1906 for (level=p->level; level >= 0; level--)
1908 while (p->nodes[search].next[level] < color)
1909 search=p->nodes[search].next[level];
1910 update[level]=search;
1913 Generate a pseudo-random level for this node.
1915 for (level=0; ; level++)
1917 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
1918 if ((pixel_list->seed & 0x300) != 0x300)
1923 if (level > (p->level+2))
1926 If we're raising the list's level, link back to the root node.
1928 while (level > p->level)
1931 update[p->level]=65536UL;
1934 Link the node into the skip-list.
1938 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
1939 p->nodes[update[level]].next[level]=color;
1940 } while (level-- > 0);
1943 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
1956 Find the maximum value for each of the color.
1958 p=(&pixel_list->skip_list);
1961 maximum=p->nodes[color].next[0];
1964 color=p->nodes[color].next[0];
1965 if (color > maximum)
1967 count+=p->nodes[color].count;
1968 } while (count < (ssize_t) pixel_list->length);
1969 *pixel=ScaleShortToQuantum((unsigned short) maximum);
1972 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
1987 Find the mean value for each of the color.
1989 p=(&pixel_list->skip_list);
1995 color=p->nodes[color].next[0];
1996 sum+=(double) p->nodes[color].count*color;
1997 count+=p->nodes[color].count;
1998 } while (count < (ssize_t) pixel_list->length);
1999 sum/=pixel_list->length;
2000 *pixel=ScaleShortToQuantum((unsigned short) sum);
2003 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2015 Find the median value for each of the color.
2017 p=(&pixel_list->skip_list);
2022 color=p->nodes[color].next[0];
2023 count+=p->nodes[color].count;
2024 } while (count <= (ssize_t) (pixel_list->length >> 1));
2025 *pixel=ScaleShortToQuantum((unsigned short) color);
2028 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2041 Find the minimum value for each of the color.
2043 p=(&pixel_list->skip_list);
2046 minimum=p->nodes[color].next[0];
2049 color=p->nodes[color].next[0];
2050 if (color < minimum)
2052 count+=p->nodes[color].count;
2053 } while (count < (ssize_t) pixel_list->length);
2054 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2057 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2071 Make each pixel the 'predominant color' of the specified neighborhood.
2073 p=(&pixel_list->skip_list);
2076 max_count=p->nodes[mode].count;
2080 color=p->nodes[color].next[0];
2081 if (p->nodes[color].count > max_count)
2084 max_count=p->nodes[mode].count;
2086 count+=p->nodes[color].count;
2087 } while (count < (ssize_t) pixel_list->length);
2088 *pixel=ScaleShortToQuantum((unsigned short) mode);
2091 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2105 Finds the non peak value for each of the colors.
2107 p=(&pixel_list->skip_list);
2109 next=p->nodes[color].next[0];
2115 next=p->nodes[color].next[0];
2116 count+=p->nodes[color].count;
2117 } while (count <= (ssize_t) (pixel_list->length >> 1));
2118 if ((previous == 65536UL) && (next != 65536UL))
2121 if ((previous != 65536UL) && (next == 65536UL))
2123 *pixel=ScaleShortToQuantum((unsigned short) color);
2126 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2143 Find the standard-deviation value for each of the color.
2145 p=(&pixel_list->skip_list);
2155 color=p->nodes[color].next[0];
2156 sum+=(double) p->nodes[color].count*color;
2157 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2158 sum_squared+=((double) color)*((double) color);
2159 count+=p->nodes[color].count;
2160 } while (count < (ssize_t) pixel_list->length);
2161 sum/=pixel_list->length;
2162 sum_squared/=pixel_list->length;
2163 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2166 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2167 PixelList *pixel_list)
2175 index=ScaleQuantumToShort(pixel);
2176 signature=pixel_list->skip_list.nodes[index].signature;
2177 if (signature == pixel_list->signature)
2179 pixel_list->skip_list.nodes[index].count++;
2182 AddNodePixelList(pixel_list,index);
2185 static inline double MagickAbsoluteValue(const double x)
2192 static inline size_t MagickMax(const size_t x,const size_t y)
2199 static void ResetPixelList(PixelList *pixel_list)
2211 Reset the skip-list.
2213 p=(&pixel_list->skip_list);
2214 root=p->nodes+65536UL;
2216 for (level=0; level < 9; level++)
2217 root->next[level]=65536UL;
2218 pixel_list->seed=pixel_list->signature++;
2221 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2222 const size_t width,const size_t height,ExceptionInfo *exception)
2224 #define StatisticImageTag "Statistic/Image"
2240 **restrict pixel_list;
2247 Initialize statistics image attributes.
2249 assert(image != (Image *) NULL);
2250 assert(image->signature == MagickSignature);
2251 if (image->debug != MagickFalse)
2252 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2253 assert(exception != (ExceptionInfo *) NULL);
2254 assert(exception->signature == MagickSignature);
2255 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2257 if (statistic_image == (Image *) NULL)
2258 return((Image *) NULL);
2259 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2260 if (status == MagickFalse)
2262 statistic_image=DestroyImage(statistic_image);
2263 return((Image *) NULL);
2265 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2266 if (pixel_list == (PixelList **) NULL)
2268 statistic_image=DestroyImage(statistic_image);
2269 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2272 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2274 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2275 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2278 image_view=AcquireVirtualCacheView(image,exception);
2279 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2280 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2281 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2282 dynamic_number_threads(image,image->columns,image->rows,1)
2284 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2287 id = GetOpenMPThreadId();
2289 register const Quantum
2298 if (status == MagickFalse)
2300 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2301 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2302 MagickMax(height,1),exception);
2303 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2304 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2309 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2314 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2326 register const Quantum
2335 channel=GetPixelChannelChannel(image,i);
2336 traits=GetPixelChannelTraits(image,channel);
2337 statistic_traits=GetPixelChannelTraits(statistic_image,channel);
2338 if ((traits == UndefinedPixelTrait) ||
2339 (statistic_traits == UndefinedPixelTrait))
2341 if (((statistic_traits & CopyPixelTrait) != 0) ||
2342 (GetPixelMask(image,p) != 0))
2344 SetPixelChannel(statistic_image,channel,p[center+i],q);
2348 ResetPixelList(pixel_list[id]);
2349 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2351 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2353 InsertPixelList(image,pixels[i],pixel_list[id]);
2354 pixels+=GetPixelChannels(image);
2356 pixels+=image->columns*GetPixelChannels(image);
2360 case GradientStatistic:
2366 GetMinimumPixelList(pixel_list[id],&pixel);
2367 minimum=(double) pixel;
2368 GetMaximumPixelList(pixel_list[id],&pixel);
2369 maximum=(double) pixel;
2370 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2373 case MaximumStatistic:
2375 GetMaximumPixelList(pixel_list[id],&pixel);
2380 GetMeanPixelList(pixel_list[id],&pixel);
2383 case MedianStatistic:
2386 GetMedianPixelList(pixel_list[id],&pixel);
2389 case MinimumStatistic:
2391 GetMinimumPixelList(pixel_list[id],&pixel);
2396 GetModePixelList(pixel_list[id],&pixel);
2399 case NonpeakStatistic:
2401 GetNonpeakPixelList(pixel_list[id],&pixel);
2404 case StandardDeviationStatistic:
2406 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2410 SetPixelChannel(statistic_image,channel,pixel,q);
2412 p+=GetPixelChannels(image);
2413 q+=GetPixelChannels(statistic_image);
2415 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2417 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2422 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2423 #pragma omp critical (MagickCore_StatisticImage)
2425 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2427 if (proceed == MagickFalse)
2431 statistic_view=DestroyCacheView(statistic_view);
2432 image_view=DestroyCacheView(image_view);
2433 pixel_list=DestroyPixelListThreadSet(pixel_list);
2434 return(statistic_image);