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/segment.h"
85 #include "MagickCore/semaphore.h"
86 #include "MagickCore/signature-private.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/thread-private.h"
90 #include "MagickCore/timer.h"
91 #include "MagickCore/utility.h"
92 #include "MagickCore/version.h"
95 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 % E v a l u a t e I m a g e %
103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 % EvaluateImage() applies a value to the image with an arithmetic, relational,
106 % or logical operator to an image. Use these operations to lighten or darken
107 % an image, to increase or decrease contrast in an image, or to produce the
108 % "negative" of an image.
110 % The format of the EvaluateImage method is:
112 % MagickBooleanType EvaluateImage(Image *image,
113 % const MagickEvaluateOperator op,const double value,
114 % ExceptionInfo *exception)
115 % MagickBooleanType EvaluateImages(Image *images,
116 % const MagickEvaluateOperator op,const double value,
117 % ExceptionInfo *exception)
119 % A description of each parameter follows:
121 % o image: the image.
123 % o op: A channel op.
125 % o value: A value value.
127 % o exception: return any errors or warnings in this structure.
131 typedef struct _PixelChannels
134 channel[CompositePixelChannel];
137 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
142 assert(pixels != (PixelChannels **) NULL);
143 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
144 if (pixels[i] != (PixelChannels *) NULL)
145 pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
146 pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
150 static PixelChannels **AcquirePixelThreadSet(const Image *image,
151 const size_t number_images)
163 number_threads=GetOpenMPMaximumThreads();
164 pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
166 if (pixels == (PixelChannels **) NULL)
167 return((PixelChannels **) NULL);
168 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
169 for (i=0; i < (ssize_t) number_threads; i++)
174 length=image->columns;
175 if (length < number_images)
176 length=number_images;
177 pixels[i]=(PixelChannels *) AcquireQuantumMemory(length,sizeof(**pixels));
178 if (pixels[i] == (PixelChannels *) NULL)
179 return(DestroyPixelThreadSet(pixels));
180 for (j=0; j < (ssize_t) length; j++)
185 for (k=0; k < MaxPixelChannels; k++)
186 pixels[i][j].channel[k]=0.0;
192 static inline double EvaluateMax(const double x,const double y)
199 #if defined(__cplusplus) || defined(c_plusplus)
203 static int IntensityCompare(const void *x,const void *y)
215 color_1=(const PixelChannels *) x;
216 color_2=(const PixelChannels *) y;
218 for (i=0; i < MaxPixelChannels; i++)
219 distance+=color_1->channel[i]-(MagickRealType) color_2->channel[i];
220 return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
223 #if defined(__cplusplus) || defined(c_plusplus)
227 static inline double MagickMin(const double x,const double y)
234 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
235 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
243 case UndefinedEvaluateOperator:
245 case AbsEvaluateOperator:
247 result=(MagickRealType) fabs((double) (pixel+value));
250 case AddEvaluateOperator:
252 result=(MagickRealType) (pixel+value);
255 case AddModulusEvaluateOperator:
258 This returns a 'floored modulus' of the addition which is a positive
259 result. It differs from % or fmod() that returns a 'truncated modulus'
260 result, where floor() is replaced by trunc() and could return a
261 negative result (which is clipped).
264 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
267 case AndEvaluateOperator:
269 result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
272 case CosineEvaluateOperator:
274 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
275 QuantumScale*pixel*value))+0.5));
278 case DivideEvaluateOperator:
280 result=pixel/(value == 0.0 ? 1.0 : value);
283 case ExponentialEvaluateOperator:
285 result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
289 case GaussianNoiseEvaluateOperator:
291 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
292 GaussianNoise,value);
295 case ImpulseNoiseEvaluateOperator:
297 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
301 case LaplacianNoiseEvaluateOperator:
303 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
304 LaplacianNoise,value);
307 case LeftShiftEvaluateOperator:
309 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
312 case LogEvaluateOperator:
314 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
315 pixel+1.0))/log((double) (value+1.0)));
318 case MaxEvaluateOperator:
320 result=(MagickRealType) EvaluateMax((double) pixel,value);
323 case MeanEvaluateOperator:
325 result=(MagickRealType) (pixel+value);
328 case MedianEvaluateOperator:
330 result=(MagickRealType) (pixel+value);
333 case MinEvaluateOperator:
335 result=(MagickRealType) MagickMin((double) pixel,value);
338 case MultiplicativeNoiseEvaluateOperator:
340 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
341 MultiplicativeGaussianNoise,value);
344 case MultiplyEvaluateOperator:
346 result=(MagickRealType) (value*pixel);
349 case OrEvaluateOperator:
351 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
354 case PoissonNoiseEvaluateOperator:
356 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
360 case PowEvaluateOperator:
362 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
366 case RightShiftEvaluateOperator:
368 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
371 case SetEvaluateOperator:
376 case SineEvaluateOperator:
378 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
379 QuantumScale*pixel*value))+0.5));
382 case SubtractEvaluateOperator:
384 result=(MagickRealType) (pixel-value);
387 case SumEvaluateOperator:
389 result=(MagickRealType) (pixel+value);
392 case ThresholdEvaluateOperator:
394 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
398 case ThresholdBlackEvaluateOperator:
400 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
403 case ThresholdWhiteEvaluateOperator:
405 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
409 case UniformNoiseEvaluateOperator:
411 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
415 case XorEvaluateOperator:
417 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
424 MagickExport Image *EvaluateImages(const Image *images,
425 const MagickEvaluateOperator op,ExceptionInfo *exception)
427 #define EvaluateImageTag "Evaluate/Image"
446 **restrict evaluate_pixels;
449 **restrict random_info;
458 Ensure the image are the same size.
460 assert(images != (Image *) NULL);
461 assert(images->signature == MagickSignature);
462 if (images->debug != MagickFalse)
463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
464 assert(exception != (ExceptionInfo *) NULL);
465 assert(exception->signature == MagickSignature);
466 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
467 if ((next->columns != images->columns) || (next->rows != images->rows))
469 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
470 "ImageWidthsOrHeightsDiffer","'%s'",images->filename);
471 return((Image *) NULL);
474 Initialize evaluate next attributes.
476 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
478 if (evaluate_image == (Image *) NULL)
479 return((Image *) NULL);
480 if (SetImageStorageClass(evaluate_image,DirectClass,exception) == MagickFalse)
482 evaluate_image=DestroyImage(evaluate_image);
483 return((Image *) NULL);
485 number_images=GetImageListLength(images);
486 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
487 if (evaluate_pixels == (PixelChannels **) NULL)
489 evaluate_image=DestroyImage(evaluate_image);
490 (void) ThrowMagickException(exception,GetMagickModule(),
491 ResourceLimitError,"MemoryAllocationFailed","'%s'",images->filename);
492 return((Image *) NULL);
495 Evaluate image pixels.
499 random_info=AcquireRandomInfoThreadSet();
500 concurrent=GetRandomSecretKey(random_info[0]) == ~0UL ? MagickTrue :
502 evaluate_view=AcquireAuthenticCacheView(evaluate_image,exception);
503 if (op == MedianEvaluateOperator)
505 #if defined(MAGICKCORE_OPENMP_SUPPORT)
506 #pragma omp parallel for schedule(static) shared(progress,status) omp_concurrent(concurrent)
508 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
517 id = GetOpenMPThreadId();
519 register PixelChannels
528 if (status == MagickFalse)
530 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
531 evaluate_image->columns,1,exception);
532 if (q == (Quantum *) NULL)
537 evaluate_pixel=evaluate_pixels[id];
538 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
544 for (j=0; j < (ssize_t) number_images; j++)
545 for (k=0; k < MaxPixelChannels; k++)
546 evaluate_pixel[j].channel[k]=0.0;
548 for (j=0; j < (ssize_t) number_images; j++)
550 register const Quantum
556 image_view=AcquireVirtualCacheView(next,exception);
557 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
558 if (p == (const Quantum *) NULL)
560 image_view=DestroyCacheView(image_view);
563 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
572 channel=GetPixelChannelMapChannel(evaluate_image,i);
573 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,channel);
574 traits=GetPixelChannelMapTraits(next,channel);
575 if ((traits == UndefinedPixelTrait) ||
576 (evaluate_traits == UndefinedPixelTrait))
578 if ((evaluate_traits & UpdatePixelTrait) == 0)
580 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
581 random_info[id],GetPixelChannel(evaluate_image,channel,p),op,
582 evaluate_pixel[j].channel[i]);
584 image_view=DestroyCacheView(image_view);
585 next=GetNextImageInList(next);
587 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
589 for (k=0; k < (ssize_t) GetPixelChannels(evaluate_image); k++)
590 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
591 q+=GetPixelChannels(evaluate_image);
593 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
595 if (images->progress_monitor != (MagickProgressMonitor) NULL)
600 #if defined(MAGICKCORE_OPENMP_SUPPORT)
601 #pragma omp critical (MagickCore_EvaluateImages)
603 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
604 evaluate_image->rows);
605 if (proceed == MagickFalse)
612 #if defined(MAGICKCORE_OPENMP_SUPPORT)
613 #pragma omp parallel for schedule(static) shared(progress,status) omp_concurrent(concurrent)
615 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
624 id = GetOpenMPThreadId();
630 register PixelChannels
639 if (status == MagickFalse)
641 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
642 evaluate_image->columns,1,exception);
643 if (q == (Quantum *) NULL)
648 evaluate_pixel=evaluate_pixels[id];
649 for (j=0; j < (ssize_t) evaluate_image->columns; j++)
650 for (i=0; i < MaxPixelChannels; i++)
651 evaluate_pixel[j].channel[i]=0.0;
653 for (j=0; j < (ssize_t) number_images; j++)
655 register const Quantum
658 image_view=AcquireVirtualCacheView(next,exception);
659 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
660 if (p == (const Quantum *) NULL)
662 image_view=DestroyCacheView(image_view);
665 for (x=0; x < (ssize_t) next->columns; x++)
670 if (GetPixelMask(next,p) != 0)
672 p+=GetPixelChannels(next);
675 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
684 channel=GetPixelChannelMapChannel(evaluate_image,i);
685 traits=GetPixelChannelMapTraits(next,channel);
686 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,channel);
687 if ((traits == UndefinedPixelTrait) ||
688 (evaluate_traits == UndefinedPixelTrait))
690 if ((traits & UpdatePixelTrait) == 0)
692 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
693 random_info[id],GetPixelChannel(evaluate_image,channel,p),j ==
694 0 ? AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
696 p+=GetPixelChannels(next);
698 image_view=DestroyCacheView(image_view);
699 next=GetNextImageInList(next);
701 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
708 case MeanEvaluateOperator:
710 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
711 evaluate_pixel[x].channel[i]/=(MagickRealType) number_images;
714 case MultiplyEvaluateOperator:
716 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
721 for (j=0; j < (ssize_t) (number_images-1); j++)
722 evaluate_pixel[x].channel[i]*=QuantumScale;
730 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
735 if (GetPixelMask(evaluate_image,q) != 0)
737 q+=GetPixelChannels(evaluate_image);
740 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
748 channel=GetPixelChannelMapChannel(evaluate_image,i);
749 traits=GetPixelChannelMapTraits(evaluate_image,channel);
750 if (traits == UndefinedPixelTrait)
752 if ((traits & UpdatePixelTrait) == 0)
754 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
756 q+=GetPixelChannels(evaluate_image);
758 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
760 if (images->progress_monitor != (MagickProgressMonitor) NULL)
765 #if defined(MAGICKCORE_OPENMP_SUPPORT)
766 #pragma omp critical (MagickCore_EvaluateImages)
768 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
769 evaluate_image->rows);
770 if (proceed == MagickFalse)
775 evaluate_view=DestroyCacheView(evaluate_view);
776 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
777 random_info=DestroyRandomInfoThreadSet(random_info);
778 if (status == MagickFalse)
779 evaluate_image=DestroyImage(evaluate_image);
780 return(evaluate_image);
783 MagickExport MagickBooleanType EvaluateImage(Image *image,
784 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
797 **restrict random_info;
802 assert(image != (Image *) NULL);
803 assert(image->signature == MagickSignature);
804 if (image->debug != MagickFalse)
805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
806 assert(exception != (ExceptionInfo *) NULL);
807 assert(exception->signature == MagickSignature);
808 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
812 random_info=AcquireRandomInfoThreadSet();
813 concurrent=GetRandomSecretKey(random_info[0]) == ~0UL ? MagickTrue :
815 image_view=AcquireAuthenticCacheView(image,exception);
816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
817 #pragma omp parallel for schedule(static,4) shared(progress,status) omp_concurrent(concurrent)
819 for (y=0; y < (ssize_t) image->rows; y++)
822 id = GetOpenMPThreadId();
830 if (status == MagickFalse)
832 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
833 if (q == (Quantum *) NULL)
838 for (x=0; x < (ssize_t) image->columns; x++)
843 if (GetPixelMask(image,q) != 0)
845 q+=GetPixelChannels(image);
848 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
856 channel=GetPixelChannelMapChannel(image,i);
857 traits=GetPixelChannelMapTraits(image,channel);
858 if (traits == UndefinedPixelTrait)
860 if ((traits & CopyPixelTrait) != 0)
862 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
865 q+=GetPixelChannels(image);
867 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
869 if (image->progress_monitor != (MagickProgressMonitor) NULL)
874 #if defined(MAGICKCORE_OPENMP_SUPPORT)
875 #pragma omp critical (MagickCore_EvaluateImage)
877 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
878 if (proceed == MagickFalse)
882 image_view=DestroyCacheView(image_view);
883 random_info=DestroyRandomInfoThreadSet(random_info);
888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
892 % F u n c t i o n I m a g e %
896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
898 % FunctionImage() applies a value to the image with an arithmetic, relational,
899 % or logical operator to an image. Use these operations to lighten or darken
900 % an image, to increase or decrease contrast in an image, or to produce the
901 % "negative" of an image.
903 % The format of the FunctionImage method is:
905 % MagickBooleanType FunctionImage(Image *image,
906 % const MagickFunction function,const ssize_t number_parameters,
907 % const double *parameters,ExceptionInfo *exception)
909 % A description of each parameter follows:
911 % o image: the image.
913 % o function: A channel function.
915 % o parameters: one or more parameters.
917 % o exception: return any errors or warnings in this structure.
921 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
922 const size_t number_parameters,const double *parameters,
923 ExceptionInfo *exception)
935 case PolynomialFunction:
938 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
942 for (i=0; i < (ssize_t) number_parameters; i++)
943 result=result*QuantumScale*pixel+parameters[i];
944 result*=QuantumRange;
947 case SinusoidFunction:
956 Sinusoid: frequency, phase, amplitude, bias.
958 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
959 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
960 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
961 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
962 result=(MagickRealType) (QuantumRange*(amplitude*sin((double) (2.0*
963 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
975 Arcsin (peged at range limits for invalid results): width, center,
978 width=(number_parameters >= 1) ? parameters[0] : 1.0;
979 center=(number_parameters >= 2) ? parameters[1] : 0.5;
980 range=(number_parameters >= 3) ? parameters[2] : 1.0;
981 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
982 result=2.0/width*(QuantumScale*pixel-center);
983 if ( result <= -1.0 )
984 result=bias-range/2.0;
987 result=bias+range/2.0;
989 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
990 result*=QuantumRange;
1002 Arctan: slope, center, range, and bias.
1004 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
1005 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1006 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1007 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1008 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
1009 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
1013 case UndefinedFunction:
1016 return(ClampToQuantum(result));
1019 MagickExport MagickBooleanType FunctionImage(Image *image,
1020 const MagickFunction function,const size_t number_parameters,
1021 const double *parameters,ExceptionInfo *exception)
1023 #define FunctionImageTag "Function/Image "
1037 assert(image != (Image *) NULL);
1038 assert(image->signature == MagickSignature);
1039 if (image->debug != MagickFalse)
1040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1041 assert(exception != (ExceptionInfo *) NULL);
1042 assert(exception->signature == MagickSignature);
1043 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1044 return(MagickFalse);
1047 image_view=AcquireAuthenticCacheView(image,exception);
1048 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1049 #pragma omp parallel for schedule(static,4) shared(progress,status)
1051 for (y=0; y < (ssize_t) image->rows; y++)
1059 if (status == MagickFalse)
1061 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1062 if (q == (Quantum *) NULL)
1067 for (x=0; x < (ssize_t) image->columns; x++)
1072 if (GetPixelMask(image,q) != 0)
1074 q+=GetPixelChannels(image);
1077 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1085 channel=GetPixelChannelMapChannel(image,i);
1086 traits=GetPixelChannelMapTraits(image,channel);
1087 if (traits == UndefinedPixelTrait)
1089 if ((traits & UpdatePixelTrait) == 0)
1091 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1094 q+=GetPixelChannels(image);
1096 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1098 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1103 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1104 #pragma omp critical (MagickCore_FunctionImage)
1106 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1107 if (proceed == MagickFalse)
1111 image_view=DestroyCacheView(image_view);
1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120 % G e t I m a g e E x t r e m a %
1124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 % GetImageExtrema() returns the extrema of one or more image channels.
1128 % The format of the GetImageExtrema method is:
1130 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1131 % size_t *maxima,ExceptionInfo *exception)
1133 % A description of each parameter follows:
1135 % o image: the image.
1137 % o minima: the minimum value in the channel.
1139 % o maxima: the maximum value in the channel.
1141 % o exception: return any errors or warnings in this structure.
1144 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1145 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1154 assert(image != (Image *) NULL);
1155 assert(image->signature == MagickSignature);
1156 if (image->debug != MagickFalse)
1157 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1158 status=GetImageRange(image,&min,&max,exception);
1159 *minima=(size_t) ceil(min-0.5);
1160 *maxima=(size_t) floor(max+0.5);
1165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % G e t I m a g e M e a n %
1173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1175 % GetImageMean() returns the mean and standard deviation of one or more
1178 % The format of the GetImageMean method is:
1180 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1181 % double *standard_deviation,ExceptionInfo *exception)
1183 % A description of each parameter follows:
1185 % o image: the image.
1187 % o mean: the average value in the channel.
1189 % o standard_deviation: the standard deviation of the channel.
1191 % o exception: return any errors or warnings in this structure.
1194 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1195 double *standard_deviation,ExceptionInfo *exception)
1198 *channel_statistics;
1206 assert(image != (Image *) NULL);
1207 assert(image->signature == MagickSignature);
1208 if (image->debug != MagickFalse)
1209 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1210 channel_statistics=GetImageStatistics(image,exception);
1211 if (channel_statistics == (ChannelStatistics *) NULL)
1212 return(MagickFalse);
1214 channel_statistics[CompositePixelChannel].mean=0.0;
1215 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1216 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1224 channel=GetPixelChannelMapChannel(image,i);
1225 traits=GetPixelChannelMapTraits(image,channel);
1226 if (traits == UndefinedPixelTrait)
1228 if ((traits & UpdatePixelTrait) == 0)
1230 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1231 channel_statistics[CompositePixelChannel].standard_deviation+=
1232 channel_statistics[i].variance-channel_statistics[i].mean*
1233 channel_statistics[i].mean;
1236 channel_statistics[CompositePixelChannel].mean/=area;
1237 channel_statistics[CompositePixelChannel].standard_deviation=
1238 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1239 *mean=channel_statistics[CompositePixelChannel].mean;
1240 *standard_deviation=
1241 channel_statistics[CompositePixelChannel].standard_deviation;
1242 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1243 channel_statistics);
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 % G e t I m a g e K u r t o s i s %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1261 % The format of the GetImageKurtosis method is:
1263 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1264 % double *skewness,ExceptionInfo *exception)
1266 % A description of each parameter follows:
1268 % o image: the image.
1270 % o kurtosis: the kurtosis of the channel.
1272 % o skewness: the skewness of the channel.
1274 % o exception: return any errors or warnings in this structure.
1277 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1278 double *kurtosis,double *skewness,ExceptionInfo *exception)
1297 assert(image != (Image *) NULL);
1298 assert(image->signature == MagickSignature);
1299 if (image->debug != MagickFalse)
1300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1306 standard_deviation=0.0;
1309 sum_fourth_power=0.0;
1310 image_view=AcquireVirtualCacheView(image,exception);
1311 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1312 #pragma omp parallel for schedule(static) shared(status)
1314 for (y=0; y < (ssize_t) image->rows; y++)
1316 register const Quantum
1322 if (status == MagickFalse)
1324 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1325 if (p == (const Quantum *) NULL)
1330 for (x=0; x < (ssize_t) image->columns; x++)
1335 if (GetPixelMask(image,p) != 0)
1337 p+=GetPixelChannels(image);
1340 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1348 channel=GetPixelChannelMapChannel(image,i);
1349 traits=GetPixelChannelMapTraits(image,channel);
1350 if (traits == UndefinedPixelTrait)
1352 if ((traits & UpdatePixelTrait) == 0)
1354 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1355 #pragma omp critical (MagickCore_GetImageKurtosis)
1359 sum_squares+=(double) p[i]*p[i];
1360 sum_cubes+=(double) p[i]*p[i]*p[i];
1361 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1365 p+=GetPixelChannels(image);
1368 image_view=DestroyCacheView(image_view);
1374 sum_fourth_power/=area;
1376 standard_deviation=sqrt(sum_squares-(mean*mean));
1377 if (standard_deviation != 0.0)
1379 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1380 3.0*mean*mean*mean*mean;
1381 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1384 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1385 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1395 % G e t I m a g e R a n g e %
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 % GetImageRange() returns the range of one or more image channels.
1403 % The format of the GetImageRange method is:
1405 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1406 % double *maxima,ExceptionInfo *exception)
1408 % A description of each parameter follows:
1410 % o image: the image.
1412 % o minima: the minimum value in the channel.
1414 % o maxima: the maximum value in the channel.
1416 % o exception: return any errors or warnings in this structure.
1419 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1420 double *maxima,ExceptionInfo *exception)
1431 assert(image != (Image *) NULL);
1432 assert(image->signature == MagickSignature);
1433 if (image->debug != MagickFalse)
1434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1436 *maxima=(-MagickHuge);
1438 image_view=AcquireVirtualCacheView(image,exception);
1439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1440 #pragma omp parallel for schedule(static) shared(status)
1442 for (y=0; y < (ssize_t) image->rows; y++)
1444 register const Quantum
1450 if (status == MagickFalse)
1452 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1453 if (p == (const Quantum *) NULL)
1458 for (x=0; x < (ssize_t) image->columns; x++)
1463 if (GetPixelMask(image,p) != 0)
1465 p+=GetPixelChannels(image);
1468 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1476 channel=GetPixelChannelMapChannel(image,i);
1477 traits=GetPixelChannelMapTraits(image,channel);
1478 if (traits == UndefinedPixelTrait)
1480 if ((traits & UpdatePixelTrait) == 0)
1482 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1483 #pragma omp critical (MagickCore_GetImageRange)
1486 if ((double) p[i] < *minima)
1487 *minima=(double) p[i];
1488 if ((double) p[i] > *maxima)
1489 *maxima=(double) p[i];
1492 p+=GetPixelChannels(image);
1495 image_view=DestroyCacheView(image_view);
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504 % G e t I m a g e S t a t i s t i c s %
1508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1510 % GetImageStatistics() returns statistics for each channel in the
1511 % image. The statistics include the channel depth, its minima, maxima, mean,
1512 % standard deviation, kurtosis and skewness. You can access the red channel
1513 % mean, for example, like this:
1515 % channel_statistics=GetImageStatistics(image,exception);
1516 % red_mean=channel_statistics[RedPixelChannel].mean;
1518 % Use MagickRelinquishMemory() to free the statistics buffer.
1520 % The format of the GetImageStatistics method is:
1522 % ChannelStatistics *GetImageStatistics(const Image *image,
1523 % ExceptionInfo *exception)
1525 % A description of each parameter follows:
1527 % o image: the image.
1529 % o exception: return any errors or warnings in this structure.
1533 static size_t GetImageChannels(const Image *image)
1542 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1550 channel=GetPixelChannelMapChannel(image,i);
1551 traits=GetPixelChannelMapTraits(image,channel);
1552 if ((traits & UpdatePixelTrait) != 0)
1558 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1559 ExceptionInfo *exception)
1562 *channel_statistics;
1583 assert(image != (Image *) NULL);
1584 assert(image->signature == MagickSignature);
1585 if (image->debug != MagickFalse)
1586 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1587 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1588 MaxPixelChannels+1,sizeof(*channel_statistics));
1589 if (channel_statistics == (ChannelStatistics *) NULL)
1590 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1591 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1592 sizeof(*channel_statistics));
1593 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1595 channel_statistics[i].depth=1;
1596 channel_statistics[i].maxima=(-MagickHuge);
1597 channel_statistics[i].minima=MagickHuge;
1599 for (y=0; y < (ssize_t) image->rows; y++)
1601 register const Quantum
1607 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1608 if (p == (const Quantum *) NULL)
1610 for (x=0; x < (ssize_t) image->columns; x++)
1615 if (GetPixelMask(image,p) != 0)
1617 p+=GetPixelChannels(image);
1620 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1628 channel=GetPixelChannelMapChannel(image,i);
1629 traits=GetPixelChannelMapTraits(image,channel);
1630 if (traits == UndefinedPixelTrait)
1632 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1634 depth=channel_statistics[channel].depth;
1635 range=GetQuantumRange(depth);
1636 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1637 range) ? MagickTrue : MagickFalse;
1638 if (status != MagickFalse)
1640 channel_statistics[channel].depth++;
1644 if ((double) p[i] < channel_statistics[channel].minima)
1645 channel_statistics[channel].minima=(double) p[i];
1646 if ((double) p[i] > channel_statistics[channel].maxima)
1647 channel_statistics[channel].maxima=(double) p[i];
1648 channel_statistics[channel].sum+=p[i];
1649 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1650 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1651 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1654 p+=GetPixelChannels(image);
1657 area=(double) image->columns*image->rows;
1658 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1660 channel_statistics[i].sum/=area;
1661 channel_statistics[i].sum_squared/=area;
1662 channel_statistics[i].sum_cubed/=area;
1663 channel_statistics[i].sum_fourth_power/=area;
1664 channel_statistics[i].mean=channel_statistics[i].sum;
1665 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1666 channel_statistics[i].standard_deviation=sqrt(
1667 channel_statistics[i].variance-(channel_statistics[i].mean*
1668 channel_statistics[i].mean));
1670 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1672 channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1673 (double) channel_statistics[CompositePixelChannel].depth,(double)
1674 channel_statistics[i].depth);
1675 channel_statistics[CompositePixelChannel].minima=MagickMin(
1676 channel_statistics[CompositePixelChannel].minima,
1677 channel_statistics[i].minima);
1678 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1679 channel_statistics[CompositePixelChannel].maxima,
1680 channel_statistics[i].maxima);
1681 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1682 channel_statistics[CompositePixelChannel].sum_squared+=
1683 channel_statistics[i].sum_squared;
1684 channel_statistics[CompositePixelChannel].sum_cubed+=
1685 channel_statistics[i].sum_cubed;
1686 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1687 channel_statistics[i].sum_fourth_power;
1688 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1689 channel_statistics[CompositePixelChannel].variance+=
1690 channel_statistics[i].variance-channel_statistics[i].mean*
1691 channel_statistics[i].mean;
1692 channel_statistics[CompositePixelChannel].standard_deviation+=
1693 channel_statistics[i].variance-channel_statistics[i].mean*
1694 channel_statistics[i].mean;
1696 channels=GetImageChannels(image);
1697 channel_statistics[CompositePixelChannel].sum/=channels;
1698 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1699 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1700 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1701 channel_statistics[CompositePixelChannel].mean/=channels;
1702 channel_statistics[CompositePixelChannel].variance/=channels;
1703 channel_statistics[CompositePixelChannel].standard_deviation=
1704 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1705 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1706 channel_statistics[CompositePixelChannel].skewness/=channels;
1707 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1709 if (channel_statistics[i].standard_deviation == 0.0)
1711 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1712 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1713 channel_statistics[i].mean*channel_statistics[i].mean*
1714 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1715 channel_statistics[i].standard_deviation*
1716 channel_statistics[i].standard_deviation);
1717 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1718 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1719 channel_statistics[i].mean*channel_statistics[i].mean*
1720 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1721 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1722 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1723 channel_statistics[i].standard_deviation*
1724 channel_statistics[i].standard_deviation*
1725 channel_statistics[i].standard_deviation)-3.0;
1727 return(channel_statistics);
1731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1735 % S t a t i s t i c I m a g e %
1739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1741 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
1742 % the neighborhood of the specified width and height.
1744 % The format of the StatisticImage method is:
1746 % Image *StatisticImage(const Image *image,const StatisticType type,
1747 % const size_t width,const size_t height,ExceptionInfo *exception)
1749 % A description of each parameter follows:
1751 % o image: the image.
1753 % o type: the statistic type (median, mode, etc.).
1755 % o width: the width of the pixel neighborhood.
1757 % o height: the height of the pixel neighborhood.
1759 % o exception: return any errors or warnings in this structure.
1763 typedef struct _SkipNode
1771 typedef struct _SkipList
1780 typedef struct _PixelList
1793 static PixelList *DestroyPixelList(PixelList *pixel_list)
1795 if (pixel_list == (PixelList *) NULL)
1796 return((PixelList *) NULL);
1797 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
1798 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
1799 pixel_list->skip_list.nodes);
1800 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
1804 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
1809 assert(pixel_list != (PixelList **) NULL);
1810 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
1811 if (pixel_list[i] != (PixelList *) NULL)
1812 pixel_list[i]=DestroyPixelList(pixel_list[i]);
1813 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
1817 static PixelList *AcquirePixelList(const size_t width,const size_t height)
1822 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
1823 if (pixel_list == (PixelList *) NULL)
1825 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
1826 pixel_list->length=width*height;
1827 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
1828 sizeof(*pixel_list->skip_list.nodes));
1829 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
1830 return(DestroyPixelList(pixel_list));
1831 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
1832 sizeof(*pixel_list->skip_list.nodes));
1833 pixel_list->signature=MagickSignature;
1837 static PixelList **AcquirePixelListThreadSet(const size_t width,
1838 const size_t height)
1849 number_threads=GetOpenMPMaximumThreads();
1850 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
1851 sizeof(*pixel_list));
1852 if (pixel_list == (PixelList **) NULL)
1853 return((PixelList **) NULL);
1854 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
1855 for (i=0; i < (ssize_t) number_threads; i++)
1857 pixel_list[i]=AcquirePixelList(width,height);
1858 if (pixel_list[i] == (PixelList *) NULL)
1859 return(DestroyPixelListThreadSet(pixel_list));
1864 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
1877 Initialize the node.
1879 p=(&pixel_list->skip_list);
1880 p->nodes[color].signature=pixel_list->signature;
1881 p->nodes[color].count=1;
1883 Determine where it belongs in the list.
1886 for (level=p->level; level >= 0; level--)
1888 while (p->nodes[search].next[level] < color)
1889 search=p->nodes[search].next[level];
1890 update[level]=search;
1893 Generate a pseudo-random level for this node.
1895 for (level=0; ; level++)
1897 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
1898 if ((pixel_list->seed & 0x300) != 0x300)
1903 if (level > (p->level+2))
1906 If we're raising the list's level, link back to the root node.
1908 while (level > p->level)
1911 update[p->level]=65536UL;
1914 Link the node into the skip-list.
1918 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
1919 p->nodes[update[level]].next[level]=color;
1920 } while (level-- > 0);
1923 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
1936 Find the maximum value for each of the color.
1938 p=(&pixel_list->skip_list);
1941 maximum=p->nodes[color].next[0];
1944 color=p->nodes[color].next[0];
1945 if (color > maximum)
1947 count+=p->nodes[color].count;
1948 } while (count < (ssize_t) pixel_list->length);
1949 *pixel=ScaleShortToQuantum((unsigned short) maximum);
1952 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
1967 Find the mean value for each of the color.
1969 p=(&pixel_list->skip_list);
1975 color=p->nodes[color].next[0];
1976 sum+=(MagickRealType) p->nodes[color].count*color;
1977 count+=p->nodes[color].count;
1978 } while (count < (ssize_t) pixel_list->length);
1979 sum/=pixel_list->length;
1980 *pixel=ScaleShortToQuantum((unsigned short) sum);
1983 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
1995 Find the median value for each of the color.
1997 p=(&pixel_list->skip_list);
2002 color=p->nodes[color].next[0];
2003 count+=p->nodes[color].count;
2004 } while (count <= (ssize_t) (pixel_list->length >> 1));
2005 *pixel=ScaleShortToQuantum((unsigned short) color);
2008 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2021 Find the minimum value for each of the color.
2023 p=(&pixel_list->skip_list);
2026 minimum=p->nodes[color].next[0];
2029 color=p->nodes[color].next[0];
2030 if (color < minimum)
2032 count+=p->nodes[color].count;
2033 } while (count < (ssize_t) pixel_list->length);
2034 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2037 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2051 Make each pixel the 'predominant color' of the specified neighborhood.
2053 p=(&pixel_list->skip_list);
2056 max_count=p->nodes[mode].count;
2060 color=p->nodes[color].next[0];
2061 if (p->nodes[color].count > max_count)
2064 max_count=p->nodes[mode].count;
2066 count+=p->nodes[color].count;
2067 } while (count < (ssize_t) pixel_list->length);
2068 *pixel=ScaleShortToQuantum((unsigned short) mode);
2071 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2085 Finds the non peak value for each of the colors.
2087 p=(&pixel_list->skip_list);
2089 next=p->nodes[color].next[0];
2095 next=p->nodes[color].next[0];
2096 count+=p->nodes[color].count;
2097 } while (count <= (ssize_t) (pixel_list->length >> 1));
2098 if ((previous == 65536UL) && (next != 65536UL))
2101 if ((previous != 65536UL) && (next == 65536UL))
2103 *pixel=ScaleShortToQuantum((unsigned short) color);
2106 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2123 Find the standard-deviation value for each of the color.
2125 p=(&pixel_list->skip_list);
2135 color=p->nodes[color].next[0];
2136 sum+=(MagickRealType) p->nodes[color].count*color;
2137 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2138 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
2139 count+=p->nodes[color].count;
2140 } while (count < (ssize_t) pixel_list->length);
2141 sum/=pixel_list->length;
2142 sum_squared/=pixel_list->length;
2143 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2146 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2147 PixelList *pixel_list)
2155 index=ScaleQuantumToShort(pixel);
2156 signature=pixel_list->skip_list.nodes[index].signature;
2157 if (signature == pixel_list->signature)
2159 pixel_list->skip_list.nodes[index].count++;
2162 AddNodePixelList(pixel_list,index);
2165 static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
2172 static inline size_t MagickMax(const size_t x,const size_t y)
2179 static void ResetPixelList(PixelList *pixel_list)
2191 Reset the skip-list.
2193 p=(&pixel_list->skip_list);
2194 root=p->nodes+65536UL;
2196 for (level=0; level < 9; level++)
2197 root->next[level]=65536UL;
2198 pixel_list->seed=pixel_list->signature++;
2201 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2202 const size_t width,const size_t height,ExceptionInfo *exception)
2204 #define StatisticImageTag "Statistic/Image"
2220 **restrict pixel_list;
2227 Initialize statistics image attributes.
2229 assert(image != (Image *) NULL);
2230 assert(image->signature == MagickSignature);
2231 if (image->debug != MagickFalse)
2232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2233 assert(exception != (ExceptionInfo *) NULL);
2234 assert(exception->signature == MagickSignature);
2235 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2237 if (statistic_image == (Image *) NULL)
2238 return((Image *) NULL);
2239 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2240 if (status == MagickFalse)
2242 statistic_image=DestroyImage(statistic_image);
2243 return((Image *) NULL);
2245 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2246 if (pixel_list == (PixelList **) NULL)
2248 statistic_image=DestroyImage(statistic_image);
2249 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2252 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2254 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2255 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2258 image_view=AcquireVirtualCacheView(image,exception);
2259 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2260 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2261 #pragma omp parallel for schedule(static,4) shared(progress,status)
2263 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2266 id = GetOpenMPThreadId();
2268 register const Quantum
2277 if (status == MagickFalse)
2279 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2280 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2281 MagickMax(height,1),exception);
2282 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2283 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2288 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2293 if (GetPixelMask(image,p) != 0)
2295 p+=GetPixelChannels(image);
2296 q+=GetPixelChannels(statistic_image);
2299 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2311 register const Quantum
2320 channel=GetPixelChannelMapChannel(image,i);
2321 traits=GetPixelChannelMapTraits(image,channel);
2322 statistic_traits=GetPixelChannelMapTraits(statistic_image,channel);
2323 if ((traits == UndefinedPixelTrait) ||
2324 (statistic_traits == UndefinedPixelTrait))
2326 if ((statistic_traits & CopyPixelTrait) != 0)
2328 SetPixelChannel(statistic_image,channel,p[center+i],q);
2332 ResetPixelList(pixel_list[id]);
2333 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2335 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2337 InsertPixelList(image,pixels[i],pixel_list[id]);
2338 pixels+=GetPixelChannels(image);
2340 pixels+=image->columns*GetPixelChannels(image);
2344 case GradientStatistic:
2350 GetMinimumPixelList(pixel_list[id],&pixel);
2351 minimum=(MagickRealType) pixel;
2352 GetMaximumPixelList(pixel_list[id],&pixel);
2353 maximum=(MagickRealType) pixel;
2354 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2357 case MaximumStatistic:
2359 GetMaximumPixelList(pixel_list[id],&pixel);
2364 GetMeanPixelList(pixel_list[id],&pixel);
2367 case MedianStatistic:
2370 GetMedianPixelList(pixel_list[id],&pixel);
2373 case MinimumStatistic:
2375 GetMinimumPixelList(pixel_list[id],&pixel);
2380 GetModePixelList(pixel_list[id],&pixel);
2383 case NonpeakStatistic:
2385 GetNonpeakPixelList(pixel_list[id],&pixel);
2388 case StandardDeviationStatistic:
2390 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2394 SetPixelChannel(statistic_image,channel,pixel,q);
2396 p+=GetPixelChannels(image);
2397 q+=GetPixelChannels(statistic_image);
2399 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2401 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2406 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2407 #pragma omp critical (MagickCore_StatisticImage)
2409 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2411 if (proceed == MagickFalse)
2415 statistic_view=DestroyCacheView(statistic_view);
2416 image_view=DestroyCacheView(image_view);
2417 pixel_list=DestroyPixelListThreadSet(pixel_list);
2418 return(statistic_image);