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 "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 **) RelinquishMagickMemory(pixels);
148 static MagickPixelPacket **AcquirePixelThreadSet(const Image *image,
149 const size_t number_images)
162 number_threads=GetOpenMPMaximumThreads();
163 pixels=(MagickPixelPacket **) AcquireQuantumMemory(number_threads,
165 if (pixels == (MagickPixelPacket **) NULL)
166 return((MagickPixelPacket **) NULL);
167 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
168 for (i=0; i < (ssize_t) number_threads; i++)
170 length=image->columns;
171 if (length < number_images)
172 length=number_images;
173 pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(length,
175 if (pixels[i] == (MagickPixelPacket *) NULL)
176 return(DestroyPixelThreadSet(pixels));
177 for (j=0; j < (ssize_t) length; j++)
178 GetMagickPixelPacket(image,&pixels[i][j]);
183 static inline double MagickMax(const double x,const double y)
190 #if defined(__cplusplus) || defined(c_plusplus)
194 static int IntensityCompare(const void *x,const void *y)
196 const MagickPixelPacket
203 color_1=(const MagickPixelPacket *) x;
204 color_2=(const MagickPixelPacket *) y;
205 intensity=(int) MagickPixelIntensity(color_2)-
206 (int) MagickPixelIntensity(color_1);
210 #if defined(__cplusplus) || defined(c_plusplus)
214 static inline double MagickMin(const double x,const double y)
221 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
222 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
230 case UndefinedEvaluateOperator:
232 case AbsEvaluateOperator:
234 result=(MagickRealType) fabs((double) (pixel+value));
237 case AddEvaluateOperator:
239 result=(MagickRealType) (pixel+value);
242 case AddModulusEvaluateOperator:
245 This returns a 'floored modulus' of the addition which is a
246 positive result. It differs from % or fmod() which returns a
247 'truncated modulus' result, where floor() is replaced by trunc()
248 and could return a negative result (which is clipped).
251 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
254 case AndEvaluateOperator:
256 result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
259 case CosineEvaluateOperator:
261 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
262 QuantumScale*pixel*value))+0.5));
265 case DivideEvaluateOperator:
267 result=pixel/(value == 0.0 ? 1.0 : value);
270 case ExponentialEvaluateOperator:
272 result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
276 case GaussianNoiseEvaluateOperator:
278 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
279 GaussianNoise,value);
282 case ImpulseNoiseEvaluateOperator:
284 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
288 case LaplacianNoiseEvaluateOperator:
290 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
291 LaplacianNoise,value);
294 case LeftShiftEvaluateOperator:
296 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
299 case LogEvaluateOperator:
301 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
302 pixel+1.0))/log((double) (value+1.0)));
305 case MaxEvaluateOperator:
307 result=(MagickRealType) MagickMax((double) pixel,value);
310 case MeanEvaluateOperator:
312 result=(MagickRealType) (pixel+value);
315 case MedianEvaluateOperator:
317 result=(MagickRealType) (pixel+value);
320 case MinEvaluateOperator:
322 result=(MagickRealType) MagickMin((double) pixel,value);
325 case MultiplicativeNoiseEvaluateOperator:
327 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
328 MultiplicativeGaussianNoise,value);
331 case MultiplyEvaluateOperator:
333 result=(MagickRealType) (value*pixel);
336 case OrEvaluateOperator:
338 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
341 case PoissonNoiseEvaluateOperator:
343 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
347 case PowEvaluateOperator:
349 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
353 case RightShiftEvaluateOperator:
355 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
358 case SetEvaluateOperator:
363 case SineEvaluateOperator:
365 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
366 QuantumScale*pixel*value))+0.5));
369 case SubtractEvaluateOperator:
371 result=(MagickRealType) (pixel-value);
374 case ThresholdEvaluateOperator:
376 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
380 case ThresholdBlackEvaluateOperator:
382 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
385 case ThresholdWhiteEvaluateOperator:
387 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
391 case UniformNoiseEvaluateOperator:
393 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
397 case XorEvaluateOperator:
399 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
406 MagickExport MagickBooleanType EvaluateImage(Image *image,
407 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
412 status=EvaluateImageChannel(image,AllChannels,op,value,exception);
416 MagickExport Image *EvaluateImages(const Image *images,
417 const MagickEvaluateOperator op,ExceptionInfo *exception)
419 #define EvaluateImageTag "Evaluate/Image"
437 **restrict evaluate_pixels,
441 **restrict random_info;
450 Ensure the image are the same size.
452 assert(images != (Image *) NULL);
453 assert(images->signature == MagickSignature);
454 if (images->debug != MagickFalse)
455 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
456 assert(exception != (ExceptionInfo *) NULL);
457 assert(exception->signature == MagickSignature);
458 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
459 if ((next->columns != images->columns) || (next->rows != images->rows))
461 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
462 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
463 return((Image *) NULL);
466 Initialize evaluate next attributes.
468 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
470 if (evaluate_image == (Image *) NULL)
471 return((Image *) NULL);
472 if (SetImageStorageClass(evaluate_image,DirectClass) == MagickFalse)
474 InheritException(exception,&evaluate_image->exception);
475 evaluate_image=DestroyImage(evaluate_image);
476 return((Image *) NULL);
478 number_images=GetImageListLength(images);
479 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
480 if (evaluate_pixels == (MagickPixelPacket **) NULL)
482 evaluate_image=DestroyImage(evaluate_image);
483 (void) ThrowMagickException(exception,GetMagickModule(),
484 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
485 return((Image *) NULL);
488 Evaluate image pixels.
492 GetMagickPixelPacket(images,&zero);
493 random_info=AcquireRandomInfoThreadSet();
494 evaluate_view=AcquireCacheView(evaluate_image);
495 if (op == MedianEvaluateOperator)
496 #if defined(MAGICKCORE_OPENMP_SUPPORT)
497 #pragma omp parallel for schedule(dynamic) shared(progress,status)
499 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
508 id = GetOpenMPThreadId();
511 *restrict evaluate_indexes;
513 register MagickPixelPacket
522 if (status == MagickFalse)
524 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
526 if (q == (PixelPacket *) NULL)
531 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
532 evaluate_pixel=evaluate_pixels[id];
533 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
538 for (i=0; i < (ssize_t) number_images; i++)
539 evaluate_pixel[i]=zero;
541 for (i=0; i < (ssize_t) number_images; i++)
543 register const IndexPacket
546 register const PixelPacket
549 image_view=AcquireCacheView(next);
550 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
551 if (p == (const PixelPacket *) NULL)
553 image_view=DestroyCacheView(image_view);
556 indexes=GetCacheViewVirtualIndexQueue(image_view);
557 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[id],
558 p->red,op,evaluate_pixel[i].red);
559 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[id],
560 p->green,op,evaluate_pixel[i].green);
561 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[id],
562 p->blue,op,evaluate_pixel[i].blue);
563 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[id],
564 p->opacity,op,evaluate_pixel[i].opacity);
565 if (evaluate_image->colorspace == CMYKColorspace)
566 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[id],
567 *indexes,op,evaluate_pixel[i].index);
568 image_view=DestroyCacheView(image_view);
569 next=GetNextImageInList(next);
571 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
573 q->red=ClampToQuantum(evaluate_pixel[i/2].red);
574 q->green=ClampToQuantum(evaluate_pixel[i/2].green);
575 q->blue=ClampToQuantum(evaluate_pixel[i/2].blue);
576 if (evaluate_image->matte == MagickFalse)
577 q->opacity=ClampToQuantum(evaluate_pixel[i/2].opacity);
579 q->opacity=ClampToQuantum(QuantumRange-evaluate_pixel[i/2].opacity);
580 if (evaluate_image->colorspace == CMYKColorspace)
581 evaluate_indexes[i]=ClampToQuantum(evaluate_pixel[i/2].index);
584 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
586 if (images->progress_monitor != (MagickProgressMonitor) NULL)
591 #if defined(MAGICKCORE_OPENMP_SUPPORT)
592 #pragma omp critical (MagickCore_EvaluateImages)
594 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
595 evaluate_image->rows);
596 if (proceed == MagickFalse)
601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
602 #pragma omp parallel for schedule(dynamic) shared(progress,status)
604 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
613 id = GetOpenMPThreadId();
616 *restrict evaluate_indexes;
622 register MagickPixelPacket
628 if (status == MagickFalse)
630 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
632 if (q == (PixelPacket *) NULL)
637 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
638 evaluate_pixel=evaluate_pixels[id];
639 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
640 evaluate_pixel[x]=zero;
642 for (i=0; i < (ssize_t) number_images; i++)
644 register const IndexPacket
647 register const PixelPacket
650 image_view=AcquireCacheView(next);
651 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
652 if (p == (const PixelPacket *) NULL)
654 image_view=DestroyCacheView(image_view);
657 indexes=GetCacheViewVirtualIndexQueue(image_view);
658 for (x=0; x < (ssize_t) next->columns; x++)
660 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],
661 p->red,i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].red);
662 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],
663 p->green,i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].green);
664 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],
665 p->blue,i == 0 ? AddEvaluateOperator : op,evaluate_pixel[x].blue);
666 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[id],
667 p->opacity,i == 0 ? AddEvaluateOperator : op,
668 evaluate_pixel[x].opacity);
669 if (evaluate_image->colorspace == CMYKColorspace)
670 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[id],
671 indexes[x],i == 0 ? AddEvaluateOperator : op,
672 evaluate_pixel[x].index);
675 image_view=DestroyCacheView(image_view);
676 next=GetNextImageInList(next);
678 if (op == MeanEvaluateOperator)
679 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
681 evaluate_pixel[x].red/=number_images;
682 evaluate_pixel[x].green/=number_images;
683 evaluate_pixel[x].blue/=number_images;
684 evaluate_pixel[x].opacity/=number_images;
685 evaluate_pixel[x].index/=number_images;
687 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
689 q->red=ClampToQuantum(evaluate_pixel[x].red);
690 q->green=ClampToQuantum(evaluate_pixel[x].green);
691 q->blue=ClampToQuantum(evaluate_pixel[x].blue);
692 if (evaluate_image->matte == MagickFalse)
693 q->opacity=ClampToQuantum(evaluate_pixel[x].opacity);
695 q->opacity=ClampToQuantum(QuantumRange-evaluate_pixel[x].opacity);
696 if (evaluate_image->colorspace == CMYKColorspace)
697 evaluate_indexes[x]=ClampToQuantum(evaluate_pixel[x].index);
700 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
702 if (images->progress_monitor != (MagickProgressMonitor) NULL)
707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
708 #pragma omp critical (MagickCore_EvaluateImages)
710 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
711 evaluate_image->rows);
712 if (proceed == MagickFalse)
716 evaluate_view=DestroyCacheView(evaluate_view);
717 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
718 random_info=DestroyRandomInfoThreadSet(random_info);
719 if (status == MagickFalse)
720 evaluate_image=DestroyImage(evaluate_image);
721 return(evaluate_image);
724 MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
725 const ChannelType channel,const MagickEvaluateOperator op,const double value,
726 ExceptionInfo *exception)
738 **restrict random_info;
743 assert(image != (Image *) NULL);
744 assert(image->signature == MagickSignature);
745 if (image->debug != MagickFalse)
746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
747 assert(exception != (ExceptionInfo *) NULL);
748 assert(exception->signature == MagickSignature);
749 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
751 InheritException(exception,&image->exception);
756 random_info=AcquireRandomInfoThreadSet();
757 image_view=AcquireCacheView(image);
758 #if defined(MAGICKCORE_OPENMP_SUPPORT)
759 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
761 for (y=0; y < (ssize_t) image->rows; y++)
764 id = GetOpenMPThreadId();
775 if (status == MagickFalse)
777 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
778 if (q == (PixelPacket *) NULL)
783 indexes=GetCacheViewAuthenticIndexQueue(image_view);
784 for (x=0; x < (ssize_t) image->columns; x++)
786 if ((channel & RedChannel) != 0)
787 q->red=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->red,op,
789 if ((channel & GreenChannel) != 0)
790 q->green=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->green,
792 if ((channel & BlueChannel) != 0)
793 q->blue=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q->blue,op,
795 if ((channel & OpacityChannel) != 0)
797 if (image->matte == MagickFalse)
798 q->opacity=ClampToQuantum(ApplyEvaluateOperator(random_info[id],
799 q->opacity,op,value));
801 q->opacity=ClampToQuantum(QuantumRange-ApplyEvaluateOperator(
802 random_info[id],(Quantum) GetAlphaPixelComponent(q),op,value));
804 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
805 indexes[x]=(IndexPacket) ClampToQuantum(ApplyEvaluateOperator(
806 random_info[id],indexes[x],op,value));
809 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
811 if (image->progress_monitor != (MagickProgressMonitor) NULL)
816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
817 #pragma omp critical (MagickCore_EvaluateImageChannel)
819 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
820 if (proceed == MagickFalse)
824 image_view=DestroyCacheView(image_view);
825 random_info=DestroyRandomInfoThreadSet(random_info);
830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 % F u n c t i o n I m a g e %
838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
840 % FunctionImage() applies a value to the image with an arithmetic, relational,
841 % or logical operator to an image. Use these operations to lighten or darken
842 % an image, to increase or decrease contrast in an image, or to produce the
843 % "negative" of an image.
845 % The format of the FunctionImageChannel method is:
847 % MagickBooleanType FunctionImage(Image *image,
848 % const MagickFunction function,const ssize_t number_parameters,
849 % const double *parameters,ExceptionInfo *exception)
850 % MagickBooleanType FunctionImageChannel(Image *image,
851 % const ChannelType channel,const MagickFunction function,
852 % const ssize_t number_parameters,const double *argument,
853 % ExceptionInfo *exception)
855 % A description of each parameter follows:
857 % o image: the image.
859 % o channel: the channel.
861 % o function: A channel function.
863 % o parameters: one or more parameters.
865 % o exception: return any errors or warnings in this structure.
869 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
870 const size_t number_parameters,const double *parameters,
871 ExceptionInfo *exception)
883 case PolynomialFunction:
887 * Parameters: polynomial constants, highest to lowest order
888 * For example: c0*x^3 + c1*x^2 + c2*x + c3
891 for (i=0; i < (ssize_t) number_parameters; i++)
892 result = result*QuantumScale*pixel + parameters[i];
893 result *= QuantumRange;
896 case SinusoidFunction:
899 * Parameters: Freq, Phase, Ampl, bias
901 double freq,phase,ampl,bias;
902 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
903 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
904 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
905 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
906 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
907 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
912 /* Arcsin Function (peged at range limits for invalid results)
913 * Parameters: Width, Center, Range, Bias
915 double width,range,center,bias;
916 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
917 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
918 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
919 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
920 result = 2.0/width*(QuantumScale*pixel - center);
921 if ( result <= -1.0 )
922 result = bias - range/2.0;
923 else if ( result >= 1.0 )
924 result = bias + range/2.0;
926 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
927 result *= QuantumRange;
933 * Parameters: Slope, Center, Range, Bias
935 double slope,range,center,bias;
936 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
937 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
938 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
939 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
940 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
941 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
945 case UndefinedFunction:
948 return(ClampToQuantum(result));
951 MagickExport MagickBooleanType FunctionImage(Image *image,
952 const MagickFunction function,const size_t number_parameters,
953 const double *parameters,ExceptionInfo *exception)
958 status=FunctionImageChannel(image,AllChannels,function,number_parameters,
959 parameters,exception);
963 MagickExport MagickBooleanType FunctionImageChannel(Image *image,
964 const ChannelType channel,const MagickFunction function,
965 const size_t number_parameters,const double *parameters,
966 ExceptionInfo *exception)
968 #define FunctionImageTag "Function/Image "
982 assert(image != (Image *) NULL);
983 assert(image->signature == MagickSignature);
984 if (image->debug != MagickFalse)
985 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
986 assert(exception != (ExceptionInfo *) NULL);
987 assert(exception->signature == MagickSignature);
988 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
990 InheritException(exception,&image->exception);
995 image_view=AcquireCacheView(image);
996 #if defined(MAGICKCORE_OPENMP_SUPPORT)
997 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
999 for (y=0; y < (ssize_t) image->rows; y++)
1001 register IndexPacket
1007 register PixelPacket
1010 if (status == MagickFalse)
1012 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1013 if (q == (PixelPacket *) NULL)
1018 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1019 for (x=0; x < (ssize_t) image->columns; x++)
1021 if ((channel & RedChannel) != 0)
1022 q->red=ApplyFunction(q->red,function,number_parameters,parameters,
1024 if ((channel & GreenChannel) != 0)
1025 q->green=ApplyFunction(q->green,function,number_parameters,parameters,
1027 if ((channel & BlueChannel) != 0)
1028 q->blue=ApplyFunction(q->blue,function,number_parameters,parameters,
1030 if ((channel & OpacityChannel) != 0)
1032 if (image->matte == MagickFalse)
1033 q->opacity=ApplyFunction(q->opacity,function,number_parameters,
1034 parameters,exception);
1036 q->opacity=(Quantum) QuantumRange-ApplyFunction((Quantum)
1037 GetAlphaPixelComponent(q),function,number_parameters,parameters,
1040 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1041 indexes[x]=(IndexPacket) ApplyFunction(indexes[x],function,
1042 number_parameters,parameters,exception);
1045 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1047 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1052 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1053 #pragma omp critical (MagickCore_FunctionImageChannel)
1055 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1056 if (proceed == MagickFalse)
1060 image_view=DestroyCacheView(image_view);
1065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1069 + G e t I m a g e C h a n n e l E x t r e m a %
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1075 % GetImageChannelExtrema() returns the extrema of one or more image channels.
1077 % The format of the GetImageChannelExtrema method is:
1079 % MagickBooleanType GetImageChannelExtrema(const Image *image,
1080 % const ChannelType channel,size_t *minima,size_t *maxima,
1081 % ExceptionInfo *exception)
1083 % A description of each parameter follows:
1085 % o image: the image.
1087 % o channel: the channel.
1089 % o minima: the minimum value in the channel.
1091 % o maxima: the maximum value in the channel.
1093 % o exception: return any errors or warnings in this structure.
1097 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1098 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1100 return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
1103 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
1104 const ChannelType channel,size_t *minima,size_t *maxima,
1105 ExceptionInfo *exception)
1114 assert(image != (Image *) NULL);
1115 assert(image->signature == MagickSignature);
1116 if (image->debug != MagickFalse)
1117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1118 status=GetImageChannelRange(image,channel,&min,&max,exception);
1119 *minima=(size_t) ceil(min-0.5);
1120 *maxima=(size_t) floor(max+0.5);
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129 % G e t I m a g e C h a n n e l M e a n %
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1135 % GetImageChannelMean() returns the mean and standard deviation of one or more
1138 % The format of the GetImageChannelMean method is:
1140 % MagickBooleanType GetImageChannelMean(const Image *image,
1141 % const ChannelType channel,double *mean,double *standard_deviation,
1142 % ExceptionInfo *exception)
1144 % A description of each parameter follows:
1146 % o image: the image.
1148 % o channel: the channel.
1150 % o mean: the average value in the channel.
1152 % o standard_deviation: the standard deviation of the channel.
1154 % o exception: return any errors or warnings in this structure.
1158 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1159 double *standard_deviation,ExceptionInfo *exception)
1164 status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
1169 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
1170 const ChannelType channel,double *mean,double *standard_deviation,
1171 ExceptionInfo *exception)
1174 *channel_statistics;
1179 assert(image != (Image *) NULL);
1180 assert(image->signature == MagickSignature);
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1183 channel_statistics=GetImageChannelStatistics(image,exception);
1184 if (channel_statistics == (ChannelStatistics *) NULL)
1185 return(MagickFalse);
1187 channel_statistics[AllChannels].mean=0.0;
1188 channel_statistics[AllChannels].standard_deviation=0.0;
1189 if ((channel & RedChannel) != 0)
1191 channel_statistics[AllChannels].mean+=
1192 channel_statistics[RedChannel].mean;
1193 channel_statistics[AllChannels].standard_deviation+=
1194 channel_statistics[RedChannel].variance-
1195 channel_statistics[RedChannel].mean*
1196 channel_statistics[RedChannel].mean;
1199 if ((channel & GreenChannel) != 0)
1201 channel_statistics[AllChannels].mean+=
1202 channel_statistics[GreenChannel].mean;
1203 channel_statistics[AllChannels].standard_deviation+=
1204 channel_statistics[GreenChannel].variance-
1205 channel_statistics[GreenChannel].mean*
1206 channel_statistics[GreenChannel].mean;
1209 if ((channel & BlueChannel) != 0)
1211 channel_statistics[AllChannels].mean+=
1212 channel_statistics[BlueChannel].mean;
1213 channel_statistics[AllChannels].standard_deviation+=
1214 channel_statistics[BlueChannel].variance-
1215 channel_statistics[BlueChannel].mean*
1216 channel_statistics[BlueChannel].mean;
1219 if (((channel & OpacityChannel) != 0) &&
1220 (image->matte != MagickFalse))
1222 channel_statistics[AllChannels].mean+=
1223 channel_statistics[OpacityChannel].mean;
1224 channel_statistics[AllChannels].standard_deviation+=
1225 channel_statistics[OpacityChannel].variance-
1226 channel_statistics[OpacityChannel].mean*
1227 channel_statistics[OpacityChannel].mean;
1230 if (((channel & IndexChannel) != 0) &&
1231 (image->colorspace == CMYKColorspace))
1233 channel_statistics[AllChannels].mean+=
1234 channel_statistics[BlackChannel].mean;
1235 channel_statistics[AllChannels].standard_deviation+=
1236 channel_statistics[BlackChannel].variance-
1237 channel_statistics[BlackChannel].mean*
1238 channel_statistics[BlackChannel].mean;
1241 channel_statistics[AllChannels].mean/=channels;
1242 channel_statistics[AllChannels].standard_deviation=
1243 sqrt(channel_statistics[AllChannels].standard_deviation/channels);
1244 *mean=channel_statistics[AllChannels].mean;
1245 *standard_deviation=channel_statistics[AllChannels].standard_deviation;
1246 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1247 channel_statistics);
1252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256 % G e t I m a g e C h a n n e l K u r t o s i s %
1260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1262 % GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
1265 % The format of the GetImageChannelKurtosis method is:
1267 % MagickBooleanType GetImageChannelKurtosis(const Image *image,
1268 % const ChannelType channel,double *kurtosis,double *skewness,
1269 % ExceptionInfo *exception)
1271 % A description of each parameter follows:
1273 % o image: the image.
1275 % o channel: the channel.
1277 % o kurtosis: the kurtosis of the channel.
1279 % o skewness: the skewness of the channel.
1281 % o exception: return any errors or warnings in this structure.
1285 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1286 double *kurtosis,double *skewness,ExceptionInfo *exception)
1291 status=GetImageChannelKurtosis(image,AllChannels,kurtosis,skewness,
1296 MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
1297 const ChannelType channel,double *kurtosis,double *skewness,
1298 ExceptionInfo *exception)
1311 assert(image != (Image *) NULL);
1312 assert(image->signature == MagickSignature);
1313 if (image->debug != MagickFalse)
1314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1319 standard_deviation=0.0;
1322 sum_fourth_power=0.0;
1323 for (y=0; y < (ssize_t) image->rows; y++)
1325 register const IndexPacket
1328 register const PixelPacket
1334 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1335 if (p == (const PixelPacket *) NULL)
1337 indexes=GetVirtualIndexQueue(image);
1338 for (x=0; x < (ssize_t) image->columns; x++)
1340 if ((channel & RedChannel) != 0)
1342 mean+=GetRedPixelComponent(p);
1343 sum_squares+=(double) p->red*GetRedPixelComponent(p);
1344 sum_cubes+=(double) p->red*p->red*GetRedPixelComponent(p);
1345 sum_fourth_power+=(double) p->red*p->red*p->red*
1346 GetRedPixelComponent(p);
1349 if ((channel & GreenChannel) != 0)
1351 mean+=GetGreenPixelComponent(p);
1352 sum_squares+=(double) p->green*GetGreenPixelComponent(p);
1353 sum_cubes+=(double) p->green*p->green*GetGreenPixelComponent(p);
1354 sum_fourth_power+=(double) p->green*p->green*p->green*
1355 GetGreenPixelComponent(p);
1358 if ((channel & BlueChannel) != 0)
1360 mean+=GetBluePixelComponent(p);
1361 sum_squares+=(double) p->blue*GetBluePixelComponent(p);
1362 sum_cubes+=(double) p->blue*p->blue*GetBluePixelComponent(p);
1363 sum_fourth_power+=(double) p->blue*p->blue*p->blue*
1364 GetBluePixelComponent(p);
1367 if ((channel & OpacityChannel) != 0)
1369 mean+=GetOpacityPixelComponent(p);
1370 sum_squares+=(double) p->opacity*GetOpacityPixelComponent(p);
1371 sum_cubes+=(double) p->opacity*p->opacity*GetOpacityPixelComponent(p);
1372 sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
1373 GetOpacityPixelComponent(p);
1376 if (((channel & IndexChannel) != 0) &&
1377 (image->colorspace == CMYKColorspace))
1380 sum_squares+=(double) indexes[x]*indexes[x];
1381 sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
1382 sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
1389 if (y < (ssize_t) image->rows)
1390 return(MagickFalse);
1396 sum_fourth_power/=area;
1398 standard_deviation=sqrt(sum_squares-(mean*mean));
1399 if (standard_deviation != 0.0)
1401 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1402 3.0*mean*mean*mean*mean;
1403 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1406 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1407 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1409 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417 % G e t I m a g e C h a n n e l R a n g e %
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 % GetImageChannelRange() returns the range of one or more image channels.
1425 % The format of the GetImageChannelRange method is:
1427 % MagickBooleanType GetImageChannelRange(const Image *image,
1428 % const ChannelType channel,double *minima,double *maxima,
1429 % ExceptionInfo *exception)
1431 % A description of each parameter follows:
1433 % o image: the image.
1435 % o channel: the channel.
1437 % o minima: the minimum value in the channel.
1439 % o maxima: the maximum value in the channel.
1441 % o exception: return any errors or warnings in this structure.
1445 MagickExport MagickBooleanType GetImageRange(const Image *image,
1446 double *minima,double *maxima,ExceptionInfo *exception)
1448 return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
1451 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
1452 const ChannelType channel,double *minima,double *maxima,
1453 ExceptionInfo *exception)
1461 assert(image != (Image *) NULL);
1462 assert(image->signature == MagickSignature);
1463 if (image->debug != MagickFalse)
1464 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1467 GetMagickPixelPacket(image,&pixel);
1468 for (y=0; y < (ssize_t) image->rows; y++)
1470 register const IndexPacket
1473 register const PixelPacket
1479 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1480 if (p == (const PixelPacket *) NULL)
1482 indexes=GetVirtualIndexQueue(image);
1483 for (x=0; x < (ssize_t) image->columns; x++)
1485 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1486 if ((channel & RedChannel) != 0)
1488 if (pixel.red < *minima)
1489 *minima=(double) pixel.red;
1490 if (pixel.red > *maxima)
1491 *maxima=(double) pixel.red;
1493 if ((channel & GreenChannel) != 0)
1495 if (pixel.green < *minima)
1496 *minima=(double) pixel.green;
1497 if (pixel.green > *maxima)
1498 *maxima=(double) pixel.green;
1500 if ((channel & BlueChannel) != 0)
1502 if (pixel.blue < *minima)
1503 *minima=(double) pixel.blue;
1504 if (pixel.blue > *maxima)
1505 *maxima=(double) pixel.blue;
1507 if ((channel & OpacityChannel) != 0)
1509 if (pixel.opacity < *minima)
1510 *minima=(double) pixel.opacity;
1511 if (pixel.opacity > *maxima)
1512 *maxima=(double) pixel.opacity;
1514 if (((channel & IndexChannel) != 0) &&
1515 (image->colorspace == CMYKColorspace))
1517 if ((double) indexes[x] < *minima)
1518 *minima=(double) indexes[x];
1519 if ((double) indexes[x] > *maxima)
1520 *maxima=(double) indexes[x];
1525 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 % 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 %
1537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539 % GetImageChannelStatistics() returns statistics for each channel in the
1540 % image. The statistics include the channel depth, its minima, maxima, mean,
1541 % standard deviation, kurtosis and skewness. You can access the red channel
1542 % mean, for example, like this:
1544 % channel_statistics=GetImageChannelStatistics(image,exception);
1545 % red_mean=channel_statistics[RedChannel].mean;
1547 % Use MagickRelinquishMemory() to free the statistics buffer.
1549 % The format of the GetImageChannelStatistics method is:
1551 % ChannelStatistics *GetImageChannelStatistics(const Image *image,
1552 % ExceptionInfo *exception)
1554 % A description of each parameter follows:
1556 % o image: the image.
1558 % o exception: return any errors or warnings in this structure.
1561 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
1562 ExceptionInfo *exception)
1565 *channel_statistics;
1587 assert(image != (Image *) NULL);
1588 assert(image->signature == MagickSignature);
1589 if (image->debug != MagickFalse)
1590 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1591 length=AllChannels+1UL;
1592 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1593 sizeof(*channel_statistics));
1594 if (channel_statistics == (ChannelStatistics *) NULL)
1595 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1596 (void) ResetMagickMemory(channel_statistics,0,length*
1597 sizeof(*channel_statistics));
1598 for (i=0; i <= AllChannels; i++)
1600 channel_statistics[i].depth=1;
1601 channel_statistics[i].maxima=(-1.0E-37);
1602 channel_statistics[i].minima=1.0E+37;
1604 for (y=0; y < (ssize_t) image->rows; y++)
1606 register const IndexPacket
1609 register const PixelPacket
1615 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1616 if (p == (const PixelPacket *) NULL)
1618 indexes=GetVirtualIndexQueue(image);
1619 for (x=0; x < (ssize_t) image->columns; )
1621 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1623 depth=channel_statistics[RedChannel].depth;
1624 range=GetQuantumRange(depth);
1625 status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
1626 range) ? MagickTrue : MagickFalse;
1627 if (status != MagickFalse)
1629 channel_statistics[RedChannel].depth++;
1633 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1635 depth=channel_statistics[GreenChannel].depth;
1636 range=GetQuantumRange(depth);
1637 status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
1638 range),range) ? MagickTrue : MagickFalse;
1639 if (status != MagickFalse)
1641 channel_statistics[GreenChannel].depth++;
1645 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1647 depth=channel_statistics[BlueChannel].depth;
1648 range=GetQuantumRange(depth);
1649 status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
1650 range),range) ? MagickTrue : MagickFalse;
1651 if (status != MagickFalse)
1653 channel_statistics[BlueChannel].depth++;
1657 if (image->matte != MagickFalse)
1659 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1661 depth=channel_statistics[OpacityChannel].depth;
1662 range=GetQuantumRange(depth);
1663 status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
1664 p->opacity,range),range) ? MagickTrue : MagickFalse;
1665 if (status != MagickFalse)
1667 channel_statistics[OpacityChannel].depth++;
1672 if (image->colorspace == CMYKColorspace)
1674 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1676 depth=channel_statistics[BlackChannel].depth;
1677 range=GetQuantumRange(depth);
1678 status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
1679 indexes[x],range),range) ? MagickTrue : MagickFalse;
1680 if (status != MagickFalse)
1682 channel_statistics[BlackChannel].depth++;
1687 if ((double) p->red < channel_statistics[RedChannel].minima)
1688 channel_statistics[RedChannel].minima=(double) GetRedPixelComponent(p);
1689 if ((double) p->red > channel_statistics[RedChannel].maxima)
1690 channel_statistics[RedChannel].maxima=(double) GetRedPixelComponent(p);
1691 channel_statistics[RedChannel].sum+=GetRedPixelComponent(p);
1692 channel_statistics[RedChannel].sum_squared+=(double) p->red*
1693 GetRedPixelComponent(p);
1694 channel_statistics[RedChannel].sum_cubed+=(double) p->red*p->red*
1695 GetRedPixelComponent(p);
1696 channel_statistics[RedChannel].sum_fourth_power+=(double) p->red*p->red*
1697 p->red*GetRedPixelComponent(p);
1698 if ((double) p->green < channel_statistics[GreenChannel].minima)
1699 channel_statistics[GreenChannel].minima=(double)
1700 GetGreenPixelComponent(p);
1701 if ((double) p->green > channel_statistics[GreenChannel].maxima)
1702 channel_statistics[GreenChannel].maxima=(double)
1703 GetGreenPixelComponent(p);
1704 channel_statistics[GreenChannel].sum+=GetGreenPixelComponent(p);
1705 channel_statistics[GreenChannel].sum_squared+=(double) p->green*
1706 GetGreenPixelComponent(p);
1707 channel_statistics[GreenChannel].sum_cubed+=(double) p->green*p->green*
1708 GetGreenPixelComponent(p);
1709 channel_statistics[GreenChannel].sum_fourth_power+=(double) p->green*
1710 p->green*p->green*GetGreenPixelComponent(p);
1711 if ((double) p->blue < channel_statistics[BlueChannel].minima)
1712 channel_statistics[BlueChannel].minima=(double)
1713 GetBluePixelComponent(p);
1714 if ((double) p->blue > channel_statistics[BlueChannel].maxima)
1715 channel_statistics[BlueChannel].maxima=(double)
1716 GetBluePixelComponent(p);
1717 channel_statistics[BlueChannel].sum+=GetBluePixelComponent(p);
1718 channel_statistics[BlueChannel].sum_squared+=(double) p->blue*
1719 GetBluePixelComponent(p);
1720 channel_statistics[BlueChannel].sum_cubed+=(double) p->blue*p->blue*
1721 GetBluePixelComponent(p);
1722 channel_statistics[BlueChannel].sum_fourth_power+=(double) p->blue*
1723 p->blue*p->blue*GetBluePixelComponent(p);
1724 if (image->matte != MagickFalse)
1726 if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
1727 channel_statistics[OpacityChannel].minima=(double)
1728 GetOpacityPixelComponent(p);
1729 if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
1730 channel_statistics[OpacityChannel].maxima=(double)
1731 GetOpacityPixelComponent(p);
1732 channel_statistics[OpacityChannel].sum+=GetOpacityPixelComponent(p);
1733 channel_statistics[OpacityChannel].sum_squared+=(double)
1734 p->opacity*GetOpacityPixelComponent(p);
1735 channel_statistics[OpacityChannel].sum_cubed+=(double) p->opacity*
1736 p->opacity*GetOpacityPixelComponent(p);
1737 channel_statistics[OpacityChannel].sum_fourth_power+=(double)
1738 p->opacity*p->opacity*p->opacity*GetOpacityPixelComponent(p);
1740 if (image->colorspace == CMYKColorspace)
1742 if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
1743 channel_statistics[BlackChannel].minima=(double) indexes[x];
1744 if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
1745 channel_statistics[BlackChannel].maxima=(double) indexes[x];
1746 channel_statistics[BlackChannel].sum+=indexes[x];
1747 channel_statistics[BlackChannel].sum_squared+=(double)
1748 indexes[x]*indexes[x];
1749 channel_statistics[BlackChannel].sum_cubed+=(double) indexes[x]*
1750 indexes[x]*indexes[x];
1751 channel_statistics[BlackChannel].sum_fourth_power+=(double)
1752 indexes[x]*indexes[x]*indexes[x]*indexes[x];
1758 area=(double) image->columns*image->rows;
1759 for (i=0; i < AllChannels; i++)
1761 channel_statistics[i].sum/=area;
1762 channel_statistics[i].sum_squared/=area;
1763 channel_statistics[i].sum_cubed/=area;
1764 channel_statistics[i].sum_fourth_power/=area;
1765 channel_statistics[i].mean=channel_statistics[i].sum;
1766 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1767 channel_statistics[i].standard_deviation=sqrt(
1768 channel_statistics[i].variance-(channel_statistics[i].mean*
1769 channel_statistics[i].mean));
1771 for (i=0; i < AllChannels; i++)
1773 channel_statistics[AllChannels].depth=(size_t) MagickMax((double)
1774 channel_statistics[AllChannels].depth,(double)
1775 channel_statistics[i].depth);
1776 channel_statistics[AllChannels].minima=MagickMin(
1777 channel_statistics[AllChannels].minima,channel_statistics[i].minima);
1778 channel_statistics[AllChannels].maxima=MagickMax(
1779 channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
1780 channel_statistics[AllChannels].sum+=channel_statistics[i].sum;
1781 channel_statistics[AllChannels].sum_squared+=
1782 channel_statistics[i].sum_squared;
1783 channel_statistics[AllChannels].sum_cubed+=channel_statistics[i].sum_cubed;
1784 channel_statistics[AllChannels].sum_fourth_power+=
1785 channel_statistics[i].sum_fourth_power;
1786 channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
1787 channel_statistics[AllChannels].variance+=channel_statistics[i].variance-
1788 channel_statistics[i].mean*channel_statistics[i].mean;
1789 channel_statistics[AllChannels].standard_deviation+=
1790 channel_statistics[i].variance-channel_statistics[i].mean*
1791 channel_statistics[i].mean;
1794 if (image->matte != MagickFalse)
1796 if (image->colorspace == CMYKColorspace)
1798 channel_statistics[AllChannels].sum/=channels;
1799 channel_statistics[AllChannels].sum_squared/=channels;
1800 channel_statistics[AllChannels].sum_cubed/=channels;
1801 channel_statistics[AllChannels].sum_fourth_power/=channels;
1802 channel_statistics[AllChannels].mean/=channels;
1803 channel_statistics[AllChannels].variance/=channels;
1804 channel_statistics[AllChannels].standard_deviation=
1805 sqrt(channel_statistics[AllChannels].standard_deviation/channels);
1806 channel_statistics[AllChannels].kurtosis/=channels;
1807 channel_statistics[AllChannels].skewness/=channels;
1808 for (i=0; i <= AllChannels; i++)
1810 if (channel_statistics[i].standard_deviation == 0.0)
1812 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-
1813 3.0*channel_statistics[i].mean*channel_statistics[i].sum_squared+
1814 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1815 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1816 channel_statistics[i].standard_deviation*
1817 channel_statistics[i].standard_deviation);
1818 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-
1819 4.0*channel_statistics[i].mean*channel_statistics[i].sum_cubed+
1820 6.0*channel_statistics[i].mean*channel_statistics[i].mean*
1821 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1822 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1823 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1824 channel_statistics[i].standard_deviation*
1825 channel_statistics[i].standard_deviation*
1826 channel_statistics[i].standard_deviation)-3.0;
1828 return(channel_statistics);