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-2011 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/geometry.h"
67 #include "MagickCore/list.h"
68 #include "MagickCore/image-private.h"
69 #include "MagickCore/magic.h"
70 #include "MagickCore/magick.h"
71 #include "MagickCore/memory_.h"
72 #include "MagickCore/module.h"
73 #include "MagickCore/monitor.h"
74 #include "MagickCore/monitor-private.h"
75 #include "MagickCore/option.h"
76 #include "MagickCore/paint.h"
77 #include "MagickCore/pixel-accessor.h"
78 #include "MagickCore/profile.h"
79 #include "MagickCore/quantize.h"
80 #include "MagickCore/quantum-private.h"
81 #include "MagickCore/random_.h"
82 #include "MagickCore/random-private.h"
83 #include "MagickCore/segment.h"
84 #include "MagickCore/semaphore.h"
85 #include "MagickCore/signature-private.h"
86 #include "MagickCore/statistic.h"
87 #include "MagickCore/string_.h"
88 #include "MagickCore/thread-private.h"
89 #include "MagickCore/timer.h"
90 #include "MagickCore/utility.h"
91 #include "MagickCore/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 EvaluateImage 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)
118 % A description of each parameter follows:
120 % o image: the image.
122 % o op: A channel op.
124 % o value: A value value.
126 % o exception: return any errors or warnings in this structure.
130 static PixelInfo **DestroyPixelThreadSet(PixelInfo **pixels)
135 assert(pixels != (PixelInfo **) NULL);
136 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
137 if (pixels[i] != (PixelInfo *) NULL)
138 pixels[i]=(PixelInfo *) RelinquishMagickMemory(pixels[i]);
139 pixels=(PixelInfo **) RelinquishMagickMemory(pixels);
143 static PixelInfo **AcquirePixelThreadSet(const Image *image,
144 const size_t number_images)
157 number_threads=GetOpenMPMaximumThreads();
158 pixels=(PixelInfo **) AcquireQuantumMemory(number_threads,
160 if (pixels == (PixelInfo **) NULL)
161 return((PixelInfo **) NULL);
162 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
163 for (i=0; i < (ssize_t) number_threads; i++)
165 length=image->columns;
166 if (length < number_images)
167 length=number_images;
168 pixels[i]=(PixelInfo *) AcquireQuantumMemory(length,
170 if (pixels[i] == (PixelInfo *) NULL)
171 return(DestroyPixelThreadSet(pixels));
172 for (j=0; j < (ssize_t) length; j++)
173 GetPixelInfo(image,&pixels[i][j]);
178 static inline double MagickMax(const double x,const double y)
185 #if defined(__cplusplus) || defined(c_plusplus)
189 static int IntensityCompare(const void *x,const void *y)
198 color_1=(const PixelInfo *) x;
199 color_2=(const PixelInfo *) y;
200 intensity=(int) GetPixelInfoIntensity(color_2)-(int)
201 GetPixelInfoIntensity(color_1);
205 #if defined(__cplusplus) || defined(c_plusplus)
209 static inline double MagickMin(const double x,const double y)
216 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
217 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
225 case UndefinedEvaluateOperator:
227 case AbsEvaluateOperator:
229 result=(MagickRealType) fabs((double) (pixel+value));
232 case AddEvaluateOperator:
234 result=(MagickRealType) (pixel+value);
237 case AddModulusEvaluateOperator:
240 This returns a 'floored modulus' of the addition which is a
241 positive result. It differs from % or fmod() which returns a
242 'truncated modulus' result, where floor() is replaced by trunc()
243 and could return a negative result (which is clipped).
246 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
249 case AndEvaluateOperator:
251 result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
254 case CosineEvaluateOperator:
256 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
257 QuantumScale*pixel*value))+0.5));
260 case DivideEvaluateOperator:
262 result=pixel/(value == 0.0 ? 1.0 : value);
265 case ExponentialEvaluateOperator:
267 result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
271 case GaussianNoiseEvaluateOperator:
273 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
274 GaussianNoise,value);
277 case ImpulseNoiseEvaluateOperator:
279 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
283 case LaplacianNoiseEvaluateOperator:
285 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
286 LaplacianNoise,value);
289 case LeftShiftEvaluateOperator:
291 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
294 case LogEvaluateOperator:
296 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
297 pixel+1.0))/log((double) (value+1.0)));
300 case MaxEvaluateOperator:
302 result=(MagickRealType) MagickMax((double) pixel,value);
305 case MeanEvaluateOperator:
307 result=(MagickRealType) (pixel+value);
310 case MedianEvaluateOperator:
312 result=(MagickRealType) (pixel+value);
315 case MinEvaluateOperator:
317 result=(MagickRealType) MagickMin((double) pixel,value);
320 case MultiplicativeNoiseEvaluateOperator:
322 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
323 MultiplicativeGaussianNoise,value);
326 case MultiplyEvaluateOperator:
328 result=(MagickRealType) (value*pixel);
331 case OrEvaluateOperator:
333 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
336 case PoissonNoiseEvaluateOperator:
338 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
342 case PowEvaluateOperator:
344 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
348 case RightShiftEvaluateOperator:
350 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
353 case SetEvaluateOperator:
358 case SineEvaluateOperator:
360 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
361 QuantumScale*pixel*value))+0.5));
364 case SubtractEvaluateOperator:
366 result=(MagickRealType) (pixel-value);
369 case ThresholdEvaluateOperator:
371 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
375 case ThresholdBlackEvaluateOperator:
377 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
380 case ThresholdWhiteEvaluateOperator:
382 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
386 case UniformNoiseEvaluateOperator:
388 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
392 case XorEvaluateOperator:
394 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
401 MagickExport Image *EvaluateImages(const Image *images,
402 const MagickEvaluateOperator op,ExceptionInfo *exception)
404 #define EvaluateImageTag "Evaluate/Image"
422 **restrict evaluate_pixels,
426 **restrict random_info;
435 Ensure the image are the same size.
437 assert(images != (Image *) NULL);
438 assert(images->signature == MagickSignature);
439 if (images->debug != MagickFalse)
440 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
441 assert(exception != (ExceptionInfo *) NULL);
442 assert(exception->signature == MagickSignature);
443 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
444 if ((next->columns != images->columns) || (next->rows != images->rows))
446 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
447 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
448 return((Image *) NULL);
451 Initialize evaluate next attributes.
453 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
455 if (evaluate_image == (Image *) NULL)
456 return((Image *) NULL);
457 if (SetImageStorageClass(evaluate_image,DirectClass,exception) == MagickFalse)
459 evaluate_image=DestroyImage(evaluate_image);
460 return((Image *) NULL);
462 number_images=GetImageListLength(images);
463 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
464 if (evaluate_pixels == (PixelInfo **) NULL)
466 evaluate_image=DestroyImage(evaluate_image);
467 (void) ThrowMagickException(exception,GetMagickModule(),
468 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
469 return((Image *) NULL);
472 Evaluate image pixels.
476 GetPixelInfo(images,&zero);
477 random_info=AcquireRandomInfoThreadSet();
478 evaluate_view=AcquireCacheView(evaluate_image);
479 if (op == MedianEvaluateOperator)
480 #if defined(MAGICKCORE_OPENMP_SUPPORT)
481 #pragma omp parallel for schedule(dynamic) shared(progress,status)
483 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
492 id = GetOpenMPThreadId();
503 if (status == MagickFalse)
505 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
507 if (q == (const Quantum *) NULL)
512 evaluate_pixel=evaluate_pixels[id];
513 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
518 for (i=0; i < (ssize_t) number_images; i++)
519 evaluate_pixel[i]=zero;
521 for (i=0; i < (ssize_t) number_images; i++)
523 register const Quantum
526 image_view=AcquireCacheView(next);
527 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
528 if (p == (const Quantum *) NULL)
530 image_view=DestroyCacheView(image_view);
533 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[id],
534 GetPixelRed(next,p),op,evaluate_pixel[i].red);
535 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[id],
536 GetPixelGreen(next,p),op,evaluate_pixel[i].green);
537 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[id],
538 GetPixelBlue(next,p),op,evaluate_pixel[i].blue);
539 if (evaluate_image->colorspace == CMYKColorspace)
540 evaluate_pixel[i].black=ApplyEvaluateOperator(random_info[id],
541 GetPixelBlack(next,p),op,evaluate_pixel[i].black);
542 evaluate_pixel[i].alpha=ApplyEvaluateOperator(random_info[id],
543 GetPixelAlpha(next,p),op,evaluate_pixel[i].alpha);
544 image_view=DestroyCacheView(image_view);
545 next=GetNextImageInList(next);
547 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
549 SetPixelRed(evaluate_image,
550 ClampToQuantum(evaluate_pixel[i/2].red),q);
551 SetPixelGreen(evaluate_image,
552 ClampToQuantum(evaluate_pixel[i/2].green),q);
553 SetPixelBlue(evaluate_image,
554 ClampToQuantum(evaluate_pixel[i/2].blue),q);
555 if (evaluate_image->colorspace == CMYKColorspace)
556 SetPixelBlack(evaluate_image,
557 ClampToQuantum(evaluate_pixel[i/2].black),q);
558 if (evaluate_image->matte == MagickFalse)
559 SetPixelAlpha(evaluate_image,
560 ClampToQuantum(evaluate_pixel[i/2].alpha),q);
562 SetPixelAlpha(evaluate_image,
563 ClampToQuantum(evaluate_pixel[i/2].alpha),q);
564 q+=GetPixelChannels(evaluate_image);
566 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
568 if (images->progress_monitor != (MagickProgressMonitor) NULL)
573 #if defined(MAGICKCORE_OPENMP_SUPPORT)
574 #pragma omp critical (MagickCore_EvaluateImages)
576 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
577 evaluate_image->rows);
578 if (proceed == MagickFalse)
583 #if defined(MAGICKCORE_OPENMP_SUPPORT)
584 #pragma omp parallel for schedule(dynamic) shared(progress,status)
586 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
595 id = GetOpenMPThreadId();
607 if (status == MagickFalse)
609 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
611 if (q == (const Quantum *) NULL)
616 evaluate_pixel=evaluate_pixels[id];
617 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
618 evaluate_pixel[x]=zero;
620 for (i=0; i < (ssize_t) number_images; i++)
622 register const Quantum
625 image_view=AcquireCacheView(next);
626 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
627 if (p == (const Quantum *) NULL)
629 image_view=DestroyCacheView(image_view);
632 for (x=0; x < (ssize_t) next->columns; x++)
634 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],
635 GetPixelRed(next,p),i == 0 ? AddEvaluateOperator : op,
636 evaluate_pixel[x].red);
637 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],
638 GetPixelGreen(next,p),i == 0 ? AddEvaluateOperator : op,
639 evaluate_pixel[x].green);
640 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],
641 GetPixelBlue(next,p),i == 0 ? AddEvaluateOperator : op,
642 evaluate_pixel[x].blue);
643 if (evaluate_image->colorspace == CMYKColorspace)
644 evaluate_pixel[x].black=ApplyEvaluateOperator(random_info[id],
645 GetPixelBlack(next,p),i == 0 ? AddEvaluateOperator : op,
646 evaluate_pixel[x].black);
647 evaluate_pixel[x].alpha=ApplyEvaluateOperator(random_info[id],
648 GetPixelAlpha(next,p),i == 0 ? AddEvaluateOperator : op,
649 evaluate_pixel[x].alpha);
650 p+=GetPixelChannels(next);
652 image_view=DestroyCacheView(image_view);
653 next=GetNextImageInList(next);
655 if (op == MeanEvaluateOperator)
656 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
658 evaluate_pixel[x].red/=number_images;
659 evaluate_pixel[x].green/=number_images;
660 evaluate_pixel[x].blue/=number_images;
661 evaluate_pixel[x].black/=number_images;
662 evaluate_pixel[x].alpha/=number_images;
664 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
666 SetPixelRed(evaluate_image,ClampToQuantum(evaluate_pixel[x].red),q);
667 SetPixelGreen(evaluate_image,ClampToQuantum(evaluate_pixel[x].green),q);
668 SetPixelBlue(evaluate_image,ClampToQuantum(evaluate_pixel[x].blue),q);
669 if (evaluate_image->colorspace == CMYKColorspace)
670 SetPixelBlack(evaluate_image,ClampToQuantum(evaluate_pixel[x].black),
672 if (evaluate_image->matte == MagickFalse)
673 SetPixelAlpha(evaluate_image,ClampToQuantum(evaluate_pixel[x].alpha),
676 SetPixelAlpha(evaluate_image,ClampToQuantum(evaluate_pixel[x].alpha),
678 q+=GetPixelChannels(evaluate_image);
680 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
682 if (images->progress_monitor != (MagickProgressMonitor) NULL)
687 #if defined(MAGICKCORE_OPENMP_SUPPORT)
688 #pragma omp critical (MagickCore_EvaluateImages)
690 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
691 evaluate_image->rows);
692 if (proceed == MagickFalse)
696 evaluate_view=DestroyCacheView(evaluate_view);
697 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
698 random_info=DestroyRandomInfoThreadSet(random_info);
699 if (status == MagickFalse)
700 evaluate_image=DestroyImage(evaluate_image);
701 return(evaluate_image);
704 MagickExport MagickBooleanType EvaluateImage(Image *image,
705 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
717 **restrict random_info;
722 assert(image != (Image *) NULL);
723 assert(image->signature == MagickSignature);
724 if (image->debug != MagickFalse)
725 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
726 assert(exception != (ExceptionInfo *) NULL);
727 assert(exception->signature == MagickSignature);
728 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
732 random_info=AcquireRandomInfoThreadSet();
733 image_view=AcquireCacheView(image);
734 #if defined(MAGICKCORE_OPENMP_SUPPORT)
735 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
737 for (y=0; y < (ssize_t) image->rows; y++)
740 id = GetOpenMPThreadId();
748 if (status == MagickFalse)
750 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
751 if (q == (const Quantum *) NULL)
756 for (x=0; x < (ssize_t) image->columns; x++)
758 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
759 SetPixelRed(image,ClampToQuantum(ApplyEvaluateOperator(
760 random_info[id],GetPixelRed(image,q),op,value)),q);
761 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
762 SetPixelGreen(image,ClampToQuantum(ApplyEvaluateOperator(
763 random_info[id],GetPixelGreen(image,q),op,value)),q);
764 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
765 SetPixelBlue(image,ClampToQuantum(ApplyEvaluateOperator(
766 random_info[id],GetPixelBlue(image,q),op,value)),q);
767 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
768 (image->colorspace == CMYKColorspace))
769 SetPixelBlack(image,ClampToQuantum(ApplyEvaluateOperator(
770 random_info[id],GetPixelBlack(image,q),op,value)),q);
771 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
773 if (image->matte == MagickFalse)
774 SetPixelAlpha(image,ClampToQuantum(ApplyEvaluateOperator(
775 random_info[id],GetPixelAlpha(image,q),op,value)),q);
777 SetPixelAlpha(image,ClampToQuantum(ApplyEvaluateOperator(
778 random_info[id],GetPixelAlpha(image,q),op,value)),q);
780 q+=GetPixelChannels(image);
782 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
784 if (image->progress_monitor != (MagickProgressMonitor) NULL)
789 #if defined(MAGICKCORE_OPENMP_SUPPORT)
790 #pragma omp critical (MagickCore_EvaluateImage)
792 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
793 if (proceed == MagickFalse)
797 image_view=DestroyCacheView(image_view);
798 random_info=DestroyRandomInfoThreadSet(random_info);
803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 % F u n c t i o n I m a g e %
811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 % FunctionImage() applies a value to the image with an arithmetic, relational,
814 % or logical operator to an image. Use these operations to lighten or darken
815 % an image, to increase or decrease contrast in an image, or to produce the
816 % "negative" of an image.
818 % The format of the FunctionImage method is:
820 % MagickBooleanType FunctionImage(Image *image,
821 % const MagickFunction function,const ssize_t number_parameters,
822 % const double *parameters,ExceptionInfo *exception)
824 % A description of each parameter follows:
826 % o image: the image.
828 % o function: A channel function.
830 % o parameters: one or more parameters.
832 % o exception: return any errors or warnings in this structure.
836 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
837 const size_t number_parameters,const double *parameters,
838 ExceptionInfo *exception)
850 case PolynomialFunction:
854 * Parameters: polynomial constants, highest to lowest order
855 * For example: c0*x^3 + c1*x^2 + c2*x + c3
858 for (i=0; i < (ssize_t) number_parameters; i++)
859 result = result*QuantumScale*pixel + parameters[i];
860 result *= QuantumRange;
863 case SinusoidFunction:
866 * Parameters: Freq, Phase, Ampl, bias
868 double freq,phase,ampl,bias;
869 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
870 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
871 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
872 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
873 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
874 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
879 /* Arcsin Function (peged at range limits for invalid results)
880 * Parameters: Width, Center, Range, Bias
882 double width,range,center,bias;
883 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
884 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
885 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
886 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
887 result = 2.0/width*(QuantumScale*pixel - center);
888 if ( result <= -1.0 )
889 result = bias - range/2.0;
890 else if ( result >= 1.0 )
891 result = bias + range/2.0;
893 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
894 result *= QuantumRange;
900 * Parameters: Slope, Center, Range, Bias
902 double slope,range,center,bias;
903 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
904 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
905 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
906 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
907 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
908 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
912 case UndefinedFunction:
915 return(ClampToQuantum(result));
918 MagickExport MagickBooleanType FunctionImage(Image *image,
919 const MagickFunction function,const size_t number_parameters,
920 const double *parameters,ExceptionInfo *exception)
922 #define FunctionImageTag "Function/Image "
936 assert(image != (Image *) NULL);
937 assert(image->signature == MagickSignature);
938 if (image->debug != MagickFalse)
939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
940 assert(exception != (ExceptionInfo *) NULL);
941 assert(exception->signature == MagickSignature);
942 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
946 image_view=AcquireCacheView(image);
947 #if defined(MAGICKCORE_OPENMP_SUPPORT)
948 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
950 for (y=0; y < (ssize_t) image->rows; y++)
958 if (status == MagickFalse)
960 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
961 if (q == (const Quantum *) NULL)
966 for (x=0; x < (ssize_t) image->columns; x++)
968 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
969 SetPixelRed(image,ApplyFunction(GetPixelRed(image,q),function,
970 number_parameters,parameters,exception),q);
971 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
972 SetPixelGreen(image,ApplyFunction(GetPixelGreen(image,q),function,
973 number_parameters,parameters,exception),q);
974 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
975 SetPixelBlue(image,ApplyFunction(GetPixelBlue(image,q),function,
976 number_parameters,parameters,exception),q);
977 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
978 (image->colorspace == CMYKColorspace))
979 SetPixelBlack(image,ApplyFunction(GetPixelBlack(image,q),function,
980 number_parameters,parameters,exception),q);
981 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
983 if (image->matte == MagickFalse)
984 SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
985 number_parameters,parameters,exception),q);
987 SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
988 number_parameters,parameters,exception),q);
990 q+=GetPixelChannels(image);
992 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
994 if (image->progress_monitor != (MagickProgressMonitor) NULL)
999 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1000 #pragma omp critical (MagickCore_FunctionImage)
1002 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1003 if (proceed == MagickFalse)
1007 image_view=DestroyCacheView(image_view);
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % G e t I m a g e E x t r e m a %
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 % GetImageExtrema() returns the extrema of one or more image channels.
1024 % The format of the GetImageExtrema method is:
1026 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1027 % size_t *maxima,ExceptionInfo *exception)
1029 % A description of each parameter follows:
1031 % o image: the image.
1033 % o minima: the minimum value in the channel.
1035 % o maxima: the maximum value in the channel.
1037 % o exception: return any errors or warnings in this structure.
1040 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1041 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1050 assert(image != (Image *) NULL);
1051 assert(image->signature == MagickSignature);
1052 if (image->debug != MagickFalse)
1053 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1054 status=GetImageRange(image,&min,&max,exception);
1055 *minima=(size_t) ceil(min-0.5);
1056 *maxima=(size_t) floor(max+0.5);
1061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065 % G e t I m a g e M e a n %
1069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071 % GetImageMean() returns the mean and standard deviation of one or more
1074 % The format of the GetImageMean method is:
1076 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1077 % double *standard_deviation,ExceptionInfo *exception)
1079 % A description of each parameter follows:
1081 % o image: the image.
1083 % o mean: the average value in the channel.
1085 % o standard_deviation: the standard deviation of the channel.
1087 % o exception: return any errors or warnings in this structure.
1090 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1091 double *standard_deviation,ExceptionInfo *exception)
1094 *channel_statistics;
1099 assert(image != (Image *) NULL);
1100 assert(image->signature == MagickSignature);
1101 if (image->debug != MagickFalse)
1102 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1103 channel_statistics=GetImageStatistics(image,exception);
1104 if (channel_statistics == (ChannelStatistics *) NULL)
1105 return(MagickFalse);
1107 channel_statistics[CompositeChannels].mean=0.0;
1108 channel_statistics[CompositeChannels].standard_deviation=0.0;
1109 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1111 channel_statistics[CompositeChannels].mean+=
1112 channel_statistics[RedChannel].mean;
1113 channel_statistics[CompositeChannels].standard_deviation+=
1114 channel_statistics[RedChannel].variance-
1115 channel_statistics[RedChannel].mean*
1116 channel_statistics[RedChannel].mean;
1119 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1121 channel_statistics[CompositeChannels].mean+=
1122 channel_statistics[GreenChannel].mean;
1123 channel_statistics[CompositeChannels].standard_deviation+=
1124 channel_statistics[GreenChannel].variance-
1125 channel_statistics[GreenChannel].mean*
1126 channel_statistics[GreenChannel].mean;
1129 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1131 channel_statistics[CompositeChannels].mean+=
1132 channel_statistics[BlueChannel].mean;
1133 channel_statistics[CompositeChannels].standard_deviation+=
1134 channel_statistics[BlueChannel].variance-
1135 channel_statistics[BlueChannel].mean*
1136 channel_statistics[BlueChannel].mean;
1139 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1140 (image->colorspace == CMYKColorspace))
1142 channel_statistics[CompositeChannels].mean+=
1143 channel_statistics[BlackChannel].mean;
1144 channel_statistics[CompositeChannels].standard_deviation+=
1145 channel_statistics[BlackChannel].variance-
1146 channel_statistics[BlackChannel].mean*
1147 channel_statistics[BlackChannel].mean;
1150 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
1151 (image->matte != MagickFalse))
1153 channel_statistics[CompositeChannels].mean+=
1154 channel_statistics[AlphaChannel].mean;
1155 channel_statistics[CompositeChannels].standard_deviation+=
1156 channel_statistics[AlphaChannel].variance-
1157 channel_statistics[AlphaChannel].mean*
1158 channel_statistics[AlphaChannel].mean;
1161 channel_statistics[CompositeChannels].mean/=channels;
1162 channel_statistics[CompositeChannels].standard_deviation=
1163 sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
1164 *mean=channel_statistics[CompositeChannels].mean;
1165 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1166 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1167 channel_statistics);
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1176 % G e t I m a g e K u r t o s i s %
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1185 % The format of the GetImageKurtosis method is:
1187 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1188 % double *skewness,ExceptionInfo *exception)
1190 % A description of each parameter follows:
1192 % o image: the image.
1194 % o kurtosis: the kurtosis of the channel.
1196 % o skewness: the skewness of the channel.
1198 % o exception: return any errors or warnings in this structure.
1201 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1202 double *kurtosis,double *skewness,ExceptionInfo *exception)
1215 assert(image != (Image *) NULL);
1216 assert(image->signature == MagickSignature);
1217 if (image->debug != MagickFalse)
1218 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1223 standard_deviation=0.0;
1226 sum_fourth_power=0.0;
1227 for (y=0; y < (ssize_t) image->rows; y++)
1229 register const Quantum
1235 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1236 if (p == (const Quantum *) NULL)
1238 for (x=0; x < (ssize_t) image->columns; x++)
1240 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1242 mean+=GetPixelRed(image,p);
1243 sum_squares+=(double) GetPixelRed(image,p)*GetPixelRed(image,p);
1244 sum_cubes+=(double) GetPixelRed(image,p)*GetPixelRed(image,p)*
1245 GetPixelRed(image,p);
1246 sum_fourth_power+=(double) GetPixelRed(image,p)*
1247 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
1250 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1252 mean+=GetPixelGreen(image,p);
1253 sum_squares+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p);
1254 sum_cubes+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1255 GetPixelGreen(image,p);
1256 sum_fourth_power+=(double) GetPixelGreen(image,p)*
1257 GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1258 GetPixelGreen(image,p);
1261 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1263 mean+=GetPixelBlue(image,p);
1264 sum_squares+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p);
1265 sum_cubes+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1266 GetPixelBlue(image,p);
1267 sum_fourth_power+=(double) GetPixelBlue(image,p)*
1268 GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1269 GetPixelBlue(image,p);
1272 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1273 (image->colorspace == CMYKColorspace))
1275 mean+=GetPixelBlack(image,p);
1276 sum_squares+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p);
1277 sum_cubes+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1278 GetPixelBlack(image,p);
1279 sum_fourth_power+=(double) GetPixelBlack(image,p)*
1280 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1281 GetPixelBlack(image,p);
1284 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1286 mean+=GetPixelAlpha(image,p);
1287 sum_squares+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1288 sum_cubes+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1289 GetPixelAlpha(image,p);
1290 sum_fourth_power+=(double) GetPixelAlpha(image,p)*
1291 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1292 GetPixelAlpha(image,p);
1295 p+=GetPixelChannels(image);
1298 if (y < (ssize_t) image->rows)
1299 return(MagickFalse);
1305 sum_fourth_power/=area;
1307 standard_deviation=sqrt(sum_squares-(mean*mean));
1308 if (standard_deviation != 0.0)
1310 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1311 3.0*mean*mean*mean*mean;
1312 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1315 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1316 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1318 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326 % G e t I m a g e R a n g e %
1330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332 % GetImageRange() returns the range of one or more image channels.
1334 % The format of the GetImageRange method is:
1336 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1337 % double *maxima,ExceptionInfo *exception)
1339 % A description of each parameter follows:
1341 % o image: the image.
1343 % o minima: the minimum value in the channel.
1345 % o maxima: the maximum value in the channel.
1347 % o exception: return any errors or warnings in this structure.
1350 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1351 double *maxima,ExceptionInfo *exception)
1359 assert(image != (Image *) NULL);
1360 assert(image->signature == MagickSignature);
1361 if (image->debug != MagickFalse)
1362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1365 GetPixelInfo(image,&pixel);
1366 for (y=0; y < (ssize_t) image->rows; y++)
1368 register const Quantum
1374 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1375 if (p == (const Quantum *) NULL)
1377 for (x=0; x < (ssize_t) image->columns; x++)
1379 SetPixelInfo(image,p,&pixel);
1380 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1382 if (pixel.red < *minima)
1383 *minima=(double) pixel.red;
1384 if (pixel.red > *maxima)
1385 *maxima=(double) pixel.red;
1387 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1389 if (pixel.green < *minima)
1390 *minima=(double) pixel.green;
1391 if (pixel.green > *maxima)
1392 *maxima=(double) pixel.green;
1394 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1396 if (pixel.blue < *minima)
1397 *minima=(double) pixel.blue;
1398 if (pixel.blue > *maxima)
1399 *maxima=(double) pixel.blue;
1401 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1402 (image->colorspace == CMYKColorspace))
1404 if (pixel.black < *minima)
1405 *minima=(double) pixel.black;
1406 if (pixel.black > *maxima)
1407 *maxima=(double) pixel.black;
1409 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1411 if (pixel.alpha < *minima)
1412 *minima=(double) pixel.alpha;
1413 if (pixel.alpha > *maxima)
1414 *maxima=(double) pixel.alpha;
1416 p+=GetPixelChannels(image);
1419 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 % G e t I m a g e S t a t i s t i c s %
1431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 % GetImageStatistics() returns statistics for each channel in the
1434 % image. The statistics include the channel depth, its minima, maxima, mean,
1435 % standard deviation, kurtosis and skewness. You can access the red channel
1436 % mean, for example, like this:
1438 % channel_statistics=GetImageStatistics(image,exception);
1439 % red_mean=channel_statistics[RedChannel].mean;
1441 % Use MagickRelinquishMemory() to free the statistics buffer.
1443 % The format of the GetImageStatistics method is:
1445 % ChannelStatistics *GetImageStatistics(const Image *image,
1446 % ExceptionInfo *exception)
1448 % A description of each parameter follows:
1450 % o image: the image.
1452 % o exception: return any errors or warnings in this structure.
1455 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1456 ExceptionInfo *exception)
1459 *channel_statistics;
1481 assert(image != (Image *) NULL);
1482 assert(image->signature == MagickSignature);
1483 if (image->debug != MagickFalse)
1484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1485 length=CompositeChannels+1UL;
1486 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1487 sizeof(*channel_statistics));
1488 if (channel_statistics == (ChannelStatistics *) NULL)
1489 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1490 (void) ResetMagickMemory(channel_statistics,0,length*
1491 sizeof(*channel_statistics));
1492 for (i=0; i <= (ssize_t) CompositeChannels; i++)
1494 channel_statistics[i].depth=1;
1495 channel_statistics[i].maxima=(-1.0E-37);
1496 channel_statistics[i].minima=1.0E+37;
1498 for (y=0; y < (ssize_t) image->rows; y++)
1500 register const Quantum
1506 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1507 if (p == (const Quantum *) NULL)
1509 for (x=0; x < (ssize_t) image->columns; )
1511 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1513 depth=channel_statistics[RedChannel].depth;
1514 range=GetQuantumRange(depth);
1515 status=GetPixelRed(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1516 GetPixelRed(image,p),range),range) ? MagickTrue : MagickFalse;
1517 if (status != MagickFalse)
1519 channel_statistics[RedChannel].depth++;
1523 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1525 depth=channel_statistics[GreenChannel].depth;
1526 range=GetQuantumRange(depth);
1527 status=GetPixelGreen(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1528 GetPixelGreen(image,p),range),range) ? MagickTrue : MagickFalse;
1529 if (status != MagickFalse)
1531 channel_statistics[GreenChannel].depth++;
1535 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1537 depth=channel_statistics[BlueChannel].depth;
1538 range=GetQuantumRange(depth);
1539 status=GetPixelBlue(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1540 GetPixelBlue(image,p),range),range) ? MagickTrue : MagickFalse;
1541 if (status != MagickFalse)
1543 channel_statistics[BlueChannel].depth++;
1547 if (image->matte != MagickFalse)
1549 if (channel_statistics[AlphaChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1551 depth=channel_statistics[AlphaChannel].depth;
1552 range=GetQuantumRange(depth);
1553 status=GetPixelAlpha(image,p) != ScaleAnyToQuantum(
1554 ScaleQuantumToAny(GetPixelAlpha(image,p),range),range) ?
1555 MagickTrue : MagickFalse;
1556 if (status != MagickFalse)
1558 channel_statistics[AlphaChannel].depth++;
1563 if (image->colorspace == CMYKColorspace)
1565 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1567 depth=channel_statistics[BlackChannel].depth;
1568 range=GetQuantumRange(depth);
1569 status=GetPixelBlack(image,p) != ScaleAnyToQuantum(
1570 ScaleQuantumToAny(GetPixelBlack(image,p),range),range) ?
1571 MagickTrue : MagickFalse;
1572 if (status != MagickFalse)
1574 channel_statistics[BlackChannel].depth++;
1579 if ((double) GetPixelRed(image,p) < channel_statistics[RedChannel].minima)
1580 channel_statistics[RedChannel].minima=(double) GetPixelRed(image,p);
1581 if ((double) GetPixelRed(image,p) > channel_statistics[RedChannel].maxima)
1582 channel_statistics[RedChannel].maxima=(double) GetPixelRed(image,p);
1583 channel_statistics[RedChannel].sum+=GetPixelRed(image,p);
1584 channel_statistics[RedChannel].sum_squared+=(double)
1585 GetPixelRed(image,p)*GetPixelRed(image,p);
1586 channel_statistics[RedChannel].sum_cubed+=(double)
1587 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
1588 channel_statistics[RedChannel].sum_fourth_power+=(double)
1589 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p)*
1590 GetPixelRed(image,p);
1591 if ((double) GetPixelGreen(image,p) < channel_statistics[GreenChannel].minima)
1592 channel_statistics[GreenChannel].minima=(double)
1593 GetPixelGreen(image,p);
1594 if ((double) GetPixelGreen(image,p) > channel_statistics[GreenChannel].maxima)
1595 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(image,p);
1596 channel_statistics[GreenChannel].sum+=GetPixelGreen(image,p);
1597 channel_statistics[GreenChannel].sum_squared+=(double)
1598 GetPixelGreen(image,p)*GetPixelGreen(image,p);
1599 channel_statistics[GreenChannel].sum_cubed+=(double)
1600 GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p);
1601 channel_statistics[GreenChannel].sum_fourth_power+=(double)
1602 GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1603 GetPixelGreen(image,p);
1604 if ((double) GetPixelBlue(image,p) < channel_statistics[BlueChannel].minima)
1605 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(image,p);
1606 if ((double) GetPixelBlue(image,p) > channel_statistics[BlueChannel].maxima)
1607 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(image,p);
1608 channel_statistics[BlueChannel].sum+=GetPixelBlue(image,p);
1609 channel_statistics[BlueChannel].sum_squared+=(double)
1610 GetPixelBlue(image,p)*GetPixelBlue(image,p);
1611 channel_statistics[BlueChannel].sum_cubed+=(double)
1612 GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p);
1613 channel_statistics[BlueChannel].sum_fourth_power+=(double)
1614 GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1615 GetPixelBlue(image,p);
1616 if (image->colorspace == CMYKColorspace)
1618 if ((double) GetPixelBlack(image,p) < channel_statistics[BlackChannel].minima)
1619 channel_statistics[BlackChannel].minima=(double)
1620 GetPixelBlack(image,p);
1621 if ((double) GetPixelBlack(image,p) > channel_statistics[BlackChannel].maxima)
1622 channel_statistics[BlackChannel].maxima=(double)
1623 GetPixelBlack(image,p);
1624 channel_statistics[BlackChannel].sum+=GetPixelBlack(image,p);
1625 channel_statistics[BlackChannel].sum_squared+=(double)
1626 GetPixelBlack(image,p)*GetPixelBlack(image,p);
1627 channel_statistics[BlackChannel].sum_cubed+=(double)
1628 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1629 GetPixelBlack(image,p);
1630 channel_statistics[BlackChannel].sum_fourth_power+=(double)
1631 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1632 GetPixelBlack(image,p)*GetPixelBlack(image,p);
1634 if (image->matte != MagickFalse)
1636 if ((double) GetPixelAlpha(image,p) < channel_statistics[AlphaChannel].minima)
1637 channel_statistics[AlphaChannel].minima=(double)
1638 GetPixelAlpha(image,p);
1639 if ((double) GetPixelAlpha(image,p) > channel_statistics[AlphaChannel].maxima)
1640 channel_statistics[AlphaChannel].maxima=(double)
1641 GetPixelAlpha(image,p);
1642 channel_statistics[AlphaChannel].sum+=GetPixelAlpha(image,p);
1643 channel_statistics[AlphaChannel].sum_squared+=(double)
1644 GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1645 channel_statistics[AlphaChannel].sum_cubed+=(double)
1646 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1647 GetPixelAlpha(image,p);
1648 channel_statistics[AlphaChannel].sum_fourth_power+=(double)
1649 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1650 GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1653 p+=GetPixelChannels(image);
1656 area=(double) image->columns*image->rows;
1657 for (i=0; i < (ssize_t) CompositeChannels; i++)
1659 channel_statistics[i].sum/=area;
1660 channel_statistics[i].sum_squared/=area;
1661 channel_statistics[i].sum_cubed/=area;
1662 channel_statistics[i].sum_fourth_power/=area;
1663 channel_statistics[i].mean=channel_statistics[i].sum;
1664 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1665 channel_statistics[i].standard_deviation=sqrt(
1666 channel_statistics[i].variance-(channel_statistics[i].mean*
1667 channel_statistics[i].mean));
1669 for (i=0; i < (ssize_t) CompositeChannels; i++)
1671 channel_statistics[CompositeChannels].depth=(size_t) MagickMax((double)
1672 channel_statistics[CompositeChannels].depth,(double)
1673 channel_statistics[i].depth);
1674 channel_statistics[CompositeChannels].minima=MagickMin(
1675 channel_statistics[CompositeChannels].minima,
1676 channel_statistics[i].minima);
1677 channel_statistics[CompositeChannels].maxima=MagickMax(
1678 channel_statistics[CompositeChannels].maxima,
1679 channel_statistics[i].maxima);
1680 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
1681 channel_statistics[CompositeChannels].sum_squared+=
1682 channel_statistics[i].sum_squared;
1683 channel_statistics[CompositeChannels].sum_cubed+=
1684 channel_statistics[i].sum_cubed;
1685 channel_statistics[CompositeChannels].sum_fourth_power+=
1686 channel_statistics[i].sum_fourth_power;
1687 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
1688 channel_statistics[CompositeChannels].variance+=
1689 channel_statistics[i].variance-channel_statistics[i].mean*
1690 channel_statistics[i].mean;
1691 channel_statistics[CompositeChannels].standard_deviation+=
1692 channel_statistics[i].variance-channel_statistics[i].mean*
1693 channel_statistics[i].mean;
1696 if (image->matte != MagickFalse)
1698 if (image->colorspace == CMYKColorspace)
1700 channel_statistics[CompositeChannels].sum/=channels;
1701 channel_statistics[CompositeChannels].sum_squared/=channels;
1702 channel_statistics[CompositeChannels].sum_cubed/=channels;
1703 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
1704 channel_statistics[CompositeChannels].mean/=channels;
1705 channel_statistics[CompositeChannels].variance/=channels;
1706 channel_statistics[CompositeChannels].standard_deviation=
1707 sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
1708 channel_statistics[CompositeChannels].kurtosis/=channels;
1709 channel_statistics[CompositeChannels].skewness/=channels;
1710 for (i=0; i <= (ssize_t) CompositeChannels; i++)
1712 if (channel_statistics[i].standard_deviation == 0.0)
1714 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-
1715 3.0*channel_statistics[i].mean*channel_statistics[i].sum_squared+
1716 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1717 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1718 channel_statistics[i].standard_deviation*
1719 channel_statistics[i].standard_deviation);
1720 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-
1721 4.0*channel_statistics[i].mean*channel_statistics[i].sum_cubed+
1722 6.0*channel_statistics[i].mean*channel_statistics[i].mean*
1723 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1724 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1725 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1726 channel_statistics[i].standard_deviation*
1727 channel_statistics[i].standard_deviation*
1728 channel_statistics[i].standard_deviation)-3.0;
1730 return(channel_statistics);