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-2010 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 "magick/studio.h"
44 #include "magick/property.h"
45 #include "magick/animate.h"
46 #include "magick/blob.h"
47 #include "magick/blob-private.h"
48 #include "magick/cache.h"
49 #include "magick/cache-private.h"
50 #include "magick/cache-view.h"
51 #include "magick/client.h"
52 #include "magick/color.h"
53 #include "magick/color-private.h"
54 #include "magick/colorspace.h"
55 #include "magick/colorspace-private.h"
56 #include "magick/composite.h"
57 #include "magick/composite-private.h"
58 #include "magick/compress.h"
59 #include "magick/constitute.h"
60 #include "magick/deprecate.h"
61 #include "magick/display.h"
62 #include "magick/draw.h"
63 #include "magick/enhance.h"
64 #include "magick/exception.h"
65 #include "magick/exception-private.h"
66 #include "magick/gem.h"
67 #include "magick/geometry.h"
68 #include "magick/list.h"
69 #include "magick/image-private.h"
70 #include "magick/magic.h"
71 #include "magick/magick.h"
72 #include "magick/memory_.h"
73 #include "magick/module.h"
74 #include "magick/monitor.h"
75 #include "magick/monitor-private.h"
76 #include "magick/option.h"
77 #include "magick/paint.h"
78 #include "magick/pixel-private.h"
79 #include "magick/profile.h"
80 #include "magick/quantize.h"
81 #include "magick/random_.h"
82 #include "magick/random-private.h"
83 #include "magick/segment.h"
84 #include "magick/semaphore.h"
85 #include "magick/signature-private.h"
86 #include "magick/statistic.h"
87 #include "magick/string_.h"
88 #include "magick/thread-private.h"
89 #include "magick/timer.h"
90 #include "magick/utility.h"
91 #include "magick/version.h"
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 % E v a l u a t e I m a g e %
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 % EvaluateImage() applies a value to the image with an arithmetic, relational,
105 % or logical operator to an image. Use these operations to lighten or darken
106 % an image, to increase or decrease contrast in an image, or to produce the
107 % "negative" of an image.
109 % The format of the EvaluateImageChannel method is:
111 % MagickBooleanType EvaluateImage(Image *image,
112 % const MagickEvaluateOperator op,const double value,
113 % ExceptionInfo *exception)
114 % MagickBooleanType EvaluateImages(Image *images,
115 % const MagickEvaluateOperator op,const double value,
116 % ExceptionInfo *exception)
117 % MagickBooleanType EvaluateImageChannel(Image *image,
118 % const ChannelType channel,const MagickEvaluateOperator op,
119 % const double value,ExceptionInfo *exception)
121 % A description of each parameter follows:
123 % o image: the image.
125 % o channel: the channel.
127 % o op: A channel op.
129 % o value: A value value.
131 % o exception: return any errors or warnings in this structure.
135 static MagickPixelPacket **DestroyPixelThreadSet(MagickPixelPacket **pixels)
140 assert(pixels != (MagickPixelPacket **) NULL);
141 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
142 if (pixels[i] != (MagickPixelPacket *) NULL)
143 pixels[i]=(MagickPixelPacket *) RelinquishMagickMemory(pixels[i]);
144 pixels=(MagickPixelPacket **) RelinquishAlignedMemory(pixels);
148 static MagickPixelPacket **AcquirePixelThreadSet(const Image *image)
160 number_threads=GetOpenMPMaximumThreads();
161 pixels=(MagickPixelPacket **) AcquireAlignedMemory(number_threads,
163 if (pixels == (MagickPixelPacket **) NULL)
164 return((MagickPixelPacket **) NULL);
165 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
166 for (i=0; i < (ssize_t) number_threads; i++)
168 pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(image->columns,
170 if (pixels[i] == (MagickPixelPacket *) NULL)
171 return(DestroyPixelThreadSet(pixels));
172 for (j=0; j < (ssize_t) image->columns; j++)
173 GetMagickPixelPacket(image,&pixels[i][j]);
178 static inline double MagickMax(const double x,const double y)
185 static inline double MagickMin(const double x,const double y)
192 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
193 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
201 case UndefinedEvaluateOperator:
203 case AddEvaluateOperator:
205 result=(MagickRealType) (pixel+value);
208 case AddModulusEvaluateOperator:
211 This returns a 'floored modulus' of the addition which is a
212 positive result. It differs from % or fmod() which returns a
213 'truncated modulus' result, where floor() is replaced by trunc()
214 and could return a negative result (which is clipped).
217 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
220 case AndEvaluateOperator:
222 result=(MagickRealType) ((size_t) pixel & (size_t)
226 case CosineEvaluateOperator:
228 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
229 QuantumScale*pixel*value))+0.5));
232 case DivideEvaluateOperator:
234 result=pixel/(value == 0.0 ? 1.0 : value);
237 case GaussianNoiseEvaluateOperator:
239 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
240 GaussianNoise,value);
243 case ImpulseNoiseEvaluateOperator:
245 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
249 case LaplacianNoiseEvaluateOperator:
251 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
252 LaplacianNoise,value);
255 case LeftShiftEvaluateOperator:
257 result=(MagickRealType) ((size_t) pixel << (size_t)
261 case LogEvaluateOperator:
263 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
264 pixel+1.0))/log((double) (value+1.0)));
267 case MaxEvaluateOperator:
269 result=(MagickRealType) MagickMax((double) pixel,value);
272 case MeanEvaluateOperator:
274 result=(MagickRealType) (pixel+value);
277 case MinEvaluateOperator:
279 result=(MagickRealType) MagickMin((double) pixel,value);
282 case MultiplicativeNoiseEvaluateOperator:
284 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
285 MultiplicativeGaussianNoise,value);
288 case MultiplyEvaluateOperator:
290 result=(MagickRealType) (value*pixel);
293 case OrEvaluateOperator:
295 result=(MagickRealType) ((size_t) pixel | (size_t)
299 case PoissonNoiseEvaluateOperator:
301 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
305 case PowEvaluateOperator:
307 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
311 case RightShiftEvaluateOperator:
313 result=(MagickRealType) ((size_t) pixel >> (size_t)
317 case SetEvaluateOperator:
322 case SineEvaluateOperator:
324 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
325 QuantumScale*pixel*value))+0.5));
328 case SubtractEvaluateOperator:
330 result=(MagickRealType) (pixel-value);
333 case ThresholdEvaluateOperator:
335 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
339 case ThresholdBlackEvaluateOperator:
341 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
344 case ThresholdWhiteEvaluateOperator:
346 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
350 case UniformNoiseEvaluateOperator:
352 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
356 case XorEvaluateOperator:
358 result=(MagickRealType) ((size_t) pixel ^ (size_t)
366 MagickExport MagickBooleanType EvaluateImage(Image *image,
367 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
372 status=EvaluateImageChannel(image,AllChannels,op,value,exception);
376 MagickExport Image *EvaluateImages(const Image *images,
377 const MagickEvaluateOperator op,ExceptionInfo *exception)
379 #define EvaluateImageTag "Evaluate/Image"
397 **restrict evaluate_pixels,
401 **restrict random_info;
410 Ensure the image are the same size.
412 assert(images != (Image *) NULL);
413 assert(images->signature == MagickSignature);
414 if (images->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
416 assert(exception != (ExceptionInfo *) NULL);
417 assert(exception->signature == MagickSignature);
418 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
419 if ((next->columns != images->columns) || (next->rows != images->rows))
421 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
422 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
423 return((Image *) NULL);
426 Initialize evaluate next attributes.
428 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
430 if (evaluate_image == (Image *) NULL)
431 return((Image *) NULL);
432 if (SetImageStorageClass(evaluate_image,DirectClass) == MagickFalse)
434 InheritException(exception,&evaluate_image->exception);
435 evaluate_image=DestroyImage(evaluate_image);
436 return((Image *) NULL);
438 evaluate_pixels=AcquirePixelThreadSet(images);
439 if (evaluate_pixels == (MagickPixelPacket **) NULL)
441 evaluate_image=DestroyImage(evaluate_image);
442 (void) ThrowMagickException(exception,GetMagickModule(),
443 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
444 return((Image *) NULL);
447 Evaluate image pixels.
451 GetMagickPixelPacket(images,&zero);
452 random_info=AcquireRandomInfoThreadSet();
453 number_images=GetImageListLength(images);
454 evaluate_view=AcquireCacheView(evaluate_image);
455 #if defined(MAGICKCORE_OPENMP_SUPPORT)
456 #pragma omp parallel for schedule(dynamic) shared(progress,status)
458 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
473 *restrict evaluate_indexes;
479 register MagickPixelPacket
485 if (status == MagickFalse)
487 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,1,
489 if (q == (PixelPacket *) NULL)
494 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
496 id=GetOpenMPThreadId();
497 evaluate_pixel=evaluate_pixels[id];
498 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
499 evaluate_pixel[x]=zero;
501 for (i=0; i < (ssize_t) number_images; i++)
503 register const IndexPacket
506 register const PixelPacket
509 image_view=AcquireCacheView(next);
510 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
511 if (p == (const PixelPacket *) NULL)
513 image_view=DestroyCacheView(image_view);
516 indexes=GetCacheViewVirtualIndexQueue(image_view);
517 for (x=0; x < (ssize_t) next->columns; x++)
519 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],p->red,
520 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].red);
521 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],p->green,
522 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].green);
523 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],p->blue,
524 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].blue);
525 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[id],
526 p->opacity,i == 0 ? AddEvaluateOperator : op,
527 evaluate_pixel[x].opacity);
528 if (evaluate_image->colorspace == CMYKColorspace)
529 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[id],
530 indexes[x],i == 0 ? AddEvaluateOperator : op,
531 evaluate_pixel[x].index);
534 image_view=DestroyCacheView(image_view);
535 next=GetNextImageInList(next);
537 if (op == MeanEvaluateOperator)
538 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
540 evaluate_pixel[x].red/=number_images;
541 evaluate_pixel[x].green/=number_images;
542 evaluate_pixel[x].blue/=number_images;
543 evaluate_pixel[x].opacity/=number_images;
544 evaluate_pixel[x].index/=number_images;
546 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
548 q->red=ClampToQuantum(evaluate_pixel[x].red);
549 q->green=ClampToQuantum(evaluate_pixel[x].green);
550 q->blue=ClampToQuantum(evaluate_pixel[x].blue);
551 if (evaluate_image->matte == MagickFalse)
552 q->opacity=ClampToQuantum(evaluate_pixel[x].opacity);
554 q->opacity=ClampToQuantum(QuantumRange-evaluate_pixel[x].opacity);
555 if (evaluate_image->colorspace == CMYKColorspace)
556 evaluate_indexes[x]=ClampToQuantum(evaluate_pixel[x].index);
559 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
561 if (images->progress_monitor != (MagickProgressMonitor) NULL)
566 #if defined(MAGICKCORE_OPENMP_SUPPORT)
567 #pragma omp critical (MagickCore_EvaluateImages)
569 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
570 evaluate_image->rows);
571 if (proceed == MagickFalse)
575 evaluate_view=DestroyCacheView(evaluate_view);
576 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
577 random_info=DestroyRandomInfoThreadSet(random_info);
578 if (status == MagickFalse)
579 evaluate_image=DestroyImage(evaluate_image);
580 return(evaluate_image);
583 MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
584 const ChannelType channel,const MagickEvaluateOperator op,const double value,
585 ExceptionInfo *exception)
597 **restrict random_info;
602 assert(image != (Image *) NULL);
603 assert(image->signature == MagickSignature);
604 if (image->debug != MagickFalse)
605 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
606 assert(exception != (ExceptionInfo *) NULL);
607 assert(exception->signature == MagickSignature);
608 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
610 InheritException(exception,&image->exception);
615 random_info=AcquireRandomInfoThreadSet();
616 image_view=AcquireCacheView(image);
617 #if defined(MAGICKCORE_OPENMP_SUPPORT)
618 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
620 for (y=0; y < (ssize_t) image->rows; y++)
634 if (status == MagickFalse)
636 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
637 if (q == (PixelPacket *) NULL)
642 indexes=GetCacheViewAuthenticIndexQueue(image_view);
643 id=GetOpenMPThreadId();
644 for (x=0; x < (ssize_t) image->columns; x++)
646 if ((channel & RedChannel) != 0)
647 q->red=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->red,op,
649 if ((channel & GreenChannel) != 0)
650 q->green=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->green,
652 if ((channel & BlueChannel) != 0)
653 q->blue=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->blue,op,
655 if ((channel & OpacityChannel) != 0)
657 if (image->matte == MagickFalse)
658 q->opacity=ClampToQuantum(ApplyEvaluateOperator(random_info[id],
659 q->opacity,op,value));
661 q->opacity=ClampToQuantum(QuantumRange-ApplyEvaluateOperator(
662 random_info[id],(Quantum) GetAlphaPixelComponent(q),op,value));
664 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
665 indexes[x]=(IndexPacket) ClampToQuantum(ApplyEvaluateOperator(
666 random_info[id],indexes[x],op,value));
669 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
671 if (image->progress_monitor != (MagickProgressMonitor) NULL)
676 #if defined(MAGICKCORE_OPENMP_SUPPORT)
677 #pragma omp critical (MagickCore_EvaluateImageChannel)
679 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
680 if (proceed == MagickFalse)
684 image_view=DestroyCacheView(image_view);
685 random_info=DestroyRandomInfoThreadSet(random_info);
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 % F u n c t i o n I m a g e %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 % FunctionImage() applies a value to the image with an arithmetic, relational,
701 % or logical operator to an image. Use these operations to lighten or darken
702 % an image, to increase or decrease contrast in an image, or to produce the
703 % "negative" of an image.
705 % The format of the FunctionImageChannel method is:
707 % MagickBooleanType FunctionImage(Image *image,
708 % const MagickFunction function,const ssize_t number_parameters,
709 % const double *parameters,ExceptionInfo *exception)
710 % MagickBooleanType FunctionImageChannel(Image *image,
711 % const ChannelType channel,const MagickFunction function,
712 % const ssize_t number_parameters,const double *argument,
713 % ExceptionInfo *exception)
715 % A description of each parameter follows:
717 % o image: the image.
719 % o channel: the channel.
721 % o function: A channel function.
723 % o parameters: one or more parameters.
725 % o exception: return any errors or warnings in this structure.
729 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
730 const size_t number_parameters,const double *parameters,
731 ExceptionInfo *exception)
743 case PolynomialFunction:
747 * Parameters: polynomial constants, highest to lowest order
748 * For example: c0*x^3 + c1*x^2 + c2*x + c3
751 for (i=0; i < (ssize_t) number_parameters; i++)
752 result = result*QuantumScale*pixel + parameters[i];
753 result *= QuantumRange;
756 case SinusoidFunction:
759 * Parameters: Freq, Phase, Ampl, bias
761 double freq,phase,ampl,bias;
762 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
763 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
764 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
765 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
766 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
767 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
772 /* Arcsin Function (peged at range limits for invalid results)
773 * Parameters: Width, Center, Range, Bias
775 double width,range,center,bias;
776 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
777 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
778 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
779 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
780 result = 2.0/width*(QuantumScale*pixel - center);
781 if ( result <= -1.0 )
782 result = bias - range/2.0;
783 else if ( result >= 1.0 )
784 result = bias + range/2.0;
786 result=range/MagickPI*asin((double)result) + bias;
787 result *= QuantumRange;
793 * Parameters: Slope, Center, Range, Bias
795 double slope,range,center,bias;
796 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
797 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
798 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
799 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
800 result = MagickPI*slope*(QuantumScale*pixel - center);
801 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
805 case UndefinedFunction:
808 return(ClampToQuantum(result));
811 MagickExport MagickBooleanType FunctionImage(Image *image,
812 const MagickFunction function,const size_t number_parameters,
813 const double *parameters,ExceptionInfo *exception)
818 status=FunctionImageChannel(image,AllChannels,function,number_parameters,
819 parameters,exception);
823 MagickExport MagickBooleanType FunctionImageChannel(Image *image,
824 const ChannelType channel,const MagickFunction function,
825 const size_t number_parameters,const double *parameters,
826 ExceptionInfo *exception)
828 #define FunctionImageTag "Function/Image "
842 assert(image != (Image *) NULL);
843 assert(image->signature == MagickSignature);
844 if (image->debug != MagickFalse)
845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
846 assert(exception != (ExceptionInfo *) NULL);
847 assert(exception->signature == MagickSignature);
848 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
850 InheritException(exception,&image->exception);
855 image_view=AcquireCacheView(image);
856 #if defined(MAGICKCORE_OPENMP_SUPPORT)
857 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
859 for (y=0; y < (ssize_t) image->rows; y++)
870 if (status == MagickFalse)
872 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
873 if (q == (PixelPacket *) NULL)
878 indexes=GetCacheViewAuthenticIndexQueue(image_view);
879 for (x=0; x < (ssize_t) image->columns; x++)
881 if ((channel & RedChannel) != 0)
882 q->red=ApplyFunction(q->red,function,number_parameters,parameters,
884 if ((channel & GreenChannel) != 0)
885 q->green=ApplyFunction(q->green,function,number_parameters,parameters,
887 if ((channel & BlueChannel) != 0)
888 q->blue=ApplyFunction(q->blue,function,number_parameters,parameters,
890 if ((channel & OpacityChannel) != 0)
892 if (image->matte == MagickFalse)
893 q->opacity=ApplyFunction(q->opacity,function,number_parameters,
894 parameters,exception);
896 q->opacity=(Quantum) QuantumRange-ApplyFunction((Quantum)
897 GetAlphaPixelComponent(q),function,number_parameters,parameters,
900 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
901 indexes[x]=(IndexPacket) ApplyFunction(indexes[x],function,
902 number_parameters,parameters,exception);
905 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
907 if (image->progress_monitor != (MagickProgressMonitor) NULL)
912 #if defined(MAGICKCORE_OPENMP_SUPPORT)
913 #pragma omp critical (MagickCore_FunctionImageChannel)
915 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
916 if (proceed == MagickFalse)
920 image_view=DestroyCacheView(image_view);
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 + G e t I m a g e C h a n n e l E x t r e m a %
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 % GetImageChannelExtrema() returns the extrema of one or more image channels.
937 % The format of the GetImageChannelExtrema method is:
939 % MagickBooleanType GetImageChannelExtrema(const Image *image,
940 % const ChannelType channel,size_t *minima,size_t *maxima,
941 % ExceptionInfo *exception)
943 % A description of each parameter follows:
945 % o image: the image.
947 % o channel: the channel.
949 % o minima: the minimum value in the channel.
951 % o maxima: the maximum value in the channel.
953 % o exception: return any errors or warnings in this structure.
957 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
958 size_t *minima,size_t *maxima,ExceptionInfo *exception)
960 return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
963 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
964 const ChannelType channel,size_t *minima,size_t *maxima,
965 ExceptionInfo *exception)
974 assert(image != (Image *) NULL);
975 assert(image->signature == MagickSignature);
976 if (image->debug != MagickFalse)
977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
978 status=GetImageChannelRange(image,channel,&min,&max,exception);
979 *minima=(size_t) ceil(min-0.5);
980 *maxima=(size_t) floor(max+0.5);
985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
989 % G e t I m a g e C h a n n e l M e a n %
993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 % GetImageChannelMean() returns the mean and standard deviation of one or more
998 % The format of the GetImageChannelMean method is:
1000 % MagickBooleanType GetImageChannelMean(const Image *image,
1001 % const ChannelType channel,double *mean,double *standard_deviation,
1002 % ExceptionInfo *exception)
1004 % A description of each parameter follows:
1006 % o image: the image.
1008 % o channel: the channel.
1010 % o mean: the average value in the channel.
1012 % o standard_deviation: the standard deviation of the channel.
1014 % o exception: return any errors or warnings in this structure.
1018 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1019 double *standard_deviation,ExceptionInfo *exception)
1024 status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
1029 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
1030 const ChannelType channel,double *mean,double *standard_deviation,
1031 ExceptionInfo *exception)
1039 assert(image != (Image *) NULL);
1040 assert(image->signature == MagickSignature);
1041 if (image->debug != MagickFalse)
1042 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1044 *standard_deviation=0.0;
1046 for (y=0; y < (ssize_t) image->rows; y++)
1048 register const IndexPacket
1051 register const PixelPacket
1057 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1058 if (p == (const PixelPacket *) NULL)
1060 indexes=GetVirtualIndexQueue(image);
1061 for (x=0; x < (ssize_t) image->columns; x++)
1063 if ((channel & RedChannel) != 0)
1065 *mean+=GetRedPixelComponent(p);
1066 *standard_deviation+=(double) p->red*GetRedPixelComponent(p);
1069 if ((channel & GreenChannel) != 0)
1071 *mean+=GetGreenPixelComponent(p);
1072 *standard_deviation+=(double) p->green*GetGreenPixelComponent(p);
1075 if ((channel & BlueChannel) != 0)
1077 *mean+=GetBluePixelComponent(p);
1078 *standard_deviation+=(double) p->blue*GetBluePixelComponent(p);
1081 if (((channel & OpacityChannel) != 0) &&
1082 (image->matte != MagickFalse))
1084 *mean+=GetOpacityPixelComponent(p);
1085 *standard_deviation+=(double) p->opacity*GetOpacityPixelComponent(p);
1088 if (((channel & IndexChannel) != 0) &&
1089 (image->colorspace == CMYKColorspace))
1092 *standard_deviation+=(double) indexes[x]*indexes[x];
1098 if (y < (ssize_t) image->rows)
1099 return(MagickFalse);
1103 *standard_deviation/=area;
1105 *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
1106 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114 % G e t I m a g e C h a n n e l K u r t o s i s %
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120 % GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
1123 % The format of the GetImageChannelKurtosis method is:
1125 % MagickBooleanType GetImageChannelKurtosis(const Image *image,
1126 % const ChannelType channel,double *kurtosis,double *skewness,
1127 % ExceptionInfo *exception)
1129 % A description of each parameter follows:
1131 % o image: the image.
1133 % o channel: the channel.
1135 % o kurtosis: the kurtosis of the channel.
1137 % o skewness: the skewness of the channel.
1139 % o exception: return any errors or warnings in this structure.
1143 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1144 double *kurtosis,double *skewness,ExceptionInfo *exception)
1149 status=GetImageChannelKurtosis(image,AllChannels,kurtosis,skewness,
1154 MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
1155 const ChannelType channel,double *kurtosis,double *skewness,
1156 ExceptionInfo *exception)
1169 assert(image != (Image *) NULL);
1170 assert(image->signature == MagickSignature);
1171 if (image->debug != MagickFalse)
1172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1177 standard_deviation=0.0;
1180 sum_fourth_power=0.0;
1181 for (y=0; y < (ssize_t) image->rows; y++)
1183 register const IndexPacket
1186 register const PixelPacket
1192 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1193 if (p == (const PixelPacket *) NULL)
1195 indexes=GetVirtualIndexQueue(image);
1196 for (x=0; x < (ssize_t) image->columns; x++)
1198 if ((channel & RedChannel) != 0)
1200 mean+=GetRedPixelComponent(p);
1201 sum_squares+=(double) p->red*GetRedPixelComponent(p);
1202 sum_cubes+=(double) p->red*p->red*GetRedPixelComponent(p);
1203 sum_fourth_power+=(double) p->red*p->red*p->red*
1204 GetRedPixelComponent(p);
1207 if ((channel & GreenChannel) != 0)
1209 mean+=GetGreenPixelComponent(p);
1210 sum_squares+=(double) p->green*GetGreenPixelComponent(p);
1211 sum_cubes+=(double) p->green*p->green*GetGreenPixelComponent(p);
1212 sum_fourth_power+=(double) p->green*p->green*p->green*
1213 GetGreenPixelComponent(p);
1216 if ((channel & BlueChannel) != 0)
1218 mean+=GetBluePixelComponent(p);
1219 sum_squares+=(double) p->blue*GetBluePixelComponent(p);
1220 sum_cubes+=(double) p->blue*p->blue*GetBluePixelComponent(p);
1221 sum_fourth_power+=(double) p->blue*p->blue*p->blue*
1222 GetBluePixelComponent(p);
1225 if ((channel & OpacityChannel) != 0)
1227 mean+=GetOpacityPixelComponent(p);
1228 sum_squares+=(double) p->opacity*GetOpacityPixelComponent(p);
1229 sum_cubes+=(double) p->opacity*p->opacity*GetOpacityPixelComponent(p);
1230 sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
1231 GetOpacityPixelComponent(p);
1234 if (((channel & IndexChannel) != 0) &&
1235 (image->colorspace == CMYKColorspace))
1238 sum_squares+=(double) indexes[x]*indexes[x];
1239 sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
1240 sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
1247 if (y < (ssize_t) image->rows)
1248 return(MagickFalse);
1254 sum_fourth_power/=area;
1256 standard_deviation=sqrt(sum_squares-(mean*mean));
1257 if (standard_deviation != 0.0)
1259 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1260 3.0*mean*mean*mean*mean;
1261 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1264 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1265 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1267 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275 % G e t I m a g e C h a n n e l R a n g e %
1279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 % GetImageChannelRange() returns the range of one or more image channels.
1283 % The format of the GetImageChannelRange method is:
1285 % MagickBooleanType GetImageChannelRange(const Image *image,
1286 % const ChannelType channel,double *minima,double *maxima,
1287 % ExceptionInfo *exception)
1289 % A description of each parameter follows:
1291 % o image: the image.
1293 % o channel: the channel.
1295 % o minima: the minimum value in the channel.
1297 % o maxima: the maximum value in the channel.
1299 % o exception: return any errors or warnings in this structure.
1303 MagickExport MagickBooleanType GetImageRange(const Image *image,
1304 double *minima,double *maxima,ExceptionInfo *exception)
1306 return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
1309 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
1310 const ChannelType channel,double *minima,double *maxima,
1311 ExceptionInfo *exception)
1319 assert(image != (Image *) NULL);
1320 assert(image->signature == MagickSignature);
1321 if (image->debug != MagickFalse)
1322 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1325 GetMagickPixelPacket(image,&pixel);
1326 for (y=0; y < (ssize_t) image->rows; y++)
1328 register const IndexPacket
1331 register const PixelPacket
1337 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1338 if (p == (const PixelPacket *) NULL)
1340 indexes=GetVirtualIndexQueue(image);
1341 for (x=0; x < (ssize_t) image->columns; x++)
1343 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1344 if ((channel & RedChannel) != 0)
1346 if (pixel.red < *minima)
1347 *minima=(double) pixel.red;
1348 if (pixel.red > *maxima)
1349 *maxima=(double) pixel.red;
1351 if ((channel & GreenChannel) != 0)
1353 if (pixel.green < *minima)
1354 *minima=(double) pixel.green;
1355 if (pixel.green > *maxima)
1356 *maxima=(double) pixel.green;
1358 if ((channel & BlueChannel) != 0)
1360 if (pixel.blue < *minima)
1361 *minima=(double) pixel.blue;
1362 if (pixel.blue > *maxima)
1363 *maxima=(double) pixel.blue;
1365 if ((channel & OpacityChannel) != 0)
1367 if (pixel.opacity < *minima)
1368 *minima=(double) pixel.opacity;
1369 if (pixel.opacity > *maxima)
1370 *maxima=(double) pixel.opacity;
1372 if (((channel & IndexChannel) != 0) &&
1373 (image->colorspace == CMYKColorspace))
1375 if ((double) indexes[x] < *minima)
1376 *minima=(double) indexes[x];
1377 if ((double) indexes[x] > *maxima)
1378 *maxima=(double) indexes[x];
1383 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 % G e t I m a g e C h a n n e l S t a t i s t i c s %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1397 % GetImageChannelStatistics() returns statistics for each channel in the
1398 % image. The statistics include the channel depth, its minima, maxima, mean,
1399 % standard deviation, kurtosis and skewness. You can access the red channel
1400 % mean, for example, like this:
1402 % channel_statistics=GetImageChannelStatistics(image,excepton);
1403 % red_mean=channel_statistics[RedChannel].mean;
1405 % Use MagickRelinquishMemory() to free the statistics buffer.
1407 % The format of the GetImageChannelStatistics method is:
1409 % ChannelStatistics *GetImageChannelStatistics(const Image *image,
1410 % ExceptionInfo *exception)
1412 % A description of each parameter follows:
1414 % o image: the image.
1416 % o exception: return any errors or warnings in this structure.
1419 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
1420 ExceptionInfo *exception)
1423 *channel_statistics;
1449 assert(image != (Image *) NULL);
1450 assert(image->signature == MagickSignature);
1451 if (image->debug != MagickFalse)
1452 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1453 length=AllChannels+1UL;
1454 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1455 sizeof(*channel_statistics));
1456 if (channel_statistics == (ChannelStatistics *) NULL)
1457 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1458 (void) ResetMagickMemory(channel_statistics,0,length*
1459 sizeof(*channel_statistics));
1460 for (i=0; i <= AllChannels; i++)
1462 channel_statistics[i].depth=1;
1463 channel_statistics[i].maxima=(-1.0E-37);
1464 channel_statistics[i].minima=1.0E+37;
1465 channel_statistics[i].mean=0.0;
1466 channel_statistics[i].standard_deviation=0.0;
1467 channel_statistics[i].kurtosis=0.0;
1468 channel_statistics[i].skewness=0.0;
1470 for (y=0; y < (ssize_t) image->rows; y++)
1472 register const IndexPacket
1475 register const PixelPacket
1481 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1482 if (p == (const PixelPacket *) NULL)
1484 indexes=GetVirtualIndexQueue(image);
1485 for (x=0; x < (ssize_t) image->columns; )
1487 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1489 depth=channel_statistics[RedChannel].depth;
1490 range=GetQuantumRange(depth);
1491 status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
1492 range) ? MagickTrue : MagickFalse;
1493 if (status != MagickFalse)
1495 channel_statistics[RedChannel].depth++;
1499 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1501 depth=channel_statistics[GreenChannel].depth;
1502 range=GetQuantumRange(depth);
1503 status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
1504 range),range) ? MagickTrue : MagickFalse;
1505 if (status != MagickFalse)
1507 channel_statistics[GreenChannel].depth++;
1511 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1513 depth=channel_statistics[BlueChannel].depth;
1514 range=GetQuantumRange(depth);
1515 status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
1516 range),range) ? MagickTrue : MagickFalse;
1517 if (status != MagickFalse)
1519 channel_statistics[BlueChannel].depth++;
1523 if (image->matte != MagickFalse)
1525 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1527 depth=channel_statistics[OpacityChannel].depth;
1528 range=GetQuantumRange(depth);
1529 status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
1530 p->opacity,range),range) ? MagickTrue : MagickFalse;
1531 if (status != MagickFalse)
1533 channel_statistics[OpacityChannel].depth++;
1538 if (image->colorspace == CMYKColorspace)
1540 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1542 depth=channel_statistics[BlackChannel].depth;
1543 range=GetQuantumRange(depth);
1544 status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
1545 indexes[x],range),range) ? MagickTrue : MagickFalse;
1546 if (status != MagickFalse)
1548 channel_statistics[BlackChannel].depth++;
1553 if ((double) p->red < channel_statistics[RedChannel].minima)
1554 channel_statistics[RedChannel].minima=(double) GetRedPixelComponent(p);
1555 if ((double) p->red > channel_statistics[RedChannel].maxima)
1556 channel_statistics[RedChannel].maxima=(double) GetRedPixelComponent(p);
1557 channel_statistics[RedChannel].mean+=GetRedPixelComponent(p);
1558 channel_statistics[RedChannel].standard_deviation+=(double) p->red*
1559 GetRedPixelComponent(p);
1560 channel_statistics[RedChannel].kurtosis+=(double) p->red*p->red*
1561 p->red*GetRedPixelComponent(p);
1562 channel_statistics[RedChannel].skewness+=(double) p->red*p->red*
1563 GetRedPixelComponent(p);
1564 if ((double) p->green < channel_statistics[GreenChannel].minima)
1565 channel_statistics[GreenChannel].minima=(double)
1566 GetGreenPixelComponent(p);
1567 if ((double) p->green > channel_statistics[GreenChannel].maxima)
1568 channel_statistics[GreenChannel].maxima=(double)
1569 GetGreenPixelComponent(p);
1570 channel_statistics[GreenChannel].mean+=GetGreenPixelComponent(p);
1571 channel_statistics[GreenChannel].standard_deviation+=(double) p->green*
1572 GetGreenPixelComponent(p);
1573 channel_statistics[GreenChannel].kurtosis+=(double) p->green*p->green*
1574 p->green*GetGreenPixelComponent(p);
1575 channel_statistics[GreenChannel].skewness+=(double) p->green*p->green*
1576 GetGreenPixelComponent(p);
1577 if ((double) p->blue < channel_statistics[BlueChannel].minima)
1578 channel_statistics[BlueChannel].minima=(double)
1579 GetBluePixelComponent(p);
1580 if ((double) p->blue > channel_statistics[BlueChannel].maxima)
1581 channel_statistics[BlueChannel].maxima=(double)
1582 GetBluePixelComponent(p);
1583 channel_statistics[BlueChannel].mean+=GetBluePixelComponent(p);
1584 channel_statistics[BlueChannel].standard_deviation+=(double) p->blue*
1585 GetBluePixelComponent(p);
1586 channel_statistics[BlueChannel].kurtosis+=(double) p->blue*p->blue*
1587 p->blue*GetBluePixelComponent(p);
1588 channel_statistics[BlueChannel].skewness+=(double) p->blue*p->blue*
1589 GetBluePixelComponent(p);
1590 if (image->matte != MagickFalse)
1592 if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
1593 channel_statistics[OpacityChannel].minima=(double)
1594 GetOpacityPixelComponent(p);
1595 if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
1596 channel_statistics[OpacityChannel].maxima=(double)
1597 GetOpacityPixelComponent(p);
1598 channel_statistics[OpacityChannel].mean+=GetOpacityPixelComponent(p);
1599 channel_statistics[OpacityChannel].standard_deviation+=(double)
1600 p->opacity*GetOpacityPixelComponent(p);
1601 channel_statistics[OpacityChannel].kurtosis+=(double) p->opacity*
1602 p->opacity*p->opacity*GetOpacityPixelComponent(p);
1603 channel_statistics[OpacityChannel].skewness+=(double) p->opacity*
1604 p->opacity*GetOpacityPixelComponent(p);
1606 if (image->colorspace == CMYKColorspace)
1608 if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
1609 channel_statistics[BlackChannel].minima=(double) indexes[x];
1610 if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
1611 channel_statistics[BlackChannel].maxima=(double) indexes[x];
1612 channel_statistics[BlackChannel].mean+=indexes[x];
1613 channel_statistics[BlackChannel].standard_deviation+=(double)
1614 indexes[x]*indexes[x];
1615 channel_statistics[BlackChannel].kurtosis+=(double) indexes[x]*
1616 indexes[x]*indexes[x]*indexes[x];
1617 channel_statistics[BlackChannel].skewness+=(double) indexes[x]*
1618 indexes[x]*indexes[x];
1624 area=(double) image->columns*image->rows;
1625 for (i=0; i < AllChannels; i++)
1627 channel_statistics[i].mean/=area;
1628 channel_statistics[i].standard_deviation/=area;
1629 channel_statistics[i].kurtosis/=area;
1630 channel_statistics[i].skewness/=area;
1632 for (i=0; i < AllChannels; i++)
1634 channel_statistics[AllChannels].depth=(size_t) MagickMax((double)
1635 channel_statistics[AllChannels].depth,(double)
1636 channel_statistics[i].depth);
1637 channel_statistics[AllChannels].minima=MagickMin(
1638 channel_statistics[AllChannels].minima,channel_statistics[i].minima);
1639 channel_statistics[AllChannels].maxima=MagickMax(
1640 channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
1641 channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
1642 channel_statistics[AllChannels].standard_deviation+=
1643 channel_statistics[i].standard_deviation;
1644 channel_statistics[AllChannels].kurtosis+=channel_statistics[i].kurtosis;
1645 channel_statistics[AllChannels].skewness+=channel_statistics[i].skewness;
1648 if (image->matte != MagickFalse)
1650 if (image->colorspace == CMYKColorspace)
1652 channel_statistics[AllChannels].mean/=channels;
1653 channel_statistics[AllChannels].standard_deviation/=channels;
1654 channel_statistics[AllChannels].kurtosis/=channels;
1655 channel_statistics[AllChannels].skewness/=channels;
1656 for (i=0; i <= AllChannels; i++)
1659 sum_squares=channel_statistics[i].standard_deviation;
1661 sum_cubes=channel_statistics[i].skewness;
1662 channel_statistics[i].standard_deviation=sqrt(
1663 channel_statistics[i].standard_deviation-
1664 (channel_statistics[i].mean*channel_statistics[i].mean));
1665 if (channel_statistics[i].standard_deviation == 0.0)
1667 channel_statistics[i].kurtosis=0.0;
1668 channel_statistics[i].skewness=0.0;
1672 channel_statistics[i].skewness=(channel_statistics[i].skewness-
1673 3.0*channel_statistics[i].mean*sum_squares+
1674 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1675 channel_statistics[i].mean)/
1676 (channel_statistics[i].standard_deviation*
1677 channel_statistics[i].standard_deviation*
1678 channel_statistics[i].standard_deviation);
1679 channel_statistics[i].kurtosis=(channel_statistics[i].kurtosis-
1680 4.0*channel_statistics[i].mean*sum_cubes+
1681 6.0*channel_statistics[i].mean*channel_statistics[i].mean*sum_squares-
1682 3.0*channel_statistics[i].mean*channel_statistics[i].mean*
1683 1.0*channel_statistics[i].mean*channel_statistics[i].mean)/
1684 (channel_statistics[i].standard_deviation*
1685 channel_statistics[i].standard_deviation*
1686 channel_statistics[i].standard_deviation*
1687 channel_statistics[i].standard_deviation)-3.0;
1690 return(channel_statistics);