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-2014 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 magick_threads(image,images,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++)
554 PixelChannel channel=GetPixelChannelChannel(image,i);
555 PixelTrait evaluate_traits=GetPixelChannelTraits(image,channel);
556 PixelTrait traits=GetPixelChannelTraits(next,channel);
557 if ((traits == UndefinedPixelTrait) ||
558 (evaluate_traits == UndefinedPixelTrait))
560 if ((evaluate_traits & UpdatePixelTrait) == 0)
562 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
563 random_info[id],GetPixelChannel(image,channel,p),op,
564 evaluate_pixel[j].channel[i]);
566 image_view=DestroyCacheView(image_view);
567 next=GetNextImageInList(next);
569 qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
571 for (k=0; k < (ssize_t) GetPixelChannels(image); k++)
572 q[k]=ClampToQuantum(evaluate_pixel[j/2].channel[k]);
573 q+=GetPixelChannels(image);
575 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
577 if (images->progress_monitor != (MagickProgressMonitor) NULL)
582 #if defined(MAGICKCORE_OPENMP_SUPPORT)
583 #pragma omp critical (MagickCore_EvaluateImages)
585 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
587 if (proceed == MagickFalse)
594 #if defined(MAGICKCORE_OPENMP_SUPPORT)
595 #pragma omp parallel for schedule(static,4) shared(progress,status) \
596 magick_threads(image,images,image->rows,key == ~0UL)
598 for (y=0; y < (ssize_t) image->rows; y++)
607 id = GetOpenMPThreadId();
613 register PixelChannels
622 if (status == MagickFalse)
624 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
626 if (q == (Quantum *) NULL)
631 evaluate_pixel=evaluate_pixels[id];
632 for (j=0; j < (ssize_t) image->columns; j++)
633 for (i=0; i < MaxPixelChannels; i++)
634 evaluate_pixel[j].channel[i]=0.0;
636 for (j=0; j < (ssize_t) number_images; j++)
638 register const Quantum
641 image_view=AcquireVirtualCacheView(next,exception);
642 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
643 if (p == (const Quantum *) NULL)
645 image_view=DestroyCacheView(image_view);
648 for (x=0; x < (ssize_t) next->columns; x++)
653 if (GetPixelReadMask(next,p) == 0)
655 p+=GetPixelChannels(next);
658 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
660 PixelChannel channel=GetPixelChannelChannel(image,i);
661 PixelTrait traits=GetPixelChannelTraits(next,channel);
662 PixelTrait evaluate_traits=GetPixelChannelTraits(image,channel);
663 if ((traits == UndefinedPixelTrait) ||
664 (evaluate_traits == UndefinedPixelTrait))
666 if ((traits & UpdatePixelTrait) == 0)
668 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
669 random_info[id],GetPixelChannel(image,channel,p),j == 0 ?
670 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
672 p+=GetPixelChannels(next);
674 image_view=DestroyCacheView(image_view);
675 next=GetNextImageInList(next);
677 for (x=0; x < (ssize_t) image->columns; x++)
684 case MeanEvaluateOperator:
686 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
687 evaluate_pixel[x].channel[i]/=(double) number_images;
690 case MultiplyEvaluateOperator:
692 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
697 for (j=0; j < (ssize_t) (number_images-1); j++)
698 evaluate_pixel[x].channel[i]*=QuantumScale;
706 for (x=0; x < (ssize_t) image->columns; x++)
711 if (GetPixelReadMask(image,q) == 0)
713 q+=GetPixelChannels(image);
716 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
718 PixelChannel channel=GetPixelChannelChannel(image,i);
719 PixelTrait traits=GetPixelChannelTraits(image,channel);
720 if (traits == UndefinedPixelTrait)
722 if ((traits & UpdatePixelTrait) == 0)
724 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
726 q+=GetPixelChannels(image);
728 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
730 if (images->progress_monitor != (MagickProgressMonitor) NULL)
735 #if defined(MAGICKCORE_OPENMP_SUPPORT)
736 #pragma omp critical (MagickCore_EvaluateImages)
738 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
740 if (proceed == MagickFalse)
745 evaluate_view=DestroyCacheView(evaluate_view);
746 evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
747 random_info=DestroyRandomInfoThreadSet(random_info);
748 if (status == MagickFalse)
749 image=DestroyImage(image);
753 MagickExport MagickBooleanType EvaluateImage(Image *image,
754 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
766 **restrict random_info;
771 #if defined(MAGICKCORE_OPENMP_SUPPORT)
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 #if defined(MAGICKCORE_OPENMP_SUPPORT)
788 key=GetRandomSecretKey(random_info[0]);
790 image_view=AcquireAuthenticCacheView(image,exception);
791 #if defined(MAGICKCORE_OPENMP_SUPPORT)
792 #pragma omp parallel for schedule(static,4) shared(progress,status) \
793 magick_threads(image,image,image->rows,key == ~0UL)
795 for (y=0; y < (ssize_t) image->rows; y++)
798 id = GetOpenMPThreadId();
806 if (status == MagickFalse)
808 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
809 if (q == (Quantum *) NULL)
814 for (x=0; x < (ssize_t) image->columns; x++)
819 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
821 PixelChannel channel=GetPixelChannelChannel(image,i);
822 PixelTrait traits=GetPixelChannelTraits(image,channel);
823 if (traits == UndefinedPixelTrait)
825 if (((traits & CopyPixelTrait) != 0) ||
826 (GetPixelReadMask(image,q) == 0))
828 q[i]=ClampToQuantum(ApplyEvaluateOperator(random_info[id],q[i],op,
831 q+=GetPixelChannels(image);
833 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
835 if (image->progress_monitor != (MagickProgressMonitor) NULL)
840 #if defined(MAGICKCORE_OPENMP_SUPPORT)
841 #pragma omp critical (MagickCore_EvaluateImage)
843 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
844 if (proceed == MagickFalse)
848 image_view=DestroyCacheView(image_view);
849 random_info=DestroyRandomInfoThreadSet(random_info);
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 % F u n c t i o n I m a g e %
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % FunctionImage() applies a value to the image with an arithmetic, relational,
865 % or logical operator to an image. Use these operations to lighten or darken
866 % an image, to increase or decrease contrast in an image, or to produce the
867 % "negative" of an image.
869 % The format of the FunctionImage method is:
871 % MagickBooleanType FunctionImage(Image *image,
872 % const MagickFunction function,const ssize_t number_parameters,
873 % const double *parameters,ExceptionInfo *exception)
875 % A description of each parameter follows:
877 % o image: the image.
879 % o function: A channel function.
881 % o parameters: one or more parameters.
883 % o exception: return any errors or warnings in this structure.
887 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
888 const size_t number_parameters,const double *parameters,
889 ExceptionInfo *exception)
901 case PolynomialFunction:
904 Polynomial: polynomial constants, highest to lowest order (e.g. c0*x^3+
908 for (i=0; i < (ssize_t) number_parameters; i++)
909 result=result*QuantumScale*pixel+parameters[i];
910 result*=QuantumRange;
913 case SinusoidFunction:
922 Sinusoid: frequency, phase, amplitude, bias.
924 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
925 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
926 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
927 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
928 result=(double) (QuantumRange*(amplitude*sin((double) (2.0*
929 MagickPI*(frequency*QuantumScale*pixel+phase/360.0)))+bias));
941 Arcsin (peged at range limits for invalid results): width, center,
944 width=(number_parameters >= 1) ? parameters[0] : 1.0;
945 center=(number_parameters >= 2) ? parameters[1] : 0.5;
946 range=(number_parameters >= 3) ? parameters[2] : 1.0;
947 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
948 result=2.0/width*(QuantumScale*pixel-center);
949 if ( result <= -1.0 )
950 result=bias-range/2.0;
953 result=bias+range/2.0;
955 result=(double) (range/MagickPI*asin((double) result)+bias);
956 result*=QuantumRange;
968 Arctan: slope, center, range, and bias.
970 slope=(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=(double) (MagickPI*slope*(QuantumScale*pixel-center));
975 result=(double) (QuantumRange*(range/MagickPI*atan((double)
979 case UndefinedFunction:
982 return(ClampToQuantum(result));
985 MagickExport MagickBooleanType FunctionImage(Image *image,
986 const MagickFunction function,const size_t number_parameters,
987 const double *parameters,ExceptionInfo *exception)
989 #define FunctionImageTag "Function/Image "
1003 assert(image != (Image *) NULL);
1004 assert(image->signature == MagickSignature);
1005 if (image->debug != MagickFalse)
1006 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1007 assert(exception != (ExceptionInfo *) NULL);
1008 assert(exception->signature == MagickSignature);
1009 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1010 return(MagickFalse);
1013 image_view=AcquireAuthenticCacheView(image,exception);
1014 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1015 #pragma omp parallel for schedule(static,4) shared(progress,status) \
1016 magick_threads(image,image,image->rows,1)
1018 for (y=0; y < (ssize_t) image->rows; y++)
1026 if (status == MagickFalse)
1028 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1029 if (q == (Quantum *) NULL)
1034 for (x=0; x < (ssize_t) image->columns; x++)
1039 if (GetPixelReadMask(image,q) == 0)
1041 q+=GetPixelChannels(image);
1044 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1046 PixelChannel channel=GetPixelChannelChannel(image,i);
1047 PixelTrait traits=GetPixelChannelTraits(image,channel);
1048 if (traits == UndefinedPixelTrait)
1050 if ((traits & UpdatePixelTrait) == 0)
1052 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1055 q+=GetPixelChannels(image);
1057 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1059 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1064 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1065 #pragma omp critical (MagickCore_FunctionImage)
1067 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1068 if (proceed == MagickFalse)
1072 image_view=DestroyCacheView(image_view);
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 % G e t I m a g e E x t r e m a %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % GetImageExtrema() returns the extrema of one or more image channels.
1089 % The format of the GetImageExtrema method is:
1091 % MagickBooleanType GetImageExtrema(const Image *image,size_t *minima,
1092 % size_t *maxima,ExceptionInfo *exception)
1094 % A description of each parameter follows:
1096 % o image: the image.
1098 % o minima: the minimum value in the channel.
1100 % o maxima: the maximum value in the channel.
1102 % o exception: return any errors or warnings in this structure.
1105 MagickExport MagickBooleanType GetImageExtrema(const Image *image,
1106 size_t *minima,size_t *maxima,ExceptionInfo *exception)
1115 assert(image != (Image *) NULL);
1116 assert(image->signature == MagickSignature);
1117 if (image->debug != MagickFalse)
1118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1119 status=GetImageRange(image,&min,&max,exception);
1120 *minima=(size_t) ceil(min-0.5);
1121 *maxima=(size_t) floor(max+0.5);
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 % G e t I m a g e K u r t o s i s %
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 % GetImageKurtosis() returns the kurtosis and skewness of one or more image
1139 % The format of the GetImageKurtosis method is:
1141 % MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
1142 % double *skewness,ExceptionInfo *exception)
1144 % A description of each parameter follows:
1146 % o image: the image.
1148 % o kurtosis: the kurtosis of the channel.
1150 % o skewness: the skewness of the channel.
1152 % o exception: return any errors or warnings in this structure.
1155 MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
1156 double *kurtosis,double *skewness,ExceptionInfo *exception)
1175 assert(image != (Image *) NULL);
1176 assert(image->signature == MagickSignature);
1177 if (image->debug != MagickFalse)
1178 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1184 standard_deviation=0.0;
1187 sum_fourth_power=0.0;
1188 image_view=AcquireVirtualCacheView(image,exception);
1189 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1190 #pragma omp parallel for schedule(static,4) shared(status) \
1191 magick_threads(image,image,image->rows,1)
1193 for (y=0; y < (ssize_t) image->rows; y++)
1195 register const Quantum
1201 if (status == MagickFalse)
1203 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1204 if (p == (const Quantum *) NULL)
1209 for (x=0; x < (ssize_t) image->columns; x++)
1214 if (GetPixelReadMask(image,p) == 0)
1216 p+=GetPixelChannels(image);
1219 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1221 PixelChannel channel=GetPixelChannelChannel(image,i);
1222 PixelTrait traits=GetPixelChannelTraits(image,channel);
1223 if (traits == UndefinedPixelTrait)
1225 if ((traits & UpdatePixelTrait) == 0)
1227 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1228 #pragma omp critical (MagickCore_GetImageKurtosis)
1232 sum_squares+=(double) p[i]*p[i];
1233 sum_cubes+=(double) p[i]*p[i]*p[i];
1234 sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
1238 p+=GetPixelChannels(image);
1241 image_view=DestroyCacheView(image_view);
1247 sum_fourth_power/=area;
1249 standard_deviation=sqrt(sum_squares-(mean*mean));
1250 if (standard_deviation != 0.0)
1252 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1253 3.0*mean*mean*mean*mean;
1254 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1257 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1258 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268 % G e t I m a g e M e a n %
1272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1274 % GetImageMean() returns the mean and standard deviation of one or more image
1277 % The format of the GetImageMean method is:
1279 % MagickBooleanType GetImageMean(const Image *image,double *mean,
1280 % double *standard_deviation,ExceptionInfo *exception)
1282 % A description of each parameter follows:
1284 % o image: the image.
1286 % o mean: the average value in the channel.
1288 % o standard_deviation: the standard deviation of the channel.
1290 % o exception: return any errors or warnings in this structure.
1293 MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
1294 double *standard_deviation,ExceptionInfo *exception)
1300 *channel_statistics;
1305 assert(image != (Image *) NULL);
1306 assert(image->signature == MagickSignature);
1307 if (image->debug != MagickFalse)
1308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1309 channel_statistics=GetImageStatistics(image,exception);
1310 if (channel_statistics == (ChannelStatistics *) NULL)
1311 return(MagickFalse);
1313 channel_statistics[CompositePixelChannel].mean=0.0;
1314 channel_statistics[CompositePixelChannel].standard_deviation=0.0;
1315 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1317 PixelChannel channel=GetPixelChannelChannel(image,i);
1318 PixelTrait traits=GetPixelChannelTraits(image,channel);
1319 if (traits == UndefinedPixelTrait)
1321 if ((traits & UpdatePixelTrait) == 0)
1323 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
1324 channel_statistics[CompositePixelChannel].standard_deviation+=
1325 channel_statistics[i].variance-channel_statistics[i].mean*
1326 channel_statistics[i].mean;
1329 channel_statistics[CompositePixelChannel].mean/=area;
1330 channel_statistics[CompositePixelChannel].standard_deviation=
1331 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area);
1332 *mean=channel_statistics[CompositePixelChannel].mean;
1333 *standard_deviation=
1334 channel_statistics[CompositePixelChannel].standard_deviation;
1335 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1336 channel_statistics);
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 % G e t I m a g e M o m e n t s %
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 % GetImageMoments() returns the normalized moments of one or more image
1354 % The format of the GetImageMoments method is:
1356 % ChannelMoments *GetImageMoments(const Image *image,
1357 % ExceptionInfo *exception)
1359 % A description of each parameter follows:
1361 % o image: the image.
1363 % o exception: return any errors or warnings in this structure.
1366 MagickExport ChannelMoments *GetImageMoments(const Image *image,
1367 ExceptionInfo *exception)
1369 #define MaxNumberImageMoments 8
1378 M00[MaxPixelChannels+1],
1379 M01[MaxPixelChannels+1],
1380 M02[MaxPixelChannels+1],
1381 M03[MaxPixelChannels+1],
1382 M10[MaxPixelChannels+1],
1383 M11[MaxPixelChannels+1],
1384 M12[MaxPixelChannels+1],
1385 M20[MaxPixelChannels+1],
1386 M21[MaxPixelChannels+1],
1387 M22[MaxPixelChannels+1],
1388 M30[MaxPixelChannels+1];
1391 centroid[MaxPixelChannels+1];
1397 assert(image != (Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 if (image->debug != MagickFalse)
1400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1401 channel_moments=(ChannelMoments *) AcquireQuantumMemory(MaxPixelChannels+1,
1402 sizeof(*channel_moments));
1403 if (channel_moments == (ChannelMoments *) NULL)
1404 return(channel_moments);
1405 (void) ResetMagickMemory(channel_moments,0,(MaxPixelChannels+1)*
1406 sizeof(*channel_moments));
1407 (void) ResetMagickMemory(centroid,0,sizeof(centroid));
1408 (void) ResetMagickMemory(M00,0,sizeof(M00));
1409 (void) ResetMagickMemory(M01,0,sizeof(M01));
1410 (void) ResetMagickMemory(M02,0,sizeof(M02));
1411 (void) ResetMagickMemory(M03,0,sizeof(M03));
1412 (void) ResetMagickMemory(M10,0,sizeof(M10));
1413 (void) ResetMagickMemory(M11,0,sizeof(M11));
1414 (void) ResetMagickMemory(M12,0,sizeof(M12));
1415 (void) ResetMagickMemory(M20,0,sizeof(M20));
1416 (void) ResetMagickMemory(M21,0,sizeof(M21));
1417 (void) ResetMagickMemory(M22,0,sizeof(M22));
1418 (void) ResetMagickMemory(M30,0,sizeof(M30));
1419 image_view=AcquireVirtualCacheView(image,exception);
1420 for (y=0; y < (ssize_t) image->rows; y++)
1422 register const Quantum
1429 Compute center of mass (centroid).
1431 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1432 if (p == (const Quantum *) NULL)
1434 for (x=0; x < (ssize_t) image->columns; x++)
1439 if (GetPixelReadMask(image,p) == 0)
1441 p+=GetPixelChannels(image);
1444 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1446 PixelChannel channel=GetPixelChannelChannel(image,i);
1447 PixelTrait traits=GetPixelChannelTraits(image,channel);
1448 if (traits == UndefinedPixelTrait)
1450 if ((traits & UpdatePixelTrait) == 0)
1452 M00[channel]+=QuantumScale*p[i];
1453 M00[MaxPixelChannels]+=QuantumScale*p[i];
1454 M10[channel]+=x*QuantumScale*p[i];
1455 M10[MaxPixelChannels]+=QuantumScale*p[i];
1456 M01[channel]+=y*QuantumScale*p[i];
1457 M01[MaxPixelChannels]+=QuantumScale*p[i];
1459 p+=GetPixelChannels(image);
1462 for (channel=0; channel <= MaxPixelChannels; channel++)
1465 Compute center of mass (centroid).
1467 if (M00[channel] < MagickEpsilon)
1469 M00[channel]+=MagickEpsilon;
1470 centroid[channel].x=image->columns/2.0;
1471 centroid[channel].y=image->rows/2.0;
1474 M00[channel]+=MagickEpsilon;
1475 centroid[channel].x=M10[channel]/M00[channel];
1476 centroid[channel].y=M01[channel]/M00[channel];
1478 for (y=0; y < (ssize_t) image->rows; y++)
1480 register const Quantum
1487 Compute the image moments.
1489 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1490 if (p == (const Quantum *) NULL)
1492 for (x=0; x < (ssize_t) image->columns; x++)
1497 if (GetPixelReadMask(image,p) == 0)
1499 p+=GetPixelChannels(image);
1502 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1504 PixelChannel channel=GetPixelChannelChannel(image,i);
1505 PixelTrait traits=GetPixelChannelTraits(image,channel);
1506 if (traits == UndefinedPixelTrait)
1508 if ((traits & UpdatePixelTrait) == 0)
1510 M11[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1512 M11[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1514 M20[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1516 M20[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1518 M02[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1520 M02[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1522 M21[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1523 (y-centroid[channel].y)*QuantumScale*p[i];
1524 M21[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1525 (y-centroid[channel].y)*QuantumScale*p[i];
1526 M12[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1527 (y-centroid[channel].y)*QuantumScale*p[i];
1528 M12[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1529 (y-centroid[channel].y)*QuantumScale*p[i];
1530 M22[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1531 (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
1532 M22[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1533 (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*p[i];
1534 M30[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1535 (x-centroid[channel].x)*QuantumScale*p[i];
1536 M30[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1537 (x-centroid[channel].x)*QuantumScale*p[i];
1538 M03[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1539 (y-centroid[channel].y)*QuantumScale*p[i];
1540 M03[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1541 (y-centroid[channel].y)*QuantumScale*p[i];
1543 p+=GetPixelChannels(image);
1546 M00[MaxPixelChannels]/=GetPixelChannels(image);
1547 M01[MaxPixelChannels]/=GetPixelChannels(image);
1548 M02[MaxPixelChannels]/=GetPixelChannels(image);
1549 M03[MaxPixelChannels]/=GetPixelChannels(image);
1550 M10[MaxPixelChannels]/=GetPixelChannels(image);
1551 M11[MaxPixelChannels]/=GetPixelChannels(image);
1552 M12[MaxPixelChannels]/=GetPixelChannels(image);
1553 M20[MaxPixelChannels]/=GetPixelChannels(image);
1554 M21[MaxPixelChannels]/=GetPixelChannels(image);
1555 M22[MaxPixelChannels]/=GetPixelChannels(image);
1556 M30[MaxPixelChannels]/=GetPixelChannels(image);
1557 for (channel=0; channel <= MaxPixelChannels; channel++)
1560 Compute elliptical angle, major and minor axes, eccentricity, & intensity.
1562 channel_moments[channel].centroid=centroid[channel];
1563 channel_moments[channel].ellipse_axis.x=sqrt((2.0/M00[channel])*
1564 ((M20[channel]+M02[channel])+sqrt(4.0*M11[channel]*M11[channel]+
1565 (M20[channel]-M02[channel])*(M20[channel]-M02[channel]))));
1566 channel_moments[channel].ellipse_axis.y=sqrt((2.0/M00[channel])*
1567 ((M20[channel]+M02[channel])-sqrt(4.0*M11[channel]*M11[channel]+
1568 (M20[channel]-M02[channel])*(M20[channel]-M02[channel]))));
1569 channel_moments[channel].ellipse_angle=RadiansToDegrees(0.5*atan(2.0*
1570 M11[channel]/(M20[channel]-M02[channel]+MagickEpsilon)));
1571 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
1572 channel_moments[channel].ellipse_axis.y/
1573 (channel_moments[channel].ellipse_axis.x+MagickEpsilon)));
1574 channel_moments[channel].ellipse_intensity=M00[channel]/
1575 (MagickPI*channel_moments[channel].ellipse_axis.x*
1576 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
1578 for (channel=0; channel <= MaxPixelChannels; channel++)
1581 Normalize image moments.
1585 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
1586 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
1587 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
1588 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
1589 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
1590 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
1591 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
1592 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
1595 image_view=DestroyCacheView(image_view);
1596 for (channel=0; channel <= MaxPixelChannels; channel++)
1599 Compute Hu invariant moments.
1601 channel_moments[channel].I[0]=M20[channel]+M02[channel];
1602 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
1603 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
1604 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
1605 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
1606 (3.0*M21[channel]-M03[channel]);
1607 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
1608 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
1609 (M21[channel]+M03[channel]);
1610 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
1611 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
1612 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
1613 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
1614 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
1615 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
1616 (M21[channel]+M03[channel]));
1617 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
1618 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
1619 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
1620 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
1621 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
1622 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
1623 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
1624 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
1625 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
1626 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
1627 (M21[channel]+M03[channel]));
1628 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
1629 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
1630 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
1631 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
1633 if (y < (ssize_t) image->rows)
1634 channel_moments=(ChannelMoments *) RelinquishMagickMemory(channel_moments);
1635 return(channel_moments);
1639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643 % G e t I m a g e C h a n n e l P e r c e p t u a l H a s h %
1647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649 % GetImagePerceptualHash() returns the perceptual hash of one or more
1652 % The format of the GetImagePerceptualHash method is:
1654 % ChannelPerceptualHash *GetImagePerceptualHash(const Image *image,
1655 % ExceptionInfo *exception)
1657 % A description of each parameter follows:
1659 % o image: the image.
1661 % o exception: return any errors or warnings in this structure.
1665 static inline double MagickLog10(const double x)
1667 #define Log10Epsilon (1.0e-11)
1669 if (fabs(x) < Log10Epsilon)
1670 return(log10(Log10Epsilon));
1671 return(log10(fabs(x)));
1674 MagickExport ChannelPerceptualHash *GetImagePerceptualHash(
1675 const Image *image,ExceptionInfo *exception)
1680 ChannelPerceptualHash
1696 Blur then transform to sRGB colorspace.
1698 hash_image=BlurImage(image,0.0,1.0,exception);
1699 if (hash_image == (Image *) NULL)
1700 return((ChannelPerceptualHash *) NULL);
1701 hash_image->depth=8;
1702 status=TransformImageColorspace(hash_image,sRGBColorspace,exception);
1703 if (status == MagickFalse)
1704 return((ChannelPerceptualHash *) NULL);
1705 moments=GetImageMoments(hash_image,exception);
1706 hash_image=DestroyImage(hash_image);
1707 if (moments == (ChannelMoments *) NULL)
1708 return((ChannelPerceptualHash *) NULL);
1709 perceptual_hash=(ChannelPerceptualHash *) AcquireQuantumMemory(
1710 CompositeChannels+1UL,sizeof(*perceptual_hash));
1711 if (perceptual_hash == (ChannelPerceptualHash *) NULL)
1712 return((ChannelPerceptualHash *) NULL);
1713 for (channel=0; channel <= MaxPixelChannels; channel++)
1714 for (i=0; i < 7; i++)
1715 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
1716 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
1718 Blur then transform to HCLp colorspace.
1720 hash_image=BlurImage(image,0.0,1.0,exception);
1721 if (hash_image == (Image *) NULL)
1723 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
1725 return((ChannelPerceptualHash *) NULL);
1727 hash_image->depth=8;
1728 status=TransformImageColorspace(hash_image,HCLpColorspace,exception);
1729 if (status == MagickFalse)
1731 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
1733 return((ChannelPerceptualHash *) NULL);
1735 moments=GetImageMoments(hash_image,exception);
1736 hash_image=DestroyImage(hash_image);
1737 if (moments == (ChannelMoments *) NULL)
1739 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
1741 return((ChannelPerceptualHash *) NULL);
1743 for (channel=0; channel <= MaxPixelChannels; channel++)
1744 for (i=0; i < 7; i++)
1745 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
1746 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
1747 return(perceptual_hash);
1751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755 % G e t I m a g e R a n g e %
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761 % GetImageRange() returns the range of one or more image channels.
1763 % The format of the GetImageRange method is:
1765 % MagickBooleanType GetImageRange(const Image *image,double *minima,
1766 % double *maxima,ExceptionInfo *exception)
1768 % A description of each parameter follows:
1770 % o image: the image.
1772 % o minima: the minimum value in the channel.
1774 % o maxima: the maximum value in the channel.
1776 % o exception: return any errors or warnings in this structure.
1779 MagickExport MagickBooleanType GetImageRange(const Image *image,double *minima,
1780 double *maxima,ExceptionInfo *exception)
1792 assert(image != (Image *) NULL);
1793 assert(image->signature == MagickSignature);
1794 if (image->debug != MagickFalse)
1795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797 initialize=MagickTrue;
1800 image_view=AcquireVirtualCacheView(image,exception);
1801 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1802 #pragma omp parallel for schedule(static,4) shared(status,initialize) \
1803 magick_threads(image,image,image->rows,1)
1805 for (y=0; y < (ssize_t) image->rows; y++)
1807 register const Quantum
1813 if (status == MagickFalse)
1815 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1816 if (p == (const Quantum *) NULL)
1821 for (x=0; x < (ssize_t) image->columns; x++)
1826 if (GetPixelReadMask(image,p) == 0)
1828 p+=GetPixelChannels(image);
1831 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1833 PixelChannel channel=GetPixelChannelChannel(image,i);
1834 PixelTrait traits=GetPixelChannelTraits(image,channel);
1835 if (traits == UndefinedPixelTrait)
1837 if ((traits & UpdatePixelTrait) == 0)
1839 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1840 #pragma omp critical (MagickCore_GetImageRange)
1843 if (initialize != MagickFalse)
1845 *minima=(double) p[i];
1846 *maxima=(double) p[i];
1847 initialize=MagickFalse;
1851 if ((double) p[i] < *minima)
1852 *minima=(double) p[i];
1853 if ((double) p[i] > *maxima)
1854 *maxima=(double) p[i];
1858 p+=GetPixelChannels(image);
1861 image_view=DestroyCacheView(image_view);
1866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1870 % G e t I m a g e S t a t i s t i c s %
1874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1876 % GetImageStatistics() returns statistics for each channel in the image. The
1877 % statistics include the channel depth, its minima, maxima, mean, standard
1878 % deviation, kurtosis and skewness. You can access the red channel mean, for
1879 % example, like this:
1881 % channel_statistics=GetImageStatistics(image,exception);
1882 % red_mean=channel_statistics[RedPixelChannel].mean;
1884 % Use MagickRelinquishMemory() to free the statistics buffer.
1886 % The format of the GetImageStatistics method is:
1888 % ChannelStatistics *GetImageStatistics(const Image *image,
1889 % ExceptionInfo *exception)
1891 % A description of each parameter follows:
1893 % o image: the image.
1895 % o exception: return any errors or warnings in this structure.
1899 static size_t GetImageChannels(const Image *image)
1908 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1910 PixelChannel channel=GetPixelChannelChannel(image,i);
1911 PixelTrait traits=GetPixelChannelTraits(image,channel);
1912 if (traits != UndefinedPixelTrait)
1918 MagickExport ChannelStatistics *GetImageStatistics(const Image *image,
1919 ExceptionInfo *exception)
1922 *channel_statistics;
1940 assert(image != (Image *) NULL);
1941 assert(image->signature == MagickSignature);
1942 if (image->debug != MagickFalse)
1943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1944 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
1945 MaxPixelChannels+1,sizeof(*channel_statistics));
1946 if (channel_statistics == (ChannelStatistics *) NULL)
1947 return(channel_statistics);
1948 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
1949 sizeof(*channel_statistics));
1950 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
1952 channel_statistics[i].depth=1;
1953 channel_statistics[i].maxima=(-MagickMaximumValue);
1954 channel_statistics[i].minima=MagickMaximumValue;
1956 for (y=0; y < (ssize_t) image->rows; y++)
1958 register const Quantum
1964 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1965 if (p == (const Quantum *) NULL)
1967 for (x=0; x < (ssize_t) image->columns; x++)
1972 if (GetPixelReadMask(image,p) == 0)
1974 p+=GetPixelChannels(image);
1977 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1979 PixelChannel channel=GetPixelChannelChannel(image,i);
1980 PixelTrait traits=GetPixelChannelTraits(image,channel);
1981 if (traits == UndefinedPixelTrait)
1983 if (channel_statistics[channel].depth != MAGICKCORE_QUANTUM_DEPTH)
1985 depth=channel_statistics[channel].depth;
1986 range=GetQuantumRange(depth);
1987 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
1988 range) ? MagickTrue : MagickFalse;
1989 if (status != MagickFalse)
1991 channel_statistics[channel].depth++;
1996 if ((double) p[i] < channel_statistics[channel].minima)
1997 channel_statistics[channel].minima=(double) p[i];
1998 if ((double) p[i] > channel_statistics[channel].maxima)
1999 channel_statistics[channel].maxima=(double) p[i];
2000 channel_statistics[channel].sum+=p[i];
2001 channel_statistics[channel].sum_squared+=(double) p[i]*p[i];
2002 channel_statistics[channel].sum_cubed+=(double) p[i]*p[i]*p[i];
2003 channel_statistics[channel].sum_fourth_power+=(double) p[i]*p[i]*p[i]*
2005 channel_statistics[channel].area++;
2007 p+=GetPixelChannels(image);
2010 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
2015 area=PerceptibleReciprocal(channel_statistics[i].area);
2016 channel_statistics[i].sum*=area;
2017 channel_statistics[i].sum_squared*=area;
2018 channel_statistics[i].sum_cubed*=area;
2019 channel_statistics[i].sum_fourth_power*=area;
2020 channel_statistics[i].mean=channel_statistics[i].sum;
2021 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2022 channel_statistics[i].standard_deviation=sqrt(
2023 channel_statistics[i].variance-(channel_statistics[i].mean*
2024 channel_statistics[i].mean));
2026 for (i=0; i < (ssize_t) MaxPixelChannels; i++)
2028 channel_statistics[CompositePixelChannel].area+=channel_statistics[i].area;
2029 channel_statistics[CompositePixelChannel].minima=MagickMin(
2030 channel_statistics[CompositePixelChannel].minima,
2031 channel_statistics[i].minima);
2032 channel_statistics[CompositePixelChannel].maxima=EvaluateMax(
2033 channel_statistics[CompositePixelChannel].maxima,
2034 channel_statistics[i].maxima);
2035 channel_statistics[CompositePixelChannel].sum+=channel_statistics[i].sum;
2036 channel_statistics[CompositePixelChannel].sum_squared+=
2037 channel_statistics[i].sum_squared;
2038 channel_statistics[CompositePixelChannel].sum_cubed+=
2039 channel_statistics[i].sum_cubed;
2040 channel_statistics[CompositePixelChannel].sum_fourth_power+=
2041 channel_statistics[i].sum_fourth_power;
2042 channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean;
2043 channel_statistics[CompositePixelChannel].variance+=
2044 channel_statistics[i].variance-channel_statistics[i].mean*
2045 channel_statistics[i].mean;
2046 channel_statistics[CompositePixelChannel].standard_deviation+=
2047 channel_statistics[i].variance-channel_statistics[i].mean*
2048 channel_statistics[i].mean;
2050 channels=GetImageChannels(image);
2051 channel_statistics[CompositePixelChannel].area/=channels;
2052 channel_statistics[CompositePixelChannel].sum/=channels;
2053 channel_statistics[CompositePixelChannel].sum_squared/=channels;
2054 channel_statistics[CompositePixelChannel].sum_cubed/=channels;
2055 channel_statistics[CompositePixelChannel].sum_fourth_power/=channels;
2056 channel_statistics[CompositePixelChannel].mean/=channels;
2057 channel_statistics[CompositePixelChannel].variance/=channels;
2058 channel_statistics[CompositePixelChannel].standard_deviation=
2059 sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels);
2060 channel_statistics[CompositePixelChannel].kurtosis/=channels;
2061 channel_statistics[CompositePixelChannel].skewness/=channels;
2062 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
2067 if (channel_statistics[i].standard_deviation == 0.0)
2069 standard_deviation=PerceptibleReciprocal(
2070 channel_statistics[i].standard_deviation);
2071 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2072 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2073 channel_statistics[i].mean*channel_statistics[i].mean*
2074 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2075 standard_deviation);
2076 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2077 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2078 channel_statistics[i].mean*channel_statistics[i].mean*
2079 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2080 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2081 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2082 standard_deviation*standard_deviation)-3.0;
2084 if (y < (ssize_t) image->rows)
2085 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2086 channel_statistics);
2087 return(channel_statistics);
2091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095 % P o l y n o m i a l I m a g e %
2099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101 % PolynomialImage() returns a new image where each pixel is the sum of the
2102 % pixels in the image sequence after applying its corresponding terms
2103 % (coefficient and degree pairs).
2105 % The format of the PolynomialImage method is:
2107 % Image *PolynomialImage(const Image *images,const size_t number_terms,
2108 % const double *terms,ExceptionInfo *exception)
2110 % A description of each parameter follows:
2112 % o images: the image sequence.
2114 % o number_terms: the number of terms in the list. The actual list length
2115 % is 2 x number_terms + 1 (the constant).
2117 % o terms: the list of polynomial coefficients and degree pairs and a
2120 % o exception: return any errors or warnings in this structure.
2124 MagickExport Image *PolynomialImage(const Image *images,
2125 const size_t number_terms,const double *terms,ExceptionInfo *exception)
2127 #define PolynomialImageTag "Polynomial/Image"
2142 **restrict polynomial_pixels;
2150 assert(images != (Image *) NULL);
2151 assert(images->signature == MagickSignature);
2152 if (images->debug != MagickFalse)
2153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
2154 assert(exception != (ExceptionInfo *) NULL);
2155 assert(exception->signature == MagickSignature);
2156 image=CloneImage(images,images->columns,images->rows,MagickTrue,
2158 if (image == (Image *) NULL)
2159 return((Image *) NULL);
2160 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2162 image=DestroyImage(image);
2163 return((Image *) NULL);
2165 number_images=GetImageListLength(images);
2166 polynomial_pixels=AcquirePixelThreadSet(images,number_images);
2167 if (polynomial_pixels == (PixelChannels **) NULL)
2169 image=DestroyImage(image);
2170 (void) ThrowMagickException(exception,GetMagickModule(),
2171 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
2172 return((Image *) NULL);
2175 Polynomial image pixels.
2179 polynomial_view=AcquireAuthenticCacheView(image,exception);
2180 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2181 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2182 magick_threads(image,image,image->rows,1)
2184 for (y=0; y < (ssize_t) image->rows; y++)
2193 id = GetOpenMPThreadId();
2199 register PixelChannels
2208 if (status == MagickFalse)
2210 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2212 if (q == (Quantum *) NULL)
2217 polynomial_pixel=polynomial_pixels[id];
2218 for (j=0; j < (ssize_t) image->columns; j++)
2219 for (i=0; i < MaxPixelChannels; i++)
2220 polynomial_pixel[j].channel[i]=0.0;
2222 for (j=0; j < (ssize_t) number_images; j++)
2224 register const Quantum
2227 if (j >= (ssize_t) number_terms)
2229 image_view=AcquireVirtualCacheView(next,exception);
2230 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2231 if (p == (const Quantum *) NULL)
2233 image_view=DestroyCacheView(image_view);
2236 for (x=0; x < (ssize_t) image->columns; x++)
2241 if (GetPixelReadMask(next,p) == 0)
2243 p+=GetPixelChannels(next);
2246 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
2252 PixelChannel channel=GetPixelChannelChannel(image,i);
2253 PixelTrait traits=GetPixelChannelTraits(next,channel);
2254 PixelTrait polynomial_traits=GetPixelChannelTraits(image,channel);
2255 if ((traits == UndefinedPixelTrait) ||
2256 (polynomial_traits == UndefinedPixelTrait))
2258 if ((traits & UpdatePixelTrait) == 0)
2260 coefficient=(MagickRealType) terms[2*i];
2261 degree=(MagickRealType) terms[(i << 1)+1];
2262 polynomial_pixel[x].channel[i]+=coefficient*
2263 pow(QuantumScale*GetPixelChannel(image,channel,p),degree);
2265 p+=GetPixelChannels(next);
2267 image_view=DestroyCacheView(image_view);
2268 next=GetNextImageInList(next);
2270 for (x=0; x < (ssize_t) image->columns; x++)
2275 if (GetPixelReadMask(image,q) == 0)
2277 q+=GetPixelChannels(image);
2280 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2282 PixelChannel channel=GetPixelChannelChannel(image,i);
2283 PixelTrait traits=GetPixelChannelTraits(image,channel);
2284 if (traits == UndefinedPixelTrait)
2286 if ((traits & UpdatePixelTrait) == 0)
2288 q[i]=ClampToQuantum(QuantumRange*polynomial_pixel[x].channel[i]);
2290 q+=GetPixelChannels(image);
2292 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2294 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2299 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2300 #pragma omp critical (MagickCore_PolynomialImages)
2302 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2304 if (proceed == MagickFalse)
2308 polynomial_view=DestroyCacheView(polynomial_view);
2309 polynomial_pixels=DestroyPixelThreadSet(polynomial_pixels);
2310 if (status == MagickFalse)
2311 image=DestroyImage(image);
2316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320 % S t a t i s t i c I m a g e %
2324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2326 % StatisticImage() makes each pixel the min / max / median / mode / etc. of
2327 % the neighborhood of the specified width and height.
2329 % The format of the StatisticImage method is:
2331 % Image *StatisticImage(const Image *image,const StatisticType type,
2332 % const size_t width,const size_t height,ExceptionInfo *exception)
2334 % A description of each parameter follows:
2336 % o image: the image.
2338 % o type: the statistic type (median, mode, etc.).
2340 % o width: the width of the pixel neighborhood.
2342 % o height: the height of the pixel neighborhood.
2344 % o exception: return any errors or warnings in this structure.
2348 typedef struct _SkipNode
2356 typedef struct _SkipList
2365 typedef struct _PixelList
2378 static PixelList *DestroyPixelList(PixelList *pixel_list)
2380 if (pixel_list == (PixelList *) NULL)
2381 return((PixelList *) NULL);
2382 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
2383 pixel_list->skip_list.nodes=(SkipNode *) RelinquishMagickMemory(
2384 pixel_list->skip_list.nodes);
2385 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
2389 static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
2394 assert(pixel_list != (PixelList **) NULL);
2395 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2396 if (pixel_list[i] != (PixelList *) NULL)
2397 pixel_list[i]=DestroyPixelList(pixel_list[i]);
2398 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
2402 static PixelList *AcquirePixelList(const size_t width,const size_t height)
2407 pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
2408 if (pixel_list == (PixelList *) NULL)
2410 (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
2411 pixel_list->length=width*height;
2412 pixel_list->skip_list.nodes=(SkipNode *) AcquireQuantumMemory(65537UL,
2413 sizeof(*pixel_list->skip_list.nodes));
2414 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
2415 return(DestroyPixelList(pixel_list));
2416 (void) ResetMagickMemory(pixel_list->skip_list.nodes,0,65537UL*
2417 sizeof(*pixel_list->skip_list.nodes));
2418 pixel_list->signature=MagickSignature;
2422 static PixelList **AcquirePixelListThreadSet(const size_t width,
2423 const size_t height)
2434 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2435 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
2436 sizeof(*pixel_list));
2437 if (pixel_list == (PixelList **) NULL)
2438 return((PixelList **) NULL);
2439 (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
2440 for (i=0; i < (ssize_t) number_threads; i++)
2442 pixel_list[i]=AcquirePixelList(width,height);
2443 if (pixel_list[i] == (PixelList *) NULL)
2444 return(DestroyPixelListThreadSet(pixel_list));
2449 static void AddNodePixelList(PixelList *pixel_list,const size_t color)
2462 Initialize the node.
2464 p=(&pixel_list->skip_list);
2465 p->nodes[color].signature=pixel_list->signature;
2466 p->nodes[color].count=1;
2468 Determine where it belongs in the list.
2471 for (level=p->level; level >= 0; level--)
2473 while (p->nodes[search].next[level] < color)
2474 search=p->nodes[search].next[level];
2475 update[level]=search;
2478 Generate a pseudo-random level for this node.
2480 for (level=0; ; level++)
2482 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
2483 if ((pixel_list->seed & 0x300) != 0x300)
2488 if (level > (p->level+2))
2491 If we're raising the list's level, link back to the root node.
2493 while (level > p->level)
2496 update[p->level]=65536UL;
2499 Link the node into the skip-list.
2503 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
2504 p->nodes[update[level]].next[level]=color;
2505 } while (level-- > 0);
2508 static inline void GetMaximumPixelList(PixelList *pixel_list,Quantum *pixel)
2521 Find the maximum value for each of the color.
2523 p=(&pixel_list->skip_list);
2526 maximum=p->nodes[color].next[0];
2529 color=p->nodes[color].next[0];
2530 if (color > maximum)
2532 count+=p->nodes[color].count;
2533 } while (count < (ssize_t) pixel_list->length);
2534 *pixel=ScaleShortToQuantum((unsigned short) maximum);
2537 static inline void GetMeanPixelList(PixelList *pixel_list,Quantum *pixel)
2552 Find the mean value for each of the color.
2554 p=(&pixel_list->skip_list);
2560 color=p->nodes[color].next[0];
2561 sum+=(double) p->nodes[color].count*color;
2562 count+=p->nodes[color].count;
2563 } while (count < (ssize_t) pixel_list->length);
2564 sum/=pixel_list->length;
2565 *pixel=ScaleShortToQuantum((unsigned short) sum);
2568 static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2580 Find the median value for each of the color.
2582 p=(&pixel_list->skip_list);
2587 color=p->nodes[color].next[0];
2588 count+=p->nodes[color].count;
2589 } while (count <= (ssize_t) (pixel_list->length >> 1));
2590 *pixel=ScaleShortToQuantum((unsigned short) color);
2593 static inline void GetMinimumPixelList(PixelList *pixel_list,Quantum *pixel)
2606 Find the minimum value for each of the color.
2608 p=(&pixel_list->skip_list);
2611 minimum=p->nodes[color].next[0];
2614 color=p->nodes[color].next[0];
2615 if (color < minimum)
2617 count+=p->nodes[color].count;
2618 } while (count < (ssize_t) pixel_list->length);
2619 *pixel=ScaleShortToQuantum((unsigned short) minimum);
2622 static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2636 Make each pixel the 'predominant color' of the specified neighborhood.
2638 p=(&pixel_list->skip_list);
2641 max_count=p->nodes[mode].count;
2645 color=p->nodes[color].next[0];
2646 if (p->nodes[color].count > max_count)
2649 max_count=p->nodes[mode].count;
2651 count+=p->nodes[color].count;
2652 } while (count < (ssize_t) pixel_list->length);
2653 *pixel=ScaleShortToQuantum((unsigned short) mode);
2656 static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2670 Finds the non peak value for each of the colors.
2672 p=(&pixel_list->skip_list);
2674 next=p->nodes[color].next[0];
2680 next=p->nodes[color].next[0];
2681 count+=p->nodes[color].count;
2682 } while (count <= (ssize_t) (pixel_list->length >> 1));
2683 if ((previous == 65536UL) && (next != 65536UL))
2686 if ((previous != 65536UL) && (next == 65536UL))
2688 *pixel=ScaleShortToQuantum((unsigned short) color);
2691 static inline void GetStandardDeviationPixelList(PixelList *pixel_list,
2708 Find the standard-deviation value for each of the color.
2710 p=(&pixel_list->skip_list);
2720 color=p->nodes[color].next[0];
2721 sum+=(double) p->nodes[color].count*color;
2722 for (i=0; i < (ssize_t) p->nodes[color].count; i++)
2723 sum_squared+=((double) color)*((double) color);
2724 count+=p->nodes[color].count;
2725 } while (count < (ssize_t) pixel_list->length);
2726 sum/=pixel_list->length;
2727 sum_squared/=pixel_list->length;
2728 *pixel=ScaleShortToQuantum((unsigned short) sqrt(sum_squared-(sum*sum)));
2731 static inline void InsertPixelList(const Quantum pixel,PixelList *pixel_list)
2739 index=ScaleQuantumToShort(pixel);
2740 signature=pixel_list->skip_list.nodes[index].signature;
2741 if (signature == pixel_list->signature)
2743 pixel_list->skip_list.nodes[index].count++;
2746 AddNodePixelList(pixel_list,index);
2749 static inline double MagickAbsoluteValue(const double x)
2756 static inline size_t MagickMax(const size_t x,const size_t y)
2763 static void ResetPixelList(PixelList *pixel_list)
2775 Reset the skip-list.
2777 p=(&pixel_list->skip_list);
2778 root=p->nodes+65536UL;
2780 for (level=0; level < 9; level++)
2781 root->next[level]=65536UL;
2782 pixel_list->seed=pixel_list->signature++;
2785 MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
2786 const size_t width,const size_t height,ExceptionInfo *exception)
2788 #define StatisticImageTag "Statistic/Image"
2804 **restrict pixel_list;
2811 Initialize statistics image attributes.
2813 assert(image != (Image *) NULL);
2814 assert(image->signature == MagickSignature);
2815 if (image->debug != MagickFalse)
2816 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2817 assert(exception != (ExceptionInfo *) NULL);
2818 assert(exception->signature == MagickSignature);
2819 statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2821 if (statistic_image == (Image *) NULL)
2822 return((Image *) NULL);
2823 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2824 if (status == MagickFalse)
2826 statistic_image=DestroyImage(statistic_image);
2827 return((Image *) NULL);
2829 pixel_list=AcquirePixelListThreadSet(MagickMax(width,1),MagickMax(height,1));
2830 if (pixel_list == (PixelList **) NULL)
2832 statistic_image=DestroyImage(statistic_image);
2833 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2836 Make each pixel the min / max / median / mode / etc. of the neighborhood.
2838 center=(ssize_t) GetPixelChannels(image)*(image->columns+MagickMax(width,1))*
2839 (MagickMax(height,1)/2L)+GetPixelChannels(image)*(MagickMax(width,1)/2L);
2842 image_view=AcquireVirtualCacheView(image,exception);
2843 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2844 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2845 #pragma omp parallel for schedule(static,4) shared(progress,status) \
2846 magick_threads(image,statistic_image,statistic_image->rows,1)
2848 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2851 id = GetOpenMPThreadId();
2853 register const Quantum
2862 if (status == MagickFalse)
2864 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2865 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
2866 MagickMax(height,1),exception);
2867 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
2868 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2873 for (x=0; x < (ssize_t) statistic_image->columns; x++)
2878 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2883 register const Quantum
2892 PixelChannel channel=GetPixelChannelChannel(image,i);
2893 PixelTrait traits=GetPixelChannelTraits(image,channel);
2894 PixelTrait statistic_traits=GetPixelChannelTraits(statistic_image,
2896 if ((traits == UndefinedPixelTrait) ||
2897 (statistic_traits == UndefinedPixelTrait))
2899 if (((statistic_traits & CopyPixelTrait) != 0) ||
2900 (GetPixelReadMask(image,p) == 0))
2902 SetPixelChannel(statistic_image,channel,p[center+i],q);
2906 ResetPixelList(pixel_list[id]);
2907 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
2909 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
2911 InsertPixelList(pixels[i],pixel_list[id]);
2912 pixels+=GetPixelChannels(image);
2914 pixels+=(image->columns-1)*GetPixelChannels(image);
2918 case GradientStatistic:
2924 GetMinimumPixelList(pixel_list[id],&pixel);
2925 minimum=(double) pixel;
2926 GetMaximumPixelList(pixel_list[id],&pixel);
2927 maximum=(double) pixel;
2928 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
2931 case MaximumStatistic:
2933 GetMaximumPixelList(pixel_list[id],&pixel);
2938 GetMeanPixelList(pixel_list[id],&pixel);
2941 case MedianStatistic:
2944 GetMedianPixelList(pixel_list[id],&pixel);
2947 case MinimumStatistic:
2949 GetMinimumPixelList(pixel_list[id],&pixel);
2954 GetModePixelList(pixel_list[id],&pixel);
2957 case NonpeakStatistic:
2959 GetNonpeakPixelList(pixel_list[id],&pixel);
2962 case StandardDeviationStatistic:
2964 GetStandardDeviationPixelList(pixel_list[id],&pixel);
2968 SetPixelChannel(statistic_image,channel,pixel,q);
2970 p+=GetPixelChannels(image);
2971 q+=GetPixelChannels(statistic_image);
2973 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
2975 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2980 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2981 #pragma omp critical (MagickCore_StatisticImage)
2983 proceed=SetImageProgress(image,StatisticImageTag,progress++,
2985 if (proceed == MagickFalse)
2989 statistic_view=DestroyCacheView(statistic_view);
2990 image_view=DestroyCacheView(image_view);
2991 pixel_list=DestroyPixelListThreadSet(pixel_list);
2992 if (status == MagickFalse)
2993 statistic_image=DestroyImage(statistic_image);
2994 return(statistic_image);