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 _WenusInfo
134 channel[MaxPixelChannels];
137 static WenusInfo **DestroyPixelThreadSet(WenusInfo **pixels)
142 assert(pixels != (WenusInfo **) NULL);
143 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
144 if (pixels[i] != (WenusInfo *) NULL)
145 pixels[i]=(WenusInfo *) RelinquishMagickMemory(pixels[i]);
146 pixels=(WenusInfo **) RelinquishMagickMemory(pixels);
150 static WenusInfo **AcquirePixelThreadSet(const Image *image,
151 const size_t number_images)
163 number_threads=GetOpenMPMaximumThreads();
164 pixels=(WenusInfo **) AcquireQuantumMemory(number_threads,sizeof(*pixels));
165 if (pixels == (WenusInfo **) NULL)
166 return((WenusInfo **) NULL);
167 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
168 for (i=0; i < (ssize_t) number_threads; i++)
173 length=image->columns;
174 if (length < number_images)
175 length=number_images;
176 pixels[i]=(WenusInfo *) AcquireQuantumMemory(length,sizeof(**pixels));
177 if (pixels[i] == (WenusInfo *) NULL)
178 return(DestroyPixelThreadSet(pixels));
179 for (j=0; j < (ssize_t) length; j++)
184 for (k=0; k < MaxPixelChannels; k++)
185 pixels[i][j].channel[k]=0.0;
191 static inline double MagickMax(const double x,const double y)
198 #if defined(__cplusplus) || defined(c_plusplus)
202 static int IntensityCompare(const void *x,const void *y)
214 color_1=(const WenusInfo *) x;
215 color_2=(const WenusInfo *) y;
217 for (i=0; i < MaxPixelChannels; i++)
218 distance+=color_1->channel[i]-(MagickRealType) color_2->channel[i];
219 return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
222 #if defined(__cplusplus) || defined(c_plusplus)
226 static inline double MagickMin(const double x,const double y)
233 static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
234 Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
242 case UndefinedEvaluateOperator:
244 case AbsEvaluateOperator:
246 result=(MagickRealType) fabs((double) (pixel+value));
249 case AddEvaluateOperator:
251 result=(MagickRealType) (pixel+value);
254 case AddModulusEvaluateOperator:
257 This returns a 'floored modulus' of the addition which is a
258 positive result. It differs from % or fmod() that returns a
259 'truncated modulus' result, where floor() is replaced by trunc() and
260 could return a negative result (which is clipped).
263 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
266 case AndEvaluateOperator:
268 result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
271 case CosineEvaluateOperator:
273 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
274 QuantumScale*pixel*value))+0.5));
277 case DivideEvaluateOperator:
279 result=pixel/(value == 0.0 ? 1.0 : value);
282 case ExponentialEvaluateOperator:
284 result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
288 case GaussianNoiseEvaluateOperator:
290 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
291 GaussianNoise,value);
294 case ImpulseNoiseEvaluateOperator:
296 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
300 case LaplacianNoiseEvaluateOperator:
302 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
303 LaplacianNoise,value);
306 case LeftShiftEvaluateOperator:
308 result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
311 case LogEvaluateOperator:
313 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
314 pixel+1.0))/log((double) (value+1.0)));
317 case MaxEvaluateOperator:
319 result=(MagickRealType) MagickMax((double) pixel,value);
322 case MeanEvaluateOperator:
324 result=(MagickRealType) (pixel+value);
327 case MedianEvaluateOperator:
329 result=(MagickRealType) (pixel+value);
332 case MinEvaluateOperator:
334 result=(MagickRealType) MagickMin((double) pixel,value);
337 case MultiplicativeNoiseEvaluateOperator:
339 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
340 MultiplicativeGaussianNoise,value);
343 case MultiplyEvaluateOperator:
345 result=(MagickRealType) (value*pixel);
348 case OrEvaluateOperator:
350 result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
353 case PoissonNoiseEvaluateOperator:
355 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
359 case PowEvaluateOperator:
361 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
365 case RightShiftEvaluateOperator:
367 result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
370 case SetEvaluateOperator:
375 case SineEvaluateOperator:
377 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
378 QuantumScale*pixel*value))+0.5));
381 case SubtractEvaluateOperator:
383 result=(MagickRealType) (pixel-value);
386 case ThresholdEvaluateOperator:
388 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
392 case ThresholdBlackEvaluateOperator:
394 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
397 case ThresholdWhiteEvaluateOperator:
399 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
403 case UniformNoiseEvaluateOperator:
405 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
409 case XorEvaluateOperator:
411 result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
418 MagickExport Image *EvaluateImages(const Image *images,
419 const MagickEvaluateOperator op,ExceptionInfo *exception)
421 #define EvaluateImageTag "Evaluate/Image"
439 **restrict evaluate_pixels;
442 **restrict random_info;
451 Ensure the image are the same size.
453 assert(images != (Image *) NULL);
454 assert(images->signature == MagickSignature);
455 if (images->debug != MagickFalse)
456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
457 assert(exception != (ExceptionInfo *) NULL);
458 assert(exception->signature == MagickSignature);
459 for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
460 if ((next->columns != images->columns) || (next->rows != images->rows))
462 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
463 "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
464 return((Image *) NULL);
467 Initialize evaluate next attributes.
469 evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
471 if (evaluate_image == (Image *) NULL)
472 return((Image *) NULL);
473 if (SetImageStorageClass(evaluate_image,DirectClass,exception) == MagickFalse)
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 == (WenusInfo **) 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 random_info=AcquireRandomInfoThreadSet();
493 evaluate_view=AcquireCacheView(evaluate_image);
494 if (op == MedianEvaluateOperator)
495 #if defined(MAGICKCORE_OPENMP_SUPPORT)
496 #pragma omp parallel for schedule(dynamic) shared(progress,status)
498 for (y=0; y < (ssize_t) evaluate_image->rows; y++)
507 id = GetOpenMPThreadId();
518 if (status == MagickFalse)
520 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
522 if (q == (Quantum *) NULL)
527 evaluate_pixel=evaluate_pixels[id];
528 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
534 for (j=0; j < (ssize_t) number_images; j++)
535 for (k=0; k < MaxPixelChannels; k++)
536 evaluate_pixel[j].channel[k]=0.0;
538 for (j=0; j < (ssize_t) number_images; j++)
540 register const Quantum
546 image_view=AcquireCacheView(next);
547 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
548 if (p == (const Quantum *) NULL)
550 image_view=DestroyCacheView(image_view);
553 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
562 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,
564 channel=GetPixelChannelMapChannel(evaluate_image,(PixelChannel) i);
565 traits=GetPixelChannelMapTraits(next,channel);
566 if ((traits == UndefinedPixelTrait) ||
567 (evaluate_traits == UndefinedPixelTrait))
569 if ((evaluate_traits & UpdatePixelTrait) == 0)
571 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(random_info[id],
572 GetPixelChannel(evaluate_image,channel,p),op,
573 evaluate_pixel[j].channel[i]);
575 image_view=DestroyCacheView(image_view);
576 next=GetNextImageInList(next);
578 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
580 for (k=0; k < (ssize_t) GetPixelChannels(evaluate_image); k++)
581 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
582 q+=GetPixelChannels(evaluate_image);
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();
628 if (status == MagickFalse)
630 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
632 if (q == (Quantum *) NULL)
637 evaluate_pixel=evaluate_pixels[id];
638 for (j=0; j < (ssize_t) evaluate_image->columns; j++)
639 for (i=0; i < MaxPixelChannels; i++)
640 evaluate_pixel[j].channel[i]=0.0;
642 for (j=0; j < (ssize_t) number_images; j++)
644 register const Quantum
647 image_view=AcquireCacheView(next);
648 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
649 if (p == (const Quantum *) NULL)
651 image_view=DestroyCacheView(image_view);
654 for (x=0; x < (ssize_t) next->columns; x++)
659 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
668 evaluate_traits=GetPixelChannelMapTraits(evaluate_image,
670 channel=GetPixelChannelMapChannel(evaluate_image,(PixelChannel) i);
671 traits=GetPixelChannelMapTraits(next,channel);
672 if ((traits == UndefinedPixelTrait) ||
673 (evaluate_traits == UndefinedPixelTrait))
675 if ((traits & UpdatePixelTrait) == 0)
677 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(random_info[id],
678 GetPixelChannel(evaluate_image,channel,p),j == 0 ?
679 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
681 p+=GetPixelChannels(next);
683 image_view=DestroyCacheView(image_view);
684 next=GetNextImageInList(next);
686 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
693 case MeanEvaluateOperator:
695 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
696 evaluate_pixel[x].channel[i]/=(MagickRealType) number_images;
699 case MultiplyEvaluateOperator:
701 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
706 for (j=0; j < (ssize_t) (number_images-1); j++)
707 evaluate_pixel[x].channel[i]*=QuantumScale;
715 for (x=0; x < (ssize_t) evaluate_image->columns; x++)
720 for (i=0; i < (ssize_t) GetPixelChannels(evaluate_image); i++)
725 traits=GetPixelChannelMapTraits(evaluate_image,(PixelChannel) i);
726 if (traits == UndefinedPixelTrait)
728 if ((traits & UpdatePixelTrait) == 0)
730 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
732 q+=GetPixelChannels(evaluate_image);
734 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
736 if (images->progress_monitor != (MagickProgressMonitor) NULL)
741 #if defined(MAGICKCORE_OPENMP_SUPPORT)
742 #pragma omp critical (MagickCore_EvaluateImages)
744 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
745 evaluate_image->rows);
746 if (proceed == MagickFalse)
750 evaluate_view=DestroyCacheView(evaluate_view);
751 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
752 random_info=DestroyRandomInfoThreadSet(random_info);
753 if (status == MagickFalse)
754 evaluate_image=DestroyImage(evaluate_image);
755 return(evaluate_image);
758 MagickExport MagickBooleanType EvaluateImage(Image *image,
759 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
771 **restrict random_info;
776 assert(image != (Image *) NULL);
777 assert(image->signature == MagickSignature);
778 if (image->debug != MagickFalse)
779 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
780 assert(exception != (ExceptionInfo *) NULL);
781 assert(exception->signature == MagickSignature);
782 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
786 random_info=AcquireRandomInfoThreadSet();
787 image_view=AcquireCacheView(image);
788 #if defined(MAGICKCORE_OPENMP_SUPPORT)
789 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
791 for (y=0; y < (ssize_t) image->rows; y++)
794 id = GetOpenMPThreadId();
802 if (status == MagickFalse)
804 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
805 if (q == (Quantum *) NULL)
810 for (x=0; x < (ssize_t) image->columns; x++)
815 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
820 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
821 if (traits == UndefinedPixelTrait)
823 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
826 q+=GetPixelChannels(image);
828 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
830 if (image->progress_monitor != (MagickProgressMonitor) NULL)
835 #if defined(MAGICKCORE_OPENMP_SUPPORT)
836 #pragma omp critical (MagickCore_EvaluateImage)
838 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
839 if (proceed == MagickFalse)
843 image_view=DestroyCacheView(image_view);
844 random_info=DestroyRandomInfoThreadSet(random_info);
849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853 % F u n c t i o n I m a g e %
857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 % FunctionImage() applies a value to the image with an arithmetic, relational,
860 % or logical operator to an image. Use these operations to lighten or darken
861 % an image, to increase or decrease contrast in an image, or to produce the
862 % "negative" of an image.
864 % The format of the FunctionImage method is:
866 % MagickBooleanType FunctionImage(Image *image,
867 % const MagickFunction function,const ssize_t number_parameters,
868 % const double *parameters,ExceptionInfo *exception)
870 % A description of each parameter follows:
872 % o image: the image.
874 % o function: A channel function.
876 % o parameters: one or more parameters.
878 % o exception: return any errors or warnings in this structure.
882 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
883 const size_t number_parameters,const double *parameters,
884 ExceptionInfo *exception)
896 case PolynomialFunction:
899 Polynomial: polynomial constants, highest to lowest order
900 (e.g. c0*x^3 + c1*x^2 + c2*x + c3).
903 for (i=0; i < (ssize_t) number_parameters; i++)
904 result=result*QuantumScale*pixel+parameters[i];
905 result*=QuantumRange;
908 case SinusoidFunction:
917 Sinusoid: frequency, phase, amplitude, bias.
919 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
920 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
921 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
922 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
923 result=(MagickRealType) (QuantumRange*(amplitude*sin((double) (2.0*
924 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
936 Arcsin (peged at range limits for invalid results):
937 width, center, range, and bias.
939 width=(number_parameters >= 1) ? parameters[0] : 1.0;
940 center=(number_parameters >= 2) ? parameters[1] : 0.5;
941 range=(number_parameters >= 3) ? parameters[2] : 1.0;
942 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
943 result=2.0/width*(QuantumScale*pixel-center);
944 if ( result <= -1.0 )
945 result=bias-range/2.0;
948 result=bias+range/2.0;
950 result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
951 result*=QuantumRange;
963 Arctan: slope, center, range, and bias.
965 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
966 center=(number_parameters >= 2) ? parameters[1] : 0.5;
967 range=(number_parameters >= 3) ? parameters[2] : 1.0;
968 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
969 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
970 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
974 case UndefinedFunction:
977 return(ClampToQuantum(result));
980 MagickExport MagickBooleanType FunctionImage(Image *image,
981 const MagickFunction function,const size_t number_parameters,
982 const double *parameters,ExceptionInfo *exception)
984 #define FunctionImageTag "Function/Image "
998 assert(image != (Image *) NULL);
999 assert(image->signature == MagickSignature);
1000 if (image->debug != MagickFalse)
1001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1002 assert(exception != (ExceptionInfo *) NULL);
1003 assert(exception->signature == MagickSignature);
1004 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1005 return(MagickFalse);
1008 image_view=AcquireCacheView(image);
1009 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1010 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1012 for (y=0; y < (ssize_t) image->rows; y++)
1020 if (status == MagickFalse)
1022 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1023 if (q == (Quantum *) NULL)
1028 for (x=0; x < (ssize_t) image->columns; x++)
1033 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1038 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1039 if (traits == UndefinedPixelTrait)
1041 if ((traits & UpdatePixelTrait) == 0)
1043 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1046 q+=GetPixelChannels(image);
1048 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1050 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1055 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1056 #pragma omp critical (MagickCore_FunctionImage)
1058 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1059 if (proceed == MagickFalse)
1063 image_view=DestroyCacheView(image_view);
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 % G e t I m a g e E x t r e m a %
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % GetImageExtrema() returns the extrema of one or more image channels.
1080 % The format of the GetImageExtrema method is:
1082 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1083 % size_t *maxima,ExceptionInfo *exception)
1085 % A description of each parameter follows:
1087 % o image: the image.
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.
1096 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1097 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1106 assert(image != (Image *) NULL);
1107 assert(image->signature == MagickSignature);
1108 if (image->debug != MagickFalse)
1109 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1110 status=GetImageRange(image,&min,&max,exception);
1111 *minima=(size_t) ceil(min-0.5);
1112 *maxima=(size_t) floor(max+0.5);
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 % G e t I m a g e M e a n %
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % GetImageMean() returns the mean and standard deviation of one or more
1130 % The format of the GetImageMean method is:
1132 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1133 % double *standard_deviation,ExceptionInfo *exception)
1135 % A description of each parameter follows:
1137 % o image: the image.
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.
1146 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1147 double *standard_deviation,ExceptionInfo *exception)
1150 *channel_statistics;
1158 assert(image != (Image *) NULL);
1159 assert(image->signature == MagickSignature);
1160 if (image->debug != MagickFalse)
1161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1162 channel_statistics=GetImageStatistics(image,exception);
1163 if (channel_statistics == (ChannelStatistics *) NULL)
1164 return(MagickFalse);
1166 channel_statistics[MaxPixelChannels].mean=0.0;
1167 channel_statistics[MaxPixelChannels].standard_deviation=0.0;
1168 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1173 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1174 if (traits == UndefinedPixelTrait)
1176 if ((traits & UpdatePixelTrait) == 0)
1178 channel_statistics[MaxPixelChannels].mean+=channel_statistics[i].mean;
1179 channel_statistics[MaxPixelChannels].standard_deviation+=
1180 channel_statistics[i].variance-channel_statistics[i].mean*
1181 channel_statistics[i].mean;
1184 channel_statistics[MaxPixelChannels].mean/=area;
1185 channel_statistics[MaxPixelChannels].standard_deviation=
1186 sqrt(channel_statistics[MaxPixelChannels].standard_deviation/area);
1187 *mean=channel_statistics[MaxPixelChannels].mean;
1188 *standard_deviation=channel_statistics[MaxPixelChannels].standard_deviation;
1189 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1190 channel_statistics);
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 % G e t I m a g e K u r t o s i s %
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1208 % The format of the GetImageKurtosis method is:
1210 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1211 % double *skewness,ExceptionInfo *exception)
1213 % A description of each parameter follows:
1215 % o image: the image.
1217 % o kurtosis: the kurtosis of the channel.
1219 % o skewness: the skewness of the channel.
1221 % o exception: return any errors or warnings in this structure.
1224 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1225 double *kurtosis,double *skewness,ExceptionInfo *exception)
1244 assert(image != (Image *) NULL);
1245 assert(image->signature == MagickSignature);
1246 if (image->debug != MagickFalse)
1247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1253 standard_deviation=0.0;
1256 sum_fourth_power=0.0;
1257 image_view=AcquireCacheView(image);
1258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1259 #pragma omp parallel for schedule(dynamic) shared(status) omp_throttle(1)
1261 for (y=0; y < (ssize_t) image->rows; y++)
1263 register const Quantum
1269 if (status == MagickFalse)
1271 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1272 if (p == (const Quantum *) NULL)
1277 for (x=0; x < (ssize_t) image->columns; x++)
1282 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1287 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1288 if (traits == UndefinedPixelTrait)
1290 if ((traits & UpdatePixelTrait) == 0)
1292 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1293 #pragma omp critical (MagickCore_GetImageKurtosis)
1297 sum_squares+=(double) p[i]*p[i];
1298 sum_cubes+=(double) p[i]*p[i]*p[i];
1299 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1303 p+=GetPixelChannels(image);
1306 image_view=DestroyCacheView(image_view);
1312 sum_fourth_power/=area;
1314 standard_deviation=sqrt(sum_squares-(mean*mean));
1315 if (standard_deviation != 0.0)
1317 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1318 3.0*mean*mean*mean*mean;
1319 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1322 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1323 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 % G e t I m a g e R a n g e %
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339 % GetImageRange() returns the range of one or more image channels.
1341 % The format of the GetImageRange method is:
1343 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1344 % double *maxima,ExceptionInfo *exception)
1346 % A description of each parameter follows:
1348 % o image: the image.
1350 % o minima: the minimum value in the channel.
1352 % o maxima: the maximum value in the channel.
1354 % o exception: return any errors or warnings in this structure.
1357 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1358 double *maxima,ExceptionInfo *exception)
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1374 *maxima=(-MagickHuge);
1376 image_view=AcquireCacheView(image);
1377 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1378 #pragma omp parallel for schedule(dynamic) shared(status) omp_throttle(1)
1380 for (y=0; y < (ssize_t) image->rows; y++)
1382 register const Quantum
1388 if (status == MagickFalse)
1390 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1391 if (p == (const Quantum *) NULL)
1396 for (x=0; x < (ssize_t) image->columns; x++)
1401 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1406 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1407 if (traits == UndefinedPixelTrait)
1409 if ((traits & UpdatePixelTrait) == 0)
1411 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1412 #pragma omp critical (MagickCore_GetImageRange)
1416 *minima=(double) p[i];
1418 *maxima=(double) p[i];
1421 p+=GetPixelChannels(image);
1424 image_view=DestroyCacheView(image_view);
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 % G e t I m a g e S t a t i s t i c s %
1437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 % GetImageStatistics() returns statistics for each channel in the
1440 % image. The statistics include the channel depth, its minima, maxima, mean,
1441 % standard deviation, kurtosis and skewness. You can access the red channel
1442 % mean, for example, like this:
1444 % channel_statistics=GetImageStatistics(image,exception);
1445 % red_mean=channel_statistics[RedPixelChannel].mean;
1447 % Use MagickRelinquishMemory() to free the statistics buffer.
1449 % The format of the GetImageStatistics method is:
1451 % ChannelStatistics *GetImageStatistics(const Image *image,
1452 % ExceptionInfo *exception)
1454 % A description of each parameter follows:
1456 % o image: the image.
1458 % o exception: return any errors or warnings in this structure.
1462 static size_t GetImageChannels(const Image *image)
1471 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1476 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1477 if ((traits & UpdatePixelTrait) != 0)
1483 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1484 ExceptionInfo *exception)
1487 *channel_statistics;
1508 assert(image != (Image *) NULL);
1509 assert(image->signature == MagickSignature);
1510 if (image->debug != MagickFalse)
1511 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1512 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1513 MaxPixelChannels+1,sizeof(*channel_statistics));
1514 if (channel_statistics == (ChannelStatistics *) NULL)
1515 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1516 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1517 sizeof(*channel_statistics));
1518 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1520 channel_statistics[i].depth=1;
1521 channel_statistics[i].maxima=(-MagickHuge);
1522 channel_statistics[i].minima=MagickHuge;
1524 for (y=0; y < (ssize_t) image->rows; y++)
1526 register const Quantum
1532 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1533 if (p == (const Quantum *) NULL)
1535 for (x=0; x < (ssize_t) image->columns; x++)
1540 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1545 traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1546 if (traits == UndefinedPixelTrait)
1548 if (channel_statistics[i].depth != MAGICKCORE_QUANTUM_DEPTH)
1550 depth=channel_statistics[i].depth;
1551 range=GetQuantumRange(depth);
1552 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1553 range) ? MagickTrue : MagickFalse;
1554 if (status != MagickFalse)
1556 channel_statistics[i].depth++;
1560 if ((double) p[i] < channel_statistics[i].minima)
1561 channel_statistics[i].minima=(double) p[i];
1562 if ((double) p[i] > channel_statistics[i].maxima)
1563 channel_statistics[i].maxima=(double) p[i];
1564 channel_statistics[i].sum+=p[i];
1565 channel_statistics[i].sum_squared+=(double) p[i]*p[i];
1566 channel_statistics[i].sum_cubed+=(double) p[i]*p[i]*p[i];
1567 channel_statistics[i].sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1569 p+=GetPixelChannels(image);
1572 area=(double) image->columns*image->rows;
1573 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1575 channel_statistics[i].sum/=area;
1576 channel_statistics[i].sum_squared/=area;
1577 channel_statistics[i].sum_cubed/=area;
1578 channel_statistics[i].sum_fourth_power/=area;
1579 channel_statistics[i].mean=channel_statistics[i].sum;
1580 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1581 channel_statistics[i].standard_deviation=sqrt(
1582 channel_statistics[i].variance-(channel_statistics[i].mean*
1583 channel_statistics[i].mean));
1585 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1587 channel_statistics[MaxPixelChannels].depth=(size_t) MagickMax((double)
1588 channel_statistics[MaxPixelChannels].depth,(double)
1589 channel_statistics[i].depth);
1590 channel_statistics[MaxPixelChannels].minima=MagickMin(
1591 channel_statistics[MaxPixelChannels].minima,
1592 channel_statistics[i].minima);
1593 channel_statistics[MaxPixelChannels].maxima=MagickMax(
1594 channel_statistics[MaxPixelChannels].maxima,
1595 channel_statistics[i].maxima);
1596 channel_statistics[MaxPixelChannels].sum+=channel_statistics[i].sum;
1597 channel_statistics[MaxPixelChannels].sum_squared+=
1598 channel_statistics[i].sum_squared;
1599 channel_statistics[MaxPixelChannels].sum_cubed+=
1600 channel_statistics[i].sum_cubed;
1601 channel_statistics[MaxPixelChannels].sum_fourth_power+=
1602 channel_statistics[i].sum_fourth_power;
1603 channel_statistics[MaxPixelChannels].mean+=channel_statistics[i].mean;
1604 channel_statistics[MaxPixelChannels].variance+=
1605 channel_statistics[i].variance-channel_statistics[i].mean*
1606 channel_statistics[i].mean;
1607 channel_statistics[MaxPixelChannels].standard_deviation+=
1608 channel_statistics[i].variance-channel_statistics[i].mean*
1609 channel_statistics[i].mean;
1611 channels=GetImageChannels(image);
1612 channel_statistics[MaxPixelChannels].sum/=channels;
1613 channel_statistics[MaxPixelChannels].sum_squared/=channels;
1614 channel_statistics[MaxPixelChannels].sum_cubed/=channels;
1615 channel_statistics[MaxPixelChannels].sum_fourth_power/=channels;
1616 channel_statistics[MaxPixelChannels].mean/=channels;
1617 channel_statistics[MaxPixelChannels].variance/=channels;
1618 channel_statistics[MaxPixelChannels].standard_deviation=
1619 sqrt(channel_statistics[MaxPixelChannels].standard_deviation/channels);
1620 channel_statistics[MaxPixelChannels].kurtosis/=channels;
1621 channel_statistics[MaxPixelChannels].skewness/=channels;
1622 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1624 if (channel_statistics[i].standard_deviation == 0.0)
1626 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-
1627 3.0*channel_statistics[i].mean*channel_statistics[i].sum_squared+
1628 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1629 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1630 channel_statistics[i].standard_deviation*
1631 channel_statistics[i].standard_deviation);
1632 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-
1633 4.0*channel_statistics[i].mean*channel_statistics[i].sum_cubed+
1634 6.0*channel_statistics[i].mean*channel_statistics[i].mean*
1635 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1636 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1637 channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
1638 channel_statistics[i].standard_deviation*
1639 channel_statistics[i].standard_deviation*
1640 channel_statistics[i].standard_deviation)-3.0;
1642 return(channel_statistics);