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-2012 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/resource_.h"
85 #include "MagickCore/segment.h"
86 #include "MagickCore/semaphore.h"
87 #include "MagickCore/signature-private.h"
88 #include "MagickCore/statistic.h"
89 #include "MagickCore/string_.h"
90 #include "MagickCore/thread-private.h"
91 #include "MagickCore/timer.h"
92 #include "MagickCore/utility.h"
93 #include "MagickCore/version.h"
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % E v a l u a t e I m a g e %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 % EvaluateImage() applies a value to the image with an arithmetic, relational,
107 % or logical operator to an image. Use these operations to lighten or darken
108 % an image, to increase or decrease contrast in an image, or to produce the
109 % "negative" of an image.
111 % The format of the EvaluateImage method is:
113 % MagickBooleanType EvaluateImage(Image *image,
114 % const MagickEvaluateOperator op,const double value,
115 % ExceptionInfo *exception)
116 % MagickBooleanType EvaluateImages(Image *images,
117 % const MagickEvaluateOperator op,const double value,
118 % ExceptionInfo *exception)
120 % A description of each parameter follows:
122 % o image: the image.
124 % o op: A channel op.
126 % o value: A value value.
128 % o exception: return any errors or warnings in this structure.
132 typedef struct _PixelChannels
135 channel[CompositePixelChannel];
138 static PixelChannels **DestroyPixelThreadSet(PixelChannels **pixels)
143 assert(pixels != (PixelChannels **) NULL);
144 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
145 if (pixels[i] != (PixelChannels *) NULL)
146 pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
147 pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
151 static PixelChannels **AcquirePixelThreadSet(const Image *image,
152 const size_t number_images)
164 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
165 pixels=(PixelChannels **) AcquireQuantumMemory(number_threads,
167 if (pixels == (PixelChannels **) NULL)
168 return((PixelChannels **) NULL);
169 (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
170 for (i=0; i < (ssize_t) number_threads; i++)
175 length=image->columns;
176 if (length < number_images)
177 length=number_images;
178 pixels[i]=(PixelChannels *) AcquireQuantumMemory(length,sizeof(**pixels));
179 if (pixels[i] == (PixelChannels *) NULL)
180 return(DestroyPixelThreadSet(pixels));
181 for (j=0; j < (ssize_t) length; j++)
186 for (k=0; k < MaxPixelChannels; k++)
187 pixels[i][j].channel[k]=0.0;
193 static inline double EvaluateMax(const double x,const double y)
200 #if defined(__cplusplus) || defined(c_plusplus)
204 static int IntensityCompare(const void *x,const void *y)
216 color_1=(const PixelChannels *) x;
217 color_2=(const PixelChannels *) y;
219 for (i=0; i < MaxPixelChannels; i++)
220 distance+=color_1->channel[i]-(double) color_2->channel[i];
221 return(distance < 0 ? -1 : distance > 0 ? 1 : 0);
224 #if defined(__cplusplus) || defined(c_plusplus)
228 static inline double MagickMin(const double x,const double y)
235 static double ApplyEvaluateOperator(RandomInfo *random_info,const Quantum pixel,
236 const MagickEvaluateOperator op,const double value)
244 case UndefinedEvaluateOperator:
246 case AbsEvaluateOperator:
248 result=(double) fabs((double) (pixel+value));
251 case AddEvaluateOperator:
253 result=(double) (pixel+value);
256 case AddModulusEvaluateOperator:
259 This returns a 'floored modulus' of the addition which is a positive
260 result. It differs from % or fmod() that returns a 'truncated modulus'
261 result, where floor() is replaced by trunc() and could return a
262 negative result (which is clipped).
265 result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
268 case AndEvaluateOperator:
270 result=(double) ((size_t) pixel & (size_t) (value+0.5));
273 case CosineEvaluateOperator:
275 result=(double) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
276 QuantumScale*pixel*value))+0.5));
279 case DivideEvaluateOperator:
281 result=pixel/(value == 0.0 ? 1.0 : value);
284 case ExponentialEvaluateOperator:
286 result=(double) (QuantumRange*exp((double) (value*QuantumScale*pixel)));
289 case GaussianNoiseEvaluateOperator:
291 result=(double) GenerateDifferentialNoise(random_info,pixel,
292 GaussianNoise,value);
295 case ImpulseNoiseEvaluateOperator:
297 result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
301 case LaplacianNoiseEvaluateOperator:
303 result=(double) GenerateDifferentialNoise(random_info,pixel,
304 LaplacianNoise,value);
307 case LeftShiftEvaluateOperator:
309 result=(double) ((size_t) pixel << (size_t) (value+0.5));
312 case LogEvaluateOperator:
314 if ((QuantumScale*pixel) >= MagickEpsilon)
315 result=(double) (QuantumRange*log((double) (QuantumScale*value*pixel+
316 1.0))/log((double) (value+1.0)));
319 case MaxEvaluateOperator:
321 result=(double) EvaluateMax((double) pixel,value);
324 case MeanEvaluateOperator:
326 result=(double) (pixel+value);
329 case MedianEvaluateOperator:
331 result=(double) (pixel+value);
334 case MinEvaluateOperator:
336 result=(double) MagickMin((double) pixel,value);
339 case MultiplicativeNoiseEvaluateOperator:
341 result=(double) GenerateDifferentialNoise(random_info,pixel,
342 MultiplicativeGaussianNoise,value);
345 case MultiplyEvaluateOperator:
347 result=(double) (value*pixel);
350 case OrEvaluateOperator:
352 result=(double) ((size_t) pixel | (size_t) (value+0.5));
355 case PoissonNoiseEvaluateOperator:
357 result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
361 case PowEvaluateOperator:
363 result=(double) (QuantumRange*pow((double) (QuantumScale*pixel),(double)
367 case RightShiftEvaluateOperator:
369 result=(double) ((size_t) pixel >> (size_t) (value+0.5));
372 case SetEvaluateOperator:
377 case SineEvaluateOperator:
379 result=(double) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
380 QuantumScale*pixel*value))+0.5));
383 case SubtractEvaluateOperator:
385 result=(double) (pixel-value);
388 case SumEvaluateOperator:
390 result=(double) (pixel+value);
393 case ThresholdEvaluateOperator:
395 result=(double) (((double) pixel <= value) ? 0 : QuantumRange);
398 case ThresholdBlackEvaluateOperator:
400 result=(double) (((double) pixel <= value) ? 0 : pixel);
403 case ThresholdWhiteEvaluateOperator:
405 result=(double) (((double) pixel > value) ? QuantumRange : pixel);
408 case UniformNoiseEvaluateOperator:
410 result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
414 case XorEvaluateOperator:
416 result=(double) ((size_t) pixel ^ (size_t) (value+0.5));
423 MagickExport Image *EvaluateImages(const Image *images,
424 const MagickEvaluateOperator op,ExceptionInfo *exception)
426 #define EvaluateImageTag "Evaluate/Image"
441 **restrict evaluate_pixels;
444 **restrict random_info;
452 #if defined(MAGICKCORE_OPENMP_SUPPORT)
457 assert(images != (Image *) NULL);
458 assert(images->signature == MagickSignature);
459 if (images->debug != MagickFalse)
460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
461 assert(exception != (ExceptionInfo *) NULL);
462 assert(exception->signature == MagickSignature);
463 image=CloneImage(images,images->columns,images->rows,MagickTrue,
465 if (image == (Image *) NULL)
466 return((Image *) NULL);
467 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
469 image=DestroyImage(image);
470 return((Image *) NULL);
472 number_images=GetImageListLength(images);
473 evaluate_pixels=AcquirePixelThreadSet(images,number_images);
474 if (evaluate_pixels == (PixelChannels **) NULL)
476 image=DestroyImage(image);
477 (void) ThrowMagickException(exception,GetMagickModule(),
478 ResourceLimitError,"MemoryAllocationFailed","'%s'",images->filename);
479 return((Image *) NULL);
482 Evaluate image pixels.
486 random_info=AcquireRandomInfoThreadSet();
487 #if defined(MAGICKCORE_OPENMP_SUPPORT)
488 key=GetRandomSecretKey(random_info[0]);
490 evaluate_view=AcquireAuthenticCacheView(image,exception);
491 if (op == MedianEvaluateOperator)
493 #if defined(MAGICKCORE_OPENMP_SUPPORT)
494 #pragma omp parallel for schedule(static,4) shared(progress,status) \
495 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
497 for (y=0; y < (ssize_t) image->rows; y++)
506 id = GetOpenMPThreadId();
508 register PixelChannels
517 if (status == MagickFalse)
519 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
521 if (q == (Quantum *) NULL)
526 evaluate_pixel=evaluate_pixels[id];
527 for (x=0; x < (ssize_t) image->columns; x++)
533 for (j=0; j < (ssize_t) number_images; j++)
534 for (k=0; k < MaxPixelChannels; k++)
535 evaluate_pixel[j].channel[k]=0.0;
537 for (j=0; j < (ssize_t) number_images; j++)
539 register const Quantum
545 image_view=AcquireVirtualCacheView(next,exception);
546 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
547 if (p == (const Quantum *) NULL)
549 image_view=DestroyCacheView(image_view);
552 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
561 channel=GetPixelChannelChannel(image,i);
562 evaluate_traits=GetPixelChannelTraits(image,channel);
563 traits=GetPixelChannelTraits(next,channel);
564 if ((traits == UndefinedPixelTrait) ||
565 (evaluate_traits == UndefinedPixelTrait))
567 if ((evaluate_traits & UpdatePixelTrait) == 0)
569 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
570 random_info[id],GetPixelChannel(image,channel,p),op,
571 evaluate_pixel[j].channel[i]);
573 image_view=DestroyCacheView(image_view);
574 next=GetNextImageInList(next);
576 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
578 for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
579 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
580 q+=GetPixelChannels(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++,
594 if (proceed == MagickFalse)
601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
602 #pragma omp parallel for schedule(static,4) shared(progress,status) \
603 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
605 for (y=0; y < (ssize_t) image->rows; y++)
614 id = GetOpenMPThreadId();
620 register PixelChannels
629 if (status == MagickFalse)
631 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,
632 image->columns,1,exception);
633 if (q == (Quantum *) NULL)
638 evaluate_pixel=evaluate_pixels[id];
639 for (j=0; j < (ssize_t) image->columns; j++)
640 for (i=0; i < MaxPixelChannels; i++)
641 evaluate_pixel[j].channel[i]=0.0;
643 for (j=0; j < (ssize_t) number_images; j++)
645 register const Quantum
648 image_view=AcquireVirtualCacheView(next,exception);
649 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
650 if (p == (const Quantum *) NULL)
652 image_view=DestroyCacheView(image_view);
655 for (x=0; x < (ssize_t) next->columns; x++)
660 if (GetPixelMask(next,p) != 0)
662 p+=GetPixelChannels(next);
665 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
674 channel=GetPixelChannelChannel(image,i);
675 traits=GetPixelChannelTraits(next,channel);
676 evaluate_traits=GetPixelChannelTraits(image,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(image,channel,p),j == 0 ?
684 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) image->columns; x++)
698 case MeanEvaluateOperator:
700 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
701 evaluate_pixel[x].channel[i]/=(double) number_images;
704 case MultiplyEvaluateOperator:
706 for (i=0; i < (ssize_t) GetPixelChannels(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) image->columns; x++)
725 if (GetPixelMask(image,q) != 0)
727 q+=GetPixelChannels(image);
730 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
738 channel=GetPixelChannelChannel(image,i);
739 traits=GetPixelChannelTraits(image,channel);
740 if (traits == UndefinedPixelTrait)
742 if ((traits & UpdatePixelTrait) == 0)
744 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
746 q+=GetPixelChannels(image);
748 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
750 if (images->progress_monitor != (MagickProgressMonitor) NULL)
755 #if defined(MAGICKCORE_OPENMP_SUPPORT)
756 #pragma omp critical (MagickCore_EvaluateImages)
758 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
760 if (proceed == MagickFalse)
765 evaluate_view=DestroyCacheView(evaluate_view);
766 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
767 random_info=DestroyRandomInfoThreadSet(random_info);
768 if (status == MagickFalse)
769 image=DestroyImage(image);
773 MagickExport MagickBooleanType EvaluateImage(Image *image,
774 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
786 **restrict random_info;
791 #if defined(MAGICKCORE_OPENMP_SUPPORT)
796 assert(image != (Image *) NULL);
797 assert(image->signature == MagickSignature);
798 if (image->debug != MagickFalse)
799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
800 assert(exception != (ExceptionInfo *) NULL);
801 assert(exception->signature == MagickSignature);
802 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
806 random_info=AcquireRandomInfoThreadSet();
807 #if defined(MAGICKCORE_OPENMP_SUPPORT)
808 key=GetRandomSecretKey(random_info[0]);
810 image_view=AcquireAuthenticCacheView(image,exception);
811 #if defined(MAGICKCORE_OPENMP_SUPPORT)
812 #pragma omp parallel for schedule(static,4) shared(progress,status) \
813 dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
815 for (y=0; y < (ssize_t) image->rows; y++)
818 id = GetOpenMPThreadId();
826 if (status == MagickFalse)
828 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
829 if (q == (Quantum *) NULL)
834 for (x=0; x < (ssize_t) image->columns; x++)
839 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
847 channel=GetPixelChannelChannel(image,i);
848 traits=GetPixelChannelTraits(image,channel);
849 if (traits == UndefinedPixelTrait)
851 if (((traits & CopyPixelTrait) != 0) ||
852 (GetPixelMask(image,q) != 0))
854 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
857 q+=GetPixelChannels(image);
859 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
861 if (image->progress_monitor != (MagickProgressMonitor) NULL)
866 #if defined(MAGICKCORE_OPENMP_SUPPORT)
867 #pragma omp critical (MagickCore_EvaluateImage)
869 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
870 if (proceed == MagickFalse)
874 image_view=DestroyCacheView(image_view);
875 random_info=DestroyRandomInfoThreadSet(random_info);
880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
884 % F u n c t i o n I m a g e %
888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890 % FunctionImage() applies a value to the image with an arithmetic, relational,
891 % or logical operator to an image. Use these operations to lighten or darken
892 % an image, to increase or decrease contrast in an image, or to produce the
893 % "negative" of an image.
895 % The format of the FunctionImage method is:
897 % MagickBooleanType FunctionImage(Image *image,
898 % const MagickFunction function,const ssize_t number_parameters,
899 % const double *parameters,ExceptionInfo *exception)
901 % A description of each parameter follows:
903 % o image: the image.
905 % o function: A channel function.
907 % o parameters: one or more parameters.
909 % o exception: return any errors or warnings in this structure.
913 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
914 const size_t number_parameters,const double *parameters,
915 ExceptionInfo *exception)
927 case PolynomialFunction:
930 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
934 for (i=0; i < (ssize_t) number_parameters; i++)
935 result=result*QuantumScale*pixel+parameters[i];
936 result*=QuantumRange;
939 case SinusoidFunction:
948 Sinusoid: frequency, phase, amplitude, bias.
950 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
951 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
952 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
953 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
954 result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
955 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
967 Arcsin (peged at range limits for invalid results): width, center,
970 width=(number_parameters >= 1) ? parameters[0] : 1.0;
971 center=(number_parameters >= 2) ? parameters[1] : 0.5;
972 range=(number_parameters >= 3) ? parameters[2] : 1.0;
973 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
974 result=2.0/width*(QuantumScale*pixel-center);
975 if ( result <= -1.0 )
976 result=bias-range/2.0;
979 result=bias+range/2.0;
981 result=(double) (range/MagickPI*asin((double) result)+bias);
982 result*=QuantumRange;
994 Arctan: slope, center, range, and bias.
996 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
997 center=(number_parameters >= 2) ? parameters[1] : 0.5;
998 range=(number_parameters >= 3) ? parameters[2] : 1.0;
999 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1000 result=(double) (MagickPI*slope*(QuantumScale*pixel-center));
1001 result=(double) (QuantumRange*(range/MagickPI*atan((double)
1005 case UndefinedFunction:
1008 return(ClampToQuantum(result));
1011 MagickExport MagickBooleanType FunctionImage(Image *image,
1012 const MagickFunction function,const size_t number_parameters,
1013 const double *parameters,ExceptionInfo *exception)
1015 #define FunctionImageTag "Function/Image "
1029 assert(image != (Image *) NULL);
1030 assert(image->signature == MagickSignature);
1031 if (image->debug != MagickFalse)
1032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1033 assert(exception != (ExceptionInfo *) NULL);
1034 assert(exception->signature == MagickSignature);
1035 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1036 return(MagickFalse);
1039 image_view=AcquireAuthenticCacheView(image,exception);
1040 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1041 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1042 dynamic_number_threads(image,image->columns,image->rows,1)
1044 for (y=0; y < (ssize_t) image->rows; y++)
1052 if (status == MagickFalse)
1054 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1055 if (q == (Quantum *) NULL)
1060 for (x=0; x < (ssize_t) image->columns; x++)
1065 if (GetPixelMask(image,q) != 0)
1067 q+=GetPixelChannels(image);
1070 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1078 channel=GetPixelChannelChannel(image,i);
1079 traits=GetPixelChannelTraits(image,channel);
1080 if (traits == UndefinedPixelTrait)
1082 if ((traits & UpdatePixelTrait) == 0)
1084 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1087 q+=GetPixelChannels(image);
1089 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1091 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1096 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1097 #pragma omp critical (MagickCore_FunctionImage)
1099 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1100 if (proceed == MagickFalse)
1104 image_view=DestroyCacheView(image_view);
1109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113 % G e t I m a g e E x t r e m a %
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 % GetImageExtrema() returns the extrema of one or more image channels.
1121 % The format of the GetImageExtrema method is:
1123 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1124 % size_t *maxima,ExceptionInfo *exception)
1126 % A description of each parameter follows:
1128 % o image: the image.
1130 % o minima: the minimum value in the channel.
1132 % o maxima: the maximum value in the channel.
1134 % o exception: return any errors or warnings in this structure.
1137 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1138 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1147 assert(image != (Image *) NULL);
1148 assert(image->signature == MagickSignature);
1149 if (image->debug != MagickFalse)
1150 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1151 status=GetImageRange(image,&min,&max,exception);
1152 *minima=(size_t) ceil(min-0.5);
1153 *maxima=(size_t) floor(max+0.5);
1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 % G e t I m a g e M e a n %
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 % GetImageMean() returns the mean and standard deviation of one or more image
1171 % The format of the GetImageMean method is:
1173 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1174 % double *standard_deviation,ExceptionInfo *exception)
1176 % A description of each parameter follows:
1178 % o image: the image.
1180 % o mean: the average value in the channel.
1182 % o standard_deviation: the standard deviation of the channel.
1184 % o exception: return any errors or warnings in this structure.
1187 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1188 double *standard_deviation,ExceptionInfo *exception)
1194 *channel_statistics;
1199 assert(image != (Image *) NULL);
1200 assert(image->signature == MagickSignature);
1201 if (image->debug != MagickFalse)
1202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1203 channel_statistics=GetImageStatistics(image,exception);
1204 if (channel_statistics == (ChannelStatistics *) NULL)
1205 return(MagickFalse);
1207 channel_statistics[CompositePixelChannel].mean=0.0;
1208 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1209 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1217 channel=GetPixelChannelChannel(image,i);
1218 traits=GetPixelChannelTraits(image,channel);
1219 if (traits == UndefinedPixelTrait)
1221 if ((traits & UpdatePixelTrait) == 0)
1223 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1224 channel_statistics[CompositePixelChannel].standard_deviation+=
1225 channel_statistics[i].variance-channel_statistics[i].mean*
1226 channel_statistics[i].mean;
1229 channel_statistics[CompositePixelChannel].mean/=area;
1230 channel_statistics[CompositePixelChannel].standard_deviation=
1231 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1232 *mean=channel_statistics[CompositePixelChannel].mean;
1233 *standard_deviation=
1234 channel_statistics[CompositePixelChannel].standard_deviation;
1235 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1236 channel_statistics);
1241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245 % G e t I m a g e K u r t o s i s %
1249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1251 % GetImageKurtosis() returns the kurtosis and skewness of one or more
1254 % The format of the GetImageKurtosis method is:
1256 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1257 % double *skewness,ExceptionInfo *exception)
1259 % A description of each parameter follows:
1261 % o image: the image.
1263 % o kurtosis: the kurtosis of the channel.
1265 % o skewness: the skewness of the channel.
1267 % o exception: return any errors or warnings in this structure.
1270 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1271 double *kurtosis,double *skewness,ExceptionInfo *exception)
1290 assert(image != (Image *) NULL);
1291 assert(image->signature == MagickSignature);
1292 if (image->debug != MagickFalse)
1293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1299 standard_deviation=0.0;
1302 sum_fourth_power=0.0;
1303 image_view=AcquireVirtualCacheView(image,exception);
1304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1305 #pragma omp parallel for schedule(static,4) shared(status) \
1306 dynamic_number_threads(image,image->columns,image->rows,1)
1308 for (y=0; y < (ssize_t) image->rows; y++)
1310 register const Quantum
1316 if (status == MagickFalse)
1318 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1319 if (p == (const Quantum *) NULL)
1324 for (x=0; x < (ssize_t) image->columns; x++)
1329 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1337 channel=GetPixelChannelChannel(image,i);
1338 traits=GetPixelChannelTraits(image,channel);
1339 if (traits == UndefinedPixelTrait)
1341 if (((traits & UpdatePixelTrait) == 0) ||
1342 (GetPixelMask(image,p) != 0))
1344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1345 #pragma omp critical (MagickCore_GetImageKurtosis)
1349 sum_squares+=(double) p[i]*p[i];
1350 sum_cubes+=(double) p[i]*p[i]*p[i];
1351 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1355 p+=GetPixelChannels(image);
1358 image_view=DestroyCacheView(image_view);
1364 sum_fourth_power/=area;
1366 standard_deviation=sqrt(sum_squares-(mean*mean));
1367 if (standard_deviation != 0.0)
1369 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1370 3.0*mean*mean*mean*mean;
1371 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1374 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1375 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % G e t I m a g e R a n g e %
1389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 % GetImageRange() returns the range of one or more image channels.
1393 % The format of the GetImageRange method is:
1395 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1396 % double *maxima,ExceptionInfo *exception)
1398 % A description of each parameter follows:
1400 % o image: the image.
1402 % o minima: the minimum value in the channel.
1404 % o maxima: the maximum value in the channel.
1406 % o exception: return any errors or warnings in this structure.
1409 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1410 double *maxima,ExceptionInfo *exception)
1422 assert(image != (Image *) NULL);
1423 assert(image->signature == MagickSignature);
1424 if (image->debug != MagickFalse)
1425 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1427 initialize=MagickTrue;
1430 image_view=AcquireVirtualCacheView(image,exception);
1431 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1432 #pragma omp parallel for schedule(static,4) shared(status,initialize) \
1433 dynamic_number_threads(image,image->columns,image->rows,1)
1435 for (y=0; y < (ssize_t) image->rows; y++)
1437 register const Quantum
1443 if (status == MagickFalse)
1445 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1446 if (p == (const Quantum *) NULL)
1451 for (x=0; x < (ssize_t) image->columns; x++)
1456 if (GetPixelMask(image,p) != 0)
1458 p+=GetPixelChannels(image);
1461 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1469 channel=GetPixelChannelChannel(image,i);
1470 traits=GetPixelChannelTraits(image,channel);
1471 if (traits == UndefinedPixelTrait)
1473 if ((traits & UpdatePixelTrait) == 0)
1475 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1476 #pragma omp critical (MagickCore_GetImageRange)
1479 if (initialize != MagickFalse)
1481 *minima=(double) p[i];
1482 *maxima=(double) p[i];
1483 initialize=MagickFalse;
1487 if ((double) p[i] < *minima)
1488 *minima=(double) p[i];
1489 if ((double) p[i] > *maxima)
1490 *maxima=(double) p[i];
1494 p+=GetPixelChannels(image);
1497 image_view=DestroyCacheView(image_view);
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 % G e t I m a g e S t a t i s t i c s %
1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % GetImageStatistics() returns statistics for each channel in the image. The
1513 % statistics include the channel depth, its minima, maxima, mean, standard
1514 % deviation, kurtosis and skewness. You can access the red channel mean, for
1515 % example, like this:
1517 % channel_statistics=GetImageStatistics(image,exception);
1518 % red_mean=channel_statistics[RedPixelChannel].mean;
1520 % Use MagickRelinquishMemory() to free the statistics buffer.
1522 % The format of the GetImageStatistics method is:
1524 % ChannelStatistics *GetImageStatistics(const Image *image,
1525 % ExceptionInfo *exception)
1527 % A description of each parameter follows:
1529 % o image: the image.
1531 % o exception: return any errors or warnings in this structure.
1535 static size_t GetImageChannels(const Image *image)
1544 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1552 channel=GetPixelChannelChannel(image,i);
1553 traits=GetPixelChannelTraits(image,channel);
1554 if ((traits & UpdatePixelTrait) != 0)
1560 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1561 ExceptionInfo *exception)
1564 *channel_statistics;
1582 assert(image != (Image *) NULL);
1583 assert(image->signature == MagickSignature);
1584 if (image->debug != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1586 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1587 MaxPixelChannels+1,sizeof(*channel_statistics));
1588 if (channel_statistics == (ChannelStatistics *) NULL)
1589 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1590 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1591 sizeof(*channel_statistics));
1592 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1594 channel_statistics[i].depth=1;
1595 channel_statistics[i].maxima=(-MagickHuge);
1596 channel_statistics[i].minima=MagickHuge;
1598 for (y=0; y < (ssize_t) image->rows; y++)
1600 register const Quantum
1606 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1607 if (p == (const Quantum *) NULL)
1609 for (x=0; x < (ssize_t) image->columns; x++)
1614 if (GetPixelMask(image,p) != 0)
1616 p+=GetPixelChannels(image);
1619 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1627 channel=GetPixelChannelChannel(image,i);
1628 traits=GetPixelChannelTraits(image,channel);
1629 if (traits == UndefinedPixelTrait)
1631 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1633 depth=channel_statistics[channel].depth;
1634 range=GetQuantumRange(depth);
1635 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1636 range) ? MagickTrue : MagickFalse;
1637 if (status != MagickFalse)
1639 channel_statistics[channel].depth++;
1644 if ((double) p[i] < channel_statistics[channel].minima)
1645 channel_statistics[channel].minima=(double) p[i];
1646 if ((double) p[i] > channel_statistics[channel].maxima)
1647 channel_statistics[channel].maxima=(double) p[i];
1648 channel_statistics[channel].sum+=p[i];
1649 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
1650 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
1651 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
1653 channel_statistics[channel].area++;
1655 p+=GetPixelChannels(image);
1658 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1663 area=PerceptibleReciprocal(channel_statistics[i].area);
1664 channel_statistics[i].sum*=area;
1665 channel_statistics[i].sum_squared*=area;
1666 channel_statistics[i].sum_cubed*=area;
1667 channel_statistics[i].sum_fourth_power*=area;
1668 channel_statistics[i].mean=channel_statistics[i].sum;
1669 channel_statistics[i].variance=channel_statistics[i].sum_squared;
1670 channel_statistics[i].standard_deviation=sqrt(
1671 channel_statistics[i].variance-(channel_statistics[i].mean*
1672 channel_statistics[i].mean));
1674 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
1676 channel_statistics[CompositePixelChannel].depth=(size_t) EvaluateMax(
1677 (double) channel_statistics[CompositePixelChannel].depth,(double)
1678 channel_statistics[i].depth);
1679 channel_statistics[CompositePixelChannel].minima=MagickMin(
1680 channel_statistics[CompositePixelChannel].minima,
1681 channel_statistics[i].minima);
1682 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
1683 channel_statistics[CompositePixelChannel].maxima,
1684 channel_statistics[i].maxima);
1685 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
1686 channel_statistics[CompositePixelChannel].sum_squared+=
1687 channel_statistics[i].sum_squared;
1688 channel_statistics[CompositePixelChannel].sum_cubed+=
1689 channel_statistics[i].sum_cubed;
1690 channel_statistics[CompositePixelChannel].sum_fourth_power+=
1691 channel_statistics[i].sum_fourth_power;
1692 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1693 channel_statistics[CompositePixelChannel].variance+=
1694 channel_statistics[i].variance-channel_statistics[i].mean*
1695 channel_statistics[i].mean;
1696 channel_statistics[CompositePixelChannel].standard_deviation+=
1697 channel_statistics[i].variance-channel_statistics[i].mean*
1698 channel_statistics[i].mean;
1700 channels=GetImageChannels(image);
1701 channel_statistics[CompositePixelChannel].sum/=channels;
1702 channel_statistics[CompositePixelChannel].sum_squared/=channels;
1703 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
1704 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
1705 channel_statistics[CompositePixelChannel].mean/=channels;
1706 channel_statistics[CompositePixelChannel].variance/=channels;
1707 channel_statistics[CompositePixelChannel].standard_deviation=
1708 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
1709 channel_statistics[CompositePixelChannel].kurtosis/=channels;
1710 channel_statistics[CompositePixelChannel].skewness/=channels;
1711 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1716 standard_deviation=PerceptibleReciprocal(
1717 channel_statistics[i].standard_deviation);
1718 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
1719 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
1720 channel_statistics[i].mean*channel_statistics[i].mean*
1721 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1722 standard_deviation);
1723 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
1724 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
1725 channel_statistics[i].mean*channel_statistics[i].mean*
1726 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
1727 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
1728 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
1729 standard_deviation*standard_deviation)-3.0;
1731 return(channel_statistics);
1735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 % P o l y n o m i a l I m a g e %
1743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745 % PolynomialImage() returns a new image where each pixel is the sum of the
1746 % pixels in the image sequence after applying its corresponding terms
1747 % (coefficient and degree pairs) and a constant.
1749 % The format of the PolynomialImage method is:
1751 % Image *PolynomialImage(const Image *images,const size_t number_terms,
1752 % const double *terms,ExceptionInfo *exception)
1754 % A description of each parameter follows:
1756 % o images: the image sequence.
1758 % o number_terms: the number of terms in the list. The actual list length
1759 % is 2 x number_terms + 1 (the constant).
1761 % o terms: the list of polynomial coefficients and degree pairs and a
1764 % o exception: return any errors or warnings in this structure.
1768 MagickExport Image *PolynomialImage(const Image *images,
1769 const size_t number_terms,const double *terms,ExceptionInfo *exception)
1771 #define PolynomialImageTag "Polynomial/Image"
1786 **restrict polynomial_pixels;
1794 assert(images != (Image *) NULL);
1795 assert(images->signature == MagickSignature);
1796 if (images->debug != MagickFalse)
1797 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1798 assert(exception != (ExceptionInfo *) NULL);
1799 assert(exception->signature == MagickSignature);
1800 image=CloneImage(images,images->columns,images->rows,MagickTrue,
1802 if (image == (Image *) NULL)
1803 return((Image *) NULL);
1804 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1806 image=DestroyImage(image);
1807 return((Image *) NULL);
1809 number_images=GetImageListLength(images);
1810 polynomial_pixels=AcquirePixelThreadSet(images,number_images);
1811 if (polynomial_pixels == (PixelChannels **) NULL)
1813 image=DestroyImage(image);
1814 (void) ThrowMagickException(exception,GetMagickModule(),
1815 ResourceLimitError,"MemoryAllocationFailed","'%s'",images->filename);
1816 return((Image *) NULL);
1819 Polynomial image pixels.
1823 polynomial_view=AcquireAuthenticCacheView(image,exception);
1824 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1825 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1826 dynamic_number_threads(image,image->columns,image->rows,1)
1828 for (y=0; y < (ssize_t) image->rows; y++)
1837 id = GetOpenMPThreadId();
1843 register PixelChannels
1852 if (status == MagickFalse)
1854 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,
1855 image->columns,1,exception);
1856 if (q == (Quantum *) NULL)
1861 polynomial_pixel=polynomial_pixels[id];
1862 for (j=0; j < (ssize_t) image->columns; j++)
1863 for (i=0; i < MaxPixelChannels; i++)
1864 polynomial_pixel[j].channel[i]=0.0;
1866 for (j=0; j < (ssize_t) number_images; j++)
1868 register const Quantum
1871 image_view=AcquireVirtualCacheView(next,exception);
1872 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
1873 if (p == (const Quantum *) NULL)
1875 image_view=DestroyCacheView(image_view);
1878 for (x=0; x < (ssize_t) next->columns; x++)
1883 if (GetPixelMask(next,p) != 0)
1885 p+=GetPixelChannels(next);
1888 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
1901 if ((i << 1) >= (ssize_t) number_terms)
1903 channel=GetPixelChannelChannel(image,i);
1904 traits=GetPixelChannelTraits(next,channel);
1905 polynomial_traits=GetPixelChannelTraits(image,channel);
1906 if ((traits == UndefinedPixelTrait) ||
1907 (polynomial_traits == UndefinedPixelTrait))
1909 if ((traits & UpdatePixelTrait) == 0)
1911 coefficient=(MagickRealType) terms[2*i];
1912 degree=(MagickRealType) terms[2*i+1];
1913 polynomial_pixel[x].channel[i]+=coefficient*
1914 pow(GetPixelChannel(image,channel,p),degree);
1916 p+=GetPixelChannels(next);
1918 image_view=DestroyCacheView(image_view);
1919 next=GetNextImageInList(next);
1921 for (x=0; x < (ssize_t) image->columns; x++)
1926 constant=(MagickRealType) terms[number_terms << 1];
1927 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1928 polynomial_pixel[x].channel[i]+=constant;
1930 for (x=0; x < (ssize_t) image->columns; x++)
1935 if (GetPixelMask(image,q) != 0)
1937 q+=GetPixelChannels(image);
1940 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1948 channel=GetPixelChannelChannel(image,i);
1949 traits=GetPixelChannelTraits(image,channel);
1950 if (traits == UndefinedPixelTrait)
1952 if ((traits & UpdatePixelTrait) == 0)
1954 q[i]=ClampToQuantum(polynomial_pixel[x].channel[i]);
1956 q+=GetPixelChannels(image);
1958 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
1960 if (images->progress_monitor != (MagickProgressMonitor) NULL)
1965 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1966 #pragma omp critical (MagickCore_PolynomialImages)
1968 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
1970 if (proceed == MagickFalse)
1974 polynomial_view=DestroyCacheView(polynomial_view);
1975 polynomial_pixels=DestroyPixelThreadSet(polynomial_pixels);
1976 if (status == MagickFalse)
1977 image=DestroyImage(image);
1982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986 % S t a t i s t i c I m a g e %
1990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
1993 % the neighborhood of the specified width and height.
1995 % The format of the StatisticImage method is:
1997 % Image *StatisticImage(const Image *image,const StatisticType type,
1998 % const size_t width,const size_t height,ExceptionInfo *exception)
2000 % A description of each parameter follows:
2002 % o image: the image.
2004 % o type: the statistic type (median, mode, etc.).
2006 % o width: the width of the pixel neighborhood.
2008 % o height: the height of the pixel neighborhood.
2010 % o exception: return any errors or warnings in this structure.
2014 typedef struct _SkipNode
2022 typedef struct _SkipList
2031 typedef struct _PixelList
2044 static PixelList *DestroyPixelList(PixelList *pixel_list)
2046 if (pixel_list == (PixelList *) NULL)
2047 return((PixelList *) NULL);
2048 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
2049 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
2050 pixel_list->skip_list.nodes);
2051 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
2055 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
2060 assert(pixel_list != (PixelList **) NULL);
2061 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2062 if (pixel_list[i] != (PixelList *) NULL)
2063 pixel_list[i]=DestroyPixelList(pixel_list[i]);
2064 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
2068 static PixelList *AcquirePixelList(const size_t width,const size_t height)
2073 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
2074 if (pixel_list == (PixelList *) NULL)
2076 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
2077 pixel_list->length=width*height;
2078 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
2079 sizeof(*pixel_list->skip_list.nodes));
2080 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
2081 return(DestroyPixelList(pixel_list));
2082 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
2083 sizeof(*pixel_list->skip_list.nodes));
2084 pixel_list->signature=MagickSignature;
2088 static PixelList **AcquirePixelListThreadSet(const size_t width,
2089 const size_t height)
2100 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2101 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
2102 sizeof(*pixel_list));
2103 if (pixel_list == (PixelList **) NULL)
2104 return((PixelList **) NULL);
2105 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
2106 for (i=0; i < (ssize_t) number_threads; i++)
2108 pixel_list[i]=AcquirePixelList(width,height);
2109 if (pixel_list[i] == (PixelList *) NULL)
2110 return(DestroyPixelListThreadSet(pixel_list));
2115 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
2128 Initialize the node.
2130 p=(&pixel_list->skip_list);
2131 p->nodes[color].signature=pixel_list->signature;
2132 p->nodes[color].count=1;
2134 Determine where it belongs in the list.
2137 for (level=p->level; level >= 0; level--)
2139 while (p->nodes[search].next[level] < color)
2140 search=p->nodes[search].next[level];
2141 update[level]=search;
2144 Generate a pseudo-random level for this node.
2146 for (level=0; ; level++)
2148 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
2149 if ((pixel_list->seed & 0x300) != 0x300)
2154 if (level > (p->level+2))
2157 If we're raising the list's level, link back to the root node.
2159 while (level > p->level)
2162 update[p->level]=65536UL;
2165 Link the node into the skip-list.
2169 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
2170 p->nodes[update[level]].next[level]=color;
2171 } while (level-- > 0);
2174 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
2187 Find the maximum value for each of the color.
2189 p=(&pixel_list->skip_list);
2192 maximum=p->nodes[color].next[0];
2195 color=p->nodes[color].next[0];
2196 if (color > maximum)
2198 count+=p->nodes[color].count;
2199 } while (count < (ssize_t) pixel_list->length);
2200 *pixel=ScaleShortToQuantum((unsigned short) maximum);
2203 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
2218 Find the mean value for each of the color.
2220 p=(&pixel_list->skip_list);
2226 color=p->nodes[color].next[0];
2227 sum+=(double) p->nodes[color].count*color;
2228 count+=p->nodes[color].count;
2229 } while (count < (ssize_t) pixel_list->length);
2230 sum/=pixel_list->length;
2231 *pixel=ScaleShortToQuantum((unsigned short) sum);
2234 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2246 Find the median value for each of the color.
2248 p=(&pixel_list->skip_list);
2253 color=p->nodes[color].next[0];
2254 count+=p->nodes[color].count;
2255 } while (count <= (ssize_t) (pixel_list->length >> 1));
2256 *pixel=ScaleShortToQuantum((unsigned short) color);
2259 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2272 Find the minimum value for each of the color.
2274 p=(&pixel_list->skip_list);
2277 minimum=p->nodes[color].next[0];
2280 color=p->nodes[color].next[0];
2281 if (color < minimum)
2283 count+=p->nodes[color].count;
2284 } while (count < (ssize_t) pixel_list->length);
2285 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2288 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2302 Make each pixel the 'predominant color' of the specified neighborhood.
2304 p=(&pixel_list->skip_list);
2307 max_count=p->nodes[mode].count;
2311 color=p->nodes[color].next[0];
2312 if (p->nodes[color].count > max_count)
2315 max_count=p->nodes[mode].count;
2317 count+=p->nodes[color].count;
2318 } while (count < (ssize_t) pixel_list->length);
2319 *pixel=ScaleShortToQuantum((unsigned short) mode);
2322 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2336 Finds the non peak value for each of the colors.
2338 p=(&pixel_list->skip_list);
2340 next=p->nodes[color].next[0];
2346 next=p->nodes[color].next[0];
2347 count+=p->nodes[color].count;
2348 } while (count <= (ssize_t) (pixel_list->length >> 1));
2349 if ((previous == 65536UL) && (next != 65536UL))
2352 if ((previous != 65536UL) && (next == 65536UL))
2354 *pixel=ScaleShortToQuantum((unsigned short) color);
2357 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2374 Find the standard-deviation value for each of the color.
2376 p=(&pixel_list->skip_list);
2386 color=p->nodes[color].next[0];
2387 sum+=(double) p->nodes[color].count*color;
2388 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2389 sum_squared+=((double) color)*((double) color);
2390 count+=p->nodes[color].count;
2391 } while (count < (ssize_t) pixel_list->length);
2392 sum/=pixel_list->length;
2393 sum_squared/=pixel_list->length;
2394 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2397 static inline void InsertPixelList(const Image *image,const Quantum pixel,
2398 PixelList *pixel_list)
2406 index=ScaleQuantumToShort(pixel);
2407 signature=pixel_list->skip_list.nodes[index].signature;
2408 if (signature == pixel_list->signature)
2410 pixel_list->skip_list.nodes[index].count++;
2413 AddNodePixelList(pixel_list,index);
2416 static inline double MagickAbsoluteValue(const double x)
2423 static inline size_t MagickMax(const size_t x,const size_t y)
2430 static void ResetPixelList(PixelList *pixel_list)
2442 Reset the skip-list.
2444 p=(&pixel_list->skip_list);
2445 root=p->nodes+65536UL;
2447 for (level=0; level < 9; level++)
2448 root->next[level]=65536UL;
2449 pixel_list->seed=pixel_list->signature++;
2452 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2453 const size_t width,const size_t height,ExceptionInfo *exception)
2455 #define StatisticImageTag "Statistic/Image"
2471 **restrict pixel_list;
2478 Initialize statistics image attributes.
2480 assert(image != (Image *) NULL);
2481 assert(image->signature == MagickSignature);
2482 if (image->debug != MagickFalse)
2483 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2484 assert(exception != (ExceptionInfo *) NULL);
2485 assert(exception->signature == MagickSignature);
2486 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2488 if (statistic_image == (Image *) NULL)
2489 return((Image *) NULL);
2490 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2491 if (status == MagickFalse)
2493 statistic_image=DestroyImage(statistic_image);
2494 return((Image *) NULL);
2496 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2497 if (pixel_list == (PixelList **) NULL)
2499 statistic_image=DestroyImage(statistic_image);
2500 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2503 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2505 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2506 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2509 image_view=AcquireVirtualCacheView(image,exception);
2510 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2511 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2512 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2513 dynamic_number_threads(image,image->columns,image->rows,1)
2515 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2518 id = GetOpenMPThreadId();
2520 register const Quantum
2529 if (status == MagickFalse)
2531 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2532 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2533 MagickMax(height,1),exception);
2534 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2535 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2540 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2545 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2557 register const Quantum
2566 channel=GetPixelChannelChannel(image,i);
2567 traits=GetPixelChannelTraits(image,channel);
2568 statistic_traits=GetPixelChannelTraits(statistic_image,channel);
2569 if ((traits == UndefinedPixelTrait) ||
2570 (statistic_traits == UndefinedPixelTrait))
2572 if (((statistic_traits & CopyPixelTrait) != 0) ||
2573 (GetPixelMask(image,p) != 0))
2575 SetPixelChannel(statistic_image,channel,p[center+i],q);
2579 ResetPixelList(pixel_list[id]);
2580 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2582 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2584 InsertPixelList(image,pixels[i],pixel_list[id]);
2585 pixels+=GetPixelChannels(image);
2587 pixels+=image->columns*GetPixelChannels(image);
2591 case GradientStatistic:
2597 GetMinimumPixelList(pixel_list[id],&pixel);
2598 minimum=(double) pixel;
2599 GetMaximumPixelList(pixel_list[id],&pixel);
2600 maximum=(double) pixel;
2601 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2604 case MaximumStatistic:
2606 GetMaximumPixelList(pixel_list[id],&pixel);
2611 GetMeanPixelList(pixel_list[id],&pixel);
2614 case MedianStatistic:
2617 GetMedianPixelList(pixel_list[id],&pixel);
2620 case MinimumStatistic:
2622 GetMinimumPixelList(pixel_list[id],&pixel);
2627 GetModePixelList(pixel_list[id],&pixel);
2630 case NonpeakStatistic:
2632 GetNonpeakPixelList(pixel_list[id],&pixel);
2635 case StandardDeviationStatistic:
2637 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2641 SetPixelChannel(statistic_image,channel,pixel,q);
2643 p+=GetPixelChannels(image);
2644 q+=GetPixelChannels(statistic_image);
2646 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2648 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2653 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2654 #pragma omp critical (MagickCore_StatisticImage)
2656 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2658 if (proceed == MagickFalse)
2662 statistic_view=DestroyCacheView(statistic_view);
2663 image_view=DestroyCacheView(image_view);
2664 pixel_list=DestroyPixelListThreadSet(pixel_list);
2665 return(statistic_image);