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=GetOpenMPMaximumThreads();
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]-(MagickRealType) 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 MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
236 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
244 case UndefinedEvaluateOperator:
246 case AbsEvaluateOperator:
248 result=(MagickRealType) fabs((double) (pixel+value));
251 case AddEvaluateOperator:
253 result=(MagickRealType) (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=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
273 case CosineEvaluateOperator:
275 result=(MagickRealType) (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=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
290 case GaussianNoiseEvaluateOperator:
292 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
293 GaussianNoise,value);
296 case ImpulseNoiseEvaluateOperator:
298 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
302 case LaplacianNoiseEvaluateOperator:
304 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
305 LaplacianNoise,value);
308 case LeftShiftEvaluateOperator:
310 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
313 case LogEvaluateOperator:
315 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
316 pixel+1.0))/log((double) (value+1.0)));
319 case MaxEvaluateOperator:
321 result=(MagickRealType) EvaluateMax((double) pixel,value);
324 case MeanEvaluateOperator:
326 result=(MagickRealType) (pixel+value);
329 case MedianEvaluateOperator:
331 result=(MagickRealType) (pixel+value);
334 case MinEvaluateOperator:
336 result=(MagickRealType) MagickMin((double) pixel,value);
339 case MultiplicativeNoiseEvaluateOperator:
341 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
342 MultiplicativeGaussianNoise,value);
345 case MultiplyEvaluateOperator:
347 result=(MagickRealType) (value*pixel);
350 case OrEvaluateOperator:
352 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
355 case PoissonNoiseEvaluateOperator:
357 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
361 case PowEvaluateOperator:
363 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
367 case RightShiftEvaluateOperator:
369 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
372 case SetEvaluateOperator:
377 case SineEvaluateOperator:
379 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
380 QuantumScale*pixel*value))+0.5));
383 case SubtractEvaluateOperator:
385 result=(MagickRealType) (pixel-value);
388 case SumEvaluateOperator:
390 result=(MagickRealType) (pixel+value);
393 case ThresholdEvaluateOperator:
395 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
399 case ThresholdBlackEvaluateOperator:
401 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
404 case ThresholdWhiteEvaluateOperator:
406 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
410 case UniformNoiseEvaluateOperator:
412 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
416 case XorEvaluateOperator:
418 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
425 MagickExport Image *EvaluateImages(const Image *images,
426 const MagickEvaluateOperator op,ExceptionInfo *exception)
428 #define EvaluateImageTag "Evaluate/Image"
446 **restrict evaluate_pixels;
449 **restrict random_info;
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 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
481 if (evaluate_image == (Image *) NULL)
482 return((Image *) NULL);
483 if (SetImageStorageClass(evaluate_image,DirectClass,exception) == MagickFalse)
485 evaluate_image=DestroyImage(evaluate_image);
486 return((Image *) NULL);
488 number_images=GetImageListLength(images);
489 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
490 if (evaluate_pixels == (PixelChannels **) NULL)
492 evaluate_image=DestroyImage(evaluate_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 key=GetRandomSecretKey(random_info[0]);
504 evaluate_view=AcquireAuthenticCacheView(evaluate_image,exception);
505 if (op == MedianEvaluateOperator)
507 #if defined(MAGICKCORE_OPENMP_SUPPORT)
508 #pragma omp parallel for schedule(static) shared(progress,status) \
509 dynamic_number_threads(images->columns,images->rows,key == ~0UL)
511 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
520 id = GetOpenMPThreadId();
522 register PixelChannels
531 if (status == MagickFalse)
533 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
534 evaluate_image->columns,1,exception);
535 if (q == (Quantum *) NULL)
540 evaluate_pixel=evaluate_pixels[id];
541 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
547 for (j=0; j < (ssize_t) number_images; j++)
548 for (k=0; k < MaxPixelChannels; k++)
549 evaluate_pixel[j].channel[k]=0.0;
551 for (j=0; j < (ssize_t) number_images; j++)
553 register const Quantum
559 image_view=AcquireVirtualCacheView(next,exception);
560 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
561 if (p == (const Quantum *) NULL)
563 image_view=DestroyCacheView(image_view);
566 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
575 channel=GetPixelChannelMapChannel(evaluate_image,i);
576 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,channel);
577 traits=GetPixelChannelMapTraits(next,channel);
578 if ((traits == UndefinedPixelTrait) ||
579 (evaluate_traits == UndefinedPixelTrait))
581 if ((evaluate_traits & UpdatePixelTrait) == 0)
583 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
584 random_info[id],GetPixelChannel(evaluate_image,channel,p),op,
585 evaluate_pixel[j].channel[i]);
587 image_view=DestroyCacheView(image_view);
588 next=GetNextImageInList(next);
590 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
592 for (k=0; k < (ssize_t) GetPixelChannels(evaluate_image); k++)
593 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
594 q+=GetPixelChannels(evaluate_image);
596 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
598 if (images->progress_monitor != (MagickProgressMonitor) NULL)
603 #if defined(MAGICKCORE_OPENMP_SUPPORT)
604 #pragma omp critical (MagickCore_EvaluateImages)
606 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
607 evaluate_image->rows);
608 if (proceed == MagickFalse)
615 #if defined(MAGICKCORE_OPENMP_SUPPORT)
616 #pragma omp parallel for schedule(static) shared(progress,status) \
617 dynamic_number_threads(images->columns,images->rows,key == ~0UL)
619 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
628 id = GetOpenMPThreadId();
634 register PixelChannels
643 if (status == MagickFalse)
645 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
646 evaluate_image->columns,1,exception);
647 if (q == (Quantum *) NULL)
652 evaluate_pixel=evaluate_pixels[id];
653 for (j=0; j < (ssize_t) evaluate_image->columns; j++)
654 for (i=0; i < MaxPixelChannels; i++)
655 evaluate_pixel[j].channel[i]=0.0;
657 for (j=0; j < (ssize_t) number_images; j++)
659 register const Quantum
662 image_view=AcquireVirtualCacheView(next,exception);
663 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
664 if (p == (const Quantum *) NULL)
666 image_view=DestroyCacheView(image_view);
669 for (x=0; x < (ssize_t) next->columns; x++)
674 if (GetPixelMask(next,p) != 0)
676 p+=GetPixelChannels(next);
679 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
688 channel=GetPixelChannelMapChannel(evaluate_image,i);
689 traits=GetPixelChannelMapTraits(next,channel);
690 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,channel);
691 if ((traits == UndefinedPixelTrait) ||
692 (evaluate_traits == UndefinedPixelTrait))
694 if ((traits & UpdatePixelTrait) == 0)
696 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
697 random_info[id],GetPixelChannel(evaluate_image,channel,p),j ==
698 0 ? AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
700 p+=GetPixelChannels(next);
702 image_view=DestroyCacheView(image_view);
703 next=GetNextImageInList(next);
705 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
712 case MeanEvaluateOperator:
714 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
715 evaluate_pixel[x].channel[i]/=(MagickRealType) number_images;
718 case MultiplyEvaluateOperator:
720 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
725 for (j=0; j < (ssize_t) (number_images-1); j++)
726 evaluate_pixel[x].channel[i]*=QuantumScale;
734 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
739 if (GetPixelMask(evaluate_image,q) != 0)
741 q+=GetPixelChannels(evaluate_image);
744 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
752 channel=GetPixelChannelMapChannel(evaluate_image,i);
753 traits=GetPixelChannelMapTraits(evaluate_image,channel);
754 if (traits == UndefinedPixelTrait)
756 if ((traits & UpdatePixelTrait) == 0)
758 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
760 q+=GetPixelChannels(evaluate_image);
762 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
764 if (images->progress_monitor != (MagickProgressMonitor) NULL)
769 #if defined(MAGICKCORE_OPENMP_SUPPORT)
770 #pragma omp critical (MagickCore_EvaluateImages)
772 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
773 evaluate_image->rows);
774 if (proceed == MagickFalse)
779 evaluate_view=DestroyCacheView(evaluate_view);
780 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
781 random_info=DestroyRandomInfoThreadSet(random_info);
782 if (status == MagickFalse)
783 evaluate_image=DestroyImage(evaluate_image);
784 return(evaluate_image);
787 MagickExport MagickBooleanType EvaluateImage(Image *image,
788 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
800 **restrict random_info;
808 assert(image != (Image *) NULL);
809 assert(image->signature == MagickSignature);
810 if (image->debug != MagickFalse)
811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
812 assert(exception != (ExceptionInfo *) NULL);
813 assert(exception->signature == MagickSignature);
814 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
818 random_info=AcquireRandomInfoThreadSet();
819 key=GetRandomSecretKey(random_info[0]);
820 image_view=AcquireAuthenticCacheView(image,exception);
821 #if defined(MAGICKCORE_OPENMP_SUPPORT)
822 #pragma omp parallel for schedule(static,4) shared(progress,status) \
823 dynamic_number_threads(image->columns,image->rows,key == ~0UL)
825 for (y=0; y < (ssize_t) image->rows; y++)
828 id = GetOpenMPThreadId();
836 if (status == MagickFalse)
838 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
839 if (q == (Quantum *) NULL)
844 for (x=0; x < (ssize_t) image->columns; x++)
849 if (GetPixelMask(image,q) != 0)
851 q+=GetPixelChannels(image);
854 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
862 channel=GetPixelChannelMapChannel(image,i);
863 traits=GetPixelChannelMapTraits(image,channel);
864 if (traits == UndefinedPixelTrait)
866 if ((traits & CopyPixelTrait) != 0)
868 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
871 q+=GetPixelChannels(image);
873 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
875 if (image->progress_monitor != (MagickProgressMonitor) NULL)
880 #if defined(MAGICKCORE_OPENMP_SUPPORT)
881 #pragma omp critical (MagickCore_EvaluateImage)
883 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
884 if (proceed == MagickFalse)
888 image_view=DestroyCacheView(image_view);
889 random_info=DestroyRandomInfoThreadSet(random_info);
894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
898 % F u n c t i o n I m a g e %
902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
904 % FunctionImage() applies a value to the image with an arithmetic, relational,
905 % or logical operator to an image. Use these operations to lighten or darken
906 % an image, to increase or decrease contrast in an image, or to produce the
907 % "negative" of an image.
909 % The format of the FunctionImage method is:
911 % MagickBooleanType FunctionImage(Image *image,
912 % const MagickFunction function,const ssize_t number_parameters,
913 % const double *parameters,ExceptionInfo *exception)
915 % A description of each parameter follows:
917 % o image: the image.
919 % o function: A channel function.
921 % o parameters: one or more parameters.
923 % o exception: return any errors or warnings in this structure.
927 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
928 const size_t number_parameters,const double *parameters,
929 ExceptionInfo *exception)
941 case PolynomialFunction:
944 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
948 for (i=0; i < (ssize_t) number_parameters; i++)
949 result=result*QuantumScale*pixel+parameters[i];
950 result*=QuantumRange;
953 case SinusoidFunction:
962 Sinusoid: frequency, phase, amplitude, bias.
964 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
965 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
966 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
967 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
968 result=(MagickRealType) (QuantumRange*(amplitude*sin((double) (2.0*
969 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
981 Arcsin (peged at range limits for invalid results): width, center,
984 width=(number_parameters >= 1) ? parameters[0] : 1.0;
985 center=(number_parameters >= 2) ? parameters[1] : 0.5;
986 range=(number_parameters >= 3) ? parameters[2] : 1.0;
987 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
988 result=2.0/width*(QuantumScale*pixel-center);
989 if ( result <= -1.0 )
990 result=bias-range/2.0;
993 result=bias+range/2.0;
995 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
996 result*=QuantumRange;
1008 Arctan: slope, center, range, and bias.
1010 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
1011 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1012 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1013 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1014 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
1015 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
1019 case UndefinedFunction:
1022 return(ClampToQuantum(result));
1025 MagickExport MagickBooleanType FunctionImage(Image *image,
1026 const MagickFunction function,const size_t number_parameters,
1027 const double *parameters,ExceptionInfo *exception)
1029 #define FunctionImageTag "Function/Image "
1043 assert(image != (Image *) NULL);
1044 assert(image->signature == MagickSignature);
1045 if (image->debug != MagickFalse)
1046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1047 assert(exception != (ExceptionInfo *) NULL);
1048 assert(exception->signature == MagickSignature);
1049 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1050 return(MagickFalse);
1053 image_view=AcquireAuthenticCacheView(image,exception);
1054 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1055 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1056 dynamic_number_threads(image->columns,image->rows,1)
1058 for (y=0; y < (ssize_t) image->rows; y++)
1066 if (status == MagickFalse)
1068 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1069 if (q == (Quantum *) NULL)
1074 for (x=0; x < (ssize_t) image->columns; x++)
1079 if (GetPixelMask(image,q) != 0)
1081 q+=GetPixelChannels(image);
1084 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1092 channel=GetPixelChannelMapChannel(image,i);
1093 traits=GetPixelChannelMapTraits(image,channel);
1094 if (traits == UndefinedPixelTrait)
1096 if ((traits & UpdatePixelTrait) == 0)
1098 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1101 q+=GetPixelChannels(image);
1103 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1105 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1110 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1111 #pragma omp critical (MagickCore_FunctionImage)
1113 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1114 if (proceed == MagickFalse)
1118 image_view=DestroyCacheView(image_view);
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % G e t I m a g e E x t r e m a %
1131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 % GetImageExtrema() returns the extrema of one or more image channels.
1135 % The format of the GetImageExtrema method is:
1137 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1138 % size_t *maxima,ExceptionInfo *exception)
1140 % A description of each parameter follows:
1142 % o image: the image.
1144 % o minima: the minimum value in the channel.
1146 % o maxima: the maximum value in the channel.
1148 % o exception: return any errors or warnings in this structure.
1151 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1152 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1161 assert(image != (Image *) NULL);
1162 assert(image->signature == MagickSignature);
1163 if (image->debug != MagickFalse)
1164 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1165 status=GetImageRange(image,&min,&max,exception);
1166 *minima=(size_t) ceil(min-0.5);
1167 *maxima=(size_t) floor(max+0.5);
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1176 % G e t I m a g e M e a n %
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182 % GetImageMean() returns the mean and standard deviation of one or more
1185 % The format of the GetImageMean method is:
1187 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1188 % double *standard_deviation,ExceptionInfo *exception)
1190 % A description of each parameter follows:
1192 % o image: the image.
1194 % o mean: the average value in the channel.
1196 % o standard_deviation: the standard deviation of the channel.
1198 % o exception: return any errors or warnings in this structure.
1201 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1202 double *standard_deviation,ExceptionInfo *exception)
1205 *channel_statistics;
1213 assert(image != (Image *) NULL);
1214 assert(image->signature == MagickSignature);
1215 if (image->debug != MagickFalse)
1216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1217 channel_statistics=GetImageStatistics(image,exception);
1218 if (channel_statistics == (ChannelStatistics *) NULL)
1219 return(MagickFalse);
1221 channel_statistics[CompositePixelChannel].mean=0.0;
1222 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1223 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1231 channel=GetPixelChannelMapChannel(image,i);
1232 traits=GetPixelChannelMapTraits(image,channel);
1233 if (traits == UndefinedPixelTrait)
1235 if ((traits & UpdatePixelTrait) == 0)
1237 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1238 channel_statistics[CompositePixelChannel].standard_deviation+=
1239 channel_statistics[i].variance-channel_statistics[i].mean*
1240 channel_statistics[i].mean;
1243 channel_statistics[CompositePixelChannel].mean/=area;
1244 channel_statistics[CompositePixelChannel].standard_deviation=
1245 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1246 *mean=channel_statistics[CompositePixelChannel].mean;
1247 *standard_deviation=
1248 channel_statistics[CompositePixelChannel].standard_deviation;
1249 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1250 channel_statistics);
1255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1259 % G e t I m a g e K u r t o s i s %
1263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1265 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1268 % The format of the GetImageKurtosis method is:
1270 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1271 % double *skewness,ExceptionInfo *exception)
1273 % A description of each parameter follows:
1275 % o image: the image.
1277 % o kurtosis: the kurtosis of the channel.
1279 % o skewness: the skewness of the channel.
1281 % o exception: return any errors or warnings in this structure.
1284 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1285 double *kurtosis,double *skewness,ExceptionInfo *exception)
1304 assert(image != (Image *) NULL);
1305 assert(image->signature == MagickSignature);
1306 if (image->debug != MagickFalse)
1307 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1313 standard_deviation=0.0;
1316 sum_fourth_power=0.0;
1317 image_view=AcquireVirtualCacheView(image,exception);
1318 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1319 #pragma omp parallel for schedule(static) shared(status) \
1320 dynamic_number_threads(image->columns,image->rows,1)
1322 for (y=0; y < (ssize_t) image->rows; y++)
1324 register const Quantum
1330 if (status == MagickFalse)
1332 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1333 if (p == (const Quantum *) NULL)
1338 for (x=0; x < (ssize_t) image->columns; x++)
1343 if (GetPixelMask(image,p) != 0)
1345 p+=GetPixelChannels(image);
1348 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1356 channel=GetPixelChannelMapChannel(image,i);
1357 traits=GetPixelChannelMapTraits(image,channel);
1358 if (traits == UndefinedPixelTrait)
1360 if ((traits & UpdatePixelTrait) == 0)
1362 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1363 #pragma omp critical (MagickCore_GetImageKurtosis)
1367 sum_squares+=(double) p[i]*p[i];
1368 sum_cubes+=(double) p[i]*p[i]*p[i];
1369 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1373 p+=GetPixelChannels(image);
1376 image_view=DestroyCacheView(image_view);
1382 sum_fourth_power/=area;
1384 standard_deviation=sqrt(sum_squares-(mean*mean));
1385 if (standard_deviation != 0.0)
1387 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1388 3.0*mean*mean*mean*mean;
1389 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1392 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1393 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403 % G e t I m a g e R a n g e %
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 % GetImageRange() returns the range of one or more image channels.
1411 % The format of the GetImageRange method is:
1413 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1414 % double *maxima,ExceptionInfo *exception)
1416 % A description of each parameter follows:
1418 % o image: the image.
1420 % o minima: the minimum value in the channel.
1422 % o maxima: the maximum value in the channel.
1424 % o exception: return any errors or warnings in this structure.
1427 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1428 double *maxima,ExceptionInfo *exception)
1439 assert(image != (Image *) NULL);
1440 assert(image->signature == MagickSignature);
1441 if (image->debug != MagickFalse)
1442 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1444 *maxima=(-MagickHuge);
1446 image_view=AcquireVirtualCacheView(image,exception);
1447 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1448 #pragma omp parallel for schedule(static) shared(status) \
1449 dynamic_number_threads(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=GetPixelChannelMapChannel(image,i);
1486 traits=GetPixelChannelMapTraits(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 ((double) p[i] < *minima)
1496 *minima=(double) p[i];
1497 if ((double) p[i] > *maxima)
1498 *maxima=(double) p[i];
1501 p+=GetPixelChannels(image);
1504 image_view=DestroyCacheView(image_view);
1509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513 % G e t I m a g e S t a t i s t i c s %
1517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1519 % GetImageStatistics() returns statistics for each channel in the
1520 % image. The statistics include the channel depth, its minima, maxima, mean,
1521 % standard deviation, kurtosis and skewness. You can access the red channel
1522 % mean, for example, like this:
1524 % channel_statistics=GetImageStatistics(image,exception);
1525 % red_mean=channel_statistics[RedPixelChannel].mean;
1527 % Use MagickRelinquishMemory() to free the statistics buffer.
1529 % The format of the GetImageStatistics method is:
1531 % ChannelStatistics *GetImageStatistics(const Image *image,
1532 % ExceptionInfo *exception)
1534 % A description of each parameter follows:
1536 % o image: the image.
1538 % o exception: return any errors or warnings in this structure.
1542 static size_t GetImageChannels(const Image *image)
1551 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1559 channel=GetPixelChannelMapChannel(image,i);
1560 traits=GetPixelChannelMapTraits(image,channel);
1561 if ((traits & UpdatePixelTrait) != 0)
1567 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1568 ExceptionInfo *exception)
1571 *channel_statistics;
1592 assert(image != (Image *) NULL);
1593 assert(image->signature == MagickSignature);
1594 if (image->debug != MagickFalse)
1595 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1596 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1597 MaxPixelChannels+1,sizeof(*channel_statistics));
1598 if (channel_statistics == (ChannelStatistics *) NULL)
1599 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1600 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1601 sizeof(*channel_statistics));
1602 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1604 channel_statistics[i].depth=1;
1605 channel_statistics[i].maxima=(-MagickHuge);
1606 channel_statistics[i].minima=MagickHuge;
1608 for (y=0; y < (ssize_t) image->rows; y++)
1610 register const Quantum
1616 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1617 if (p == (const Quantum *) NULL)
1619 for (x=0; x < (ssize_t) image->columns; x++)
1624 if (GetPixelMask(image,p) != 0)
1626 p+=GetPixelChannels(image);
1629 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1637 channel=GetPixelChannelMapChannel(image,i);
1638 traits=GetPixelChannelMapTraits(image,channel);
1639 if (traits == UndefinedPixelTrait)
1641 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1643 depth=channel_statistics[channel].depth;
1644 range=GetQuantumRange(depth);
1645 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1646 range) ? MagickTrue : MagickFalse;
1647 if (status != MagickFalse)
1649 channel_statistics[channel].depth++;
1653 if ((double) p[i] < channel_statistics[channel].minima)
1654 channel_statistics[channel].minima=(double) p[i];
1655 if ((double) p[i] > channel_statistics[channel].maxima)
1656 channel_statistics[channel].maxima=(double) p[i];
1657 channel_statistics[channel].sum+=p[i];
1658 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1659 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1660 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1663 p+=GetPixelChannels(image);
1666 area=(double) image->columns*image->rows;
1667 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1669 channel_statistics[i].sum/=area;
1670 channel_statistics[i].sum_squared/=area;
1671 channel_statistics[i].sum_cubed/=area;
1672 channel_statistics[i].sum_fourth_power/=area;
1673 channel_statistics[i].mean=channel_statistics[i].sum;
1674 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1675 channel_statistics[i].standard_deviation=sqrt(
1676 channel_statistics[i].variance-(channel_statistics[i].mean*
1677 channel_statistics[i].mean));
1679 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1681 channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1682 (double) channel_statistics[CompositePixelChannel].depth,(double)
1683 channel_statistics[i].depth);
1684 channel_statistics[CompositePixelChannel].minima=MagickMin(
1685 channel_statistics[CompositePixelChannel].minima,
1686 channel_statistics[i].minima);
1687 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1688 channel_statistics[CompositePixelChannel].maxima,
1689 channel_statistics[i].maxima);
1690 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1691 channel_statistics[CompositePixelChannel].sum_squared+=
1692 channel_statistics[i].sum_squared;
1693 channel_statistics[CompositePixelChannel].sum_cubed+=
1694 channel_statistics[i].sum_cubed;
1695 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1696 channel_statistics[i].sum_fourth_power;
1697 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1698 channel_statistics[CompositePixelChannel].variance+=
1699 channel_statistics[i].variance-channel_statistics[i].mean*
1700 channel_statistics[i].mean;
1701 channel_statistics[CompositePixelChannel].standard_deviation+=
1702 channel_statistics[i].variance-channel_statistics[i].mean*
1703 channel_statistics[i].mean;
1705 channels=GetImageChannels(image);
1706 channel_statistics[CompositePixelChannel].sum/=channels;
1707 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1708 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1709 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1710 channel_statistics[CompositePixelChannel].mean/=channels;
1711 channel_statistics[CompositePixelChannel].variance/=channels;
1712 channel_statistics[CompositePixelChannel].standard_deviation=
1713 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1714 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1715 channel_statistics[CompositePixelChannel].skewness/=channels;
1716 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1718 if (channel_statistics[i].standard_deviation == 0.0)
1720 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1721 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1722 channel_statistics[i].mean*channel_statistics[i].mean*
1723 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1724 channel_statistics[i].standard_deviation*
1725 channel_statistics[i].standard_deviation);
1726 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1727 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1728 channel_statistics[i].mean*channel_statistics[i].mean*
1729 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1730 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1731 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1732 channel_statistics[i].standard_deviation*
1733 channel_statistics[i].standard_deviation*
1734 channel_statistics[i].standard_deviation)-3.0;
1736 return(channel_statistics);
1740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744 % S t a t i s t i c I m a g e %
1748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1750 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
1751 % the neighborhood of the specified width and height.
1753 % The format of the StatisticImage method is:
1755 % Image *StatisticImage(const Image *image,const StatisticType type,
1756 % const size_t width,const size_t height,ExceptionInfo *exception)
1758 % A description of each parameter follows:
1760 % o image: the image.
1762 % o type: the statistic type (median, mode, etc.).
1764 % o width: the width of the pixel neighborhood.
1766 % o height: the height of the pixel neighborhood.
1768 % o exception: return any errors or warnings in this structure.
1772 typedef struct _SkipNode
1780 typedef struct _SkipList
1789 typedef struct _PixelList
1802 static PixelList *DestroyPixelList(PixelList *pixel_list)
1804 if (pixel_list == (PixelList *) NULL)
1805 return((PixelList *) NULL);
1806 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
1807 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
1808 pixel_list->skip_list.nodes);
1809 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
1813 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
1818 assert(pixel_list != (PixelList **) NULL);
1819 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
1820 if (pixel_list[i] != (PixelList *) NULL)
1821 pixel_list[i]=DestroyPixelList(pixel_list[i]);
1822 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
1826 static PixelList *AcquirePixelList(const size_t width,const size_t height)
1831 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
1832 if (pixel_list == (PixelList *) NULL)
1834 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
1835 pixel_list->length=width*height;
1836 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
1837 sizeof(*pixel_list->skip_list.nodes));
1838 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
1839 return(DestroyPixelList(pixel_list));
1840 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
1841 sizeof(*pixel_list->skip_list.nodes));
1842 pixel_list->signature=MagickSignature;
1846 static PixelList **AcquirePixelListThreadSet(const size_t width,
1847 const size_t height)
1858 number_threads=GetOpenMPMaximumThreads();
1859 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
1860 sizeof(*pixel_list));
1861 if (pixel_list == (PixelList **) NULL)
1862 return((PixelList **) NULL);
1863 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
1864 for (i=0; i < (ssize_t) number_threads; i++)
1866 pixel_list[i]=AcquirePixelList(width,height);
1867 if (pixel_list[i] == (PixelList *) NULL)
1868 return(DestroyPixelListThreadSet(pixel_list));
1873 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
1886 Initialize the node.
1888 p=(&pixel_list->skip_list);
1889 p->nodes[color].signature=pixel_list->signature;
1890 p->nodes[color].count=1;
1892 Determine where it belongs in the list.
1895 for (level=p->level; level >= 0; level--)
1897 while (p->nodes[search].next[level] < color)
1898 search=p->nodes[search].next[level];
1899 update[level]=search;
1902 Generate a pseudo-random level for this node.
1904 for (level=0; ; level++)
1906 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
1907 if ((pixel_list->seed & 0x300) != 0x300)
1912 if (level > (p->level+2))
1915 If we're raising the list's level, link back to the root node.
1917 while (level > p->level)
1920 update[p->level]=65536UL;
1923 Link the node into the skip-list.
1927 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
1928 p->nodes[update[level]].next[level]=color;
1929 } while (level-- > 0);
1932 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
1945 Find the maximum value for each of the color.
1947 p=(&pixel_list->skip_list);
1950 maximum=p->nodes[color].next[0];
1953 color=p->nodes[color].next[0];
1954 if (color > maximum)
1956 count+=p->nodes[color].count;
1957 } while (count < (ssize_t) pixel_list->length);
1958 *pixel=ScaleShortToQuantum((unsigned short) maximum);
1961 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
1976 Find the mean value for each of the color.
1978 p=(&pixel_list->skip_list);
1984 color=p->nodes[color].next[0];
1985 sum+=(MagickRealType) p->nodes[color].count*color;
1986 count+=p->nodes[color].count;
1987 } while (count < (ssize_t) pixel_list->length);
1988 sum/=pixel_list->length;
1989 *pixel=ScaleShortToQuantum((unsigned short) sum);
1992 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2004 Find the median value for each of the color.
2006 p=(&pixel_list->skip_list);
2011 color=p->nodes[color].next[0];
2012 count+=p->nodes[color].count;
2013 } while (count <= (ssize_t) (pixel_list->length >> 1));
2014 *pixel=ScaleShortToQuantum((unsigned short) color);
2017 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2030 Find the minimum value for each of the color.
2032 p=(&pixel_list->skip_list);
2035 minimum=p->nodes[color].next[0];
2038 color=p->nodes[color].next[0];
2039 if (color < minimum)
2041 count+=p->nodes[color].count;
2042 } while (count < (ssize_t) pixel_list->length);
2043 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2046 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2060 Make each pixel the 'predominant color' of the specified neighborhood.
2062 p=(&pixel_list->skip_list);
2065 max_count=p->nodes[mode].count;
2069 color=p->nodes[color].next[0];
2070 if (p->nodes[color].count > max_count)
2073 max_count=p->nodes[mode].count;
2075 count+=p->nodes[color].count;
2076 } while (count < (ssize_t) pixel_list->length);
2077 *pixel=ScaleShortToQuantum((unsigned short) mode);
2080 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2094 Finds the non peak value for each of the colors.
2096 p=(&pixel_list->skip_list);
2098 next=p->nodes[color].next[0];
2104 next=p->nodes[color].next[0];
2105 count+=p->nodes[color].count;
2106 } while (count <= (ssize_t) (pixel_list->length >> 1));
2107 if ((previous == 65536UL) && (next != 65536UL))
2110 if ((previous != 65536UL) && (next == 65536UL))
2112 *pixel=ScaleShortToQuantum((unsigned short) color);
2115 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2132 Find the standard-deviation value for each of the color.
2134 p=(&pixel_list->skip_list);
2144 color=p->nodes[color].next[0];
2145 sum+=(MagickRealType) p->nodes[color].count*color;
2146 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2147 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
2148 count+=p->nodes[color].count;
2149 } while (count < (ssize_t) pixel_list->length);
2150 sum/=pixel_list->length;
2151 sum_squared/=pixel_list->length;
2152 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2155 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2156 PixelList *pixel_list)
2164 index=ScaleQuantumToShort(pixel);
2165 signature=pixel_list->skip_list.nodes[index].signature;
2166 if (signature == pixel_list->signature)
2168 pixel_list->skip_list.nodes[index].count++;
2171 AddNodePixelList(pixel_list,index);
2174 static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
2181 static inline size_t MagickMax(const size_t x,const size_t y)
2188 static void ResetPixelList(PixelList *pixel_list)
2200 Reset the skip-list.
2202 p=(&pixel_list->skip_list);
2203 root=p->nodes+65536UL;
2205 for (level=0; level < 9; level++)
2206 root->next[level]=65536UL;
2207 pixel_list->seed=pixel_list->signature++;
2210 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2211 const size_t width,const size_t height,ExceptionInfo *exception)
2213 #define StatisticImageTag "Statistic/Image"
2229 **restrict pixel_list;
2236 Initialize statistics image attributes.
2238 assert(image != (Image *) NULL);
2239 assert(image->signature == MagickSignature);
2240 if (image->debug != MagickFalse)
2241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2242 assert(exception != (ExceptionInfo *) NULL);
2243 assert(exception->signature == MagickSignature);
2244 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2246 if (statistic_image == (Image *) NULL)
2247 return((Image *) NULL);
2248 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2249 if (status == MagickFalse)
2251 statistic_image=DestroyImage(statistic_image);
2252 return((Image *) NULL);
2254 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2255 if (pixel_list == (PixelList **) NULL)
2257 statistic_image=DestroyImage(statistic_image);
2258 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2261 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2263 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2264 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2267 image_view=AcquireVirtualCacheView(image,exception);
2268 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2269 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2270 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2271 dynamic_number_threads(image->columns,image->rows,1)
2273 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2276 id = GetOpenMPThreadId();
2278 register const Quantum
2287 if (status == MagickFalse)
2289 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2290 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2291 MagickMax(height,1),exception);
2292 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2293 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2298 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2303 if (GetPixelMask(image,p) != 0)
2305 p+=GetPixelChannels(image);
2306 q+=GetPixelChannels(statistic_image);
2309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2321 register const Quantum
2330 channel=GetPixelChannelMapChannel(image,i);
2331 traits=GetPixelChannelMapTraits(image,channel);
2332 statistic_traits=GetPixelChannelMapTraits(statistic_image,channel);
2333 if ((traits == UndefinedPixelTrait) ||
2334 (statistic_traits == UndefinedPixelTrait))
2336 if ((statistic_traits & CopyPixelTrait) != 0)
2338 SetPixelChannel(statistic_image,channel,p[center+i],q);
2342 ResetPixelList(pixel_list[id]);
2343 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2345 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2347 InsertPixelList(image,pixels[i],pixel_list[id]);
2348 pixels+=GetPixelChannels(image);
2350 pixels+=image->columns*GetPixelChannels(image);
2354 case GradientStatistic:
2360 GetMinimumPixelList(pixel_list[id],&pixel);
2361 minimum=(MagickRealType) pixel;
2362 GetMaximumPixelList(pixel_list[id],&pixel);
2363 maximum=(MagickRealType) pixel;
2364 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2367 case MaximumStatistic:
2369 GetMaximumPixelList(pixel_list[id],&pixel);
2374 GetMeanPixelList(pixel_list[id],&pixel);
2377 case MedianStatistic:
2380 GetMedianPixelList(pixel_list[id],&pixel);
2383 case MinimumStatistic:
2385 GetMinimumPixelList(pixel_list[id],&pixel);
2390 GetModePixelList(pixel_list[id],&pixel);
2393 case NonpeakStatistic:
2395 GetNonpeakPixelList(pixel_list[id],&pixel);
2398 case StandardDeviationStatistic:
2400 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2404 SetPixelChannel(statistic_image,channel,pixel,q);
2406 p+=GetPixelChannels(image);
2407 q+=GetPixelChannels(statistic_image);
2409 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2411 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2416 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2417 #pragma omp critical (MagickCore_StatisticImage)
2419 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2421 if (proceed == MagickFalse)
2425 statistic_view=DestroyCacheView(statistic_view);
2426 image_view=DestroyCacheView(image_view);
2427 pixel_list=DestroyPixelListThreadSet(pixel_list);
2428 return(statistic_image);