44 #include "magick/studio.h"
45 #include "magick/accelerate-private.h"
46 #include "magick/animate.h"
47 #include "magick/animate.h"
48 #include "magick/blob.h"
49 #include "magick/blob-private.h"
50 #include "magick/cache.h"
51 #include "magick/cache-private.h"
52 #include "magick/cache-view.h"
53 #include "magick/client.h"
54 #include "magick/color.h"
55 #include "magick/color-private.h"
56 #include "magick/colorspace.h"
57 #include "magick/colorspace-private.h"
58 #include "magick/composite.h"
59 #include "magick/composite-private.h"
60 #include "magick/compress.h"
61 #include "magick/constitute.h"
62 #include "magick/deprecate.h"
63 #include "magick/display.h"
64 #include "magick/draw.h"
65 #include "magick/enhance.h"
66 #include "magick/exception.h"
67 #include "magick/exception-private.h"
68 #include "magick/gem.h"
69 #include "magick/geometry.h"
70 #include "magick/list.h"
71 #include "magick/image-private.h"
72 #include "magick/magic.h"
73 #include "magick/magick.h"
74 #include "magick/memory_.h"
75 #include "magick/module.h"
76 #include "magick/monitor.h"
77 #include "magick/monitor-private.h"
78 #include "magick/option.h"
79 #include "magick/paint.h"
80 #include "magick/pixel-private.h"
81 #include "magick/profile.h"
82 #include "magick/property.h"
83 #include "magick/quantize.h"
84 #include "magick/random_.h"
85 #include "magick/random-private.h"
86 #include "magick/resource_.h"
87 #include "magick/segment.h"
88 #include "magick/semaphore.h"
89 #include "magick/signature-private.h"
90 #include "magick/statistic.h"
91 #include "magick/string_.h"
92 #include "magick/thread-private.h"
93 #include "magick/timer.h"
94 #include "magick/utility.h"
95 #include "magick/version.h"
149 rows=MagickMax(GetImageListLength(images),
150 (
size_t) GetMagickResourceLimit(ThreadResource));
151 for (i=0; i < (ssize_t) rows; i++)
174 rows=MagickMax(GetImageListLength(images),
175 (
size_t) GetMagickResourceLimit(ThreadResource));
179 (void) memset(pixels,0,rows*
sizeof(*pixels));
180 columns=GetImageListLength(images);
181 for (next=images; next != (
Image *) NULL; next=next->next)
182 columns=MagickMax(next->columns,columns);
183 for (i=0; i < (ssize_t) rows; i++)
188 return(DestroyPixelTLS(images,pixels));
189 for (j=0; j < (ssize_t) columns; j++)
190 GetMagickPixelPacket(images,&pixels[i][j]);
195 static inline double EvaluateMax(
const double x,
const double y)
202 #if defined(__cplusplus) || defined(c_plusplus)
206 static int IntensityCompare(
const void *x,
const void *y)
217 intensity=(int) MagickPixelIntensity(color_2)-(int)
218 MagickPixelIntensity(color_1);
222 #if defined(__cplusplus) || defined(c_plusplus)
226 static MagickRealType ApplyEvaluateOperator(
RandomInfo *random_info,
227 const Quantum pixel,
const MagickEvaluateOperator op,
228 const MagickRealType value)
239 case UndefinedEvaluateOperator:
241 case AbsEvaluateOperator:
243 result=(MagickRealType) fabs((
double) (pixel+value));
246 case AddEvaluateOperator:
248 result=(MagickRealType) (pixel+value);
251 case AddModulusEvaluateOperator:
260 result-=(QuantumRange+1.0)*floor((
double) result/(QuantumRange+1.0));
263 case AndEvaluateOperator:
265 result=(MagickRealType) ((ssize_t) pixel & (ssize_t) (value+0.5));
268 case CosineEvaluateOperator:
270 result=(MagickRealType) (QuantumRange*(0.5*cos((
double) (2.0*MagickPI*
271 QuantumScale*pixel*value))+0.5));
274 case DivideEvaluateOperator:
276 result=pixel/(value == 0.0 ? 1.0 : value);
279 case ExponentialEvaluateOperator:
281 result=(MagickRealType) (QuantumRange*exp((
double) (value*QuantumScale*
285 case GaussianNoiseEvaluateOperator:
287 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
288 GaussianNoise,value);
291 case ImpulseNoiseEvaluateOperator:
293 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
297 case InverseLogEvaluateOperator:
299 result=(QuantumRange*pow((value+1.0),QuantumScale*pixel)-1.0)*
300 PerceptibleReciprocal(value);
303 case LaplacianNoiseEvaluateOperator:
305 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
306 LaplacianNoise,value);
309 case LeftShiftEvaluateOperator:
311 result=(double) pixel;
312 for (i=0; i < (ssize_t) value; i++)
316 case LogEvaluateOperator:
318 if ((QuantumScale*pixel) >= MagickEpsilon)
319 result=(MagickRealType) (QuantumRange*log((
double) (QuantumScale*value*
320 pixel+1.0))/log((
double) (value+1.0)));
323 case MaxEvaluateOperator:
325 result=(MagickRealType) EvaluateMax((
double) pixel,value);
328 case MeanEvaluateOperator:
330 result=(MagickRealType) (pixel+value);
333 case MedianEvaluateOperator:
335 result=(MagickRealType) (pixel+value);
338 case MinEvaluateOperator:
340 result=(MagickRealType) MagickMin((
double) pixel,value);
343 case MultiplicativeNoiseEvaluateOperator:
345 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
346 MultiplicativeGaussianNoise,value);
349 case MultiplyEvaluateOperator:
351 result=(MagickRealType) (value*pixel);
354 case OrEvaluateOperator:
356 result=(MagickRealType) ((ssize_t) pixel | (ssize_t) (value+0.5));
359 case PoissonNoiseEvaluateOperator:
361 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
365 case PowEvaluateOperator:
367 if ((pixel < 0) && ((value-floor(value)) > MagickEpsilon))
368 result=(
double) -(QuantumRange*pow((
double) -(QuantumScale*pixel),
371 result=(double) (QuantumRange*pow((
double) (QuantumScale*pixel),
375 case RightShiftEvaluateOperator:
377 result=(MagickRealType) pixel;
378 for (i=0; i < (ssize_t) value; i++)
382 case RootMeanSquareEvaluateOperator:
384 result=((MagickRealType) pixel*pixel+value);
387 case SetEvaluateOperator:
392 case SineEvaluateOperator:
394 result=(MagickRealType) (QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
395 QuantumScale*pixel*value))+0.5));
398 case SubtractEvaluateOperator:
400 result=(MagickRealType) (pixel-value);
403 case SumEvaluateOperator:
405 result=(MagickRealType) (pixel+value);
408 case ThresholdEvaluateOperator:
410 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
414 case ThresholdBlackEvaluateOperator:
416 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
419 case ThresholdWhiteEvaluateOperator:
421 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
425 case UniformNoiseEvaluateOperator:
427 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
431 case XorEvaluateOperator:
433 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
452 columns=images->columns;
455 for (p=images; p != (
Image *) NULL; p=p->next)
461 if (p->matte != MagickFalse)
463 if (p->colorspace == CMYKColorspace)
465 if (channels > number_channels)
467 number_channels=channels;
470 if (p->columns > columns)
475 return(CloneImage(q,columns,rows,MagickTrue,exception));
478 MagickExport MagickBooleanType EvaluateImage(
Image *image,
479 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
484 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
488 MagickExport
Image *EvaluateImages(
const Image *images,
491 #define EvaluateImageTag "Evaluate/Image"
506 **magick_restrict evaluate_pixels,
510 **magick_restrict random_info;
518 #if defined(MAGICKCORE_OPENMP_SUPPORT)
523 assert(images != (
Image *) NULL);
524 assert(images->signature == MagickCoreSignature);
526 assert(exception->signature == MagickCoreSignature);
527 if (IsEventLogging() != MagickFalse)
528 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
529 image=AcquireImageCanvas(images,exception);
530 if (image == (
Image *) NULL)
531 return((
Image *) NULL);
532 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
534 InheritException(exception,&image->exception);
535 image=DestroyImage(image);
536 return((
Image *) NULL);
538 evaluate_pixels=AcquirePixelTLS(images);
541 image=DestroyImage(image);
542 (void) ThrowMagickException(exception,GetMagickModule(),
543 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
544 return((
Image *) NULL);
551 number_images=GetImageListLength(images);
552 GetMagickPixelPacket(images,&zero);
553 random_info=AcquireRandomInfoTLS();
554 evaluate_view=AcquireAuthenticCacheView(image,exception);
555 if (op == MedianEvaluateOperator)
557 #if defined(MAGICKCORE_OPENMP_SUPPORT)
558 key=GetRandomSecretKey(random_info[0]);
559 #pragma omp parallel for schedule(static) shared(progress,status) \
560 magick_number_threads(image,images,image->rows,key == ~0UL)
562 for (y=0; y < (ssize_t) image->rows; y++)
571 id = GetOpenMPThreadId();
574 *magick_restrict evaluate_indexes;
585 if (status == MagickFalse)
587 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
594 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
595 evaluate_pixel=evaluate_pixels[id];
596 for (x=0; x < (ssize_t) image->columns; x++)
601 for (i=0; i < (ssize_t) number_images; i++)
602 evaluate_pixel[i]=zero;
604 for (i=0; i < (ssize_t) number_images; i++)
612 image_view=AcquireVirtualCacheView(next,exception);
613 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
616 image_view=DestroyCacheView(image_view);
619 indexes=GetCacheViewVirtualIndexQueue(image_view);
620 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
621 GetPixelRed(p),op,evaluate_pixel[i].red);
622 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
623 GetPixelGreen(p),op,evaluate_pixel[i].green);
624 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
625 GetPixelBlue(p),op,evaluate_pixel[i].blue);
626 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
627 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
628 if (image->colorspace == CMYKColorspace)
629 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
630 *indexes,op,evaluate_pixel[i].index);
631 image_view=DestroyCacheView(image_view);
632 next=GetNextImageInList(next);
634 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
636 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
637 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
638 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
639 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
640 if (image->colorspace == CMYKColorspace)
641 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
642 evaluate_pixel[i/2].index));
645 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
647 if (images->progress_monitor != (MagickProgressMonitor) NULL)
652 #if defined(MAGICKCORE_OPENMP_SUPPORT)
656 proceed=SetImageProgress(images,EvaluateImageTag,progress,
658 if (proceed == MagickFalse)
665 #if defined(MAGICKCORE_OPENMP_SUPPORT)
666 key=GetRandomSecretKey(random_info[0]);
667 #pragma omp parallel for schedule(static) shared(progress,status) \
668 magick_number_threads(image,images,image->rows,key == ~0UL)
670 for (y=0; y < (ssize_t) image->rows; y++)
679 id = GetOpenMPThreadId();
682 *magick_restrict evaluate_indexes;
694 if (status == MagickFalse)
696 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
703 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
704 evaluate_pixel=evaluate_pixels[id];
705 for (x=0; x < (ssize_t) image->columns; x++)
706 evaluate_pixel[x]=zero;
708 for (i=0; i < (ssize_t) number_images; i++)
716 image_view=AcquireVirtualCacheView(next,exception);
717 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
721 image_view=DestroyCacheView(image_view);
724 indexes=GetCacheViewVirtualIndexQueue(image_view);
725 for (x=0; x < (ssize_t) image->columns; x++)
727 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
728 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
729 evaluate_pixel[x].red);
730 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
731 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
732 evaluate_pixel[x].green);
733 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
734 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
735 evaluate_pixel[x].blue);
736 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
737 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
738 evaluate_pixel[x].opacity);
739 if (image->colorspace == CMYKColorspace)
740 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
741 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
742 evaluate_pixel[x].index);
745 image_view=DestroyCacheView(image_view);
746 next=GetNextImageInList(next);
748 if (op == MeanEvaluateOperator)
749 for (x=0; x < (ssize_t) image->columns; x++)
751 evaluate_pixel[x].red/=number_images;
752 evaluate_pixel[x].green/=number_images;
753 evaluate_pixel[x].blue/=number_images;
754 evaluate_pixel[x].opacity/=number_images;
755 evaluate_pixel[x].index/=number_images;
757 if (op == RootMeanSquareEvaluateOperator)
758 for (x=0; x < (ssize_t) image->columns; x++)
760 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
762 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
764 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
766 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
768 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
771 if (op == MultiplyEvaluateOperator)
772 for (x=0; x < (ssize_t) image->columns; x++)
777 for (j=0; j < (ssize_t) (number_images-1); j++)
779 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
780 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
781 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
782 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
786 for (x=0; x < (ssize_t) image->columns; x++)
788 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
789 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
790 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
791 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
792 if (image->colorspace == CMYKColorspace)
793 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
794 evaluate_pixel[x].index));
797 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
799 if (images->progress_monitor != (MagickProgressMonitor) NULL)
804 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
806 if (proceed == MagickFalse)
811 evaluate_view=DestroyCacheView(evaluate_view);
812 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
813 random_info=DestroyRandomInfoTLS(random_info);
814 if (status == MagickFalse)
815 image=DestroyImage(image);
819 MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
820 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
833 **magick_restrict random_info;
838 #if defined(MAGICKCORE_OPENMP_SUPPORT)
843 assert(image != (
Image *) NULL);
844 assert(image->signature == MagickCoreSignature);
846 assert(exception->signature == MagickCoreSignature);
847 if (IsEventLogging() != MagickFalse)
848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
849 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
851 InheritException(exception,&image->exception);
856 random_info=AcquireRandomInfoTLS();
857 image_view=AcquireAuthenticCacheView(image,exception);
858 #if defined(MAGICKCORE_OPENMP_SUPPORT)
859 key=GetRandomSecretKey(random_info[0]);
860 #pragma omp parallel for schedule(static) shared(progress,status) \
861 magick_number_threads(image,image,image->rows,key == ~0UL)
863 for (y=0; y < (ssize_t) image->rows; y++)
866 id = GetOpenMPThreadId();
869 *magick_restrict indexes;
877 if (status == MagickFalse)
879 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
885 indexes=GetCacheViewAuthenticIndexQueue(image_view);
886 for (x=0; x < (ssize_t) image->columns; x++)
891 if ((channel & RedChannel) != 0)
893 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
894 if (op == MeanEvaluateOperator)
896 SetPixelRed(q,ClampToQuantum(result));
898 if ((channel & GreenChannel) != 0)
900 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
902 if (op == MeanEvaluateOperator)
904 SetPixelGreen(q,ClampToQuantum(result));
906 if ((channel & BlueChannel) != 0)
908 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
910 if (op == MeanEvaluateOperator)
912 SetPixelBlue(q,ClampToQuantum(result));
914 if ((channel & OpacityChannel) != 0)
916 if (image->matte == MagickFalse)
918 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
920 if (op == MeanEvaluateOperator)
922 SetPixelOpacity(q,ClampToQuantum(result));
926 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
928 if (op == MeanEvaluateOperator)
930 SetPixelAlpha(q,ClampToQuantum(result));
933 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
935 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
937 if (op == MeanEvaluateOperator)
939 SetPixelIndex(indexes+x,ClampToQuantum(result));
943 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
945 if (image->progress_monitor != (MagickProgressMonitor) NULL)
950 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
951 if (proceed == MagickFalse)
955 image_view=DestroyCacheView(image_view);
956 random_info=DestroyRandomInfoTLS(random_info);
1000 static Quantum ApplyFunction(Quantum pixel,
const MagickFunction
function,
1001 const size_t number_parameters,
const double *parameters,
1014 case PolynomialFunction:
1022 for (i=0; i < (ssize_t) number_parameters; i++)
1023 result=result*QuantumScale*pixel + parameters[i];
1024 result*=QuantumRange;
1027 case SinusoidFunction:
1032 double freq,phase,ampl,bias;
1033 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1034 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1035 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1036 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1037 result=(MagickRealType) (QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1038 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
1041 case ArcsinFunction:
1052 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1053 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1054 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1055 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1056 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*pixel-center);
1058 result=bias-range/2.0;
1061 result=bias+range/2.0;
1063 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1064 result*=QuantumRange;
1067 case ArctanFunction:
1072 double slope,range,center,bias;
1073 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1074 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1075 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1076 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1077 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
1078 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((
double)
1082 case UndefinedFunction:
1085 return(ClampToQuantum(result));
1088 MagickExport MagickBooleanType FunctionImage(
Image *image,
1089 const MagickFunction
function,
const size_t number_parameters,
1095 status=FunctionImageChannel(image,CompositeChannels,
function,
1096 number_parameters,parameters,exception);
1100 MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1101 const ChannelType channel,
const MagickFunction
function,
1102 const size_t number_parameters,
const double *parameters,
1105 #define FunctionImageTag "Function/Image "
1119 assert(image != (
Image *) NULL);
1120 assert(image->signature == MagickCoreSignature);
1122 assert(exception->signature == MagickCoreSignature);
1123 if (IsEventLogging() != MagickFalse)
1124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1125 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1127 InheritException(exception,&image->exception);
1128 return(MagickFalse);
1130 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1131 status=AccelerateFunctionImage(image,channel,
function,number_parameters,
1132 parameters,exception);
1133 if (status != MagickFalse)
1138 image_view=AcquireAuthenticCacheView(image,exception);
1139 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1140 #pragma omp parallel for schedule(static) shared(progress,status) \
1141 magick_number_threads(image,image,image->rows,1)
1143 for (y=0; y < (ssize_t) image->rows; y++)
1146 *magick_restrict indexes;
1154 if (status == MagickFalse)
1156 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1162 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1163 for (x=0; x < (ssize_t) image->columns; x++)
1165 if ((channel & RedChannel) != 0)
1166 SetPixelRed(q,ApplyFunction(GetPixelRed(q),
function,
1167 number_parameters,parameters,exception));
1168 if ((channel & GreenChannel) != 0)
1169 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),
function,
1170 number_parameters,parameters,exception));
1171 if ((channel & BlueChannel) != 0)
1172 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),
function,
1173 number_parameters,parameters,exception));
1174 if ((channel & OpacityChannel) != 0)
1176 if (image->matte == MagickFalse)
1177 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),
function,
1178 number_parameters,parameters,exception));
1180 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),
function,
1181 number_parameters,parameters,exception));
1183 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1184 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),
function,
1185 number_parameters,parameters,exception));
1188 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1190 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1195 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1196 if (proceed == MagickFalse)
1200 image_view=DestroyCacheView(image_view);
1234 MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1240 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1244 MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1245 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1248 *channel_statistics;
1253 assert(image != (
Image *) NULL);
1254 assert(image->signature == MagickCoreSignature);
1255 if (IsEventLogging() != MagickFalse)
1256 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1257 channel_statistics=GetImageChannelStatistics(image,exception);
1259 return(MagickFalse);
1261 channel_statistics[CompositeChannels].entropy=0.0;
1262 if ((channel & RedChannel) != 0)
1264 channel_statistics[CompositeChannels].entropy+=
1265 channel_statistics[RedChannel].entropy;
1268 if ((channel & GreenChannel) != 0)
1270 channel_statistics[CompositeChannels].entropy+=
1271 channel_statistics[GreenChannel].entropy;
1274 if ((channel & BlueChannel) != 0)
1276 channel_statistics[CompositeChannels].entropy+=
1277 channel_statistics[BlueChannel].entropy;
1280 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1282 channel_statistics[CompositeChannels].entropy+=
1283 channel_statistics[OpacityChannel].entropy;
1286 if (((channel & IndexChannel) != 0) &&
1287 (image->colorspace == CMYKColorspace))
1289 channel_statistics[CompositeChannels].entropy+=
1290 channel_statistics[BlackChannel].entropy;
1293 channel_statistics[CompositeChannels].entropy/=channels;
1294 *entropy=channel_statistics[CompositeChannels].entropy;
1296 channel_statistics);
1333 MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1339 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1344 MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1345 const ChannelType channel,
size_t *minima,
size_t *maxima,
1355 assert(image != (
Image *) NULL);
1356 assert(image->signature == MagickCoreSignature);
1357 if (IsEventLogging() != MagickFalse)
1358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1359 status=GetImageChannelRange(image,channel,&min,&max,exception);
1360 *minima=(size_t) ceil(min-0.5);
1361 *maxima=(size_t) floor(max+0.5);
1399 MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1405 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1410 MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1411 const ChannelType channel,
double *kurtosis,
double *skewness,
1425 assert(image != (
Image *) NULL);
1426 assert(image->signature == MagickCoreSignature);
1427 if (IsEventLogging() != MagickFalse)
1428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1433 standard_deviation=0.0;
1436 sum_fourth_power=0.0;
1437 for (y=0; y < (ssize_t) image->rows; y++)
1440 *magick_restrict indexes;
1448 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1451 indexes=GetVirtualIndexQueue(image);
1452 for (x=0; x < (ssize_t) image->columns; x++)
1454 if ((channel & RedChannel) != 0)
1456 mean+=GetPixelRed(p);
1457 sum_squares+=(double) GetPixelRed(p)*GetPixelRed(p);
1458 sum_cubes+=(double) GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
1459 sum_fourth_power+=(double) GetPixelRed(p)*GetPixelRed(p)*
1460 GetPixelRed(p)*GetPixelRed(p);
1463 if ((channel & GreenChannel) != 0)
1465 mean+=GetPixelGreen(p);
1466 sum_squares+=(double) GetPixelGreen(p)*GetPixelGreen(p);
1467 sum_cubes+=(double) GetPixelGreen(p)*GetPixelGreen(p)*
1469 sum_fourth_power+=(double) GetPixelGreen(p)*GetPixelGreen(p)*
1470 GetPixelGreen(p)*GetPixelGreen(p);
1473 if ((channel & BlueChannel) != 0)
1475 mean+=GetPixelBlue(p);
1476 sum_squares+=(double) GetPixelBlue(p)*GetPixelBlue(p);
1477 sum_cubes+=(double) GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p);
1478 sum_fourth_power+=(double) GetPixelBlue(p)*GetPixelBlue(p)*
1479 GetPixelBlue(p)*GetPixelBlue(p);
1482 if ((channel & OpacityChannel) != 0)
1484 mean+=GetPixelAlpha(p);
1485 sum_squares+=(double) GetPixelOpacity(p)*GetPixelAlpha(p);
1486 sum_cubes+=(double) GetPixelOpacity(p)*GetPixelAlpha(p)*
1488 sum_fourth_power+=(double) GetPixelAlpha(p)*GetPixelAlpha(p)*
1489 GetPixelAlpha(p)*GetPixelAlpha(p);
1492 if (((channel & IndexChannel) != 0) &&
1493 (image->colorspace == CMYKColorspace))
1498 index=(double) GetPixelIndex(indexes+x);
1500 sum_squares+=index*index;
1501 sum_cubes+=index*index*index;
1502 sum_fourth_power+=index*index*index*index;
1508 if (y < (ssize_t) image->rows)
1509 return(MagickFalse);
1515 sum_fourth_power/=area;
1517 standard_deviation=sqrt(sum_squares-(mean*mean));
1518 if (standard_deviation != 0.0)
1520 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1521 3.0*mean*mean*mean*mean;
1522 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1525 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1526 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1528 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1565 MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1571 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1576 MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1577 const ChannelType channel,
double *mean,
double *standard_deviation,
1581 *channel_statistics;
1586 assert(image != (
Image *) NULL);
1587 assert(image->signature == MagickCoreSignature);
1588 if (IsEventLogging() != MagickFalse)
1589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1590 channel_statistics=GetImageChannelStatistics(image,exception);
1592 return(MagickFalse);
1594 channel_statistics[CompositeChannels].mean=0.0;
1595 channel_statistics[CompositeChannels].standard_deviation=0.0;
1596 if ((channel & RedChannel) != 0)
1598 channel_statistics[CompositeChannels].mean+=
1599 channel_statistics[RedChannel].mean;
1600 channel_statistics[CompositeChannels].standard_deviation+=
1601 channel_statistics[RedChannel].standard_deviation;
1604 if ((channel & GreenChannel) != 0)
1606 channel_statistics[CompositeChannels].mean+=
1607 channel_statistics[GreenChannel].mean;
1608 channel_statistics[CompositeChannels].standard_deviation+=
1609 channel_statistics[GreenChannel].standard_deviation;
1612 if ((channel & BlueChannel) != 0)
1614 channel_statistics[CompositeChannels].mean+=
1615 channel_statistics[BlueChannel].mean;
1616 channel_statistics[CompositeChannels].standard_deviation+=
1617 channel_statistics[BlueChannel].standard_deviation;
1620 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1622 channel_statistics[CompositeChannels].mean+=
1623 channel_statistics[OpacityChannel].mean;
1624 channel_statistics[CompositeChannels].standard_deviation+=
1625 channel_statistics[OpacityChannel].standard_deviation;
1628 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1630 channel_statistics[CompositeChannels].mean+=
1631 channel_statistics[BlackChannel].mean;
1632 channel_statistics[CompositeChannels].standard_deviation+=
1633 channel_statistics[CompositeChannels].standard_deviation;
1636 channel_statistics[CompositeChannels].mean/=channels;
1637 channel_statistics[CompositeChannels].standard_deviation/=channels;
1638 *mean=channel_statistics[CompositeChannels].mean;
1639 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1641 channel_statistics);
1674 #define MaxNumberImageMoments 8
1680 M00[CompositeChannels+1],
1681 M01[CompositeChannels+1],
1682 M02[CompositeChannels+1],
1683 M03[CompositeChannels+1],
1684 M10[CompositeChannels+1],
1685 M11[CompositeChannels+1],
1686 M12[CompositeChannels+1],
1687 M20[CompositeChannels+1],
1688 M21[CompositeChannels+1],
1689 M22[CompositeChannels+1],
1690 M30[CompositeChannels+1];
1696 centroid[CompositeChannels+1];
1706 assert(image != (
Image *) NULL);
1707 assert(image->signature == MagickCoreSignature);
1708 if (IsEventLogging() != MagickFalse)
1709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1710 length=CompositeChannels+1UL;
1712 sizeof(*channel_moments));
1714 return(channel_moments);
1715 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1716 (void) memset(centroid,0,
sizeof(centroid));
1717 (void) memset(M00,0,
sizeof(M00));
1718 (void) memset(M01,0,
sizeof(M01));
1719 (void) memset(M02,0,
sizeof(M02));
1720 (void) memset(M03,0,
sizeof(M03));
1721 (void) memset(M10,0,
sizeof(M10));
1722 (void) memset(M11,0,
sizeof(M11));
1723 (void) memset(M12,0,
sizeof(M12));
1724 (void) memset(M20,0,
sizeof(M20));
1725 (void) memset(M21,0,
sizeof(M21));
1726 (void) memset(M22,0,
sizeof(M22));
1727 (void) memset(M30,0,
sizeof(M30));
1728 GetMagickPixelPacket(image,&pixel);
1729 for (y=0; y < (ssize_t) image->rows; y++)
1732 *magick_restrict indexes;
1743 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1746 indexes=GetVirtualIndexQueue(image);
1747 for (x=0; x < (ssize_t) image->columns; x++)
1749 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1750 M00[RedChannel]+=QuantumScale*pixel.red;
1751 M10[RedChannel]+=x*QuantumScale*pixel.red;
1752 M01[RedChannel]+=y*QuantumScale*pixel.red;
1753 M00[GreenChannel]+=QuantumScale*pixel.green;
1754 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1755 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1756 M00[BlueChannel]+=QuantumScale*pixel.blue;
1757 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1758 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1759 if (image->matte != MagickFalse)
1761 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1762 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1763 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1765 if (image->colorspace == CMYKColorspace)
1767 M00[IndexChannel]+=QuantumScale*pixel.index;
1768 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1769 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1774 for (channel=0; channel <= CompositeChannels; channel++)
1779 if (M00[channel] < MagickEpsilon)
1781 M00[channel]+=MagickEpsilon;
1782 centroid[channel].x=(double) image->columns/2.0;
1783 centroid[channel].y=(
double) image->rows/2.0;
1786 M00[channel]+=MagickEpsilon;
1787 centroid[channel].x=M10[channel]/M00[channel];
1788 centroid[channel].y=M01[channel]/M00[channel];
1790 for (y=0; y < (ssize_t) image->rows; y++)
1793 *magick_restrict indexes;
1804 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1807 indexes=GetVirtualIndexQueue(image);
1808 for (x=0; x < (ssize_t) image->columns; x++)
1810 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1811 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1812 centroid[RedChannel].y)*QuantumScale*pixel.red;
1813 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1814 centroid[RedChannel].x)*QuantumScale*pixel.red;
1815 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1816 centroid[RedChannel].y)*QuantumScale*pixel.red;
1817 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1818 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1820 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1821 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1823 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1824 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1825 centroid[RedChannel].y)*QuantumScale*pixel.red;
1826 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1827 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1829 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1830 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1832 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1833 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1834 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1835 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1836 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1837 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1838 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1839 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1841 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1842 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1844 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1845 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1846 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1847 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1848 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1850 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1851 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1853 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1854 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1855 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1856 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1857 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1858 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1859 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1860 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1862 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1863 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1865 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1866 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1867 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1868 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1869 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1871 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1872 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1874 if (image->matte != MagickFalse)
1876 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1877 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1878 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1879 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1880 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1881 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1882 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1883 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1884 QuantumScale*pixel.opacity;
1885 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1886 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1887 QuantumScale*pixel.opacity;
1888 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1889 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1890 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1891 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1892 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1893 QuantumScale*pixel.opacity;
1894 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1895 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1896 QuantumScale*pixel.opacity;
1898 if (image->colorspace == CMYKColorspace)
1900 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1901 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1902 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1903 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1904 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1905 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1906 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1907 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1908 QuantumScale*pixel.index;
1909 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1910 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1911 QuantumScale*pixel.index;
1912 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1913 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1914 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1915 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1916 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1917 QuantumScale*pixel.index;
1918 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1919 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1920 QuantumScale*pixel.index;
1926 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1927 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1928 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1929 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1930 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1931 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1932 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1933 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1934 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1935 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1936 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1937 if (image->matte != MagickFalse)
1940 M00[CompositeChannels]+=M00[OpacityChannel];
1941 M01[CompositeChannels]+=M01[OpacityChannel];
1942 M02[CompositeChannels]+=M02[OpacityChannel];
1943 M03[CompositeChannels]+=M03[OpacityChannel];
1944 M10[CompositeChannels]+=M10[OpacityChannel];
1945 M11[CompositeChannels]+=M11[OpacityChannel];
1946 M12[CompositeChannels]+=M12[OpacityChannel];
1947 M20[CompositeChannels]+=M20[OpacityChannel];
1948 M21[CompositeChannels]+=M21[OpacityChannel];
1949 M22[CompositeChannels]+=M22[OpacityChannel];
1950 M30[CompositeChannels]+=M30[OpacityChannel];
1952 if (image->colorspace == CMYKColorspace)
1955 M00[CompositeChannels]+=M00[IndexChannel];
1956 M01[CompositeChannels]+=M01[IndexChannel];
1957 M02[CompositeChannels]+=M02[IndexChannel];
1958 M03[CompositeChannels]+=M03[IndexChannel];
1959 M10[CompositeChannels]+=M10[IndexChannel];
1960 M11[CompositeChannels]+=M11[IndexChannel];
1961 M12[CompositeChannels]+=M12[IndexChannel];
1962 M20[CompositeChannels]+=M20[IndexChannel];
1963 M21[CompositeChannels]+=M21[IndexChannel];
1964 M22[CompositeChannels]+=M22[IndexChannel];
1965 M30[CompositeChannels]+=M30[IndexChannel];
1967 M00[CompositeChannels]/=(double) channels;
1968 M01[CompositeChannels]/=(double) channels;
1969 M02[CompositeChannels]/=(double) channels;
1970 M03[CompositeChannels]/=(double) channels;
1971 M10[CompositeChannels]/=(double) channels;
1972 M11[CompositeChannels]/=(double) channels;
1973 M12[CompositeChannels]/=(double) channels;
1974 M20[CompositeChannels]/=(double) channels;
1975 M21[CompositeChannels]/=(double) channels;
1976 M22[CompositeChannels]/=(double) channels;
1977 M30[CompositeChannels]/=(double) channels;
1978 for (channel=0; channel <= CompositeChannels; channel++)
1983 channel_moments[channel].centroid=centroid[channel];
1984 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
1985 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
1986 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1987 (M20[channel]-M02[channel]))));
1988 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
1989 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
1990 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1991 (M20[channel]-M02[channel]))));
1992 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
1993 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
1994 if (fabs(M11[channel]) < 0.0)
1996 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
1997 ((M20[channel]-M02[channel]) < 0.0))
1998 channel_moments[channel].ellipse_angle+=90.0;
2001 if (M11[channel] < 0.0)
2003 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2005 if ((M20[channel]-M02[channel]) < 0.0)
2006 channel_moments[channel].ellipse_angle+=90.0;
2008 channel_moments[channel].ellipse_angle+=180.0;
2012 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2013 ((M20[channel]-M02[channel]) < 0.0))
2014 channel_moments[channel].ellipse_angle+=90.0;
2015 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2016 channel_moments[channel].ellipse_axis.y*
2017 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2018 channel_moments[channel].ellipse_axis.x*
2019 channel_moments[channel].ellipse_axis.x)));
2020 channel_moments[channel].ellipse_intensity=M00[channel]/
2021 (MagickPI*channel_moments[channel].ellipse_axis.x*
2022 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2024 for (channel=0; channel <= CompositeChannels; channel++)
2031 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2032 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2033 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2034 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2035 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2036 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2037 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2038 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2041 for (channel=0; channel <= CompositeChannels; channel++)
2046 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2047 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2048 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2049 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2050 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2051 (3.0*M21[channel]-M03[channel]);
2052 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2053 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2054 (M21[channel]+M03[channel]);
2055 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2056 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2057 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2058 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2059 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2060 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2061 (M21[channel]+M03[channel]));
2062 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2063 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2064 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2065 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2066 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2067 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2068 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2069 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2070 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2071 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2072 (M21[channel]+M03[channel]));
2073 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2074 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2075 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2076 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2078 if (y < (ssize_t) image->rows)
2079 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2080 return(channel_moments);
2110 static inline double MagickLog10(
const double x)
2112 #define Log10Epsilon (1.0e-11)
2114 if (fabs(x) < Log10Epsilon)
2115 return(log10(Log10Epsilon));
2116 return(log10(fabs(x)));
2143 hash_image=BlurImage(image,0.0,1.0,exception);
2144 if (hash_image == (
Image *) NULL)
2146 hash_image->depth=8;
2147 status=TransformImageColorspace(hash_image,sRGBColorspace);
2148 if (status == MagickFalse)
2150 moments=GetImageChannelMoments(hash_image,exception);
2151 hash_image=DestroyImage(hash_image);
2155 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2158 for (channel=0; channel <= CompositeChannels; channel++)
2159 for (i=0; i < MaximumNumberOfImageMoments; i++)
2160 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2165 hash_image=BlurImage(image,0.0,1.0,exception);
2166 if (hash_image == (
Image *) NULL)
2172 hash_image->depth=8;
2173 status=TransformImageColorspace(hash_image,HCLpColorspace);
2174 if (status == MagickFalse)
2180 moments=GetImageChannelMoments(hash_image,exception);
2181 hash_image=DestroyImage(hash_image);
2188 for (channel=0; channel <= CompositeChannels; channel++)
2189 for (i=0; i < MaximumNumberOfImageMoments; i++)
2190 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2192 return(perceptual_hash);
2228 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2231 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2234 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2235 const ChannelType channel,
double *minima,
double *maxima,
2244 assert(image != (
Image *) NULL);
2245 assert(image->signature == MagickCoreSignature);
2246 if (IsEventLogging() != MagickFalse)
2247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2248 *maxima=(-MagickMaximumValue);
2249 *minima=MagickMaximumValue;
2250 GetMagickPixelPacket(image,&pixel);
2251 for (y=0; y < (ssize_t) image->rows; y++)
2254 *magick_restrict indexes;
2262 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2265 indexes=GetVirtualIndexQueue(image);
2266 for (x=0; x < (ssize_t) image->columns; x++)
2268 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2269 if ((channel & RedChannel) != 0)
2271 if (pixel.red < *minima)
2272 *minima=(double) pixel.red;
2273 if (pixel.red > *maxima)
2274 *maxima=(double) pixel.red;
2276 if ((channel & GreenChannel) != 0)
2278 if (pixel.green < *minima)
2279 *minima=(double) pixel.green;
2280 if (pixel.green > *maxima)
2281 *maxima=(double) pixel.green;
2283 if ((channel & BlueChannel) != 0)
2285 if (pixel.blue < *minima)
2286 *minima=(double) pixel.blue;
2287 if (pixel.blue > *maxima)
2288 *maxima=(double) pixel.blue;
2290 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2292 if ((QuantumRange-pixel.opacity) < *minima)
2293 *minima=(
double) (QuantumRange-pixel.opacity);
2294 if ((QuantumRange-pixel.opacity) > *maxima)
2295 *maxima=(
double) (QuantumRange-pixel.opacity);
2297 if (((channel & IndexChannel) != 0) &&
2298 (image->colorspace == CMYKColorspace))
2300 if ((
double) pixel.index < *minima)
2301 *minima=(
double) pixel.index;
2302 if ((
double) pixel.index > *maxima)
2303 *maxima=(
double) pixel.index;
2308 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2348 *channel_statistics;
2372 assert(image != (
Image *) NULL);
2373 assert(image->signature == MagickCoreSignature);
2374 if (IsEventLogging() != MagickFalse)
2375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2376 length=CompositeChannels+1UL;
2378 sizeof(*channel_statistics));
2380 sizeof(*histogram));
2388 channel_statistics);
2389 return(channel_statistics);
2391 (void) memset(channel_statistics,0,length*
2392 sizeof(*channel_statistics));
2393 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2395 channel_statistics[i].depth=1;
2396 channel_statistics[i].maxima=(-MagickMaximumValue);
2397 channel_statistics[i].minima=MagickMaximumValue;
2399 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2400 (void) memset(&number_bins,0,
sizeof(number_bins));
2401 for (y=0; y < (ssize_t) image->rows; y++)
2404 *magick_restrict indexes;
2415 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2418 indexes=GetVirtualIndexQueue(image);
2419 for (x=0; x < (ssize_t) image->columns; )
2421 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2423 depth=channel_statistics[RedChannel].depth;
2424 range=GetQuantumRange(depth);
2425 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2427 channel_statistics[RedChannel].depth++;
2431 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2433 depth=channel_statistics[GreenChannel].depth;
2434 range=GetQuantumRange(depth);
2435 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2437 channel_statistics[GreenChannel].depth++;
2441 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2443 depth=channel_statistics[BlueChannel].depth;
2444 range=GetQuantumRange(depth);
2445 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2447 channel_statistics[BlueChannel].depth++;
2451 if (image->matte != MagickFalse)
2453 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2455 depth=channel_statistics[OpacityChannel].depth;
2456 range=GetQuantumRange(depth);
2457 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2459 channel_statistics[OpacityChannel].depth++;
2464 if (image->colorspace == CMYKColorspace)
2466 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2468 depth=channel_statistics[BlackChannel].depth;
2469 range=GetQuantumRange(depth);
2470 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2472 channel_statistics[BlackChannel].depth++;
2477 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2478 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2479 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2480 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2481 channel_statistics[RedChannel].sum+=GetPixelRed(p);
2482 channel_statistics[RedChannel].sum_squared+=(double) GetPixelRed(p)*
2484 channel_statistics[RedChannel].sum_cubed+=(double)
2485 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2486 channel_statistics[RedChannel].sum_fourth_power+=(double)
2487 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2488 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2489 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2490 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2491 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2492 channel_statistics[GreenChannel].sum+=GetPixelGreen(p);
2493 channel_statistics[GreenChannel].sum_squared+=(double) GetPixelGreen(p)*
2495 channel_statistics[GreenChannel].sum_cubed+=(double) GetPixelGreen(p)*
2496 GetPixelGreen(p)*GetPixelGreen(p);
2497 channel_statistics[GreenChannel].sum_fourth_power+=(double)
2498 GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p);
2499 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2500 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2501 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2502 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2503 channel_statistics[BlueChannel].sum+=GetPixelBlue(p);
2504 channel_statistics[BlueChannel].sum_squared+=(double) GetPixelBlue(p)*
2506 channel_statistics[BlueChannel].sum_cubed+=(double) GetPixelBlue(p)*
2507 GetPixelBlue(p)*GetPixelBlue(p);
2508 channel_statistics[BlueChannel].sum_fourth_power+=(double)
2509 GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p);
2510 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2511 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2512 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2513 if (image->matte != MagickFalse)
2515 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2516 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2517 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2518 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2519 channel_statistics[OpacityChannel].sum+=GetPixelAlpha(p);
2520 channel_statistics[OpacityChannel].sum_squared+=(double)
2521 GetPixelAlpha(p)*GetPixelAlpha(p);
2522 channel_statistics[OpacityChannel].sum_cubed+=(double)
2523 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2524 channel_statistics[OpacityChannel].sum_fourth_power+=(double)
2525 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2526 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2528 if (image->colorspace == CMYKColorspace)
2530 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2531 channel_statistics[BlackChannel].minima=(double)
2532 GetPixelIndex(indexes+x);
2533 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2534 channel_statistics[BlackChannel].maxima=(
double)
2535 GetPixelIndex(indexes+x);
2536 channel_statistics[BlackChannel].sum+=GetPixelIndex(indexes+x);
2537 channel_statistics[BlackChannel].sum_squared+=(double)
2538 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2539 channel_statistics[BlackChannel].sum_cubed+=(double)
2540 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2541 GetPixelIndex(indexes+x);
2542 channel_statistics[BlackChannel].sum_fourth_power+=(double)
2543 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2544 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2545 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2551 for (i=0; i < (ssize_t) CompositeChannels; i++)
2561 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2562 mean=channel_statistics[i].sum*area;
2563 channel_statistics[i].sum=mean;
2564 channel_statistics[i].sum_squared*=area;
2565 channel_statistics[i].sum_cubed*=area;
2566 channel_statistics[i].sum_fourth_power*=area;
2567 channel_statistics[i].mean=mean;
2568 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2569 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2570 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2571 ((double) image->columns*image->rows);
2572 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2573 channel_statistics[i].standard_deviation=standard_deviation;
2575 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2577 if (histogram[i].red > 0.0)
2579 if (histogram[i].green > 0.0)
2580 number_bins.green++;
2581 if (histogram[i].blue > 0.0)
2583 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2584 number_bins.opacity++;
2585 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2586 number_bins.index++;
2588 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2589 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2594 histogram[i].red*=area;
2595 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2596 MagickLog10(histogram[i].red)*
2597 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2598 histogram[i].green*=area;
2599 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2600 MagickLog10(histogram[i].green)*
2601 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2602 histogram[i].blue*=area;
2603 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2604 MagickLog10(histogram[i].blue)*
2605 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2606 if (image->matte != MagickFalse)
2608 histogram[i].opacity*=area;
2609 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2610 MagickLog10(histogram[i].opacity)*
2611 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2613 if (image->colorspace == CMYKColorspace)
2615 histogram[i].index*=area;
2616 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2617 MagickLog10(histogram[i].index)*
2618 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2624 for (i=0; i < (ssize_t) CompositeChannels; i++)
2626 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2627 channel_statistics[CompositeChannels].depth,(double)
2628 channel_statistics[i].depth);
2629 channel_statistics[CompositeChannels].minima=MagickMin(
2630 channel_statistics[CompositeChannels].minima,
2631 channel_statistics[i].minima);
2632 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2633 channel_statistics[CompositeChannels].maxima,
2634 channel_statistics[i].maxima);
2635 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2636 channel_statistics[CompositeChannels].sum_squared+=
2637 channel_statistics[i].sum_squared;
2638 channel_statistics[CompositeChannels].sum_cubed+=
2639 channel_statistics[i].sum_cubed;
2640 channel_statistics[CompositeChannels].sum_fourth_power+=
2641 channel_statistics[i].sum_fourth_power;
2642 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2643 channel_statistics[CompositeChannels].variance+=
2644 channel_statistics[i].variance-channel_statistics[i].mean*
2645 channel_statistics[i].mean;
2646 standard_deviation=sqrt(channel_statistics[i].variance-
2647 (channel_statistics[i].mean*channel_statistics[i].mean));
2648 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2649 ((double) image->columns*image->rows);
2650 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2651 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2652 channel_statistics[CompositeChannels].entropy+=
2653 channel_statistics[i].entropy;
2656 if (image->matte != MagickFalse)
2658 if (image->colorspace == CMYKColorspace)
2660 channel_statistics[CompositeChannels].sum/=channels;
2661 channel_statistics[CompositeChannels].sum_squared/=channels;
2662 channel_statistics[CompositeChannels].sum_cubed/=channels;
2663 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2664 channel_statistics[CompositeChannels].mean/=channels;
2665 channel_statistics[CompositeChannels].kurtosis/=channels;
2666 channel_statistics[CompositeChannels].skewness/=channels;
2667 channel_statistics[CompositeChannels].entropy/=channels;
2668 i=CompositeChannels;
2669 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2670 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2671 channel_statistics[i].mean=channel_statistics[i].sum;
2672 standard_deviation=sqrt(channel_statistics[i].variance-
2673 (channel_statistics[i].mean*channel_statistics[i].mean));
2674 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2675 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2676 standard_deviation*standard_deviation);
2677 channel_statistics[i].standard_deviation=standard_deviation;
2678 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2683 standard_deviation=PerceptibleReciprocal(
2684 channel_statistics[i].standard_deviation);
2685 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2686 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2687 channel_statistics[i].mean*channel_statistics[i].mean*
2688 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2689 standard_deviation);
2690 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2691 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2692 channel_statistics[i].mean*channel_statistics[i].mean*
2693 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2694 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2695 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2696 standard_deviation*standard_deviation)-3.0;
2698 channel_statistics[CompositeChannels].mean=0.0;
2699 channel_statistics[CompositeChannels].standard_deviation=0.0;
2700 for (i=0; i < (ssize_t) CompositeChannels; i++)
2702 channel_statistics[CompositeChannels].mean+=
2703 channel_statistics[i].mean;
2704 channel_statistics[CompositeChannels].standard_deviation+=
2705 channel_statistics[i].standard_deviation;
2707 channel_statistics[CompositeChannels].mean/=(double) channels;
2708 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2710 if (y < (ssize_t) image->rows)
2712 channel_statistics);
2713 return(channel_statistics);
2754 MagickExport
Image *PolynomialImage(
const Image *images,
2755 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2760 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2762 return(polynomial_image);
2765 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2766 const ChannelType channel,
const size_t number_terms,
const double *terms,
2769 #define PolynomialImageTag "Polynomial/Image"
2784 **magick_restrict polynomial_pixels,
2790 assert(images != (
Image *) NULL);
2791 assert(images->signature == MagickCoreSignature);
2792 if (IsEventLogging() != MagickFalse)
2793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2795 assert(exception->signature == MagickCoreSignature);
2796 image=AcquireImageCanvas(images,exception);
2797 if (image == (
Image *) NULL)
2798 return((
Image *) NULL);
2799 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2801 InheritException(exception,&image->exception);
2802 image=DestroyImage(image);
2803 return((
Image *) NULL);
2805 polynomial_pixels=AcquirePixelTLS(images);
2808 image=DestroyImage(image);
2809 (void) ThrowMagickException(exception,GetMagickModule(),
2810 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2811 return((
Image *) NULL);
2818 GetMagickPixelPacket(images,&zero);
2819 polynomial_view=AcquireAuthenticCacheView(image,exception);
2820 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2821 #pragma omp parallel for schedule(static) shared(progress,status) \
2822 magick_number_threads(image,image,image->rows,1)
2824 for (y=0; y < (ssize_t) image->rows; y++)
2833 id = GetOpenMPThreadId();
2836 *magick_restrict polynomial_indexes;
2851 if (status == MagickFalse)
2853 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2860 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2861 polynomial_pixel=polynomial_pixels[id];
2862 for (x=0; x < (ssize_t) image->columns; x++)
2863 polynomial_pixel[x]=zero;
2865 number_images=GetImageListLength(images);
2866 for (i=0; i < (ssize_t) number_images; i++)
2874 if (i >= (ssize_t) number_terms)
2876 image_view=AcquireVirtualCacheView(next,exception);
2877 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2880 image_view=DestroyCacheView(image_view);
2883 indexes=GetCacheViewVirtualIndexQueue(image_view);
2884 for (x=0; x < (ssize_t) image->columns; x++)
2890 coefficient=terms[i << 1];
2891 degree=terms[(i << 1)+1];
2892 if ((channel & RedChannel) != 0)
2893 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*p->red,degree);
2894 if ((channel & GreenChannel) != 0)
2895 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*p->green,
2897 if ((channel & BlueChannel) != 0)
2898 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*p->blue,
2900 if ((channel & OpacityChannel) != 0)
2901 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2902 (QuantumRange-p->opacity),degree);
2903 if (((channel & IndexChannel) != 0) &&
2904 (image->colorspace == CMYKColorspace))
2905 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*indexes[x],
2909 image_view=DestroyCacheView(image_view);
2910 next=GetNextImageInList(next);
2912 for (x=0; x < (ssize_t) image->columns; x++)
2914 SetPixelRed(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].red));
2915 SetPixelGreen(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].green));
2916 SetPixelBlue(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].blue));
2917 if (image->matte == MagickFalse)
2918 SetPixelOpacity(q,ClampToQuantum(QuantumRange-QuantumRange*
2919 polynomial_pixel[x].opacity));
2921 SetPixelAlpha(q,ClampToQuantum(QuantumRange-QuantumRange*
2922 polynomial_pixel[x].opacity));
2923 if (image->colorspace == CMYKColorspace)
2924 SetPixelIndex(polynomial_indexes+x,ClampToQuantum(QuantumRange*
2925 polynomial_pixel[x].index));
2928 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2930 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2935 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2937 if (proceed == MagickFalse)
2941 polynomial_view=DestroyCacheView(polynomial_view);
2942 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2943 if (status == MagickFalse)
2944 image=DestroyImage(image);
2986 #define ListChannels 5
3013 lists[ListChannels];
3023 for (i=0; i < ListChannels; i++)
3024 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3025 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3026 pixel_list->lists[i].nodes);
3027 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3036 assert(pixel_list != (
PixelList **) NULL);
3037 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3038 if (pixel_list[i] != (
PixelList *) NULL)
3039 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3040 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3044 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3052 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3055 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3056 pixel_list->length=width*height;
3057 for (i=0; i < ListChannels; i++)
3059 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3060 sizeof(*pixel_list->lists[i].nodes));
3061 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3062 return(DestroyPixelList(pixel_list));
3063 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3064 sizeof(*pixel_list->lists[i].nodes));
3066 pixel_list->signature=MagickCoreSignature;
3070 static PixelList **AcquirePixelListTLS(
const size_t width,
3071 const size_t height)
3082 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3083 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3084 sizeof(*pixel_list));
3087 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3088 for (i=0; i < (ssize_t) number_threads; i++)
3090 pixel_list[i]=AcquirePixelList(width,height);
3091 if (pixel_list[i] == (
PixelList *) NULL)
3092 return(DestroyPixelListTLS(pixel_list));
3097 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3113 list=pixel_list->lists+channel;
3114 list->nodes[color].signature=pixel_list->signature;
3115 list->nodes[color].count=1;
3120 for (level=list->level; level >= 0; level--)
3122 while (list->nodes[search].next[level] < color)
3123 search=list->nodes[search].next[level];
3124 update[level]=search;
3129 for (level=0; ; level++)
3131 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3132 if ((pixel_list->seed & 0x300) != 0x300)
3137 if (level > (list->level+2))
3138 level=list->level+2;
3142 while (level > list->level)
3145 update[list->level]=65536UL;
3152 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3153 list->nodes[update[level]].next[level]=color;
3154 }
while (level-- > 0);
3173 channels[ListChannels];
3178 for (channel=0; channel < 5; channel++)
3180 list=pixel_list->lists+channel;
3183 maximum=list->nodes[color].next[0];
3186 color=list->nodes[color].next[0];
3187 if (color > maximum)
3189 count+=list->nodes[color].count;
3190 }
while (count < (ssize_t) pixel_list->length);
3191 channels[channel]=(
unsigned short) maximum;
3193 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3194 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3195 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3196 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3197 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3218 channels[ListChannels];
3223 for (channel=0; channel < 5; channel++)
3225 list=pixel_list->lists+channel;
3231 color=list->nodes[color].next[0];
3232 sum+=(MagickRealType) list->nodes[color].count*color;
3233 count+=list->nodes[color].count;
3234 }
while (count < (ssize_t) pixel_list->length);
3235 sum/=pixel_list->length;
3236 channels[channel]=(
unsigned short) sum;
3238 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3239 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3240 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3241 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3242 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3260 channels[ListChannels];
3265 for (channel=0; channel < 5; channel++)
3267 list=pixel_list->lists+channel;
3272 color=list->nodes[color].next[0];
3273 count+=list->nodes[color].count;
3274 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3275 channels[channel]=(
unsigned short) color;
3277 GetMagickPixelPacket((
const Image *) NULL,pixel);
3278 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3279 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3280 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3281 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3282 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3301 channels[ListChannels];
3306 for (channel=0; channel < 5; channel++)
3308 list=pixel_list->lists+channel;
3311 minimum=list->nodes[color].next[0];
3314 color=list->nodes[color].next[0];
3315 if (color < minimum)
3317 count+=list->nodes[color].count;
3318 }
while (count < (ssize_t) pixel_list->length);
3319 channels[channel]=(
unsigned short) minimum;
3321 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3322 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3323 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3324 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3325 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3350 for (channel=0; channel < 5; channel++)
3352 list=pixel_list->lists+channel;
3355 max_count=list->nodes[mode].count;
3359 color=list->nodes[color].next[0];
3360 if (list->nodes[color].count > max_count)
3363 max_count=list->nodes[mode].count;
3365 count+=list->nodes[color].count;
3366 }
while (count < (ssize_t) pixel_list->length);
3367 channels[channel]=(
unsigned short) mode;
3369 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3370 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3371 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3372 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3373 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3398 for (channel=0; channel < 5; channel++)
3400 list=pixel_list->lists+channel;
3402 next=list->nodes[color].next[0];
3408 next=list->nodes[color].next[0];
3409 count+=list->nodes[color].count;
3410 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3411 if ((previous == 65536UL) && (next != 65536UL))
3414 if ((previous != 65536UL) && (next == 65536UL))
3416 channels[channel]=(
unsigned short) color;
3418 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3419 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3420 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3421 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3422 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3425 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3444 channels[ListChannels];
3449 for (channel=0; channel < 5; channel++)
3451 list=pixel_list->lists+channel;
3457 color=list->nodes[color].next[0];
3458 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3459 count+=list->nodes[color].count;
3460 }
while (count < (ssize_t) pixel_list->length);
3461 sum/=pixel_list->length;
3462 channels[channel]=(
unsigned short) sqrt(sum);
3464 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3465 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3466 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3467 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3468 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3471 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3491 channels[ListChannels];
3496 for (channel=0; channel < 5; channel++)
3498 list=pixel_list->lists+channel;
3508 color=list->nodes[color].next[0];
3509 sum+=(MagickRealType) list->nodes[color].count*color;
3510 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3511 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3512 count+=list->nodes[color].count;
3513 }
while (count < (ssize_t) pixel_list->length);
3514 sum/=pixel_list->length;
3515 sum_squared/=pixel_list->length;
3516 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3518 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3519 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3520 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3521 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3522 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3525 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3526 const IndexPacket *indexes,
PixelList *pixel_list)
3534 index=ScaleQuantumToShort(GetPixelRed(pixel));
3535 signature=pixel_list->lists[0].nodes[index].signature;
3536 if (signature == pixel_list->signature)
3537 pixel_list->lists[0].nodes[index].count++;
3539 AddNodePixelList(pixel_list,0,index);
3540 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3541 signature=pixel_list->lists[1].nodes[index].signature;
3542 if (signature == pixel_list->signature)
3543 pixel_list->lists[1].nodes[index].count++;
3545 AddNodePixelList(pixel_list,1,index);
3546 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3547 signature=pixel_list->lists[2].nodes[index].signature;
3548 if (signature == pixel_list->signature)
3549 pixel_list->lists[2].nodes[index].count++;
3551 AddNodePixelList(pixel_list,2,index);
3552 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3553 signature=pixel_list->lists[3].nodes[index].signature;
3554 if (signature == pixel_list->signature)
3555 pixel_list->lists[3].nodes[index].count++;
3557 AddNodePixelList(pixel_list,3,index);
3558 if (image->colorspace == CMYKColorspace)
3559 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3560 signature=pixel_list->lists[4].nodes[index].signature;
3561 if (signature == pixel_list->signature)
3562 pixel_list->lists[4].nodes[index].count++;
3564 AddNodePixelList(pixel_list,4,index);
3567 static void ResetPixelList(
PixelList *pixel_list)
3584 for (channel=0; channel < 5; channel++)
3586 list=pixel_list->lists+channel;
3587 root=list->nodes+65536UL;
3589 for (level=0; level < 9; level++)
3590 root->next[level]=65536UL;
3592 pixel_list->seed=pixel_list->signature++;
3595 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3596 const size_t width,
const size_t height,
ExceptionInfo *exception)
3601 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3603 return(statistic_image);
3606 MagickExport
Image *StatisticImageChannel(
const Image *image,
3607 const ChannelType channel,
const StatisticType type,
const size_t width,
3610 #define StatisticImageTag "Statistic/Image"
3626 **magick_restrict pixel_list;
3638 assert(image != (
Image *) NULL);
3639 assert(image->signature == MagickCoreSignature);
3640 if (IsEventLogging() != MagickFalse)
3641 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3643 assert(exception->signature == MagickCoreSignature);
3644 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3645 if (statistic_image == (
Image *) NULL)
3646 return((
Image *) NULL);
3647 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3649 InheritException(exception,&statistic_image->exception);
3650 statistic_image=DestroyImage(statistic_image);
3651 return((
Image *) NULL);
3653 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3655 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3657 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3660 statistic_image=DestroyImage(statistic_image);
3661 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3668 image_view=AcquireVirtualCacheView(image,exception);
3669 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3670 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3671 #pragma omp parallel for schedule(static) shared(progress,status) \
3672 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3674 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3677 id = GetOpenMPThreadId();
3680 *magick_restrict indexes;
3686 *magick_restrict statistic_indexes;
3694 if (status == MagickFalse)
3696 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3697 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3698 neighbor_height,exception);
3699 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3705 indexes=GetCacheViewVirtualIndexQueue(image_view);
3706 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3707 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3724 ResetPixelList(pixel_list[
id]);
3725 for (v=0; v < (ssize_t) neighbor_height; v++)
3727 for (u=0; u < (ssize_t) neighbor_width; u++)
3728 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3729 r+=image->columns+neighbor_width;
3730 s+=image->columns+neighbor_width;
3732 GetMagickPixelPacket(image,&pixel);
3733 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3734 neighbor_width*neighbor_height/2,&pixel);
3737 case GradientStatistic:
3743 GetMinimumPixelList(pixel_list[
id],&pixel);
3745 GetMaximumPixelList(pixel_list[
id],&pixel);
3747 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3748 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3749 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3750 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3751 if (image->colorspace == CMYKColorspace)
3752 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3755 case MaximumStatistic:
3757 GetMaximumPixelList(pixel_list[
id],&pixel);
3762 GetMeanPixelList(pixel_list[
id],&pixel);
3765 case MedianStatistic:
3768 GetMedianPixelList(pixel_list[
id],&pixel);
3771 case MinimumStatistic:
3773 GetMinimumPixelList(pixel_list[
id],&pixel);
3778 GetModePixelList(pixel_list[
id],&pixel);
3781 case NonpeakStatistic:
3783 GetNonpeakPixelList(pixel_list[
id],&pixel);
3786 case RootMeanSquareStatistic:
3788 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3791 case StandardDeviationStatistic:
3793 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3797 if ((channel & RedChannel) != 0)
3798 SetPixelRed(q,ClampToQuantum(pixel.red));
3799 if ((channel & GreenChannel) != 0)
3800 SetPixelGreen(q,ClampToQuantum(pixel.green));
3801 if ((channel & BlueChannel) != 0)
3802 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3803 if ((channel & OpacityChannel) != 0)
3804 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3805 if (((channel & IndexChannel) != 0) &&
3806 (image->colorspace == CMYKColorspace))
3807 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3811 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3813 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3818 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3820 if (proceed == MagickFalse)
3824 statistic_view=DestroyCacheView(statistic_view);
3825 image_view=DestroyCacheView(image_view);
3826 pixel_list=DestroyPixelListTLS(pixel_list);
3827 if (status == MagickFalse)
3828 statistic_image=DestroyImage(statistic_image);
3829 return(statistic_image);