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 < (long) 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 < (long) 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 < (long) 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)*floor(result/(QuantumRange+1));
220 case AndEvaluateOperator:
222 result=(MagickRealType) ((unsigned long) pixel & (unsigned long)
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) ((unsigned long) pixel << (unsigned long)
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)/2.0);
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) ((unsigned long) pixel | (unsigned long)
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) ((unsigned long) pixel >> (unsigned long)
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) ((unsigned long) pixel ^ (unsigned long)
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"
398 **restrict evaluate_pixels,
402 **restrict random_info;
408 Ensure the image are the same size.
410 assert(images != (Image *) NULL);
411 assert(images->signature == MagickSignature);
412 if (images->debug != MagickFalse)
413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
414 assert(exception != (ExceptionInfo *) NULL);
415 assert(exception->signature == MagickSignature);
416 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
417 if ((next->columns != images->columns) || (next->rows != images->rows))
419 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
420 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
421 return((Image *) NULL);
424 Initialize evaluate next attributes.
426 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
428 if (evaluate_image == (Image *) NULL)
429 return((Image *) NULL);
430 if (SetImageStorageClass(evaluate_image,DirectClass) == MagickFalse)
432 InheritException(exception,&evaluate_image->exception);
433 evaluate_image=DestroyImage(evaluate_image);
434 return((Image *) NULL);
436 evaluate_pixels=AcquirePixelThreadSet(images);
437 if (evaluate_pixels == (MagickPixelPacket **) NULL)
439 evaluate_image=DestroyImage(evaluate_image);
440 (void) ThrowMagickException(exception,GetMagickModule(),
441 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
442 return((Image *) NULL);
445 Evaluate image pixels.
449 GetMagickPixelPacket(images,&zero);
450 random_info=AcquireRandomInfoThreadSet();
451 number_images=GetImageListLength(images);
452 evaluate_view=AcquireCacheView(evaluate_image);
453 #if defined(MAGICKCORE_OPENMP_SUPPORT)
454 #pragma omp parallel for schedule(dynamic) shared(progress,status)
456 for (y=0; y < (long) evaluate_image->rows; y++)
468 *restrict evaluate_indexes;
475 register MagickPixelPacket
481 if (status == MagickFalse)
483 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,1,
485 if (q == (PixelPacket *) NULL)
490 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
492 id=GetOpenMPThreadId();
493 evaluate_pixel=evaluate_pixels[id];
494 for (x=0; x < (long) evaluate_image->columns; x++)
495 evaluate_pixel[x]=zero;
497 for (i=0; i < (long) number_images; i++)
499 register const IndexPacket
502 register const PixelPacket
505 image_view=AcquireCacheView(next);
506 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
507 if (p == (const PixelPacket *) NULL)
509 image_view=DestroyCacheView(image_view);
512 indexes=GetCacheViewVirtualIndexQueue(image_view);
513 for (x=0; x < (long) next->columns; x++)
515 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],p->red,
516 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].red);
517 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],p->green,
518 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].green);
519 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],p->blue,
520 i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].blue);
521 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[id],
522 p->opacity,i == 0 ? AddEvaluateOperator : op,
523 evaluate_pixel[x].opacity);
524 if (evaluate_image->colorspace == CMYKColorspace)
525 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[id],
526 indexes[x],i == 0 ? AddEvaluateOperator : op,
527 evaluate_pixel[x].index);
530 image_view=DestroyCacheView(image_view);
531 next=GetNextImageInList(next);
533 for (x=0; x < (long) evaluate_image->columns; x++)
535 q->red=ClampToQuantum(evaluate_pixel[x].red);
536 q->green=ClampToQuantum(evaluate_pixel[x].green);
537 q->blue=ClampToQuantum(evaluate_pixel[x].blue);
538 if (evaluate_image->matte == MagickFalse)
539 q->opacity=ClampToQuantum(evaluate_pixel[x].opacity);
541 q->opacity=ClampToQuantum(QuantumRange-evaluate_pixel[x].opacity);
542 if (evaluate_image->colorspace == CMYKColorspace)
543 evaluate_indexes[x]=ClampToQuantum(evaluate_pixel[x].index);
546 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
548 if (images->progress_monitor != (MagickProgressMonitor) NULL)
553 #if defined(MAGICKCORE_OPENMP_SUPPORT)
554 #pragma omp critical (MagickCore_EvaluateImages)
556 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
557 evaluate_image->rows);
558 if (proceed == MagickFalse)
562 evaluate_view=DestroyCacheView(evaluate_view);
563 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
564 random_info=DestroyRandomInfoThreadSet(random_info);
565 if (status == MagickFalse)
566 evaluate_image=DestroyImage(evaluate_image);
567 return(evaluate_image);
570 MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
571 const ChannelType channel,const MagickEvaluateOperator op,const double value,
572 ExceptionInfo *exception)
585 **restrict random_info;
587 assert(image != (Image *) NULL);
588 assert(image->signature == MagickSignature);
589 if (image->debug != MagickFalse)
590 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
591 assert(exception != (ExceptionInfo *) NULL);
592 assert(exception->signature == MagickSignature);
593 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
595 InheritException(exception,&image->exception);
600 random_info=AcquireRandomInfoThreadSet();
601 image_view=AcquireCacheView(image);
602 #if defined(MAGICKCORE_OPENMP_SUPPORT)
603 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
605 for (y=0; y < (long) image->rows; y++)
617 if (status == MagickFalse)
619 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
620 if (q == (PixelPacket *) NULL)
625 indexes=GetCacheViewAuthenticIndexQueue(image_view);
626 id=GetOpenMPThreadId();
627 for (x=0; x < (long) image->columns; x++)
629 if ((channel & RedChannel) != 0)
630 q->red=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->red,op,
632 if ((channel & GreenChannel) != 0)
633 q->green=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->green,
635 if ((channel & BlueChannel) != 0)
636 q->blue=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->blue,op,
638 if ((channel & OpacityChannel) != 0)
640 if (image->matte == MagickFalse)
641 q->opacity=ClampToQuantum(ApplyEvaluateOperator(random_info[id],
642 q->opacity,op,value));
644 q->opacity=ClampToQuantum(QuantumRange-ApplyEvaluateOperator(
645 random_info[id],(Quantum) GetAlphaPixelComponent(q),op,value));
647 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
648 indexes[x]=(IndexPacket) ClampToQuantum(ApplyEvaluateOperator(
649 random_info[id],indexes[x],op,value));
652 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
654 if (image->progress_monitor != (MagickProgressMonitor) NULL)
659 #if defined(MAGICKCORE_OPENMP_SUPPORT)
660 #pragma omp critical (MagickCore_EvaluateImageChannel)
662 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
663 if (proceed == MagickFalse)
667 image_view=DestroyCacheView(image_view);
668 random_info=DestroyRandomInfoThreadSet(random_info);
673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 % F u n c t i o n I m a g e %
681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 % FunctionImage() applies a value to the image with an arithmetic, relational,
684 % or logical operator to an image. Use these operations to lighten or darken
685 % an image, to increase or decrease contrast in an image, or to produce the
686 % "negative" of an image.
688 % The format of the FunctionImageChannel method is:
690 % MagickBooleanType FunctionImage(Image *image,
691 % const MagickFunction function,const long number_parameters,
692 % const double *parameters,ExceptionInfo *exception)
693 % MagickBooleanType FunctionImageChannel(Image *image,
694 % const ChannelType channel,const MagickFunction function,
695 % const long number_parameters,const double *argument,
696 % ExceptionInfo *exception)
698 % A description of each parameter follows:
700 % o image: the image.
702 % o channel: the channel.
704 % o function: A channel function.
706 % o parameters: one or more parameters.
708 % o exception: return any errors or warnings in this structure.
712 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
713 const unsigned long number_parameters,const double *parameters,
714 ExceptionInfo *exception)
726 case PolynomialFunction:
730 * Parameters: polynomial constants, highest to lowest order
731 * For example: c0*x^3 + c1*x^2 + c2*x + c3
734 for (i=0; i < (long) number_parameters; i++)
735 result = result*QuantumScale*pixel + parameters[i];
736 result *= QuantumRange;
739 case SinusoidFunction:
742 * Parameters: Freq, Phase, Ampl, bias
744 double freq,phase,ampl,bias;
745 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
746 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
747 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
748 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
749 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
750 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
755 /* Arcsin Function (peged at range limits for invalid results)
756 * Parameters: Width, Center, Range, Bias
758 double width,range,center,bias;
759 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
760 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
761 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
762 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
763 result = 2.0/width*(QuantumScale*pixel - center);
764 if ( result <= -1.0 )
765 result = bias - range/2.0;
766 else if ( result >= 1.0 )
767 result = bias + range/2.0;
769 result=range/MagickPI*asin((double)result) + bias;
770 result *= QuantumRange;
776 * Parameters: Slope, Center, Range, Bias
778 double slope,range,center,bias;
779 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
780 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
781 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
782 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
783 result = MagickPI*slope*(QuantumScale*pixel - center);
784 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
788 case UndefinedFunction:
791 return(ClampToQuantum(result));
794 MagickExport MagickBooleanType FunctionImage(Image *image,
795 const MagickFunction function,const unsigned long number_parameters,
796 const double *parameters,ExceptionInfo *exception)
801 status=FunctionImageChannel(image,AllChannels,function,number_parameters,
802 parameters,exception);
806 MagickExport MagickBooleanType FunctionImageChannel(Image *image,
807 const ChannelType channel,const MagickFunction function,
808 const unsigned long number_parameters,const double *parameters,
809 ExceptionInfo *exception)
811 #define FunctionImageTag "Function/Image "
823 assert(image != (Image *) NULL);
824 assert(image->signature == MagickSignature);
825 if (image->debug != MagickFalse)
826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
827 assert(exception != (ExceptionInfo *) NULL);
828 assert(exception->signature == MagickSignature);
829 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
831 InheritException(exception,&image->exception);
836 image_view=AcquireCacheView(image);
837 #if defined(MAGICKCORE_OPENMP_SUPPORT)
838 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
840 for (y=0; y < (long) image->rows; y++)
851 if (status == MagickFalse)
853 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
854 if (q == (PixelPacket *) NULL)
859 indexes=GetCacheViewAuthenticIndexQueue(image_view);
860 for (x=0; x < (long) image->columns; x++)
862 if ((channel & RedChannel) != 0)
863 q->red=ApplyFunction(q->red,function,number_parameters,parameters,
865 if ((channel & GreenChannel) != 0)
866 q->green=ApplyFunction(q->green,function,number_parameters,parameters,
868 if ((channel & BlueChannel) != 0)
869 q->blue=ApplyFunction(q->blue,function,number_parameters,parameters,
871 if ((channel & OpacityChannel) != 0)
873 if (image->matte == MagickFalse)
874 q->opacity=ApplyFunction(q->opacity,function,number_parameters,
875 parameters,exception);
877 q->opacity=(Quantum) QuantumRange-ApplyFunction((Quantum)
878 GetAlphaPixelComponent(q),function,number_parameters,parameters,
881 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
882 indexes[x]=(IndexPacket) ApplyFunction(indexes[x],function,
883 number_parameters,parameters,exception);
886 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
888 if (image->progress_monitor != (MagickProgressMonitor) NULL)
893 #if defined(MAGICKCORE_OPENMP_SUPPORT)
894 #pragma omp critical (MagickCore_FunctionImageChannel)
896 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
897 if (proceed == MagickFalse)
901 image_view=DestroyCacheView(image_view);
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 + G e t I m a g e C h a n n e l E x t r e m a %
914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 % GetImageChannelExtrema() returns the extrema of one or more image channels.
918 % The format of the GetImageChannelExtrema method is:
920 % MagickBooleanType GetImageChannelExtrema(const Image *image,
921 % const ChannelType channel,unsigned long *minima,unsigned long *maxima,
922 % ExceptionInfo *exception)
924 % A description of each parameter follows:
926 % o image: the image.
928 % o channel: the channel.
930 % o minima: the minimum value in the channel.
932 % o maxima: the maximum value in the channel.
934 % o exception: return any errors or warnings in this structure.
938 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
939 unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
941 return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
944 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
945 const ChannelType channel,unsigned long *minima,unsigned long *maxima,
946 ExceptionInfo *exception)
955 assert(image != (Image *) NULL);
956 assert(image->signature == MagickSignature);
957 if (image->debug != MagickFalse)
958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
959 status=GetImageChannelRange(image,channel,&min,&max,exception);
960 *minima=(unsigned long) ceil(min-0.5);
961 *maxima=(unsigned long) floor(max+0.5);
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970 % G e t I m a g e C h a n n e l M e a n %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 % GetImageChannelMean() returns the mean and standard deviation of one or more
979 % The format of the GetImageChannelMean method is:
981 % MagickBooleanType GetImageChannelMean(const Image *image,
982 % const ChannelType channel,double *mean,double *standard_deviation,
983 % ExceptionInfo *exception)
985 % A description of each parameter follows:
987 % o image: the image.
989 % o channel: the channel.
991 % o mean: the average value in the channel.
993 % o standard_deviation: the standard deviation of the channel.
995 % o exception: return any errors or warnings in this structure.
999 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1000 double *standard_deviation,ExceptionInfo *exception)
1005 status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
1010 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
1011 const ChannelType channel,double *mean,double *standard_deviation,
1012 ExceptionInfo *exception)
1020 assert(image != (Image *) NULL);
1021 assert(image->signature == MagickSignature);
1022 if (image->debug != MagickFalse)
1023 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1025 *standard_deviation=0.0;
1027 for (y=0; y < (long) image->rows; y++)
1029 register const IndexPacket
1032 register const PixelPacket
1038 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1039 if (p == (const PixelPacket *) NULL)
1041 indexes=GetVirtualIndexQueue(image);
1042 for (x=0; x < (long) image->columns; x++)
1044 if ((channel & RedChannel) != 0)
1046 *mean+=GetRedPixelComponent(p);
1047 *standard_deviation+=(double) p->red*GetRedPixelComponent(p);
1050 if ((channel & GreenChannel) != 0)
1052 *mean+=GetGreenPixelComponent(p);
1053 *standard_deviation+=(double) p->green*GetGreenPixelComponent(p);
1056 if ((channel & BlueChannel) != 0)
1058 *mean+=GetBluePixelComponent(p);
1059 *standard_deviation+=(double) p->blue*GetBluePixelComponent(p);
1062 if ((channel & OpacityChannel) != 0)
1064 *mean+=GetOpacityPixelComponent(p);
1065 *standard_deviation+=(double) p->opacity*GetOpacityPixelComponent(p);
1068 if (((channel & IndexChannel) != 0) &&
1069 (image->colorspace == CMYKColorspace))
1072 *standard_deviation+=(double) indexes[x]*indexes[x];
1078 if (y < (long) image->rows)
1079 return(MagickFalse);
1083 *standard_deviation/=area;
1085 *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
1086 return(y == (long) image->rows ? MagickTrue : MagickFalse);
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % G e t I m a g e C h a n n e l K u r t o s i s %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 % GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
1103 % The format of the GetImageChannelKurtosis method is:
1105 % MagickBooleanType GetImageChannelKurtosis(const Image *image,
1106 % const ChannelType channel,double *kurtosis,double *skewness,
1107 % ExceptionInfo *exception)
1109 % A description of each parameter follows:
1111 % o image: the image.
1113 % o channel: the channel.
1115 % o kurtosis: the kurtosis of the channel.
1117 % o skewness: the skewness of the channel.
1119 % o exception: return any errors or warnings in this structure.
1123 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1124 double *kurtosis,double *skewness,ExceptionInfo *exception)
1129 status=GetImageChannelKurtosis(image,AllChannels,kurtosis,skewness,
1134 MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
1135 const ChannelType channel,double *kurtosis,double *skewness,
1136 ExceptionInfo *exception)
1149 assert(image != (Image *) NULL);
1150 assert(image->signature == MagickSignature);
1151 if (image->debug != MagickFalse)
1152 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1157 standard_deviation=0.0;
1160 sum_fourth_power=0.0;
1161 for (y=0; y < (long) image->rows; y++)
1163 register const IndexPacket
1166 register const PixelPacket
1172 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1173 if (p == (const PixelPacket *) NULL)
1175 indexes=GetVirtualIndexQueue(image);
1176 for (x=0; x < (long) image->columns; x++)
1178 if ((channel & RedChannel) != 0)
1180 mean+=GetRedPixelComponent(p);
1181 sum_squares+=(double) p->red*GetRedPixelComponent(p);
1182 sum_cubes+=(double) p->red*p->red*GetRedPixelComponent(p);
1183 sum_fourth_power+=(double) p->red*p->red*p->red*
1184 GetRedPixelComponent(p);
1187 if ((channel & GreenChannel) != 0)
1189 mean+=GetGreenPixelComponent(p);
1190 sum_squares+=(double) p->green*GetGreenPixelComponent(p);
1191 sum_cubes+=(double) p->green*p->green*GetGreenPixelComponent(p);
1192 sum_fourth_power+=(double) p->green*p->green*p->green*
1193 GetGreenPixelComponent(p);
1196 if ((channel & BlueChannel) != 0)
1198 mean+=GetBluePixelComponent(p);
1199 sum_squares+=(double) p->blue*GetBluePixelComponent(p);
1200 sum_cubes+=(double) p->blue*p->blue*GetBluePixelComponent(p);
1201 sum_fourth_power+=(double) p->blue*p->blue*p->blue*
1202 GetBluePixelComponent(p);
1205 if ((channel & OpacityChannel) != 0)
1207 mean+=GetOpacityPixelComponent(p);
1208 sum_squares+=(double) p->opacity*GetOpacityPixelComponent(p);
1209 sum_cubes+=(double) p->opacity*p->opacity*GetOpacityPixelComponent(p);
1210 sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
1211 GetOpacityPixelComponent(p);
1214 if (((channel & IndexChannel) != 0) &&
1215 (image->colorspace == CMYKColorspace))
1218 sum_squares+=(double) indexes[x]*indexes[x];
1219 sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
1220 sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
1227 if (y < (long) image->rows)
1228 return(MagickFalse);
1234 sum_fourth_power/=area;
1236 standard_deviation=sqrt(sum_squares-(mean*mean));
1237 if (standard_deviation != 0.0)
1239 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1240 3.0*mean*mean*mean*mean;
1241 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1244 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1245 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1247 return(y == (long) image->rows ? MagickTrue : MagickFalse);
1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 % G e t I m a g e C h a n n e l R a n g e %
1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261 % GetImageChannelRange() returns the range of one or more image channels.
1263 % The format of the GetImageChannelRange method is:
1265 % MagickBooleanType GetImageChannelRange(const Image *image,
1266 % const ChannelType channel,double *minima,double *maxima,
1267 % ExceptionInfo *exception)
1269 % A description of each parameter follows:
1271 % o image: the image.
1273 % o channel: the channel.
1275 % o minima: the minimum value in the channel.
1277 % o maxima: the maximum value in the channel.
1279 % o exception: return any errors or warnings in this structure.
1283 MagickExport MagickBooleanType GetImageRange(const Image *image,
1284 double *minima,double *maxima,ExceptionInfo *exception)
1286 return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
1289 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
1290 const ChannelType channel,double *minima,double *maxima,
1291 ExceptionInfo *exception)
1299 assert(image != (Image *) NULL);
1300 assert(image->signature == MagickSignature);
1301 if (image->debug != MagickFalse)
1302 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1305 GetMagickPixelPacket(image,&pixel);
1306 for (y=0; y < (long) image->rows; y++)
1308 register const IndexPacket
1311 register const PixelPacket
1317 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1318 if (p == (const PixelPacket *) NULL)
1320 indexes=GetVirtualIndexQueue(image);
1321 for (x=0; x < (long) image->columns; x++)
1323 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1324 if ((channel & RedChannel) != 0)
1326 if (pixel.red < *minima)
1327 *minima=(double) pixel.red;
1328 if (pixel.red > *maxima)
1329 *maxima=(double) pixel.red;
1331 if ((channel & GreenChannel) != 0)
1333 if (pixel.green < *minima)
1334 *minima=(double) pixel.green;
1335 if (pixel.green > *maxima)
1336 *maxima=(double) pixel.green;
1338 if ((channel & BlueChannel) != 0)
1340 if (pixel.blue < *minima)
1341 *minima=(double) pixel.blue;
1342 if (pixel.blue > *maxima)
1343 *maxima=(double) pixel.blue;
1345 if ((channel & OpacityChannel) != 0)
1347 if (pixel.opacity < *minima)
1348 *minima=(double) pixel.opacity;
1349 if (pixel.opacity > *maxima)
1350 *maxima=(double) pixel.opacity;
1352 if (((channel & IndexChannel) != 0) &&
1353 (image->colorspace == CMYKColorspace))
1355 if ((double) indexes[x] < *minima)
1356 *minima=(double) indexes[x];
1357 if ((double) indexes[x] > *maxima)
1358 *maxima=(double) indexes[x];
1363 return(y == (long) image->rows ? MagickTrue : MagickFalse);
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371 % 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 %
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % GetImageChannelStatistics() returns statistics for each channel in the
1378 % image. The statistics include the channel depth, its minima, maxima, mean,
1379 % standard deviation, kurtosis and skewness. You can access the red channel
1380 % mean, for example, like this:
1382 % channel_statistics=GetImageChannelStatistics(image,excepton);
1383 % red_mean=channel_statistics[RedChannel].mean;
1385 % Use MagickRelinquishMemory() to free the statistics buffer.
1387 % The format of the GetImageChannelStatistics method is:
1389 % ChannelStatistics *GetImageChannelStatistics(const Image *image,
1390 % ExceptionInfo *exception)
1392 % A description of each parameter follows:
1394 % o image: the image.
1396 % o exception: return any errors or warnings in this structure.
1399 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
1400 ExceptionInfo *exception)
1403 *channel_statistics;
1429 assert(image != (Image *) NULL);
1430 assert(image->signature == MagickSignature);
1431 if (image->debug != MagickFalse)
1432 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1433 length=AllChannels+1UL;
1434 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1435 sizeof(*channel_statistics));
1436 if (channel_statistics == (ChannelStatistics *) NULL)
1437 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1438 (void) ResetMagickMemory(channel_statistics,0,length*
1439 sizeof(*channel_statistics));
1440 for (i=0; i <= AllChannels; i++)
1442 channel_statistics[i].depth=1;
1443 channel_statistics[i].maxima=(-1.0E-37);
1444 channel_statistics[i].minima=1.0E+37;
1445 channel_statistics[i].mean=0.0;
1446 channel_statistics[i].standard_deviation=0.0;
1447 channel_statistics[i].kurtosis=0.0;
1448 channel_statistics[i].skewness=0.0;
1450 for (y=0; y < (long) image->rows; y++)
1452 register const IndexPacket
1455 register const PixelPacket
1461 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1462 if (p == (const PixelPacket *) NULL)
1464 indexes=GetVirtualIndexQueue(image);
1465 for (x=0; x < (long) image->columns; )
1467 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1469 depth=channel_statistics[RedChannel].depth;
1470 range=GetQuantumRange(depth);
1471 status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
1472 range) ? MagickTrue : MagickFalse;
1473 if (status != MagickFalse)
1475 channel_statistics[RedChannel].depth++;
1479 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1481 depth=channel_statistics[GreenChannel].depth;
1482 range=GetQuantumRange(depth);
1483 status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
1484 range),range) ? MagickTrue : MagickFalse;
1485 if (status != MagickFalse)
1487 channel_statistics[GreenChannel].depth++;
1491 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1493 depth=channel_statistics[BlueChannel].depth;
1494 range=GetQuantumRange(depth);
1495 status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
1496 range),range) ? MagickTrue : MagickFalse;
1497 if (status != MagickFalse)
1499 channel_statistics[BlueChannel].depth++;
1503 if (image->matte != MagickFalse)
1505 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1507 depth=channel_statistics[OpacityChannel].depth;
1508 range=GetQuantumRange(depth);
1509 status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
1510 p->opacity,range),range) ? MagickTrue : MagickFalse;
1511 if (status != MagickFalse)
1513 channel_statistics[OpacityChannel].depth++;
1518 if (image->colorspace == CMYKColorspace)
1520 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1522 depth=channel_statistics[BlackChannel].depth;
1523 range=GetQuantumRange(depth);
1524 status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
1525 indexes[x],range),range) ? MagickTrue : MagickFalse;
1526 if (status != MagickFalse)
1528 channel_statistics[BlackChannel].depth++;
1533 if ((double) p->red < channel_statistics[RedChannel].minima)
1534 channel_statistics[RedChannel].minima=(double) GetRedPixelComponent(p);
1535 if ((double) p->red > channel_statistics[RedChannel].maxima)
1536 channel_statistics[RedChannel].maxima=(double) GetRedPixelComponent(p);
1537 channel_statistics[RedChannel].mean+=GetRedPixelComponent(p);
1538 channel_statistics[RedChannel].standard_deviation+=(double) p->red*
1539 GetRedPixelComponent(p);
1540 channel_statistics[RedChannel].kurtosis+=(double) p->red*p->red*
1541 p->red*GetRedPixelComponent(p);
1542 channel_statistics[RedChannel].skewness+=(double) p->red*p->red*
1543 GetRedPixelComponent(p);
1544 if ((double) p->green < channel_statistics[GreenChannel].minima)
1545 channel_statistics[GreenChannel].minima=(double)
1546 GetGreenPixelComponent(p);
1547 if ((double) p->green > channel_statistics[GreenChannel].maxima)
1548 channel_statistics[GreenChannel].maxima=(double)
1549 GetGreenPixelComponent(p);
1550 channel_statistics[GreenChannel].mean+=GetGreenPixelComponent(p);
1551 channel_statistics[GreenChannel].standard_deviation+=(double) p->green*
1552 GetGreenPixelComponent(p);
1553 channel_statistics[GreenChannel].kurtosis+=(double) p->green*p->green*
1554 p->green*GetGreenPixelComponent(p);
1555 channel_statistics[GreenChannel].skewness+=(double) p->green*p->green*
1556 GetGreenPixelComponent(p);
1557 if ((double) p->blue < channel_statistics[BlueChannel].minima)
1558 channel_statistics[BlueChannel].minima=(double)
1559 GetBluePixelComponent(p);
1560 if ((double) p->blue > channel_statistics[BlueChannel].maxima)
1561 channel_statistics[BlueChannel].maxima=(double)
1562 GetBluePixelComponent(p);
1563 channel_statistics[BlueChannel].mean+=GetBluePixelComponent(p);
1564 channel_statistics[BlueChannel].standard_deviation+=(double) p->blue*
1565 GetBluePixelComponent(p);
1566 channel_statistics[BlueChannel].kurtosis+=(double) p->blue*p->blue*
1567 p->blue*GetBluePixelComponent(p);
1568 channel_statistics[BlueChannel].skewness+=(double) p->blue*p->blue*
1569 GetBluePixelComponent(p);
1570 if (image->matte != MagickFalse)
1572 if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
1573 channel_statistics[OpacityChannel].minima=(double)
1574 GetOpacityPixelComponent(p);
1575 if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
1576 channel_statistics[OpacityChannel].maxima=(double)
1577 GetOpacityPixelComponent(p);
1578 channel_statistics[OpacityChannel].mean+=GetOpacityPixelComponent(p);
1579 channel_statistics[OpacityChannel].standard_deviation+=(double)
1580 p->opacity*GetOpacityPixelComponent(p);
1581 channel_statistics[OpacityChannel].kurtosis+=(double) p->opacity*
1582 p->opacity*p->opacity*GetOpacityPixelComponent(p);
1583 channel_statistics[OpacityChannel].skewness+=(double) p->opacity*
1584 p->opacity*GetOpacityPixelComponent(p);
1586 if (image->colorspace == CMYKColorspace)
1588 if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
1589 channel_statistics[BlackChannel].minima=(double) indexes[x];
1590 if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
1591 channel_statistics[BlackChannel].maxima=(double) indexes[x];
1592 channel_statistics[BlackChannel].mean+=indexes[x];
1593 channel_statistics[BlackChannel].standard_deviation+=(double)
1594 indexes[x]*indexes[x];
1595 channel_statistics[BlackChannel].kurtosis+=(double) indexes[x]*
1596 indexes[x]*indexes[x]*indexes[x];
1597 channel_statistics[BlackChannel].skewness+=(double) indexes[x]*
1598 indexes[x]*indexes[x];
1604 area=(double) image->columns*image->rows;
1605 for (i=0; i < AllChannels; i++)
1607 channel_statistics[i].mean/=area;
1608 channel_statistics[i].standard_deviation/=area;
1609 channel_statistics[i].kurtosis/=area;
1610 channel_statistics[i].skewness/=area;
1612 for (i=0; i < AllChannels; i++)
1614 channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double)
1615 channel_statistics[AllChannels].depth,(double)
1616 channel_statistics[i].depth);
1617 channel_statistics[AllChannels].minima=MagickMin(
1618 channel_statistics[AllChannels].minima,channel_statistics[i].minima);
1619 channel_statistics[AllChannels].maxima=MagickMax(
1620 channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
1621 channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
1622 channel_statistics[AllChannels].standard_deviation+=
1623 channel_statistics[i].standard_deviation;
1624 channel_statistics[AllChannels].kurtosis+=channel_statistics[i].kurtosis;
1625 channel_statistics[AllChannels].skewness+=channel_statistics[i].skewness;
1628 if (image->colorspace == CMYKColorspace)
1630 channel_statistics[AllChannels].mean/=channels;
1631 channel_statistics[AllChannels].standard_deviation/=channels;
1632 channel_statistics[AllChannels].kurtosis/=channels;
1633 channel_statistics[AllChannels].skewness/=channels;
1634 for (i=0; i <= AllChannels; i++)
1637 sum_squares=channel_statistics[i].standard_deviation;
1639 sum_cubes=channel_statistics[i].skewness;
1640 channel_statistics[i].standard_deviation=sqrt(
1641 channel_statistics[i].standard_deviation-
1642 (channel_statistics[i].mean*channel_statistics[i].mean));
1643 if (channel_statistics[i].standard_deviation == 0.0)
1645 channel_statistics[i].kurtosis=0.0;
1646 channel_statistics[i].skewness=0.0;
1650 channel_statistics[i].skewness=(channel_statistics[i].skewness-
1651 3.0*channel_statistics[i].mean*sum_squares+
1652 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1653 channel_statistics[i].mean)/
1654 (channel_statistics[i].standard_deviation*
1655 channel_statistics[i].standard_deviation*
1656 channel_statistics[i].standard_deviation);
1657 channel_statistics[i].kurtosis=(channel_statistics[i].kurtosis-
1658 4.0*channel_statistics[i].mean*sum_cubes+
1659 6.0*channel_statistics[i].mean*channel_statistics[i].mean*sum_squares-
1660 3.0*channel_statistics[i].mean*channel_statistics[i].mean*
1661 1.0*channel_statistics[i].mean*channel_statistics[i].mean)/
1662 (channel_statistics[i].standard_deviation*
1663 channel_statistics[i].standard_deviation*
1664 channel_statistics[i].standard_deviation*
1665 channel_statistics[i].standard_deviation)-3.0;
1668 return(channel_statistics);