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/gem-private.h"
67 #include "MagickCore/geometry.h"
68 #include "MagickCore/list.h"
69 #include "MagickCore/image-private.h"
70 #include "MagickCore/magic.h"
71 #include "MagickCore/magick.h"
72 #include "MagickCore/memory_.h"
73 #include "MagickCore/module.h"
74 #include "MagickCore/monitor.h"
75 #include "MagickCore/monitor-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/paint.h"
78 #include "MagickCore/pixel-accessor.h"
79 #include "MagickCore/profile.h"
80 #include "MagickCore/quantize.h"
81 #include "MagickCore/quantum-private.h"
82 #include "MagickCore/random_.h"
83 #include "MagickCore/random-private.h"
84 #include "MagickCore/segment.h"
85 #include "MagickCore/semaphore.h"
86 #include "MagickCore/signature-private.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/thread-private.h"
90 #include "MagickCore/timer.h"
91 #include "MagickCore/utility.h"
92 #include "MagickCore/version.h"
95 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 % E v a l u a t e I m a g e %
103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 % EvaluateImage() applies a value to the image with an arithmetic, relational,
106 % or logical operator to an image. Use these operations to lighten or darken
107 % an image, to increase or decrease contrast in an image, or to produce the
108 % "negative" of an image.
110 % The format of the EvaluateImage method is:
112 % MagickBooleanType EvaluateImage(Image *image,
113 % const MagickEvaluateOperator op,const double value,
114 % ExceptionInfo *exception)
115 % MagickBooleanType EvaluateImages(Image *images,
116 % const MagickEvaluateOperator op,const double value,
117 % ExceptionInfo *exception)
119 % A description of each parameter follows:
121 % o image: the image.
123 % o op: A channel op.
125 % o value: A value value.
127 % o exception: return any errors or warnings in this structure.
131 typedef struct _PixelChannels
134 channel[CompositePixelChannel];
137 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
142 assert(pixels != (PixelChannels **) NULL);
143 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
144 if (pixels[i] != (PixelChannels *) NULL)
145 pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
146 pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
150 static PixelChannels **AcquirePixelThreadSet(const Image *image,
151 const size_t number_images)
163 number_threads=GetOpenMPMaximumThreads();
164 pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
166 if (pixels == (PixelChannels **) NULL)
167 return((PixelChannels **) NULL);
168 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
169 for (i=0; i < (ssize_t) number_threads; i++)
174 length=image->columns;
175 if (length < number_images)
176 length=number_images;
177 pixels[i]=(PixelChannels *) AcquireQuantumMemory(length,sizeof(**pixels));
178 if (pixels[i] == (PixelChannels *) NULL)
179 return(DestroyPixelThreadSet(pixels));
180 for (j=0; j < (ssize_t) length; j++)
185 for (k=0; k < MaxPixelChannels; k++)
186 pixels[i][j].channel[k]=0.0;
192 static inline double MagickMax(const double x,const double y)
199 #if defined(__cplusplus) || defined(c_plusplus)
203 static int IntensityCompare(const void *x,const void *y)
215 color_1=(const PixelChannels *) x;
216 color_2=(const PixelChannels *) y;
218 for (i=0; i < MaxPixelChannels; i++)
219 distance+=color_1->channel[i]-(MagickRealType) color_2->channel[i];
220 return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
223 #if defined(__cplusplus) || defined(c_plusplus)
227 static inline double MagickMin(const double x,const double y)
234 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
235 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
243 case UndefinedEvaluateOperator:
245 case AbsEvaluateOperator:
247 result=(MagickRealType) fabs((double) (pixel+value));
250 case AddEvaluateOperator:
252 result=(MagickRealType) (pixel+value);
255 case AddModulusEvaluateOperator:
258 This returns a 'floored modulus' of the addition which is a positive
259 result. It differs from % or fmod() that returns a 'truncated modulus'
260 result, where floor() is replaced by trunc() and could return a
261 negative result (which is clipped).
264 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
267 case AndEvaluateOperator:
269 result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
272 case CosineEvaluateOperator:
274 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
275 QuantumScale*pixel*value))+0.5));
278 case DivideEvaluateOperator:
280 result=pixel/(value == 0.0 ? 1.0 : value);
283 case ExponentialEvaluateOperator:
285 result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
289 case GaussianNoiseEvaluateOperator:
291 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
292 GaussianNoise,value);
295 case ImpulseNoiseEvaluateOperator:
297 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
301 case LaplacianNoiseEvaluateOperator:
303 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
304 LaplacianNoise,value);
307 case LeftShiftEvaluateOperator:
309 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
312 case LogEvaluateOperator:
314 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
315 pixel+1.0))/log((double) (value+1.0)));
318 case MaxEvaluateOperator:
320 result=(MagickRealType) MagickMax((double) pixel,value);
323 case MeanEvaluateOperator:
325 result=(MagickRealType) (pixel+value);
328 case MedianEvaluateOperator:
330 result=(MagickRealType) (pixel+value);
333 case MinEvaluateOperator:
335 result=(MagickRealType) MagickMin((double) pixel,value);
338 case MultiplicativeNoiseEvaluateOperator:
340 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
341 MultiplicativeGaussianNoise,value);
344 case MultiplyEvaluateOperator:
346 result=(MagickRealType) (value*pixel);
349 case OrEvaluateOperator:
351 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
354 case PoissonNoiseEvaluateOperator:
356 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
360 case PowEvaluateOperator:
362 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
366 case RightShiftEvaluateOperator:
368 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
371 case SetEvaluateOperator:
376 case SineEvaluateOperator:
378 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
379 QuantumScale*pixel*value))+0.5));
382 case SubtractEvaluateOperator:
384 result=(MagickRealType) (pixel-value);
387 case ThresholdEvaluateOperator:
389 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
393 case ThresholdBlackEvaluateOperator:
395 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
398 case ThresholdWhiteEvaluateOperator:
400 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
404 case UniformNoiseEvaluateOperator:
406 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
410 case XorEvaluateOperator:
412 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
419 MagickExport Image *EvaluateImages(const Image *images,
420 const MagickEvaluateOperator op,ExceptionInfo *exception)
422 #define EvaluateImageTag "Evaluate/Image"
440 **restrict evaluate_pixels;
443 **restrict random_info;
452 Ensure the image are the same size.
454 assert(images != (Image *) NULL);
455 assert(images->signature == MagickSignature);
456 if (images->debug != MagickFalse)
457 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
458 assert(exception != (ExceptionInfo *) NULL);
459 assert(exception->signature == MagickSignature);
460 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
461 if ((next->columns != images->columns) || (next->rows != images->rows))
463 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
464 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
465 return((Image *) NULL);
468 Initialize evaluate next attributes.
470 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
472 if (evaluate_image == (Image *) NULL)
473 return((Image *) NULL);
474 if (SetImageStorageClass(evaluate_image,DirectClass,exception) == MagickFalse)
476 evaluate_image=DestroyImage(evaluate_image);
477 return((Image *) NULL);
479 number_images=GetImageListLength(images);
480 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
481 if (evaluate_pixels == (PixelChannels **) NULL)
483 evaluate_image=DestroyImage(evaluate_image);
484 (void) ThrowMagickException(exception,GetMagickModule(),
485 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
486 return((Image *) NULL);
489 Evaluate image pixels.
493 random_info=AcquireRandomInfoThreadSet();
494 evaluate_view=AcquireCacheView(evaluate_image);
495 if (op == MedianEvaluateOperator)
497 #if defined(MAGICKCORE_OPENMP_SUPPORT)
498 #pragma omp parallel for schedule(dynamic) shared(progress,status)
500 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
509 id = GetOpenMPThreadId();
511 register PixelChannels
520 if (status == MagickFalse)
522 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
523 evaluate_image->columns,1,exception);
524 if (q == (Quantum *) NULL)
529 evaluate_pixel=evaluate_pixels[id];
530 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
536 for (j=0; j < (ssize_t) number_images; j++)
537 for (k=0; k < MaxPixelChannels; k++)
538 evaluate_pixel[j].channel[k]=0.0;
540 for (j=0; j < (ssize_t) number_images; j++)
542 register const Quantum
548 image_view=AcquireCacheView(next);
549 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
550 if (p == (const Quantum *) NULL)
552 image_view=DestroyCacheView(image_view);
555 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
564 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,
566 channel=GetPixelChannelMapChannel(evaluate_image,
568 traits=GetPixelChannelMapTraits(next,channel);
569 if ((traits == UndefinedPixelTrait) ||
570 (evaluate_traits == UndefinedPixelTrait))
572 if ((evaluate_traits & UpdatePixelTrait) == 0)
574 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
575 random_info[id],GetPixelChannel(evaluate_image,channel,p),op,
576 evaluate_pixel[j].channel[i]);
578 image_view=DestroyCacheView(image_view);
579 next=GetNextImageInList(next);
581 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
583 for (k=0; k < (ssize_t) GetPixelChannels(evaluate_image); k++)
584 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
585 q+=GetPixelChannels(evaluate_image);
587 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
589 if (images->progress_monitor != (MagickProgressMonitor) NULL)
594 #if defined(MAGICKCORE_OPENMP_SUPPORT)
595 #pragma omp critical (MagickCore_EvaluateImages)
597 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
598 evaluate_image->rows);
599 if (proceed == MagickFalse)
606 #if defined(MAGICKCORE_OPENMP_SUPPORT)
607 #pragma omp parallel for schedule(dynamic) shared(progress,status)
609 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
618 id = GetOpenMPThreadId();
624 register PixelChannels
633 if (status == MagickFalse)
635 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
636 evaluate_image->columns,1,exception);
637 if (q == (Quantum *) NULL)
642 evaluate_pixel=evaluate_pixels[id];
643 for (j=0; j < (ssize_t) evaluate_image->columns; j++)
644 for (i=0; i < MaxPixelChannels; i++)
645 evaluate_pixel[j].channel[i]=0.0;
647 for (j=0; j < (ssize_t) number_images; j++)
649 register const Quantum
652 image_view=AcquireCacheView(next);
653 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
654 if (p == (const Quantum *) NULL)
656 image_view=DestroyCacheView(image_view);
659 for (x=0; x < (ssize_t) next->columns; x++)
664 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
673 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,
675 channel=GetPixelChannelMapChannel(evaluate_image,i);
676 traits=GetPixelChannelMapTraits(next,channel);
677 if ((traits == UndefinedPixelTrait) ||
678 (evaluate_traits == UndefinedPixelTrait))
680 if ((traits & UpdatePixelTrait) == 0)
682 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
683 random_info[id],GetPixelChannel(evaluate_image,channel,p),j ==
684 0 ? AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
686 p+=GetPixelChannels(next);
688 image_view=DestroyCacheView(image_view);
689 next=GetNextImageInList(next);
691 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
698 case MeanEvaluateOperator:
700 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
701 evaluate_pixel[x].channel[i]/=(MagickRealType) number_images;
704 case MultiplyEvaluateOperator:
706 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
711 for (j=0; j < (ssize_t) (number_images-1); j++)
712 evaluate_pixel[x].channel[i]*=QuantumScale;
720 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
725 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
730 traits=GetPixelChannelMapTraits(evaluate_image,i);
731 if (traits == UndefinedPixelTrait)
733 if ((traits & UpdatePixelTrait) == 0)
735 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
737 q+=GetPixelChannels(evaluate_image);
739 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
741 if (images->progress_monitor != (MagickProgressMonitor) NULL)
746 #if defined(MAGICKCORE_OPENMP_SUPPORT)
747 #pragma omp critical (MagickCore_EvaluateImages)
749 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
750 evaluate_image->rows);
751 if (proceed == MagickFalse)
756 evaluate_view=DestroyCacheView(evaluate_view);
757 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
758 random_info=DestroyRandomInfoThreadSet(random_info);
759 if (status == MagickFalse)
760 evaluate_image=DestroyImage(evaluate_image);
761 return(evaluate_image);
764 MagickExport MagickBooleanType EvaluateImage(Image *image,
765 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
777 **restrict random_info;
782 assert(image != (Image *) NULL);
783 assert(image->signature == MagickSignature);
784 if (image->debug != MagickFalse)
785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
786 assert(exception != (ExceptionInfo *) NULL);
787 assert(exception->signature == MagickSignature);
788 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
792 random_info=AcquireRandomInfoThreadSet();
793 image_view=AcquireCacheView(image);
794 #if defined(MAGICKCORE_OPENMP_SUPPORT)
795 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
797 for (y=0; y < (ssize_t) image->rows; y++)
800 id = GetOpenMPThreadId();
808 if (status == MagickFalse)
810 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
811 if (q == (Quantum *) NULL)
816 for (x=0; x < (ssize_t) image->columns; x++)
821 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
826 traits=GetPixelChannelMapTraits(image,i);
827 if (traits == UndefinedPixelTrait)
829 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
832 q+=GetPixelChannels(image);
834 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
836 if (image->progress_monitor != (MagickProgressMonitor) NULL)
841 #if defined(MAGICKCORE_OPENMP_SUPPORT)
842 #pragma omp critical (MagickCore_EvaluateImage)
844 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
845 if (proceed == MagickFalse)
849 image_view=DestroyCacheView(image_view);
850 random_info=DestroyRandomInfoThreadSet(random_info);
855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 % F u n c t i o n I m a g e %
863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865 % FunctionImage() applies a value to the image with an arithmetic, relational,
866 % or logical operator to an image. Use these operations to lighten or darken
867 % an image, to increase or decrease contrast in an image, or to produce the
868 % "negative" of an image.
870 % The format of the FunctionImage method is:
872 % MagickBooleanType FunctionImage(Image *image,
873 % const MagickFunction function,const ssize_t number_parameters,
874 % const double *parameters,ExceptionInfo *exception)
876 % A description of each parameter follows:
878 % o image: the image.
880 % o function: A channel function.
882 % o parameters: one or more parameters.
884 % o exception: return any errors or warnings in this structure.
888 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
889 const size_t number_parameters,const double *parameters,
890 ExceptionInfo *exception)
902 case PolynomialFunction:
905 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
909 for (i=0; i < (ssize_t) number_parameters; i++)
910 result=result*QuantumScale*pixel+parameters[i];
911 result*=QuantumRange;
914 case SinusoidFunction:
923 Sinusoid: frequency, phase, amplitude, bias.
925 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
926 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
927 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
928 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
929 result=(MagickRealType) (QuantumRange*(amplitude*sin((double) (2.0*
930 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
942 Arcsin (peged at range limits for invalid results): width, center,
945 width=(number_parameters >= 1) ? parameters[0] : 1.0;
946 center=(number_parameters >= 2) ? parameters[1] : 0.5;
947 range=(number_parameters >= 3) ? parameters[2] : 1.0;
948 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
949 result=2.0/width*(QuantumScale*pixel-center);
950 if ( result <= -1.0 )
951 result=bias-range/2.0;
954 result=bias+range/2.0;
956 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
957 result*=QuantumRange;
969 Arctan: slope, center, range, and bias.
971 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
972 center=(number_parameters >= 2) ? parameters[1] : 0.5;
973 range=(number_parameters >= 3) ? parameters[2] : 1.0;
974 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
975 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
976 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
980 case UndefinedFunction:
983 return(ClampToQuantum(result));
986 MagickExport MagickBooleanType FunctionImage(Image *image,
987 const MagickFunction function,const size_t number_parameters,
988 const double *parameters,ExceptionInfo *exception)
990 #define FunctionImageTag "Function/Image "
1004 assert(image != (Image *) NULL);
1005 assert(image->signature == MagickSignature);
1006 if (image->debug != MagickFalse)
1007 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1008 assert(exception != (ExceptionInfo *) NULL);
1009 assert(exception->signature == MagickSignature);
1010 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1011 return(MagickFalse);
1014 image_view=AcquireCacheView(image);
1015 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1016 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1018 for (y=0; y < (ssize_t) image->rows; y++)
1026 if (status == MagickFalse)
1028 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1029 if (q == (Quantum *) NULL)
1034 for (x=0; x < (ssize_t) image->columns; x++)
1039 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1044 traits=GetPixelChannelMapTraits(image,i);
1045 if (traits == UndefinedPixelTrait)
1047 if ((traits & UpdatePixelTrait) == 0)
1049 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1052 q+=GetPixelChannels(image);
1054 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1056 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1061 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1062 #pragma omp critical (MagickCore_FunctionImage)
1064 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1065 if (proceed == MagickFalse)
1069 image_view=DestroyCacheView(image_view);
1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % G e t I m a g e E x t r e m a %
1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 % GetImageExtrema() returns the extrema of one or more image channels.
1086 % The format of the GetImageExtrema method is:
1088 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1089 % size_t *maxima,ExceptionInfo *exception)
1091 % A description of each parameter follows:
1093 % o image: the image.
1095 % o minima: the minimum value in the channel.
1097 % o maxima: the maximum value in the channel.
1099 % o exception: return any errors or warnings in this structure.
1102 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1103 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1112 assert(image != (Image *) NULL);
1113 assert(image->signature == MagickSignature);
1114 if (image->debug != MagickFalse)
1115 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1116 status=GetImageRange(image,&min,&max,exception);
1117 *minima=(size_t) ceil(min-0.5);
1118 *maxima=(size_t) floor(max+0.5);
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % G e t I m a g e M e a n %
1131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 % GetImageMean() returns the mean and standard deviation of one or more
1136 % The format of the GetImageMean method is:
1138 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1139 % double *standard_deviation,ExceptionInfo *exception)
1141 % A description of each parameter follows:
1143 % o image: the image.
1145 % o mean: the average value in the channel.
1147 % o standard_deviation: the standard deviation of the channel.
1149 % o exception: return any errors or warnings in this structure.
1152 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1153 double *standard_deviation,ExceptionInfo *exception)
1156 *channel_statistics;
1164 assert(image != (Image *) NULL);
1165 assert(image->signature == MagickSignature);
1166 if (image->debug != MagickFalse)
1167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1168 channel_statistics=GetImageStatistics(image,exception);
1169 if (channel_statistics == (ChannelStatistics *) NULL)
1170 return(MagickFalse);
1172 channel_statistics[CompositePixelChannel].mean=0.0;
1173 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1174 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1179 traits=GetPixelChannelMapTraits(image,i);
1180 if (traits == UndefinedPixelTrait)
1182 if ((traits & UpdatePixelTrait) == 0)
1184 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1185 channel_statistics[CompositePixelChannel].standard_deviation+=
1186 channel_statistics[i].variance-channel_statistics[i].mean*
1187 channel_statistics[i].mean;
1190 channel_statistics[CompositePixelChannel].mean/=area;
1191 channel_statistics[CompositePixelChannel].standard_deviation=
1192 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1193 *mean=channel_statistics[CompositePixelChannel].mean;
1194 *standard_deviation=
1195 channel_statistics[CompositePixelChannel].standard_deviation;
1196 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1197 channel_statistics);
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 % G e t I m a g e K u r t o s i s %
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1215 % The format of the GetImageKurtosis method is:
1217 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1218 % double *skewness,ExceptionInfo *exception)
1220 % A description of each parameter follows:
1222 % o image: the image.
1224 % o kurtosis: the kurtosis of the channel.
1226 % o skewness: the skewness of the channel.
1228 % o exception: return any errors or warnings in this structure.
1231 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1232 double *kurtosis,double *skewness,ExceptionInfo *exception)
1251 assert(image != (Image *) NULL);
1252 assert(image->signature == MagickSignature);
1253 if (image->debug != MagickFalse)
1254 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1260 standard_deviation=0.0;
1263 sum_fourth_power=0.0;
1264 image_view=AcquireCacheView(image);
1265 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1266 #pragma omp parallel for schedule(dynamic) shared(status) omp_throttle(1)
1268 for (y=0; y < (ssize_t) image->rows; y++)
1270 register const Quantum
1276 if (status == MagickFalse)
1278 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1279 if (p == (const Quantum *) NULL)
1284 for (x=0; x < (ssize_t) image->columns; x++)
1289 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1294 traits=GetPixelChannelMapTraits(image,i);
1295 if (traits == UndefinedPixelTrait)
1297 if ((traits & UpdatePixelTrait) == 0)
1299 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1300 #pragma omp critical (MagickCore_GetImageKurtosis)
1304 sum_squares+=(double) p[i]*p[i];
1305 sum_cubes+=(double) p[i]*p[i]*p[i];
1306 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1310 p+=GetPixelChannels(image);
1313 image_view=DestroyCacheView(image_view);
1319 sum_fourth_power/=area;
1321 standard_deviation=sqrt(sum_squares-(mean*mean));
1322 if (standard_deviation != 0.0)
1324 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1325 3.0*mean*mean*mean*mean;
1326 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1329 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1330 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340 % G e t I m a g e R a n g e %
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 % GetImageRange() returns the range of one or more image channels.
1348 % The format of the GetImageRange method is:
1350 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1351 % double *maxima,ExceptionInfo *exception)
1353 % A description of each parameter follows:
1355 % o image: the image.
1357 % o minima: the minimum value in the channel.
1359 % o maxima: the maximum value in the channel.
1361 % o exception: return any errors or warnings in this structure.
1364 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1365 double *maxima,ExceptionInfo *exception)
1376 assert(image != (Image *) NULL);
1377 assert(image->signature == MagickSignature);
1378 if (image->debug != MagickFalse)
1379 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1381 *maxima=(-MagickHuge);
1383 image_view=AcquireCacheView(image);
1384 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1385 #pragma omp parallel for schedule(dynamic) shared(status) omp_throttle(1)
1387 for (y=0; y < (ssize_t) image->rows; y++)
1389 register const Quantum
1395 if (status == MagickFalse)
1397 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1398 if (p == (const Quantum *) NULL)
1403 for (x=0; x < (ssize_t) image->columns; x++)
1408 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1413 traits=GetPixelChannelMapTraits(image,i);
1414 if (traits == UndefinedPixelTrait)
1416 if ((traits & UpdatePixelTrait) == 0)
1418 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1419 #pragma omp critical (MagickCore_GetImageRange)
1423 *minima=(double) p[i];
1425 *maxima=(double) p[i];
1428 p+=GetPixelChannels(image);
1431 image_view=DestroyCacheView(image_view);
1436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % G e t I m a g e S t a t i s t i c s %
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 % GetImageStatistics() returns statistics for each channel in the
1447 % image. The statistics include the channel depth, its minima, maxima, mean,
1448 % standard deviation, kurtosis and skewness. You can access the red channel
1449 % mean, for example, like this:
1451 % channel_statistics=GetImageStatistics(image,exception);
1452 % red_mean=channel_statistics[RedPixelChannel].mean;
1454 % Use MagickRelinquishMemory() to free the statistics buffer.
1456 % The format of the GetImageStatistics method is:
1458 % ChannelStatistics *GetImageStatistics(const Image *image,
1459 % ExceptionInfo *exception)
1461 % A description of each parameter follows:
1463 % o image: the image.
1465 % o exception: return any errors or warnings in this structure.
1469 static size_t GetImageChannels(const Image *image)
1478 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1483 traits=GetPixelChannelMapTraits(image,i);
1484 if ((traits & UpdatePixelTrait) != 0)
1490 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1491 ExceptionInfo *exception)
1494 *channel_statistics;
1515 assert(image != (Image *) NULL);
1516 assert(image->signature == MagickSignature);
1517 if (image->debug != MagickFalse)
1518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1519 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1520 MaxPixelChannels+1,sizeof(*channel_statistics));
1521 if (channel_statistics == (ChannelStatistics *) NULL)
1522 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1523 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1524 sizeof(*channel_statistics));
1525 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1527 channel_statistics[i].depth=1;
1528 channel_statistics[i].maxima=(-MagickHuge);
1529 channel_statistics[i].minima=MagickHuge;
1531 for (y=0; y < (ssize_t) image->rows; y++)
1533 register const Quantum
1539 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1540 if (p == (const Quantum *) NULL)
1542 for (x=0; x < (ssize_t) image->columns; x++)
1547 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1552 traits=GetPixelChannelMapTraits(image,i);
1553 if (traits == UndefinedPixelTrait)
1555 if (channel_statistics[i].depth != MAGICKCORE_QUANTUM_DEPTH)
1557 depth=channel_statistics[i].depth;
1558 range=GetQuantumRange(depth);
1559 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1560 range) ? MagickTrue : MagickFalse;
1561 if (status != MagickFalse)
1563 channel_statistics[i].depth++;
1567 if ((double) p[i] < channel_statistics[i].minima)
1568 channel_statistics[i].minima=(double) p[i];
1569 if ((double) p[i] > channel_statistics[i].maxima)
1570 channel_statistics[i].maxima=(double) p[i];
1571 channel_statistics[i].sum+=p[i];
1572 channel_statistics[i].sum_squared+=(double) p[i]*p[i];
1573 channel_statistics[i].sum_cubed+=(double) p[i]*p[i]*p[i];
1574 channel_statistics[i].sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1576 p+=GetPixelChannels(image);
1579 area=(double) image->columns*image->rows;
1580 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1582 channel_statistics[i].sum/=area;
1583 channel_statistics[i].sum_squared/=area;
1584 channel_statistics[i].sum_cubed/=area;
1585 channel_statistics[i].sum_fourth_power/=area;
1586 channel_statistics[i].mean=channel_statistics[i].sum;
1587 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1588 channel_statistics[i].standard_deviation=sqrt(
1589 channel_statistics[i].variance-(channel_statistics[i].mean*
1590 channel_statistics[i].mean));
1592 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1594 channel_statistics[CompositePixelChannel].depth=(size_t) MagickMax((double)
1595 channel_statistics[CompositePixelChannel].depth,(double)
1596 channel_statistics[i].depth);
1597 channel_statistics[CompositePixelChannel].minima=MagickMin(
1598 channel_statistics[CompositePixelChannel].minima,
1599 channel_statistics[i].minima);
1600 channel_statistics[CompositePixelChannel].maxima=MagickMax(
1601 channel_statistics[CompositePixelChannel].maxima,
1602 channel_statistics[i].maxima);
1603 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1604 channel_statistics[CompositePixelChannel].sum_squared+=
1605 channel_statistics[i].sum_squared;
1606 channel_statistics[CompositePixelChannel].sum_cubed+=
1607 channel_statistics[i].sum_cubed;
1608 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1609 channel_statistics[i].sum_fourth_power;
1610 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1611 channel_statistics[CompositePixelChannel].variance+=
1612 channel_statistics[i].variance-channel_statistics[i].mean*
1613 channel_statistics[i].mean;
1614 channel_statistics[CompositePixelChannel].standard_deviation+=
1615 channel_statistics[i].variance-channel_statistics[i].mean*
1616 channel_statistics[i].mean;
1618 channels=GetImageChannels(image);
1619 channel_statistics[CompositePixelChannel].sum/=channels;
1620 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1621 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1622 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1623 channel_statistics[CompositePixelChannel].mean/=channels;
1624 channel_statistics[CompositePixelChannel].variance/=channels;
1625 channel_statistics[CompositePixelChannel].standard_deviation=
1626 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1627 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1628 channel_statistics[CompositePixelChannel].skewness/=channels;
1629 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1631 if (channel_statistics[i].standard_deviation == 0.0)
1633 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1634 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1635 channel_statistics[i].mean*channel_statistics[i].mean*
1636 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1637 channel_statistics[i].standard_deviation*
1638 channel_statistics[i].standard_deviation);
1639 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1640 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1641 channel_statistics[i].mean*channel_statistics[i].mean*
1642 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1643 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1644 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1645 channel_statistics[i].standard_deviation*
1646 channel_statistics[i].standard_deviation*
1647 channel_statistics[i].standard_deviation)-3.0;
1649 return(channel_statistics);