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 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 PixelInfo **DestroyPixelThreadSet(PixelInfo **pixels)
140 assert(pixels != (PixelInfo **) NULL);
141 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
142 if (pixels[i] != (PixelInfo *) NULL)
143 pixels[i]=(PixelInfo *) RelinquishMagickMemory(pixels[i]);
144 pixels=(PixelInfo **) RelinquishMagickMemory(pixels);
148 static PixelInfo **AcquirePixelThreadSet(const Image *image,
149 const size_t number_images)
162 number_threads=GetOpenMPMaximumThreads();
163 pixels=(PixelInfo **) AcquireQuantumMemory(number_threads,
165 if (pixels == (PixelInfo **) NULL)
166 return((PixelInfo **) 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]=(PixelInfo *) AcquireQuantumMemory(length,
175 if (pixels[i] == (PixelInfo *) NULL)
176 return(DestroyPixelThreadSet(pixels));
177 for (j=0; j < (ssize_t) length; j++)
178 GetPixelInfo(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)
203 color_1=(const PixelInfo *) x;
204 color_2=(const PixelInfo *) y;
205 intensity=(int) GetPixelInfoIntensity(color_2)-(int)
206 GetPixelInfoIntensity(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,CompositeChannels,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 == (PixelInfo **) 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 GetPixelInfo(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();
519 if (status == MagickFalse)
521 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
523 if (q == (const Quantum *) NULL)
528 evaluate_pixel=evaluate_pixels[id];
529 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
534 for (i=0; i < (ssize_t) number_images; i++)
535 evaluate_pixel[i]=zero;
537 for (i=0; i < (ssize_t) number_images; i++)
539 register const Quantum
542 image_view=AcquireCacheView(next);
543 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
544 if (p == (const Quantum *) NULL)
546 image_view=DestroyCacheView(image_view);
549 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[id],
550 GetPixelRed(next,p),op,evaluate_pixel[i].red);
551 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[id],
552 GetPixelGreen(next,p),op,evaluate_pixel[i].green);
553 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[id],
554 GetPixelBlue(next,p),op,evaluate_pixel[i].blue);
555 if (evaluate_image->colorspace == CMYKColorspace)
556 evaluate_pixel[i].black=ApplyEvaluateOperator(random_info[id],
557 GetPixelBlack(next,p),op,evaluate_pixel[i].black);
558 evaluate_pixel[i].alpha=ApplyEvaluateOperator(random_info[id],
559 GetPixelAlpha(next,p),op,evaluate_pixel[i].alpha);
560 image_view=DestroyCacheView(image_view);
561 next=GetNextImageInList(next);
563 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
565 SetPixelRed(evaluate_image,
566 ClampToQuantum(evaluate_pixel[i/2].red),q);
567 SetPixelGreen(evaluate_image,
568 ClampToQuantum(evaluate_pixel[i/2].green),q);
569 SetPixelBlue(evaluate_image,
570 ClampToQuantum(evaluate_pixel[i/2].blue),q);
571 if (evaluate_image->colorspace == CMYKColorspace)
572 SetPixelBlack(evaluate_image,
573 ClampToQuantum(evaluate_pixel[i/2].black),q);
574 if (evaluate_image->matte == MagickFalse)
575 SetPixelAlpha(evaluate_image,
576 ClampToQuantum(evaluate_pixel[i/2].alpha),q);
578 SetPixelAlpha(evaluate_image,
579 ClampToQuantum(evaluate_pixel[i/2].alpha),q);
580 q+=GetPixelChannels(evaluate_image);
582 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
584 if (images->progress_monitor != (MagickProgressMonitor) NULL)
589 #if defined(MAGICKCORE_OPENMP_SUPPORT)
590 #pragma omp critical (MagickCore_EvaluateImages)
592 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
593 evaluate_image->rows);
594 if (proceed == MagickFalse)
599 #if defined(MAGICKCORE_OPENMP_SUPPORT)
600 #pragma omp parallel for schedule(dynamic) shared(progress,status)
602 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
611 id = GetOpenMPThreadId();
623 if (status == MagickFalse)
625 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
627 if (q == (const Quantum *) NULL)
632 evaluate_pixel=evaluate_pixels[id];
633 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
634 evaluate_pixel[x]=zero;
636 for (i=0; i < (ssize_t) number_images; i++)
638 register const Quantum
641 image_view=AcquireCacheView(next);
642 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
643 if (p == (const Quantum *) NULL)
645 image_view=DestroyCacheView(image_view);
648 for (x=0; x < (ssize_t) next->columns; x++)
650 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],
651 GetPixelRed(next,p),i == 0 ? AddEvaluateOperator : op,
652 evaluate_pixel[x].red);
653 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],
654 GetPixelGreen(next,p),i == 0 ? AddEvaluateOperator : op,
655 evaluate_pixel[x].green);
656 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],
657 GetPixelBlue(next,p),i == 0 ? AddEvaluateOperator : op,
658 evaluate_pixel[x].blue);
659 if (evaluate_image->colorspace == CMYKColorspace)
660 evaluate_pixel[x].black=ApplyEvaluateOperator(random_info[id],
661 GetPixelBlack(next,p),i == 0 ? AddEvaluateOperator : op,
662 evaluate_pixel[x].black);
663 evaluate_pixel[x].alpha=ApplyEvaluateOperator(random_info[id],
664 GetPixelAlpha(next,p),i == 0 ? AddEvaluateOperator : op,
665 evaluate_pixel[x].alpha);
666 p+=GetPixelChannels(next);
668 image_view=DestroyCacheView(image_view);
669 next=GetNextImageInList(next);
671 if (op == MeanEvaluateOperator)
672 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
674 evaluate_pixel[x].red/=number_images;
675 evaluate_pixel[x].green/=number_images;
676 evaluate_pixel[x].blue/=number_images;
677 evaluate_pixel[x].black/=number_images;
678 evaluate_pixel[x].alpha/=number_images;
680 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
682 SetPixelRed(evaluate_image,ClampToQuantum(evaluate_pixel[x].red),q);
683 SetPixelGreen(evaluate_image,ClampToQuantum(evaluate_pixel[x].green),q);
684 SetPixelBlue(evaluate_image,ClampToQuantum(evaluate_pixel[x].blue),q);
685 if (evaluate_image->colorspace == CMYKColorspace)
686 SetPixelBlack(evaluate_image,ClampToQuantum(evaluate_pixel[x].black),
688 if (evaluate_image->matte == MagickFalse)
689 SetPixelAlpha(evaluate_image,ClampToQuantum(evaluate_pixel[x].alpha),
692 SetPixelAlpha(evaluate_image,ClampToQuantum(evaluate_pixel[x].alpha),
694 q+=GetPixelChannels(evaluate_image);
696 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
698 if (images->progress_monitor != (MagickProgressMonitor) NULL)
703 #if defined(MAGICKCORE_OPENMP_SUPPORT)
704 #pragma omp critical (MagickCore_EvaluateImages)
706 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
707 evaluate_image->rows);
708 if (proceed == MagickFalse)
712 evaluate_view=DestroyCacheView(evaluate_view);
713 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
714 random_info=DestroyRandomInfoThreadSet(random_info);
715 if (status == MagickFalse)
716 evaluate_image=DestroyImage(evaluate_image);
717 return(evaluate_image);
720 MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
721 const ChannelType channel,const MagickEvaluateOperator op,const double value,
722 ExceptionInfo *exception)
734 **restrict random_info;
739 assert(image != (Image *) NULL);
740 assert(image->signature == MagickSignature);
741 if (image->debug != MagickFalse)
742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
743 assert(exception != (ExceptionInfo *) NULL);
744 assert(exception->signature == MagickSignature);
745 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
747 InheritException(exception,&image->exception);
752 random_info=AcquireRandomInfoThreadSet();
753 image_view=AcquireCacheView(image);
754 #if defined(MAGICKCORE_OPENMP_SUPPORT)
755 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
757 for (y=0; y < (ssize_t) image->rows; y++)
760 id = GetOpenMPThreadId();
768 if (status == MagickFalse)
770 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
771 if (q == (const Quantum *) NULL)
776 for (x=0; x < (ssize_t) image->columns; x++)
778 if ((channel & RedChannel) != 0)
779 SetPixelRed(image,ClampToQuantum(ApplyEvaluateOperator(
780 random_info[id],GetPixelRed(image,q),op,value)),q);
781 if ((channel & GreenChannel) != 0)
782 SetPixelGreen(image,ClampToQuantum(ApplyEvaluateOperator(
783 random_info[id],GetPixelGreen(image,q),op,value)),q);
784 if ((channel & BlueChannel) != 0)
785 SetPixelBlue(image,ClampToQuantum(ApplyEvaluateOperator(
786 random_info[id],GetPixelBlue(image,q),op,value)),q);
787 if (((channel & BlackChannel) != 0) &&
788 (image->colorspace == CMYKColorspace))
789 SetPixelBlack(image,ClampToQuantum(ApplyEvaluateOperator(
790 random_info[id],GetPixelBlack(image,q),op,value)),q);
791 if ((channel & AlphaChannel) != 0)
793 if (image->matte == MagickFalse)
794 SetPixelAlpha(image,ClampToQuantum(ApplyEvaluateOperator(
795 random_info[id],GetPixelAlpha(image,q),op,value)),q);
797 SetPixelAlpha(image,ClampToQuantum(ApplyEvaluateOperator(
798 random_info[id],GetPixelAlpha(image,q),op,value)),q);
800 q+=GetPixelChannels(image);
802 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
804 if (image->progress_monitor != (MagickProgressMonitor) NULL)
809 #if defined(MAGICKCORE_OPENMP_SUPPORT)
810 #pragma omp critical (MagickCore_EvaluateImageChannel)
812 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
813 if (proceed == MagickFalse)
817 image_view=DestroyCacheView(image_view);
818 random_info=DestroyRandomInfoThreadSet(random_info);
823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827 % F u n c t i o n I m a g e %
831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833 % FunctionImage() applies a value to the image with an arithmetic, relational,
834 % or logical operator to an image. Use these operations to lighten or darken
835 % an image, to increase or decrease contrast in an image, or to produce the
836 % "negative" of an image.
838 % The format of the FunctionImageChannel method is:
840 % MagickBooleanType FunctionImage(Image *image,
841 % const MagickFunction function,const ssize_t number_parameters,
842 % const double *parameters,ExceptionInfo *exception)
843 % MagickBooleanType FunctionImageChannel(Image *image,
844 % const ChannelType channel,const MagickFunction function,
845 % const ssize_t number_parameters,const double *argument,
846 % ExceptionInfo *exception)
848 % A description of each parameter follows:
850 % o image: the image.
852 % o channel: the channel.
854 % o function: A channel function.
856 % o parameters: one or more parameters.
858 % o exception: return any errors or warnings in this structure.
862 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
863 const size_t number_parameters,const double *parameters,
864 ExceptionInfo *exception)
876 case PolynomialFunction:
880 * Parameters: polynomial constants, highest to lowest order
881 * For example: c0*x^3 + c1*x^2 + c2*x + c3
884 for (i=0; i < (ssize_t) number_parameters; i++)
885 result = result*QuantumScale*pixel + parameters[i];
886 result *= QuantumRange;
889 case SinusoidFunction:
892 * Parameters: Freq, Phase, Ampl, bias
894 double freq,phase,ampl,bias;
895 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
896 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
897 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
898 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
899 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
900 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
905 /* Arcsin Function (peged at range limits for invalid results)
906 * Parameters: Width, Center, Range, Bias
908 double width,range,center,bias;
909 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
910 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
911 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
912 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
913 result = 2.0/width*(QuantumScale*pixel - center);
914 if ( result <= -1.0 )
915 result = bias - range/2.0;
916 else if ( result >= 1.0 )
917 result = bias + range/2.0;
919 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
920 result *= QuantumRange;
926 * Parameters: Slope, Center, Range, Bias
928 double slope,range,center,bias;
929 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
930 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
931 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
932 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
933 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
934 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
938 case UndefinedFunction:
941 return(ClampToQuantum(result));
944 MagickExport MagickBooleanType FunctionImage(Image *image,
945 const MagickFunction function,const size_t number_parameters,
946 const double *parameters,ExceptionInfo *exception)
951 status=FunctionImageChannel(image,CompositeChannels,function,number_parameters,
952 parameters,exception);
956 MagickExport MagickBooleanType FunctionImageChannel(Image *image,
957 const ChannelType channel,const MagickFunction function,
958 const size_t number_parameters,const double *parameters,
959 ExceptionInfo *exception)
961 #define FunctionImageTag "Function/Image "
975 assert(image != (Image *) NULL);
976 assert(image->signature == MagickSignature);
977 if (image->debug != MagickFalse)
978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
979 assert(exception != (ExceptionInfo *) NULL);
980 assert(exception->signature == MagickSignature);
981 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
983 InheritException(exception,&image->exception);
988 image_view=AcquireCacheView(image);
989 #if defined(MAGICKCORE_OPENMP_SUPPORT)
990 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
992 for (y=0; y < (ssize_t) image->rows; y++)
1000 if (status == MagickFalse)
1002 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1003 if (q == (const Quantum *) NULL)
1008 for (x=0; x < (ssize_t) image->columns; x++)
1010 if ((channel & RedChannel) != 0)
1011 SetPixelRed(image,ApplyFunction(GetPixelRed(image,q),function,
1012 number_parameters,parameters,exception),q);
1013 if ((channel & GreenChannel) != 0)
1014 SetPixelGreen(image,ApplyFunction(GetPixelGreen(image,q),function,
1015 number_parameters,parameters,exception),q);
1016 if ((channel & BlueChannel) != 0)
1017 SetPixelBlue(image,ApplyFunction(GetPixelBlue(image,q),function,
1018 number_parameters,parameters,exception),q);
1019 if (((channel & BlackChannel) != 0) &&
1020 (image->colorspace == CMYKColorspace))
1021 SetPixelBlack(image,ApplyFunction(GetPixelBlack(image,q),function,
1022 number_parameters,parameters,exception),q);
1023 if ((channel & AlphaChannel) != 0)
1025 if (image->matte == MagickFalse)
1026 SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
1027 number_parameters,parameters,exception),q);
1029 SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
1030 number_parameters,parameters,exception),q);
1032 q+=GetPixelChannels(image);
1034 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1036 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1041 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1042 #pragma omp critical (MagickCore_FunctionImageChannel)
1044 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1045 if (proceed == MagickFalse)
1049 image_view=DestroyCacheView(image_view);
1054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1058 + G e t I m a g e C h a n n e l E x t r e m a %
1062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064 % GetImageChannelExtrema() returns the extrema of one or more image channels.
1066 % The format of the GetImageChannelExtrema method is:
1068 % MagickBooleanType GetImageChannelExtrema(const Image *image,
1069 % const ChannelType channel,size_t *minima,size_t *maxima,
1070 % ExceptionInfo *exception)
1072 % A description of each parameter follows:
1074 % o image: the image.
1076 % o channel: the channel.
1078 % o minima: the minimum value in the channel.
1080 % o maxima: the maximum value in the channel.
1082 % o exception: return any errors or warnings in this structure.
1086 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1087 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1089 return(GetImageChannelExtrema(image,CompositeChannels,minima,maxima,exception));
1092 MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
1093 const ChannelType channel,size_t *minima,size_t *maxima,
1094 ExceptionInfo *exception)
1103 assert(image != (Image *) NULL);
1104 assert(image->signature == MagickSignature);
1105 if (image->debug != MagickFalse)
1106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1107 status=GetImageChannelRange(image,channel,&min,&max,exception);
1108 *minima=(size_t) ceil(min-0.5);
1109 *maxima=(size_t) floor(max+0.5);
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 % G e t I m a g e C h a n n e l M e a n %
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 % GetImageChannelMean() returns the mean and standard deviation of one or more
1127 % The format of the GetImageChannelMean method is:
1129 % MagickBooleanType GetImageChannelMean(const Image *image,
1130 % const ChannelType channel,double *mean,double *standard_deviation,
1131 % ExceptionInfo *exception)
1133 % A description of each parameter follows:
1135 % o image: the image.
1137 % o channel: the channel.
1139 % o mean: the average value in the channel.
1141 % o standard_deviation: the standard deviation of the channel.
1143 % o exception: return any errors or warnings in this structure.
1147 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1148 double *standard_deviation,ExceptionInfo *exception)
1153 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1158 MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
1159 const ChannelType channel,double *mean,double *standard_deviation,
1160 ExceptionInfo *exception)
1163 *channel_statistics;
1168 assert(image != (Image *) NULL);
1169 assert(image->signature == MagickSignature);
1170 if (image->debug != MagickFalse)
1171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1172 channel_statistics=GetImageChannelStatistics(image,exception);
1173 if (channel_statistics == (ChannelStatistics *) NULL)
1174 return(MagickFalse);
1176 channel_statistics[CompositeChannels].mean=0.0;
1177 channel_statistics[CompositeChannels].standard_deviation=0.0;
1178 if ((channel & RedChannel) != 0)
1180 channel_statistics[CompositeChannels].mean+=
1181 channel_statistics[RedChannel].mean;
1182 channel_statistics[CompositeChannels].standard_deviation+=
1183 channel_statistics[RedChannel].variance-
1184 channel_statistics[RedChannel].mean*
1185 channel_statistics[RedChannel].mean;
1188 if ((channel & GreenChannel) != 0)
1190 channel_statistics[CompositeChannels].mean+=
1191 channel_statistics[GreenChannel].mean;
1192 channel_statistics[CompositeChannels].standard_deviation+=
1193 channel_statistics[GreenChannel].variance-
1194 channel_statistics[GreenChannel].mean*
1195 channel_statistics[GreenChannel].mean;
1198 if ((channel & BlueChannel) != 0)
1200 channel_statistics[CompositeChannels].mean+=
1201 channel_statistics[BlueChannel].mean;
1202 channel_statistics[CompositeChannels].standard_deviation+=
1203 channel_statistics[BlueChannel].variance-
1204 channel_statistics[BlueChannel].mean*
1205 channel_statistics[BlueChannel].mean;
1208 if (((channel & BlackChannel) != 0) &&
1209 (image->colorspace == CMYKColorspace))
1211 channel_statistics[CompositeChannels].mean+=
1212 channel_statistics[BlackChannel].mean;
1213 channel_statistics[CompositeChannels].standard_deviation+=
1214 channel_statistics[BlackChannel].variance-
1215 channel_statistics[BlackChannel].mean*
1216 channel_statistics[BlackChannel].mean;
1219 if (((channel & AlphaChannel) != 0) &&
1220 (image->matte != MagickFalse))
1222 channel_statistics[CompositeChannels].mean+=
1223 channel_statistics[AlphaChannel].mean;
1224 channel_statistics[CompositeChannels].standard_deviation+=
1225 channel_statistics[AlphaChannel].variance-
1226 channel_statistics[AlphaChannel].mean*
1227 channel_statistics[AlphaChannel].mean;
1230 channel_statistics[CompositeChannels].mean/=channels;
1231 channel_statistics[CompositeChannels].standard_deviation=
1232 sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
1233 *mean=channel_statistics[CompositeChannels].mean;
1234 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1235 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1236 channel_statistics);
1241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245 % G e t I m a g e C h a n n e l K u r t o s i s %
1249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1251 % GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
1254 % The format of the GetImageChannelKurtosis method is:
1256 % MagickBooleanType GetImageChannelKurtosis(const Image *image,
1257 % const ChannelType channel,double *kurtosis,double *skewness,
1258 % ExceptionInfo *exception)
1260 % A description of each parameter follows:
1262 % o image: the image.
1264 % o channel: the channel.
1266 % o kurtosis: the kurtosis of the channel.
1268 % o skewness: the skewness of the channel.
1270 % o exception: return any errors or warnings in this structure.
1274 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1275 double *kurtosis,double *skewness,ExceptionInfo *exception)
1280 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1285 MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
1286 const ChannelType channel,double *kurtosis,double *skewness,
1287 ExceptionInfo *exception)
1300 assert(image != (Image *) NULL);
1301 assert(image->signature == MagickSignature);
1302 if (image->debug != MagickFalse)
1303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1308 standard_deviation=0.0;
1311 sum_fourth_power=0.0;
1312 for (y=0; y < (ssize_t) image->rows; y++)
1314 register const Quantum
1320 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1321 if (p == (const Quantum *) NULL)
1323 for (x=0; x < (ssize_t) image->columns; x++)
1325 if ((channel & RedChannel) != 0)
1327 mean+=GetPixelRed(image,p);
1328 sum_squares+=(double) GetPixelRed(image,p)*GetPixelRed(image,p);
1329 sum_cubes+=(double) GetPixelRed(image,p)*GetPixelRed(image,p)*
1330 GetPixelRed(image,p);
1331 sum_fourth_power+=(double) GetPixelRed(image,p)*
1332 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
1335 if ((channel & GreenChannel) != 0)
1337 mean+=GetPixelGreen(image,p);
1338 sum_squares+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p);
1339 sum_cubes+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1340 GetPixelGreen(image,p);
1341 sum_fourth_power+=(double) GetPixelGreen(image,p)*
1342 GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1343 GetPixelGreen(image,p);
1346 if ((channel & BlueChannel) != 0)
1348 mean+=GetPixelBlue(image,p);
1349 sum_squares+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p);
1350 sum_cubes+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1351 GetPixelBlue(image,p);
1352 sum_fourth_power+=(double) GetPixelBlue(image,p)*
1353 GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1354 GetPixelBlue(image,p);
1357 if (((channel & BlackChannel) != 0) &&
1358 (image->colorspace == CMYKColorspace))
1360 mean+=GetPixelBlack(image,p);
1361 sum_squares+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p);
1362 sum_cubes+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1363 GetPixelBlack(image,p);
1364 sum_fourth_power+=(double) GetPixelBlack(image,p)*
1365 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1366 GetPixelBlack(image,p);
1369 if ((channel & AlphaChannel) != 0)
1371 mean+=GetPixelAlpha(image,p);
1372 sum_squares+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1373 sum_cubes+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1374 GetPixelAlpha(image,p);
1375 sum_fourth_power+=(double) GetPixelAlpha(image,p)*
1376 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1377 GetPixelAlpha(image,p);
1380 p+=GetPixelChannels(image);
1383 if (y < (ssize_t) image->rows)
1384 return(MagickFalse);
1390 sum_fourth_power/=area;
1392 standard_deviation=sqrt(sum_squares-(mean*mean));
1393 if (standard_deviation != 0.0)
1395 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1396 3.0*mean*mean*mean*mean;
1397 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1400 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1401 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1403 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411 % G e t I m a g e C h a n n e l R a n g e %
1415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417 % GetImageChannelRange() returns the range of one or more image channels.
1419 % The format of the GetImageChannelRange method is:
1421 % MagickBooleanType GetImageChannelRange(const Image *image,
1422 % const ChannelType channel,double *minima,double *maxima,
1423 % ExceptionInfo *exception)
1425 % A description of each parameter follows:
1427 % o image: the image.
1429 % o channel: the channel.
1431 % o minima: the minimum value in the channel.
1433 % o maxima: the maximum value in the channel.
1435 % o exception: return any errors or warnings in this structure.
1439 MagickExport MagickBooleanType GetImageRange(const Image *image,
1440 double *minima,double *maxima,ExceptionInfo *exception)
1442 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
1445 MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
1446 const ChannelType channel,double *minima,double *maxima,
1447 ExceptionInfo *exception)
1455 assert(image != (Image *) NULL);
1456 assert(image->signature == MagickSignature);
1457 if (image->debug != MagickFalse)
1458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1461 GetPixelInfo(image,&pixel);
1462 for (y=0; y < (ssize_t) image->rows; y++)
1464 register const Quantum
1470 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1471 if (p == (const Quantum *) NULL)
1473 for (x=0; x < (ssize_t) image->columns; x++)
1475 SetPixelInfo(image,p,&pixel);
1476 if ((channel & RedChannel) != 0)
1478 if (pixel.red < *minima)
1479 *minima=(double) pixel.red;
1480 if (pixel.red > *maxima)
1481 *maxima=(double) pixel.red;
1483 if ((channel & GreenChannel) != 0)
1485 if (pixel.green < *minima)
1486 *minima=(double) pixel.green;
1487 if (pixel.green > *maxima)
1488 *maxima=(double) pixel.green;
1490 if ((channel & BlueChannel) != 0)
1492 if (pixel.blue < *minima)
1493 *minima=(double) pixel.blue;
1494 if (pixel.blue > *maxima)
1495 *maxima=(double) pixel.blue;
1497 if (((channel & BlackChannel) != 0) &&
1498 (image->colorspace == CMYKColorspace))
1500 if (pixel.black < *minima)
1501 *minima=(double) pixel.black;
1502 if (pixel.black > *maxima)
1503 *maxima=(double) pixel.black;
1505 if ((channel & AlphaChannel) != 0)
1507 if (pixel.alpha < *minima)
1508 *minima=(double) pixel.alpha;
1509 if (pixel.alpha > *maxima)
1510 *maxima=(double) pixel.alpha;
1512 p+=GetPixelChannels(image);
1515 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523 % 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 %
1527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529 % GetImageChannelStatistics() returns statistics for each channel in the
1530 % image. The statistics include the channel depth, its minima, maxima, mean,
1531 % standard deviation, kurtosis and skewness. You can access the red channel
1532 % mean, for example, like this:
1534 % channel_statistics=GetImageChannelStatistics(image,exception);
1535 % red_mean=channel_statistics[RedChannel].mean;
1537 % Use MagickRelinquishMemory() to free the statistics buffer.
1539 % The format of the GetImageChannelStatistics method is:
1541 % ChannelStatistics *GetImageChannelStatistics(const Image *image,
1542 % ExceptionInfo *exception)
1544 % A description of each parameter follows:
1546 % o image: the image.
1548 % o exception: return any errors or warnings in this structure.
1551 MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
1552 ExceptionInfo *exception)
1555 *channel_statistics;
1577 assert(image != (Image *) NULL);
1578 assert(image->signature == MagickSignature);
1579 if (image->debug != MagickFalse)
1580 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1581 length=CompositeChannels+1UL;
1582 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
1583 sizeof(*channel_statistics));
1584 if (channel_statistics == (ChannelStatistics *) NULL)
1585 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1586 (void) ResetMagickMemory(channel_statistics,0,length*
1587 sizeof(*channel_statistics));
1588 for (i=0; i <= (ssize_t) CompositeChannels; i++)
1590 channel_statistics[i].depth=1;
1591 channel_statistics[i].maxima=(-1.0E-37);
1592 channel_statistics[i].minima=1.0E+37;
1594 for (y=0; y < (ssize_t) image->rows; y++)
1596 register const Quantum
1602 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1603 if (p == (const Quantum *) NULL)
1605 for (x=0; x < (ssize_t) image->columns; )
1607 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1609 depth=channel_statistics[RedChannel].depth;
1610 range=GetQuantumRange(depth);
1611 status=GetPixelRed(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1612 GetPixelRed(image,p),range),range) ? MagickTrue : MagickFalse;
1613 if (status != MagickFalse)
1615 channel_statistics[RedChannel].depth++;
1619 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1621 depth=channel_statistics[GreenChannel].depth;
1622 range=GetQuantumRange(depth);
1623 status=GetPixelGreen(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1624 GetPixelGreen(image,p),range),range) ? MagickTrue : MagickFalse;
1625 if (status != MagickFalse)
1627 channel_statistics[GreenChannel].depth++;
1631 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1633 depth=channel_statistics[BlueChannel].depth;
1634 range=GetQuantumRange(depth);
1635 status=GetPixelBlue(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
1636 GetPixelBlue(image,p),range),range) ? MagickTrue : MagickFalse;
1637 if (status != MagickFalse)
1639 channel_statistics[BlueChannel].depth++;
1643 if (image->matte != MagickFalse)
1645 if (channel_statistics[AlphaChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1647 depth=channel_statistics[AlphaChannel].depth;
1648 range=GetQuantumRange(depth);
1649 status=GetPixelAlpha(image,p) != ScaleAnyToQuantum(
1650 ScaleQuantumToAny(GetPixelAlpha(image,p),range),range) ?
1651 MagickTrue : MagickFalse;
1652 if (status != MagickFalse)
1654 channel_statistics[AlphaChannel].depth++;
1659 if (image->colorspace == CMYKColorspace)
1661 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1663 depth=channel_statistics[BlackChannel].depth;
1664 range=GetQuantumRange(depth);
1665 status=GetPixelBlack(image,p) != ScaleAnyToQuantum(
1666 ScaleQuantumToAny(GetPixelBlack(image,p),range),range) ?
1667 MagickTrue : MagickFalse;
1668 if (status != MagickFalse)
1670 channel_statistics[BlackChannel].depth++;
1675 if ((double) GetPixelRed(image,p) < channel_statistics[RedChannel].minima)
1676 channel_statistics[RedChannel].minima=(double) GetPixelRed(image,p);
1677 if ((double) GetPixelRed(image,p) > channel_statistics[RedChannel].maxima)
1678 channel_statistics[RedChannel].maxima=(double) GetPixelRed(image,p);
1679 channel_statistics[RedChannel].sum+=GetPixelRed(image,p);
1680 channel_statistics[RedChannel].sum_squared+=(double)
1681 GetPixelRed(image,p)*GetPixelRed(image,p);
1682 channel_statistics[RedChannel].sum_cubed+=(double)
1683 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
1684 channel_statistics[RedChannel].sum_fourth_power+=(double)
1685 GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p)*
1686 GetPixelRed(image,p);
1687 if ((double) GetPixelGreen(image,p) < channel_statistics[GreenChannel].minima)
1688 channel_statistics[GreenChannel].minima=(double)
1689 GetPixelGreen(image,p);
1690 if ((double) GetPixelGreen(image,p) > channel_statistics[GreenChannel].maxima)
1691 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(image,p);
1692 channel_statistics[GreenChannel].sum+=GetPixelGreen(image,p);
1693 channel_statistics[GreenChannel].sum_squared+=(double)
1694 GetPixelGreen(image,p)*GetPixelGreen(image,p);
1695 channel_statistics[GreenChannel].sum_cubed+=(double)
1696 GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p);
1697 channel_statistics[GreenChannel].sum_fourth_power+=(double)
1698 GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p)*
1699 GetPixelGreen(image,p);
1700 if ((double) GetPixelBlue(image,p) < channel_statistics[BlueChannel].minima)
1701 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(image,p);
1702 if ((double) GetPixelBlue(image,p) > channel_statistics[BlueChannel].maxima)
1703 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(image,p);
1704 channel_statistics[BlueChannel].sum+=GetPixelBlue(image,p);
1705 channel_statistics[BlueChannel].sum_squared+=(double)
1706 GetPixelBlue(image,p)*GetPixelBlue(image,p);
1707 channel_statistics[BlueChannel].sum_cubed+=(double)
1708 GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p);
1709 channel_statistics[BlueChannel].sum_fourth_power+=(double)
1710 GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p)*
1711 GetPixelBlue(image,p);
1712 if (image->colorspace == CMYKColorspace)
1714 if ((double) GetPixelBlack(image,p) < channel_statistics[BlackChannel].minima)
1715 channel_statistics[BlackChannel].minima=(double)
1716 GetPixelBlack(image,p);
1717 if ((double) GetPixelBlack(image,p) > channel_statistics[BlackChannel].maxima)
1718 channel_statistics[BlackChannel].maxima=(double)
1719 GetPixelBlack(image,p);
1720 channel_statistics[BlackChannel].sum+=GetPixelBlack(image,p);
1721 channel_statistics[BlackChannel].sum_squared+=(double)
1722 GetPixelBlack(image,p)*GetPixelBlack(image,p);
1723 channel_statistics[BlackChannel].sum_cubed+=(double)
1724 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1725 GetPixelBlack(image,p);
1726 channel_statistics[BlackChannel].sum_fourth_power+=(double)
1727 GetPixelBlack(image,p)*GetPixelBlack(image,p)*
1728 GetPixelBlack(image,p)*GetPixelBlack(image,p);
1730 if (image->matte != MagickFalse)
1732 if ((double) GetPixelAlpha(image,p) < channel_statistics[AlphaChannel].minima)
1733 channel_statistics[AlphaChannel].minima=(double)
1734 GetPixelAlpha(image,p);
1735 if ((double) GetPixelAlpha(image,p) > channel_statistics[AlphaChannel].maxima)
1736 channel_statistics[AlphaChannel].maxima=(double)
1737 GetPixelAlpha(image,p);
1738 channel_statistics[AlphaChannel].sum+=GetPixelAlpha(image,p);
1739 channel_statistics[AlphaChannel].sum_squared+=(double)
1740 GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1741 channel_statistics[AlphaChannel].sum_cubed+=(double)
1742 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1743 GetPixelAlpha(image,p);
1744 channel_statistics[AlphaChannel].sum_fourth_power+=(double)
1745 GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
1746 GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
1749 p+=GetPixelChannels(image);
1752 area=(double) image->columns*image->rows;
1753 for (i=0; i < (ssize_t) CompositeChannels; i++)
1755 channel_statistics[i].sum/=area;
1756 channel_statistics[i].sum_squared/=area;
1757 channel_statistics[i].sum_cubed/=area;
1758 channel_statistics[i].sum_fourth_power/=area;
1759 channel_statistics[i].mean=channel_statistics[i].sum;
1760 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1761 channel_statistics[i].standard_deviation=sqrt(
1762 channel_statistics[i].variance-(channel_statistics[i].mean*
1763 channel_statistics[i].mean));
1765 for (i=0; i < (ssize_t) CompositeChannels; i++)
1767 channel_statistics[CompositeChannels].depth=(size_t) MagickMax((double)
1768 channel_statistics[CompositeChannels].depth,(double)
1769 channel_statistics[i].depth);
1770 channel_statistics[CompositeChannels].minima=MagickMin(
1771 channel_statistics[CompositeChannels].minima,
1772 channel_statistics[i].minima);
1773 channel_statistics[CompositeChannels].maxima=MagickMax(
1774 channel_statistics[CompositeChannels].maxima,
1775 channel_statistics[i].maxima);
1776 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
1777 channel_statistics[CompositeChannels].sum_squared+=
1778 channel_statistics[i].sum_squared;
1779 channel_statistics[CompositeChannels].sum_cubed+=
1780 channel_statistics[i].sum_cubed;
1781 channel_statistics[CompositeChannels].sum_fourth_power+=
1782 channel_statistics[i].sum_fourth_power;
1783 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
1784 channel_statistics[CompositeChannels].variance+=
1785 channel_statistics[i].variance-channel_statistics[i].mean*
1786 channel_statistics[i].mean;
1787 channel_statistics[CompositeChannels].standard_deviation+=
1788 channel_statistics[i].variance-channel_statistics[i].mean*
1789 channel_statistics[i].mean;
1792 if (image->matte != MagickFalse)
1794 if (image->colorspace == CMYKColorspace)
1796 channel_statistics[CompositeChannels].sum/=channels;
1797 channel_statistics[CompositeChannels].sum_squared/=channels;
1798 channel_statistics[CompositeChannels].sum_cubed/=channels;
1799 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
1800 channel_statistics[CompositeChannels].mean/=channels;
1801 channel_statistics[CompositeChannels].variance/=channels;
1802 channel_statistics[CompositeChannels].standard_deviation=
1803 sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
1804 channel_statistics[CompositeChannels].kurtosis/=channels;
1805 channel_statistics[CompositeChannels].skewness/=channels;
1806 for (i=0; i <= (ssize_t) CompositeChannels; i++)
1808 if (channel_statistics[i].standard_deviation == 0.0)
1810 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-
1811 3.0*channel_statistics[i].mean*channel_statistics[i].sum_squared+
1812 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1813 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1814 channel_statistics[i].standard_deviation*
1815 channel_statistics[i].standard_deviation);
1816 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-
1817 4.0*channel_statistics[i].mean*channel_statistics[i].sum_cubed+
1818 6.0*channel_statistics[i].mean*channel_statistics[i].mean*
1819 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1820 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1821 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1822 channel_statistics[i].standard_deviation*
1823 channel_statistics[i].standard_deviation*
1824 channel_statistics[i].standard_deviation)-3.0;
1826 return(channel_statistics);