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 result=(MagickRealType) (QuantumRange*pow((
double) (QuantumScale*pixel),
371 case RightShiftEvaluateOperator:
373 result=(MagickRealType) pixel;
374 for (i=0; i < (ssize_t) value; i++)
378 case RootMeanSquareEvaluateOperator:
380 result=((MagickRealType) pixel*pixel+value);
383 case SetEvaluateOperator:
388 case SineEvaluateOperator:
390 result=(MagickRealType) (QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
391 QuantumScale*pixel*value))+0.5));
394 case SubtractEvaluateOperator:
396 result=(MagickRealType) (pixel-value);
399 case SumEvaluateOperator:
401 result=(MagickRealType) (pixel+value);
404 case ThresholdEvaluateOperator:
406 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
410 case ThresholdBlackEvaluateOperator:
412 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
415 case ThresholdWhiteEvaluateOperator:
417 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
421 case UniformNoiseEvaluateOperator:
423 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
427 case XorEvaluateOperator:
429 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
448 columns=images->columns;
451 for (p=images; p != (
Image *) NULL; p=p->next)
457 if (p->matte != MagickFalse)
459 if (p->colorspace == CMYKColorspace)
461 if (channels > number_channels)
463 number_channels=channels;
466 if (p->columns > columns)
471 return(CloneImage(q,columns,rows,MagickTrue,exception));
474 MagickExport MagickBooleanType EvaluateImage(
Image *image,
475 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
480 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
484 MagickExport
Image *EvaluateImages(
const Image *images,
487 #define EvaluateImageTag "Evaluate/Image"
502 **magick_restrict evaluate_pixels,
506 **magick_restrict random_info;
514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
519 assert(images != (
Image *) NULL);
520 assert(images->signature == MagickCoreSignature);
522 assert(exception->signature == MagickCoreSignature);
523 if (IsEventLogging() != MagickFalse)
524 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
525 image=AcquireImageCanvas(images,exception);
526 if (image == (
Image *) NULL)
527 return((
Image *) NULL);
528 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
530 InheritException(exception,&image->exception);
531 image=DestroyImage(image);
532 return((
Image *) NULL);
534 evaluate_pixels=AcquirePixelTLS(images);
537 image=DestroyImage(image);
538 (void) ThrowMagickException(exception,GetMagickModule(),
539 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
540 return((
Image *) NULL);
547 number_images=GetImageListLength(images);
548 GetMagickPixelPacket(images,&zero);
549 random_info=AcquireRandomInfoTLS();
550 evaluate_view=AcquireAuthenticCacheView(image,exception);
551 if (op == MedianEvaluateOperator)
553 #if defined(MAGICKCORE_OPENMP_SUPPORT)
554 key=GetRandomSecretKey(random_info[0]);
555 #pragma omp parallel for schedule(static) shared(progress,status) \
556 magick_number_threads(image,images,image->rows,key == ~0UL)
558 for (y=0; y < (ssize_t) image->rows; y++)
567 id = GetOpenMPThreadId();
570 *magick_restrict evaluate_indexes;
581 if (status == MagickFalse)
583 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
590 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
591 evaluate_pixel=evaluate_pixels[id];
592 for (x=0; x < (ssize_t) image->columns; x++)
597 for (i=0; i < (ssize_t) number_images; i++)
598 evaluate_pixel[i]=zero;
600 for (i=0; i < (ssize_t) number_images; i++)
608 image_view=AcquireVirtualCacheView(next,exception);
609 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
612 image_view=DestroyCacheView(image_view);
615 indexes=GetCacheViewVirtualIndexQueue(image_view);
616 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
617 GetPixelRed(p),op,evaluate_pixel[i].red);
618 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
619 GetPixelGreen(p),op,evaluate_pixel[i].green);
620 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
621 GetPixelBlue(p),op,evaluate_pixel[i].blue);
622 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
623 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
624 if (image->colorspace == CMYKColorspace)
625 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
626 *indexes,op,evaluate_pixel[i].index);
627 image_view=DestroyCacheView(image_view);
628 next=GetNextImageInList(next);
630 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
632 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
633 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
634 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
635 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
636 if (image->colorspace == CMYKColorspace)
637 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
638 evaluate_pixel[i/2].index));
641 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
643 if (images->progress_monitor != (MagickProgressMonitor) NULL)
648 #if defined(MAGICKCORE_OPENMP_SUPPORT)
652 proceed=SetImageProgress(images,EvaluateImageTag,progress,
654 if (proceed == MagickFalse)
661 #if defined(MAGICKCORE_OPENMP_SUPPORT)
662 key=GetRandomSecretKey(random_info[0]);
663 #pragma omp parallel for schedule(static) shared(progress,status) \
664 magick_number_threads(image,images,image->rows,key == ~0UL)
666 for (y=0; y < (ssize_t) image->rows; y++)
675 id = GetOpenMPThreadId();
678 *magick_restrict evaluate_indexes;
690 if (status == MagickFalse)
692 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
699 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
700 evaluate_pixel=evaluate_pixels[id];
701 for (x=0; x < (ssize_t) image->columns; x++)
702 evaluate_pixel[x]=zero;
704 for (i=0; i < (ssize_t) number_images; i++)
712 image_view=AcquireVirtualCacheView(next,exception);
713 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
717 image_view=DestroyCacheView(image_view);
720 indexes=GetCacheViewVirtualIndexQueue(image_view);
721 for (x=0; x < (ssize_t) image->columns; x++)
723 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
724 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
725 evaluate_pixel[x].red);
726 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
727 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
728 evaluate_pixel[x].green);
729 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
730 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
731 evaluate_pixel[x].blue);
732 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
733 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
734 evaluate_pixel[x].opacity);
735 if (image->colorspace == CMYKColorspace)
736 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
737 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
738 evaluate_pixel[x].index);
741 image_view=DestroyCacheView(image_view);
742 next=GetNextImageInList(next);
744 if (op == MeanEvaluateOperator)
745 for (x=0; x < (ssize_t) image->columns; x++)
747 evaluate_pixel[x].red/=number_images;
748 evaluate_pixel[x].green/=number_images;
749 evaluate_pixel[x].blue/=number_images;
750 evaluate_pixel[x].opacity/=number_images;
751 evaluate_pixel[x].index/=number_images;
753 if (op == RootMeanSquareEvaluateOperator)
754 for (x=0; x < (ssize_t) image->columns; x++)
756 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
758 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
760 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
762 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
764 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
767 if (op == MultiplyEvaluateOperator)
768 for (x=0; x < (ssize_t) image->columns; x++)
773 for (j=0; j < (ssize_t) (number_images-1); j++)
775 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
776 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
777 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
778 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
779 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
782 for (x=0; x < (ssize_t) image->columns; x++)
784 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
785 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
786 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
787 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
788 if (image->colorspace == CMYKColorspace)
789 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
790 evaluate_pixel[x].index));
793 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
795 if (images->progress_monitor != (MagickProgressMonitor) NULL)
800 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
802 if (proceed == MagickFalse)
807 evaluate_view=DestroyCacheView(evaluate_view);
808 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
809 random_info=DestroyRandomInfoTLS(random_info);
810 if (status == MagickFalse)
811 image=DestroyImage(image);
815 MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
816 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
829 **magick_restrict random_info;
834 #if defined(MAGICKCORE_OPENMP_SUPPORT)
839 assert(image != (
Image *) NULL);
840 assert(image->signature == MagickCoreSignature);
842 assert(exception->signature == MagickCoreSignature);
843 if (IsEventLogging() != MagickFalse)
844 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
845 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
847 InheritException(exception,&image->exception);
852 random_info=AcquireRandomInfoTLS();
853 image_view=AcquireAuthenticCacheView(image,exception);
854 #if defined(MAGICKCORE_OPENMP_SUPPORT)
855 key=GetRandomSecretKey(random_info[0]);
856 #pragma omp parallel for schedule(static) shared(progress,status) \
857 magick_number_threads(image,image,image->rows,key == ~0UL)
859 for (y=0; y < (ssize_t) image->rows; y++)
862 id = GetOpenMPThreadId();
865 *magick_restrict indexes;
873 if (status == MagickFalse)
875 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
881 indexes=GetCacheViewAuthenticIndexQueue(image_view);
882 for (x=0; x < (ssize_t) image->columns; x++)
887 if ((channel & RedChannel) != 0)
889 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
890 if (op == MeanEvaluateOperator)
892 SetPixelRed(q,ClampToQuantum(result));
894 if ((channel & GreenChannel) != 0)
896 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
898 if (op == MeanEvaluateOperator)
900 SetPixelGreen(q,ClampToQuantum(result));
902 if ((channel & BlueChannel) != 0)
904 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
906 if (op == MeanEvaluateOperator)
908 SetPixelBlue(q,ClampToQuantum(result));
910 if ((channel & OpacityChannel) != 0)
912 if (image->matte == MagickFalse)
914 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
916 if (op == MeanEvaluateOperator)
918 SetPixelOpacity(q,ClampToQuantum(result));
922 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
924 if (op == MeanEvaluateOperator)
926 SetPixelAlpha(q,ClampToQuantum(result));
929 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
931 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
933 if (op == MeanEvaluateOperator)
935 SetPixelIndex(indexes+x,ClampToQuantum(result));
939 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
941 if (image->progress_monitor != (MagickProgressMonitor) NULL)
946 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
947 if (proceed == MagickFalse)
951 image_view=DestroyCacheView(image_view);
952 random_info=DestroyRandomInfoTLS(random_info);
996 static Quantum ApplyFunction(Quantum pixel,
const MagickFunction
function,
997 const size_t number_parameters,
const double *parameters,
1010 case PolynomialFunction:
1018 for (i=0; i < (ssize_t) number_parameters; i++)
1019 result=result*QuantumScale*pixel + parameters[i];
1020 result*=QuantumRange;
1023 case SinusoidFunction:
1028 double freq,phase,ampl,bias;
1029 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1030 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1031 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1032 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1033 result=(MagickRealType) (QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1034 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
1037 case ArcsinFunction:
1048 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1049 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1050 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1051 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1052 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*pixel-center);
1054 result=bias-range/2.0;
1057 result=bias+range/2.0;
1059 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1060 result*=QuantumRange;
1063 case ArctanFunction:
1068 double slope,range,center,bias;
1069 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1070 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1071 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1072 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1073 result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
1074 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((
double)
1078 case UndefinedFunction:
1081 return(ClampToQuantum(result));
1084 MagickExport MagickBooleanType FunctionImage(
Image *image,
1085 const MagickFunction
function,
const size_t number_parameters,
1091 status=FunctionImageChannel(image,CompositeChannels,
function,
1092 number_parameters,parameters,exception);
1096 MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1097 const ChannelType channel,
const MagickFunction
function,
1098 const size_t number_parameters,
const double *parameters,
1101 #define FunctionImageTag "Function/Image "
1115 assert(image != (
Image *) NULL);
1116 assert(image->signature == MagickCoreSignature);
1118 assert(exception->signature == MagickCoreSignature);
1119 if (IsEventLogging() != MagickFalse)
1120 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1121 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1123 InheritException(exception,&image->exception);
1124 return(MagickFalse);
1126 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1127 status=AccelerateFunctionImage(image,channel,
function,number_parameters,
1128 parameters,exception);
1129 if (status != MagickFalse)
1134 image_view=AcquireAuthenticCacheView(image,exception);
1135 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1136 #pragma omp parallel for schedule(static) shared(progress,status) \
1137 magick_number_threads(image,image,image->rows,1)
1139 for (y=0; y < (ssize_t) image->rows; y++)
1142 *magick_restrict indexes;
1150 if (status == MagickFalse)
1152 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1158 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1159 for (x=0; x < (ssize_t) image->columns; x++)
1161 if ((channel & RedChannel) != 0)
1162 SetPixelRed(q,ApplyFunction(GetPixelRed(q),
function,
1163 number_parameters,parameters,exception));
1164 if ((channel & GreenChannel) != 0)
1165 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),
function,
1166 number_parameters,parameters,exception));
1167 if ((channel & BlueChannel) != 0)
1168 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),
function,
1169 number_parameters,parameters,exception));
1170 if ((channel & OpacityChannel) != 0)
1172 if (image->matte == MagickFalse)
1173 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),
function,
1174 number_parameters,parameters,exception));
1176 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),
function,
1177 number_parameters,parameters,exception));
1179 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1180 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),
function,
1181 number_parameters,parameters,exception));
1184 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1186 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1191 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1192 if (proceed == MagickFalse)
1196 image_view=DestroyCacheView(image_view);
1230 MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1236 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1240 MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1241 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1244 *channel_statistics;
1249 assert(image != (
Image *) NULL);
1250 assert(image->signature == MagickCoreSignature);
1251 if (IsEventLogging() != MagickFalse)
1252 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1253 channel_statistics=GetImageChannelStatistics(image,exception);
1255 return(MagickFalse);
1257 channel_statistics[CompositeChannels].entropy=0.0;
1258 if ((channel & RedChannel) != 0)
1260 channel_statistics[CompositeChannels].entropy+=
1261 channel_statistics[RedChannel].entropy;
1264 if ((channel & GreenChannel) != 0)
1266 channel_statistics[CompositeChannels].entropy+=
1267 channel_statistics[GreenChannel].entropy;
1270 if ((channel & BlueChannel) != 0)
1272 channel_statistics[CompositeChannels].entropy+=
1273 channel_statistics[BlueChannel].entropy;
1276 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1278 channel_statistics[CompositeChannels].entropy+=
1279 channel_statistics[OpacityChannel].entropy;
1282 if (((channel & IndexChannel) != 0) &&
1283 (image->colorspace == CMYKColorspace))
1285 channel_statistics[CompositeChannels].entropy+=
1286 channel_statistics[BlackChannel].entropy;
1289 channel_statistics[CompositeChannels].entropy/=channels;
1290 *entropy=channel_statistics[CompositeChannels].entropy;
1292 channel_statistics);
1329 MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1335 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1340 MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1341 const ChannelType channel,
size_t *minima,
size_t *maxima,
1351 assert(image != (
Image *) NULL);
1352 assert(image->signature == MagickCoreSignature);
1353 if (IsEventLogging() != MagickFalse)
1354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1355 status=GetImageChannelRange(image,channel,&min,&max,exception);
1356 *minima=(size_t) ceil(min-0.5);
1357 *maxima=(size_t) floor(max+0.5);
1395 MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1401 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1406 MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1407 const ChannelType channel,
double *kurtosis,
double *skewness,
1421 assert(image != (
Image *) NULL);
1422 assert(image->signature == MagickCoreSignature);
1423 if (IsEventLogging() != MagickFalse)
1424 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1429 standard_deviation=0.0;
1432 sum_fourth_power=0.0;
1433 for (y=0; y < (ssize_t) image->rows; y++)
1436 *magick_restrict indexes;
1444 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1447 indexes=GetVirtualIndexQueue(image);
1448 for (x=0; x < (ssize_t) image->columns; x++)
1450 if ((channel & RedChannel) != 0)
1452 mean+=GetPixelRed(p);
1453 sum_squares+=(double) GetPixelRed(p)*GetPixelRed(p);
1454 sum_cubes+=(double) GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
1455 sum_fourth_power+=(double) GetPixelRed(p)*GetPixelRed(p)*
1456 GetPixelRed(p)*GetPixelRed(p);
1459 if ((channel & GreenChannel) != 0)
1461 mean+=GetPixelGreen(p);
1462 sum_squares+=(double) GetPixelGreen(p)*GetPixelGreen(p);
1463 sum_cubes+=(double) GetPixelGreen(p)*GetPixelGreen(p)*
1465 sum_fourth_power+=(double) GetPixelGreen(p)*GetPixelGreen(p)*
1466 GetPixelGreen(p)*GetPixelGreen(p);
1469 if ((channel & BlueChannel) != 0)
1471 mean+=GetPixelBlue(p);
1472 sum_squares+=(double) GetPixelBlue(p)*GetPixelBlue(p);
1473 sum_cubes+=(double) GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p);
1474 sum_fourth_power+=(double) GetPixelBlue(p)*GetPixelBlue(p)*
1475 GetPixelBlue(p)*GetPixelBlue(p);
1478 if ((channel & OpacityChannel) != 0)
1480 mean+=GetPixelAlpha(p);
1481 sum_squares+=(double) GetPixelOpacity(p)*GetPixelAlpha(p);
1482 sum_cubes+=(double) GetPixelOpacity(p)*GetPixelAlpha(p)*
1484 sum_fourth_power+=(double) GetPixelAlpha(p)*GetPixelAlpha(p)*
1485 GetPixelAlpha(p)*GetPixelAlpha(p);
1488 if (((channel & IndexChannel) != 0) &&
1489 (image->colorspace == CMYKColorspace))
1494 index=(double) GetPixelIndex(indexes+x);
1496 sum_squares+=index*index;
1497 sum_cubes+=index*index*index;
1498 sum_fourth_power+=index*index*index*index;
1504 if (y < (ssize_t) image->rows)
1505 return(MagickFalse);
1511 sum_fourth_power/=area;
1513 standard_deviation=sqrt(sum_squares-(mean*mean));
1514 if (standard_deviation != 0.0)
1516 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1517 3.0*mean*mean*mean*mean;
1518 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1521 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1522 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1524 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1561 MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1567 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1572 MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1573 const ChannelType channel,
double *mean,
double *standard_deviation,
1577 *channel_statistics;
1582 assert(image != (
Image *) NULL);
1583 assert(image->signature == MagickCoreSignature);
1584 if (IsEventLogging() != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1586 channel_statistics=GetImageChannelStatistics(image,exception);
1588 return(MagickFalse);
1590 channel_statistics[CompositeChannels].mean=0.0;
1591 channel_statistics[CompositeChannels].standard_deviation=0.0;
1592 if ((channel & RedChannel) != 0)
1594 channel_statistics[CompositeChannels].mean+=
1595 channel_statistics[RedChannel].mean;
1596 channel_statistics[CompositeChannels].standard_deviation+=
1597 channel_statistics[RedChannel].standard_deviation;
1600 if ((channel & GreenChannel) != 0)
1602 channel_statistics[CompositeChannels].mean+=
1603 channel_statistics[GreenChannel].mean;
1604 channel_statistics[CompositeChannels].standard_deviation+=
1605 channel_statistics[GreenChannel].standard_deviation;
1608 if ((channel & BlueChannel) != 0)
1610 channel_statistics[CompositeChannels].mean+=
1611 channel_statistics[BlueChannel].mean;
1612 channel_statistics[CompositeChannels].standard_deviation+=
1613 channel_statistics[BlueChannel].standard_deviation;
1616 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1618 channel_statistics[CompositeChannels].mean+=
1619 channel_statistics[OpacityChannel].mean;
1620 channel_statistics[CompositeChannels].standard_deviation+=
1621 channel_statistics[OpacityChannel].standard_deviation;
1624 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1626 channel_statistics[CompositeChannels].mean+=
1627 channel_statistics[BlackChannel].mean;
1628 channel_statistics[CompositeChannels].standard_deviation+=
1629 channel_statistics[CompositeChannels].standard_deviation;
1632 channel_statistics[CompositeChannels].mean/=channels;
1633 channel_statistics[CompositeChannels].standard_deviation/=channels;
1634 *mean=channel_statistics[CompositeChannels].mean;
1635 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1637 channel_statistics);
1670 #define MaxNumberImageMoments 8
1676 M00[CompositeChannels+1],
1677 M01[CompositeChannels+1],
1678 M02[CompositeChannels+1],
1679 M03[CompositeChannels+1],
1680 M10[CompositeChannels+1],
1681 M11[CompositeChannels+1],
1682 M12[CompositeChannels+1],
1683 M20[CompositeChannels+1],
1684 M21[CompositeChannels+1],
1685 M22[CompositeChannels+1],
1686 M30[CompositeChannels+1];
1692 centroid[CompositeChannels+1];
1702 assert(image != (
Image *) NULL);
1703 assert(image->signature == MagickCoreSignature);
1704 if (IsEventLogging() != MagickFalse)
1705 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1706 length=CompositeChannels+1UL;
1708 sizeof(*channel_moments));
1710 return(channel_moments);
1711 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1712 (void) memset(centroid,0,
sizeof(centroid));
1713 (void) memset(M00,0,
sizeof(M00));
1714 (void) memset(M01,0,
sizeof(M01));
1715 (void) memset(M02,0,
sizeof(M02));
1716 (void) memset(M03,0,
sizeof(M03));
1717 (void) memset(M10,0,
sizeof(M10));
1718 (void) memset(M11,0,
sizeof(M11));
1719 (void) memset(M12,0,
sizeof(M12));
1720 (void) memset(M20,0,
sizeof(M20));
1721 (void) memset(M21,0,
sizeof(M21));
1722 (void) memset(M22,0,
sizeof(M22));
1723 (void) memset(M30,0,
sizeof(M30));
1724 GetMagickPixelPacket(image,&pixel);
1725 for (y=0; y < (ssize_t) image->rows; y++)
1728 *magick_restrict indexes;
1739 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1742 indexes=GetVirtualIndexQueue(image);
1743 for (x=0; x < (ssize_t) image->columns; x++)
1745 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1746 M00[RedChannel]+=QuantumScale*pixel.red;
1747 M10[RedChannel]+=x*QuantumScale*pixel.red;
1748 M01[RedChannel]+=y*QuantumScale*pixel.red;
1749 M00[GreenChannel]+=QuantumScale*pixel.green;
1750 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1751 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1752 M00[BlueChannel]+=QuantumScale*pixel.blue;
1753 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1754 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1755 if (image->matte != MagickFalse)
1757 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1758 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1759 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1761 if (image->colorspace == CMYKColorspace)
1763 M00[IndexChannel]+=QuantumScale*pixel.index;
1764 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1765 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1770 for (channel=0; channel <= CompositeChannels; channel++)
1775 if (M00[channel] < MagickEpsilon)
1777 M00[channel]+=MagickEpsilon;
1778 centroid[channel].x=(double) image->columns/2.0;
1779 centroid[channel].y=(
double) image->rows/2.0;
1782 M00[channel]+=MagickEpsilon;
1783 centroid[channel].x=M10[channel]/M00[channel];
1784 centroid[channel].y=M01[channel]/M00[channel];
1786 for (y=0; y < (ssize_t) image->rows; y++)
1789 *magick_restrict indexes;
1800 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1803 indexes=GetVirtualIndexQueue(image);
1804 for (x=0; x < (ssize_t) image->columns; x++)
1806 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1807 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1808 centroid[RedChannel].y)*QuantumScale*pixel.red;
1809 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1810 centroid[RedChannel].x)*QuantumScale*pixel.red;
1811 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1812 centroid[RedChannel].y)*QuantumScale*pixel.red;
1813 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1814 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1816 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1817 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1819 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1820 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1821 centroid[RedChannel].y)*QuantumScale*pixel.red;
1822 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1823 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1825 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1826 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1828 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1829 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1830 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1831 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1832 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1833 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1834 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1835 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1837 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1838 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1840 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1841 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1842 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1843 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1844 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1846 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1847 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1849 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1850 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1851 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1852 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1853 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1854 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1855 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1856 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1858 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1859 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1861 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1862 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1863 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1864 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1865 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1867 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1868 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1870 if (image->matte != MagickFalse)
1872 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1873 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1874 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1875 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1876 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1877 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1878 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1879 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1880 QuantumScale*pixel.opacity;
1881 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1882 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1883 QuantumScale*pixel.opacity;
1884 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1885 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1886 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1887 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1888 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1889 QuantumScale*pixel.opacity;
1890 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1891 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1892 QuantumScale*pixel.opacity;
1894 if (image->colorspace == CMYKColorspace)
1896 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1897 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1898 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1899 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1900 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1901 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1902 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1903 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1904 QuantumScale*pixel.index;
1905 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1906 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1907 QuantumScale*pixel.index;
1908 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1909 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1910 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1911 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1912 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1913 QuantumScale*pixel.index;
1914 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1915 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1916 QuantumScale*pixel.index;
1922 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1923 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1924 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1925 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1926 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1927 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1928 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1929 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1930 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1931 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1932 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1933 if (image->matte != MagickFalse)
1936 M00[CompositeChannels]+=M00[OpacityChannel];
1937 M01[CompositeChannels]+=M01[OpacityChannel];
1938 M02[CompositeChannels]+=M02[OpacityChannel];
1939 M03[CompositeChannels]+=M03[OpacityChannel];
1940 M10[CompositeChannels]+=M10[OpacityChannel];
1941 M11[CompositeChannels]+=M11[OpacityChannel];
1942 M12[CompositeChannels]+=M12[OpacityChannel];
1943 M20[CompositeChannels]+=M20[OpacityChannel];
1944 M21[CompositeChannels]+=M21[OpacityChannel];
1945 M22[CompositeChannels]+=M22[OpacityChannel];
1946 M30[CompositeChannels]+=M30[OpacityChannel];
1948 if (image->colorspace == CMYKColorspace)
1951 M00[CompositeChannels]+=M00[IndexChannel];
1952 M01[CompositeChannels]+=M01[IndexChannel];
1953 M02[CompositeChannels]+=M02[IndexChannel];
1954 M03[CompositeChannels]+=M03[IndexChannel];
1955 M10[CompositeChannels]+=M10[IndexChannel];
1956 M11[CompositeChannels]+=M11[IndexChannel];
1957 M12[CompositeChannels]+=M12[IndexChannel];
1958 M20[CompositeChannels]+=M20[IndexChannel];
1959 M21[CompositeChannels]+=M21[IndexChannel];
1960 M22[CompositeChannels]+=M22[IndexChannel];
1961 M30[CompositeChannels]+=M30[IndexChannel];
1963 M00[CompositeChannels]/=(double) channels;
1964 M01[CompositeChannels]/=(double) channels;
1965 M02[CompositeChannels]/=(double) channels;
1966 M03[CompositeChannels]/=(double) channels;
1967 M10[CompositeChannels]/=(double) channels;
1968 M11[CompositeChannels]/=(double) channels;
1969 M12[CompositeChannels]/=(double) channels;
1970 M20[CompositeChannels]/=(double) channels;
1971 M21[CompositeChannels]/=(double) channels;
1972 M22[CompositeChannels]/=(double) channels;
1973 M30[CompositeChannels]/=(double) channels;
1974 for (channel=0; channel <= CompositeChannels; channel++)
1979 channel_moments[channel].centroid=centroid[channel];
1980 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
1981 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
1982 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1983 (M20[channel]-M02[channel]))));
1984 channel_moments[channel].ellipse_axis.y=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_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
1989 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
1990 if (fabs(M11[channel]) < 0.0)
1992 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
1993 ((M20[channel]-M02[channel]) < 0.0))
1994 channel_moments[channel].ellipse_angle+=90.0;
1997 if (M11[channel] < 0.0)
1999 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2001 if ((M20[channel]-M02[channel]) < 0.0)
2002 channel_moments[channel].ellipse_angle+=90.0;
2004 channel_moments[channel].ellipse_angle+=180.0;
2008 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2009 ((M20[channel]-M02[channel]) < 0.0))
2010 channel_moments[channel].ellipse_angle+=90.0;
2011 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2012 channel_moments[channel].ellipse_axis.y*
2013 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2014 channel_moments[channel].ellipse_axis.x*
2015 channel_moments[channel].ellipse_axis.x)));
2016 channel_moments[channel].ellipse_intensity=M00[channel]/
2017 (MagickPI*channel_moments[channel].ellipse_axis.x*
2018 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2020 for (channel=0; channel <= CompositeChannels; channel++)
2027 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2028 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2029 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2030 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2031 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2032 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2033 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2034 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2037 for (channel=0; channel <= CompositeChannels; channel++)
2042 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2043 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2044 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2045 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2046 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2047 (3.0*M21[channel]-M03[channel]);
2048 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2049 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2050 (M21[channel]+M03[channel]);
2051 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2052 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2053 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2054 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2055 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2056 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2057 (M21[channel]+M03[channel]));
2058 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2059 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2060 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2061 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2062 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2063 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2064 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2065 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2066 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2067 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2068 (M21[channel]+M03[channel]));
2069 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2070 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2071 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2072 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2074 if (y < (ssize_t) image->rows)
2075 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2076 return(channel_moments);
2106 static inline double MagickLog10(
const double x)
2108 #define Log10Epsilon (1.0e-11)
2110 if (fabs(x) < Log10Epsilon)
2111 return(log10(Log10Epsilon));
2112 return(log10(fabs(x)));
2139 hash_image=BlurImage(image,0.0,1.0,exception);
2140 if (hash_image == (
Image *) NULL)
2142 hash_image->depth=8;
2143 status=TransformImageColorspace(hash_image,sRGBColorspace);
2144 if (status == MagickFalse)
2146 moments=GetImageChannelMoments(hash_image,exception);
2147 hash_image=DestroyImage(hash_image);
2151 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2154 for (channel=0; channel <= CompositeChannels; channel++)
2155 for (i=0; i < MaximumNumberOfImageMoments; i++)
2156 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2161 hash_image=BlurImage(image,0.0,1.0,exception);
2162 if (hash_image == (
Image *) NULL)
2168 hash_image->depth=8;
2169 status=TransformImageColorspace(hash_image,HCLpColorspace);
2170 if (status == MagickFalse)
2176 moments=GetImageChannelMoments(hash_image,exception);
2177 hash_image=DestroyImage(hash_image);
2184 for (channel=0; channel <= CompositeChannels; channel++)
2185 for (i=0; i < MaximumNumberOfImageMoments; i++)
2186 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2188 return(perceptual_hash);
2224 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2227 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2230 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2231 const ChannelType channel,
double *minima,
double *maxima,
2240 assert(image != (
Image *) NULL);
2241 assert(image->signature == MagickCoreSignature);
2242 if (IsEventLogging() != MagickFalse)
2243 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2244 *maxima=(-MagickMaximumValue);
2245 *minima=MagickMaximumValue;
2246 GetMagickPixelPacket(image,&pixel);
2247 for (y=0; y < (ssize_t) image->rows; y++)
2250 *magick_restrict indexes;
2258 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2261 indexes=GetVirtualIndexQueue(image);
2262 for (x=0; x < (ssize_t) image->columns; x++)
2264 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2265 if ((channel & RedChannel) != 0)
2267 if (pixel.red < *minima)
2268 *minima=(double) pixel.red;
2269 if (pixel.red > *maxima)
2270 *maxima=(double) pixel.red;
2272 if ((channel & GreenChannel) != 0)
2274 if (pixel.green < *minima)
2275 *minima=(double) pixel.green;
2276 if (pixel.green > *maxima)
2277 *maxima=(double) pixel.green;
2279 if ((channel & BlueChannel) != 0)
2281 if (pixel.blue < *minima)
2282 *minima=(double) pixel.blue;
2283 if (pixel.blue > *maxima)
2284 *maxima=(double) pixel.blue;
2286 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2288 if ((QuantumRange-pixel.opacity) < *minima)
2289 *minima=(
double) (QuantumRange-pixel.opacity);
2290 if ((QuantumRange-pixel.opacity) > *maxima)
2291 *maxima=(
double) (QuantumRange-pixel.opacity);
2293 if (((channel & IndexChannel) != 0) &&
2294 (image->colorspace == CMYKColorspace))
2296 if ((
double) pixel.index < *minima)
2297 *minima=(
double) pixel.index;
2298 if ((
double) pixel.index > *maxima)
2299 *maxima=(
double) pixel.index;
2304 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2344 *channel_statistics;
2368 assert(image != (
Image *) NULL);
2369 assert(image->signature == MagickCoreSignature);
2370 if (IsEventLogging() != MagickFalse)
2371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2372 length=CompositeChannels+1UL;
2374 sizeof(*channel_statistics));
2376 sizeof(*histogram));
2384 channel_statistics);
2385 return(channel_statistics);
2387 (void) memset(channel_statistics,0,length*
2388 sizeof(*channel_statistics));
2389 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2391 channel_statistics[i].depth=1;
2392 channel_statistics[i].maxima=(-MagickMaximumValue);
2393 channel_statistics[i].minima=MagickMaximumValue;
2395 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2396 (void) memset(&number_bins,0,
sizeof(number_bins));
2397 for (y=0; y < (ssize_t) image->rows; y++)
2400 *magick_restrict indexes;
2411 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2414 indexes=GetVirtualIndexQueue(image);
2415 for (x=0; x < (ssize_t) image->columns; )
2417 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2419 depth=channel_statistics[RedChannel].depth;
2420 range=GetQuantumRange(depth);
2421 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2423 channel_statistics[RedChannel].depth++;
2427 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2429 depth=channel_statistics[GreenChannel].depth;
2430 range=GetQuantumRange(depth);
2431 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2433 channel_statistics[GreenChannel].depth++;
2437 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2439 depth=channel_statistics[BlueChannel].depth;
2440 range=GetQuantumRange(depth);
2441 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2443 channel_statistics[BlueChannel].depth++;
2447 if (image->matte != MagickFalse)
2449 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2451 depth=channel_statistics[OpacityChannel].depth;
2452 range=GetQuantumRange(depth);
2453 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2455 channel_statistics[OpacityChannel].depth++;
2460 if (image->colorspace == CMYKColorspace)
2462 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2464 depth=channel_statistics[BlackChannel].depth;
2465 range=GetQuantumRange(depth);
2466 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2468 channel_statistics[BlackChannel].depth++;
2473 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2474 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2475 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2476 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2477 channel_statistics[RedChannel].sum+=GetPixelRed(p);
2478 channel_statistics[RedChannel].sum_squared+=(double) GetPixelRed(p)*
2480 channel_statistics[RedChannel].sum_cubed+=(double)
2481 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2482 channel_statistics[RedChannel].sum_fourth_power+=(double)
2483 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2484 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2485 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2486 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2487 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2488 channel_statistics[GreenChannel].sum+=GetPixelGreen(p);
2489 channel_statistics[GreenChannel].sum_squared+=(double) GetPixelGreen(p)*
2491 channel_statistics[GreenChannel].sum_cubed+=(double) GetPixelGreen(p)*
2492 GetPixelGreen(p)*GetPixelGreen(p);
2493 channel_statistics[GreenChannel].sum_fourth_power+=(double)
2494 GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p);
2495 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2496 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2497 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2498 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2499 channel_statistics[BlueChannel].sum+=GetPixelBlue(p);
2500 channel_statistics[BlueChannel].sum_squared+=(double) GetPixelBlue(p)*
2502 channel_statistics[BlueChannel].sum_cubed+=(double) GetPixelBlue(p)*
2503 GetPixelBlue(p)*GetPixelBlue(p);
2504 channel_statistics[BlueChannel].sum_fourth_power+=(double)
2505 GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p);
2506 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2507 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2508 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2509 if (image->matte != MagickFalse)
2511 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2512 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2513 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2514 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2515 channel_statistics[OpacityChannel].sum+=GetPixelAlpha(p);
2516 channel_statistics[OpacityChannel].sum_squared+=(double)
2517 GetPixelAlpha(p)*GetPixelAlpha(p);
2518 channel_statistics[OpacityChannel].sum_cubed+=(double)
2519 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2520 channel_statistics[OpacityChannel].sum_fourth_power+=(double)
2521 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2522 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2524 if (image->colorspace == CMYKColorspace)
2526 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2527 channel_statistics[BlackChannel].minima=(double)
2528 GetPixelIndex(indexes+x);
2529 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2530 channel_statistics[BlackChannel].maxima=(
double)
2531 GetPixelIndex(indexes+x);
2532 channel_statistics[BlackChannel].sum+=GetPixelIndex(indexes+x);
2533 channel_statistics[BlackChannel].sum_squared+=(double)
2534 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2535 channel_statistics[BlackChannel].sum_cubed+=(double)
2536 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2537 GetPixelIndex(indexes+x);
2538 channel_statistics[BlackChannel].sum_fourth_power+=(double)
2539 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2540 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2541 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2547 for (i=0; i < (ssize_t) CompositeChannels; i++)
2557 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2558 mean=channel_statistics[i].sum*area;
2559 channel_statistics[i].sum=mean;
2560 channel_statistics[i].sum_squared*=area;
2561 channel_statistics[i].sum_cubed*=area;
2562 channel_statistics[i].sum_fourth_power*=area;
2563 channel_statistics[i].mean=mean;
2564 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2565 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2566 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2567 ((double) image->columns*image->rows);
2568 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2569 channel_statistics[i].standard_deviation=standard_deviation;
2571 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2573 if (histogram[i].red > 0.0)
2575 if (histogram[i].green > 0.0)
2576 number_bins.green++;
2577 if (histogram[i].blue > 0.0)
2579 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2580 number_bins.opacity++;
2581 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2582 number_bins.index++;
2584 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2585 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2590 histogram[i].red*=area;
2591 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2592 MagickLog10(histogram[i].red)*
2593 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2594 histogram[i].green*=area;
2595 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2596 MagickLog10(histogram[i].green)*
2597 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2598 histogram[i].blue*=area;
2599 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2600 MagickLog10(histogram[i].blue)*
2601 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2602 if (image->matte != MagickFalse)
2604 histogram[i].opacity*=area;
2605 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2606 MagickLog10(histogram[i].opacity)*
2607 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2609 if (image->colorspace == CMYKColorspace)
2611 histogram[i].index*=area;
2612 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2613 MagickLog10(histogram[i].index)*
2614 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2620 for (i=0; i < (ssize_t) CompositeChannels; i++)
2622 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2623 channel_statistics[CompositeChannels].depth,(double)
2624 channel_statistics[i].depth);
2625 channel_statistics[CompositeChannels].minima=MagickMin(
2626 channel_statistics[CompositeChannels].minima,
2627 channel_statistics[i].minima);
2628 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2629 channel_statistics[CompositeChannels].maxima,
2630 channel_statistics[i].maxima);
2631 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2632 channel_statistics[CompositeChannels].sum_squared+=
2633 channel_statistics[i].sum_squared;
2634 channel_statistics[CompositeChannels].sum_cubed+=
2635 channel_statistics[i].sum_cubed;
2636 channel_statistics[CompositeChannels].sum_fourth_power+=
2637 channel_statistics[i].sum_fourth_power;
2638 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2639 channel_statistics[CompositeChannels].variance+=
2640 channel_statistics[i].variance-channel_statistics[i].mean*
2641 channel_statistics[i].mean;
2642 standard_deviation=sqrt(channel_statistics[i].variance-
2643 (channel_statistics[i].mean*channel_statistics[i].mean));
2644 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2645 ((double) image->columns*image->rows);
2646 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2647 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2648 channel_statistics[CompositeChannels].entropy+=
2649 channel_statistics[i].entropy;
2652 if (image->matte != MagickFalse)
2654 if (image->colorspace == CMYKColorspace)
2656 channel_statistics[CompositeChannels].sum/=channels;
2657 channel_statistics[CompositeChannels].sum_squared/=channels;
2658 channel_statistics[CompositeChannels].sum_cubed/=channels;
2659 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2660 channel_statistics[CompositeChannels].mean/=channels;
2661 channel_statistics[CompositeChannels].kurtosis/=channels;
2662 channel_statistics[CompositeChannels].skewness/=channels;
2663 channel_statistics[CompositeChannels].entropy/=channels;
2664 i=CompositeChannels;
2665 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2666 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2667 channel_statistics[i].mean=channel_statistics[i].sum;
2668 standard_deviation=sqrt(channel_statistics[i].variance-
2669 (channel_statistics[i].mean*channel_statistics[i].mean));
2670 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2671 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2672 standard_deviation*standard_deviation);
2673 channel_statistics[i].standard_deviation=standard_deviation;
2674 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2679 standard_deviation=PerceptibleReciprocal(
2680 channel_statistics[i].standard_deviation);
2681 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2682 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2683 channel_statistics[i].mean*channel_statistics[i].mean*
2684 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2685 standard_deviation);
2686 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2687 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2688 channel_statistics[i].mean*channel_statistics[i].mean*
2689 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2690 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2691 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2692 standard_deviation*standard_deviation)-3.0;
2694 channel_statistics[CompositeChannels].mean=0.0;
2695 channel_statistics[CompositeChannels].standard_deviation=0.0;
2696 for (i=0; i < (ssize_t) CompositeChannels; i++)
2698 channel_statistics[CompositeChannels].mean+=
2699 channel_statistics[i].mean;
2700 channel_statistics[CompositeChannels].standard_deviation+=
2701 channel_statistics[i].standard_deviation;
2703 channel_statistics[CompositeChannels].mean/=(double) channels;
2704 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2706 if (y < (ssize_t) image->rows)
2708 channel_statistics);
2709 return(channel_statistics);
2750 MagickExport
Image *PolynomialImage(
const Image *images,
2751 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2756 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2758 return(polynomial_image);
2761 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2762 const ChannelType channel,
const size_t number_terms,
const double *terms,
2765 #define PolynomialImageTag "Polynomial/Image"
2780 **magick_restrict polynomial_pixels,
2786 assert(images != (
Image *) NULL);
2787 assert(images->signature == MagickCoreSignature);
2788 if (IsEventLogging() != MagickFalse)
2789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2791 assert(exception->signature == MagickCoreSignature);
2792 image=AcquireImageCanvas(images,exception);
2793 if (image == (
Image *) NULL)
2794 return((
Image *) NULL);
2795 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2797 InheritException(exception,&image->exception);
2798 image=DestroyImage(image);
2799 return((
Image *) NULL);
2801 polynomial_pixels=AcquirePixelTLS(images);
2804 image=DestroyImage(image);
2805 (void) ThrowMagickException(exception,GetMagickModule(),
2806 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2807 return((
Image *) NULL);
2814 GetMagickPixelPacket(images,&zero);
2815 polynomial_view=AcquireAuthenticCacheView(image,exception);
2816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2817 #pragma omp parallel for schedule(static) shared(progress,status) \
2818 magick_number_threads(image,image,image->rows,1)
2820 for (y=0; y < (ssize_t) image->rows; y++)
2829 id = GetOpenMPThreadId();
2832 *magick_restrict polynomial_indexes;
2847 if (status == MagickFalse)
2849 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2856 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2857 polynomial_pixel=polynomial_pixels[id];
2858 for (x=0; x < (ssize_t) image->columns; x++)
2859 polynomial_pixel[x]=zero;
2861 number_images=GetImageListLength(images);
2862 for (i=0; i < (ssize_t) number_images; i++)
2870 if (i >= (ssize_t) number_terms)
2872 image_view=AcquireVirtualCacheView(next,exception);
2873 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2876 image_view=DestroyCacheView(image_view);
2879 indexes=GetCacheViewVirtualIndexQueue(image_view);
2880 for (x=0; x < (ssize_t) image->columns; x++)
2886 coefficient=terms[i << 1];
2887 degree=terms[(i << 1)+1];
2888 if ((channel & RedChannel) != 0)
2889 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*p->red,degree);
2890 if ((channel & GreenChannel) != 0)
2891 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*p->green,
2893 if ((channel & BlueChannel) != 0)
2894 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*p->blue,
2896 if ((channel & OpacityChannel) != 0)
2897 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2898 (QuantumRange-p->opacity),degree);
2899 if (((channel & IndexChannel) != 0) &&
2900 (image->colorspace == CMYKColorspace))
2901 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*indexes[x],
2905 image_view=DestroyCacheView(image_view);
2906 next=GetNextImageInList(next);
2908 for (x=0; x < (ssize_t) image->columns; x++)
2910 SetPixelRed(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].red));
2911 SetPixelGreen(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].green));
2912 SetPixelBlue(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].blue));
2913 if (image->matte == MagickFalse)
2914 SetPixelOpacity(q,ClampToQuantum(QuantumRange-QuantumRange*
2915 polynomial_pixel[x].opacity));
2917 SetPixelAlpha(q,ClampToQuantum(QuantumRange-QuantumRange*
2918 polynomial_pixel[x].opacity));
2919 if (image->colorspace == CMYKColorspace)
2920 SetPixelIndex(polynomial_indexes+x,ClampToQuantum(QuantumRange*
2921 polynomial_pixel[x].index));
2924 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2926 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2931 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2933 if (proceed == MagickFalse)
2937 polynomial_view=DestroyCacheView(polynomial_view);
2938 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2939 if (status == MagickFalse)
2940 image=DestroyImage(image);
2982 #define ListChannels 5
3009 lists[ListChannels];
3019 for (i=0; i < ListChannels; i++)
3020 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3021 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3022 pixel_list->lists[i].nodes);
3023 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3032 assert(pixel_list != (
PixelList **) NULL);
3033 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3034 if (pixel_list[i] != (
PixelList *) NULL)
3035 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3036 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3040 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3048 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3051 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3052 pixel_list->length=width*height;
3053 for (i=0; i < ListChannels; i++)
3055 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3056 sizeof(*pixel_list->lists[i].nodes));
3057 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3058 return(DestroyPixelList(pixel_list));
3059 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3060 sizeof(*pixel_list->lists[i].nodes));
3062 pixel_list->signature=MagickCoreSignature;
3066 static PixelList **AcquirePixelListTLS(
const size_t width,
3067 const size_t height)
3078 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3079 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3080 sizeof(*pixel_list));
3083 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3084 for (i=0; i < (ssize_t) number_threads; i++)
3086 pixel_list[i]=AcquirePixelList(width,height);
3087 if (pixel_list[i] == (
PixelList *) NULL)
3088 return(DestroyPixelListTLS(pixel_list));
3093 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3109 list=pixel_list->lists+channel;
3110 list->nodes[color].signature=pixel_list->signature;
3111 list->nodes[color].count=1;
3116 for (level=list->level; level >= 0; level--)
3118 while (list->nodes[search].next[level] < color)
3119 search=list->nodes[search].next[level];
3120 update[level]=search;
3125 for (level=0; ; level++)
3127 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3128 if ((pixel_list->seed & 0x300) != 0x300)
3133 if (level > (list->level+2))
3134 level=list->level+2;
3138 while (level > list->level)
3141 update[list->level]=65536UL;
3148 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3149 list->nodes[update[level]].next[level]=color;
3150 }
while (level-- > 0);
3169 channels[ListChannels];
3174 for (channel=0; channel < 5; channel++)
3176 list=pixel_list->lists+channel;
3179 maximum=list->nodes[color].next[0];
3182 color=list->nodes[color].next[0];
3183 if (color > maximum)
3185 count+=list->nodes[color].count;
3186 }
while (count < (ssize_t) pixel_list->length);
3187 channels[channel]=(
unsigned short) maximum;
3189 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3190 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3191 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3192 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3193 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3214 channels[ListChannels];
3219 for (channel=0; channel < 5; channel++)
3221 list=pixel_list->lists+channel;
3227 color=list->nodes[color].next[0];
3228 sum+=(MagickRealType) list->nodes[color].count*color;
3229 count+=list->nodes[color].count;
3230 }
while (count < (ssize_t) pixel_list->length);
3231 sum/=pixel_list->length;
3232 channels[channel]=(
unsigned short) sum;
3234 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3235 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3236 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3237 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3238 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3256 channels[ListChannels];
3261 for (channel=0; channel < 5; channel++)
3263 list=pixel_list->lists+channel;
3268 color=list->nodes[color].next[0];
3269 count+=list->nodes[color].count;
3270 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3271 channels[channel]=(
unsigned short) color;
3273 GetMagickPixelPacket((
const Image *) NULL,pixel);
3274 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3275 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3276 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3277 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3278 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3297 channels[ListChannels];
3302 for (channel=0; channel < 5; channel++)
3304 list=pixel_list->lists+channel;
3307 minimum=list->nodes[color].next[0];
3310 color=list->nodes[color].next[0];
3311 if (color < minimum)
3313 count+=list->nodes[color].count;
3314 }
while (count < (ssize_t) pixel_list->length);
3315 channels[channel]=(
unsigned short) minimum;
3317 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3318 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3319 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3320 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3321 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3346 for (channel=0; channel < 5; channel++)
3348 list=pixel_list->lists+channel;
3351 max_count=list->nodes[mode].count;
3355 color=list->nodes[color].next[0];
3356 if (list->nodes[color].count > max_count)
3359 max_count=list->nodes[mode].count;
3361 count+=list->nodes[color].count;
3362 }
while (count < (ssize_t) pixel_list->length);
3363 channels[channel]=(
unsigned short) mode;
3365 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3366 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3367 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3368 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3369 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3394 for (channel=0; channel < 5; channel++)
3396 list=pixel_list->lists+channel;
3398 next=list->nodes[color].next[0];
3404 next=list->nodes[color].next[0];
3405 count+=list->nodes[color].count;
3406 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3407 if ((previous == 65536UL) && (next != 65536UL))
3410 if ((previous != 65536UL) && (next == 65536UL))
3412 channels[channel]=(
unsigned short) color;
3414 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3415 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3416 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3417 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3418 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3421 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3440 channels[ListChannels];
3445 for (channel=0; channel < 5; channel++)
3447 list=pixel_list->lists+channel;
3453 color=list->nodes[color].next[0];
3454 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3455 count+=list->nodes[color].count;
3456 }
while (count < (ssize_t) pixel_list->length);
3457 sum/=pixel_list->length;
3458 channels[channel]=(
unsigned short) sqrt(sum);
3460 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3461 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3462 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3463 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3464 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3467 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3487 channels[ListChannels];
3492 for (channel=0; channel < 5; channel++)
3494 list=pixel_list->lists+channel;
3504 color=list->nodes[color].next[0];
3505 sum+=(MagickRealType) list->nodes[color].count*color;
3506 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3507 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3508 count+=list->nodes[color].count;
3509 }
while (count < (ssize_t) pixel_list->length);
3510 sum/=pixel_list->length;
3511 sum_squared/=pixel_list->length;
3512 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3514 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3515 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3516 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3517 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3518 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3521 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3522 const IndexPacket *indexes,
PixelList *pixel_list)
3530 index=ScaleQuantumToShort(GetPixelRed(pixel));
3531 signature=pixel_list->lists[0].nodes[index].signature;
3532 if (signature == pixel_list->signature)
3533 pixel_list->lists[0].nodes[index].count++;
3535 AddNodePixelList(pixel_list,0,index);
3536 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3537 signature=pixel_list->lists[1].nodes[index].signature;
3538 if (signature == pixel_list->signature)
3539 pixel_list->lists[1].nodes[index].count++;
3541 AddNodePixelList(pixel_list,1,index);
3542 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3543 signature=pixel_list->lists[2].nodes[index].signature;
3544 if (signature == pixel_list->signature)
3545 pixel_list->lists[2].nodes[index].count++;
3547 AddNodePixelList(pixel_list,2,index);
3548 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3549 signature=pixel_list->lists[3].nodes[index].signature;
3550 if (signature == pixel_list->signature)
3551 pixel_list->lists[3].nodes[index].count++;
3553 AddNodePixelList(pixel_list,3,index);
3554 if (image->colorspace == CMYKColorspace)
3555 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3556 signature=pixel_list->lists[4].nodes[index].signature;
3557 if (signature == pixel_list->signature)
3558 pixel_list->lists[4].nodes[index].count++;
3560 AddNodePixelList(pixel_list,4,index);
3563 static void ResetPixelList(
PixelList *pixel_list)
3580 for (channel=0; channel < 5; channel++)
3582 list=pixel_list->lists+channel;
3583 root=list->nodes+65536UL;
3585 for (level=0; level < 9; level++)
3586 root->next[level]=65536UL;
3588 pixel_list->seed=pixel_list->signature++;
3591 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3592 const size_t width,
const size_t height,
ExceptionInfo *exception)
3597 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3599 return(statistic_image);
3602 MagickExport
Image *StatisticImageChannel(
const Image *image,
3603 const ChannelType channel,
const StatisticType type,
const size_t width,
3606 #define StatisticImageTag "Statistic/Image"
3622 **magick_restrict pixel_list;
3634 assert(image != (
Image *) NULL);
3635 assert(image->signature == MagickCoreSignature);
3636 if (IsEventLogging() != MagickFalse)
3637 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3639 assert(exception->signature == MagickCoreSignature);
3640 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3641 if (statistic_image == (
Image *) NULL)
3642 return((
Image *) NULL);
3643 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3645 InheritException(exception,&statistic_image->exception);
3646 statistic_image=DestroyImage(statistic_image);
3647 return((
Image *) NULL);
3649 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3651 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3653 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3656 statistic_image=DestroyImage(statistic_image);
3657 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3664 image_view=AcquireVirtualCacheView(image,exception);
3665 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3666 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3667 #pragma omp parallel for schedule(static) shared(progress,status) \
3668 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3670 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3673 id = GetOpenMPThreadId();
3676 *magick_restrict indexes;
3682 *magick_restrict statistic_indexes;
3690 if (status == MagickFalse)
3692 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3693 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3694 neighbor_height,exception);
3695 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3701 indexes=GetCacheViewVirtualIndexQueue(image_view);
3702 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3703 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3720 ResetPixelList(pixel_list[
id]);
3721 for (v=0; v < (ssize_t) neighbor_height; v++)
3723 for (u=0; u < (ssize_t) neighbor_width; u++)
3724 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3725 r+=image->columns+neighbor_width;
3726 s+=image->columns+neighbor_width;
3728 GetMagickPixelPacket(image,&pixel);
3729 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3730 neighbor_width*neighbor_height/2,&pixel);
3733 case GradientStatistic:
3739 GetMinimumPixelList(pixel_list[
id],&pixel);
3741 GetMaximumPixelList(pixel_list[
id],&pixel);
3743 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3744 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3745 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3746 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3747 if (image->colorspace == CMYKColorspace)
3748 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3751 case MaximumStatistic:
3753 GetMaximumPixelList(pixel_list[
id],&pixel);
3758 GetMeanPixelList(pixel_list[
id],&pixel);
3761 case MedianStatistic:
3764 GetMedianPixelList(pixel_list[
id],&pixel);
3767 case MinimumStatistic:
3769 GetMinimumPixelList(pixel_list[
id],&pixel);
3774 GetModePixelList(pixel_list[
id],&pixel);
3777 case NonpeakStatistic:
3779 GetNonpeakPixelList(pixel_list[
id],&pixel);
3782 case RootMeanSquareStatistic:
3784 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3787 case StandardDeviationStatistic:
3789 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3793 if ((channel & RedChannel) != 0)
3794 SetPixelRed(q,ClampToQuantum(pixel.red));
3795 if ((channel & GreenChannel) != 0)
3796 SetPixelGreen(q,ClampToQuantum(pixel.green));
3797 if ((channel & BlueChannel) != 0)
3798 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3799 if ((channel & OpacityChannel) != 0)
3800 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3801 if (((channel & IndexChannel) != 0) &&
3802 (image->colorspace == CMYKColorspace))
3803 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3807 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3809 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3814 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3816 if (proceed == MagickFalse)
3820 statistic_view=DestroyCacheView(statistic_view);
3821 image_view=DestroyCacheView(image_view);
3822 pixel_list=DestroyPixelListTLS(pixel_list);
3823 if (status == MagickFalse)
3824 statistic_image=DestroyImage(statistic_image);
3825 return(statistic_image);