43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/animate.h"
46 #include "magick/animate.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/cache-private.h"
51 #include "magick/cache-view.h"
52 #include "magick/client.h"
53 #include "magick/color.h"
54 #include "magick/color-private.h"
55 #include "magick/colorspace.h"
56 #include "magick/colorspace-private.h"
57 #include "magick/composite.h"
58 #include "magick/composite-private.h"
59 #include "magick/compress.h"
60 #include "magick/constitute.h"
61 #include "magick/deprecate.h"
62 #include "magick/display.h"
63 #include "magick/draw.h"
64 #include "magick/enhance.h"
65 #include "magick/exception.h"
66 #include "magick/exception-private.h"
67 #include "magick/gem.h"
68 #include "magick/geometry.h"
69 #include "magick/list.h"
70 #include "magick/image-private.h"
71 #include "magick/magic.h"
72 #include "magick/magick.h"
73 #include "magick/memory_.h"
74 #include "magick/module.h"
75 #include "magick/monitor.h"
76 #include "magick/monitor-private.h"
77 #include "magick/option.h"
78 #include "magick/paint.h"
79 #include "magick/pixel-private.h"
80 #include "magick/profile.h"
81 #include "magick/property.h"
82 #include "magick/quantize.h"
83 #include "magick/random_.h"
84 #include "magick/random-private.h"
85 #include "magick/resource_.h"
86 #include "magick/segment.h"
87 #include "magick/semaphore.h"
88 #include "magick/signature-private.h"
89 #include "magick/statistic.h"
90 #include "magick/statistic-private.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);
2133 hash_image=BlurImage(image,0.0,1.0,exception);
2134 if (hash_image == (
Image *) NULL)
2136 hash_image->depth=8;
2137 status=TransformImageColorspace(hash_image,sRGBColorspace);
2138 if (status == MagickFalse)
2140 moments=GetImageChannelMoments(hash_image,exception);
2141 hash_image=DestroyImage(hash_image);
2145 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2148 for (channel=0; channel <= CompositeChannels; channel++)
2149 for (i=0; i < MaximumNumberOfImageMoments; i++)
2150 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2155 hash_image=BlurImage(image,0.0,1.0,exception);
2156 if (hash_image == (
Image *) NULL)
2162 hash_image->depth=8;
2163 status=TransformImageColorspace(hash_image,HCLpColorspace);
2164 if (status == MagickFalse)
2170 moments=GetImageChannelMoments(hash_image,exception);
2171 hash_image=DestroyImage(hash_image);
2178 for (channel=0; channel <= CompositeChannels; channel++)
2179 for (i=0; i < MaximumNumberOfImageMoments; i++)
2180 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2182 return(perceptual_hash);
2218 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2221 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2224 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2225 const ChannelType channel,
double *minima,
double *maxima,
2234 assert(image != (
Image *) NULL);
2235 assert(image->signature == MagickCoreSignature);
2236 if (IsEventLogging() != MagickFalse)
2237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2238 *maxima=(-MagickMaximumValue);
2239 *minima=MagickMaximumValue;
2240 GetMagickPixelPacket(image,&pixel);
2241 for (y=0; y < (ssize_t) image->rows; y++)
2244 *magick_restrict indexes;
2252 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2255 indexes=GetVirtualIndexQueue(image);
2256 for (x=0; x < (ssize_t) image->columns; x++)
2258 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2259 if ((channel & RedChannel) != 0)
2261 if (pixel.red < *minima)
2262 *minima=(double) pixel.red;
2263 if (pixel.red > *maxima)
2264 *maxima=(double) pixel.red;
2266 if ((channel & GreenChannel) != 0)
2268 if (pixel.green < *minima)
2269 *minima=(double) pixel.green;
2270 if (pixel.green > *maxima)
2271 *maxima=(double) pixel.green;
2273 if ((channel & BlueChannel) != 0)
2275 if (pixel.blue < *minima)
2276 *minima=(double) pixel.blue;
2277 if (pixel.blue > *maxima)
2278 *maxima=(double) pixel.blue;
2280 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2282 if ((QuantumRange-pixel.opacity) < *minima)
2283 *minima=(
double) (QuantumRange-pixel.opacity);
2284 if ((QuantumRange-pixel.opacity) > *maxima)
2285 *maxima=(
double) (QuantumRange-pixel.opacity);
2287 if (((channel & IndexChannel) != 0) &&
2288 (image->colorspace == CMYKColorspace))
2290 if ((
double) pixel.index < *minima)
2291 *minima=(
double) pixel.index;
2292 if ((
double) pixel.index > *maxima)
2293 *maxima=(
double) pixel.index;
2298 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2338 *channel_statistics;
2362 assert(image != (
Image *) NULL);
2363 assert(image->signature == MagickCoreSignature);
2364 if (IsEventLogging() != MagickFalse)
2365 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2366 length=CompositeChannels+1UL;
2368 sizeof(*channel_statistics));
2370 sizeof(*histogram));
2378 channel_statistics);
2379 return(channel_statistics);
2381 (void) memset(channel_statistics,0,length*
2382 sizeof(*channel_statistics));
2383 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2385 channel_statistics[i].depth=1;
2386 channel_statistics[i].maxima=(-MagickMaximumValue);
2387 channel_statistics[i].minima=MagickMaximumValue;
2389 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2390 (void) memset(&number_bins,0,
sizeof(number_bins));
2391 for (y=0; y < (ssize_t) image->rows; y++)
2394 *magick_restrict indexes;
2405 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2408 indexes=GetVirtualIndexQueue(image);
2409 for (x=0; x < (ssize_t) image->columns; )
2411 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2413 depth=channel_statistics[RedChannel].depth;
2414 range=GetQuantumRange(depth);
2415 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2417 channel_statistics[RedChannel].depth++;
2421 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2423 depth=channel_statistics[GreenChannel].depth;
2424 range=GetQuantumRange(depth);
2425 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2427 channel_statistics[GreenChannel].depth++;
2431 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2433 depth=channel_statistics[BlueChannel].depth;
2434 range=GetQuantumRange(depth);
2435 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2437 channel_statistics[BlueChannel].depth++;
2441 if (image->matte != MagickFalse)
2443 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2445 depth=channel_statistics[OpacityChannel].depth;
2446 range=GetQuantumRange(depth);
2447 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2449 channel_statistics[OpacityChannel].depth++;
2454 if (image->colorspace == CMYKColorspace)
2456 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2458 depth=channel_statistics[BlackChannel].depth;
2459 range=GetQuantumRange(depth);
2460 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2462 channel_statistics[BlackChannel].depth++;
2467 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2468 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2469 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2470 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2471 channel_statistics[RedChannel].sum+=GetPixelRed(p);
2472 channel_statistics[RedChannel].sum_squared+=(double) GetPixelRed(p)*
2474 channel_statistics[RedChannel].sum_cubed+=(double)
2475 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2476 channel_statistics[RedChannel].sum_fourth_power+=(double)
2477 GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p)*GetPixelRed(p);
2478 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2479 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2480 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2481 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2482 channel_statistics[GreenChannel].sum+=GetPixelGreen(p);
2483 channel_statistics[GreenChannel].sum_squared+=(double) GetPixelGreen(p)*
2485 channel_statistics[GreenChannel].sum_cubed+=(double) GetPixelGreen(p)*
2486 GetPixelGreen(p)*GetPixelGreen(p);
2487 channel_statistics[GreenChannel].sum_fourth_power+=(double)
2488 GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p)*GetPixelGreen(p);
2489 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2490 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2491 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2492 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2493 channel_statistics[BlueChannel].sum+=GetPixelBlue(p);
2494 channel_statistics[BlueChannel].sum_squared+=(double) GetPixelBlue(p)*
2496 channel_statistics[BlueChannel].sum_cubed+=(double) GetPixelBlue(p)*
2497 GetPixelBlue(p)*GetPixelBlue(p);
2498 channel_statistics[BlueChannel].sum_fourth_power+=(double)
2499 GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p)*GetPixelBlue(p);
2500 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2501 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2502 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2503 if (image->matte != MagickFalse)
2505 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2506 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2507 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2508 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2509 channel_statistics[OpacityChannel].sum+=GetPixelAlpha(p);
2510 channel_statistics[OpacityChannel].sum_squared+=(double)
2511 GetPixelAlpha(p)*GetPixelAlpha(p);
2512 channel_statistics[OpacityChannel].sum_cubed+=(double)
2513 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2514 channel_statistics[OpacityChannel].sum_fourth_power+=(double)
2515 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2516 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2518 if (image->colorspace == CMYKColorspace)
2520 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2521 channel_statistics[BlackChannel].minima=(double)
2522 GetPixelIndex(indexes+x);
2523 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2524 channel_statistics[BlackChannel].maxima=(
double)
2525 GetPixelIndex(indexes+x);
2526 channel_statistics[BlackChannel].sum+=GetPixelIndex(indexes+x);
2527 channel_statistics[BlackChannel].sum_squared+=(double)
2528 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2529 channel_statistics[BlackChannel].sum_cubed+=(double)
2530 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2531 GetPixelIndex(indexes+x);
2532 channel_statistics[BlackChannel].sum_fourth_power+=(double)
2533 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x)*
2534 GetPixelIndex(indexes+x)*GetPixelIndex(indexes+x);
2535 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2541 for (i=0; i < (ssize_t) CompositeChannels; i++)
2551 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2552 mean=channel_statistics[i].sum*area;
2553 channel_statistics[i].sum=mean;
2554 channel_statistics[i].sum_squared*=area;
2555 channel_statistics[i].sum_cubed*=area;
2556 channel_statistics[i].sum_fourth_power*=area;
2557 channel_statistics[i].mean=mean;
2558 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2559 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2560 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2561 ((double) image->columns*image->rows);
2562 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2563 channel_statistics[i].standard_deviation=standard_deviation;
2565 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2567 if (histogram[i].red > 0.0)
2569 if (histogram[i].green > 0.0)
2570 number_bins.green++;
2571 if (histogram[i].blue > 0.0)
2573 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2574 number_bins.opacity++;
2575 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2576 number_bins.index++;
2578 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2579 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2584 histogram[i].red*=area;
2585 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2586 MagickLog10(histogram[i].red)*
2587 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2588 histogram[i].green*=area;
2589 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2590 MagickLog10(histogram[i].green)*
2591 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2592 histogram[i].blue*=area;
2593 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2594 MagickLog10(histogram[i].blue)*
2595 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2596 if (image->matte != MagickFalse)
2598 histogram[i].opacity*=area;
2599 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2600 MagickLog10(histogram[i].opacity)*
2601 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2603 if (image->colorspace == CMYKColorspace)
2605 histogram[i].index*=area;
2606 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2607 MagickLog10(histogram[i].index)*
2608 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2614 for (i=0; i < (ssize_t) CompositeChannels; i++)
2616 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2617 channel_statistics[CompositeChannels].depth,(double)
2618 channel_statistics[i].depth);
2619 channel_statistics[CompositeChannels].minima=MagickMin(
2620 channel_statistics[CompositeChannels].minima,
2621 channel_statistics[i].minima);
2622 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2623 channel_statistics[CompositeChannels].maxima,
2624 channel_statistics[i].maxima);
2625 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2626 channel_statistics[CompositeChannels].sum_squared+=
2627 channel_statistics[i].sum_squared;
2628 channel_statistics[CompositeChannels].sum_cubed+=
2629 channel_statistics[i].sum_cubed;
2630 channel_statistics[CompositeChannels].sum_fourth_power+=
2631 channel_statistics[i].sum_fourth_power;
2632 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2633 channel_statistics[CompositeChannels].variance+=
2634 channel_statistics[i].variance-channel_statistics[i].mean*
2635 channel_statistics[i].mean;
2636 standard_deviation=sqrt(channel_statistics[i].variance-
2637 (channel_statistics[i].mean*channel_statistics[i].mean));
2638 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2639 ((double) image->columns*image->rows);
2640 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2641 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2642 channel_statistics[CompositeChannels].entropy+=
2643 channel_statistics[i].entropy;
2646 if (image->matte != MagickFalse)
2648 if (image->colorspace == CMYKColorspace)
2650 channel_statistics[CompositeChannels].sum/=channels;
2651 channel_statistics[CompositeChannels].sum_squared/=channels;
2652 channel_statistics[CompositeChannels].sum_cubed/=channels;
2653 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2654 channel_statistics[CompositeChannels].mean/=channels;
2655 channel_statistics[CompositeChannels].kurtosis/=channels;
2656 channel_statistics[CompositeChannels].skewness/=channels;
2657 channel_statistics[CompositeChannels].entropy/=channels;
2658 i=CompositeChannels;
2659 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2660 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2661 channel_statistics[i].mean=channel_statistics[i].sum;
2662 standard_deviation=sqrt(channel_statistics[i].variance-
2663 (channel_statistics[i].mean*channel_statistics[i].mean));
2664 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2665 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2666 standard_deviation*standard_deviation);
2667 channel_statistics[i].standard_deviation=standard_deviation;
2668 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2673 standard_deviation=PerceptibleReciprocal(
2674 channel_statistics[i].standard_deviation);
2675 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2676 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2677 channel_statistics[i].mean*channel_statistics[i].mean*
2678 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2679 standard_deviation);
2680 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2681 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2682 channel_statistics[i].mean*channel_statistics[i].mean*
2683 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2684 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2685 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2686 standard_deviation*standard_deviation)-3.0;
2688 channel_statistics[CompositeChannels].mean=0.0;
2689 channel_statistics[CompositeChannels].standard_deviation=0.0;
2690 for (i=0; i < (ssize_t) CompositeChannels; i++)
2692 channel_statistics[CompositeChannels].mean+=
2693 channel_statistics[i].mean;
2694 channel_statistics[CompositeChannels].standard_deviation+=
2695 channel_statistics[i].standard_deviation;
2697 channel_statistics[CompositeChannels].mean/=(double) channels;
2698 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2700 if (y < (ssize_t) image->rows)
2702 channel_statistics);
2703 return(channel_statistics);
2744 MagickExport
Image *PolynomialImage(
const Image *images,
2745 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2750 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2752 return(polynomial_image);
2755 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2756 const ChannelType channel,
const size_t number_terms,
const double *terms,
2759 #define PolynomialImageTag "Polynomial/Image"
2774 **magick_restrict polynomial_pixels,
2780 assert(images != (
Image *) NULL);
2781 assert(images->signature == MagickCoreSignature);
2782 if (IsEventLogging() != MagickFalse)
2783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2785 assert(exception->signature == MagickCoreSignature);
2786 image=AcquireImageCanvas(images,exception);
2787 if (image == (
Image *) NULL)
2788 return((
Image *) NULL);
2789 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2791 InheritException(exception,&image->exception);
2792 image=DestroyImage(image);
2793 return((
Image *) NULL);
2795 polynomial_pixels=AcquirePixelTLS(images);
2798 image=DestroyImage(image);
2799 (void) ThrowMagickException(exception,GetMagickModule(),
2800 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2801 return((
Image *) NULL);
2808 GetMagickPixelPacket(images,&zero);
2809 polynomial_view=AcquireAuthenticCacheView(image,exception);
2810 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2811 #pragma omp parallel for schedule(static) shared(progress,status) \
2812 magick_number_threads(image,image,image->rows,1)
2814 for (y=0; y < (ssize_t) image->rows; y++)
2823 id = GetOpenMPThreadId();
2826 *magick_restrict polynomial_indexes;
2841 if (status == MagickFalse)
2843 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2850 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2851 polynomial_pixel=polynomial_pixels[id];
2852 for (x=0; x < (ssize_t) image->columns; x++)
2853 polynomial_pixel[x]=zero;
2855 number_images=GetImageListLength(images);
2856 for (i=0; i < (ssize_t) number_images; i++)
2864 if (i >= (ssize_t) number_terms)
2866 image_view=AcquireVirtualCacheView(next,exception);
2867 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2870 image_view=DestroyCacheView(image_view);
2873 indexes=GetCacheViewVirtualIndexQueue(image_view);
2874 for (x=0; x < (ssize_t) image->columns; x++)
2880 coefficient=terms[i << 1];
2881 degree=terms[(i << 1)+1];
2882 if ((channel & RedChannel) != 0)
2883 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*p->red,degree);
2884 if ((channel & GreenChannel) != 0)
2885 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*p->green,
2887 if ((channel & BlueChannel) != 0)
2888 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*p->blue,
2890 if ((channel & OpacityChannel) != 0)
2891 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2892 (QuantumRange-p->opacity),degree);
2893 if (((channel & IndexChannel) != 0) &&
2894 (image->colorspace == CMYKColorspace))
2895 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*indexes[x],
2899 image_view=DestroyCacheView(image_view);
2900 next=GetNextImageInList(next);
2902 for (x=0; x < (ssize_t) image->columns; x++)
2904 SetPixelRed(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].red));
2905 SetPixelGreen(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].green));
2906 SetPixelBlue(q,ClampToQuantum(QuantumRange*polynomial_pixel[x].blue));
2907 if (image->matte == MagickFalse)
2908 SetPixelOpacity(q,ClampToQuantum(QuantumRange-QuantumRange*
2909 polynomial_pixel[x].opacity));
2911 SetPixelAlpha(q,ClampToQuantum(QuantumRange-QuantumRange*
2912 polynomial_pixel[x].opacity));
2913 if (image->colorspace == CMYKColorspace)
2914 SetPixelIndex(polynomial_indexes+x,ClampToQuantum(QuantumRange*
2915 polynomial_pixel[x].index));
2918 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2920 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2925 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2927 if (proceed == MagickFalse)
2931 polynomial_view=DestroyCacheView(polynomial_view);
2932 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2933 if (status == MagickFalse)
2934 image=DestroyImage(image);
2976 #define ListChannels 5
3003 lists[ListChannels];
3013 for (i=0; i < ListChannels; i++)
3014 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3015 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3016 pixel_list->lists[i].nodes);
3017 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3026 assert(pixel_list != (
PixelList **) NULL);
3027 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3028 if (pixel_list[i] != (
PixelList *) NULL)
3029 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3030 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3034 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3042 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3045 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3046 pixel_list->length=width*height;
3047 for (i=0; i < ListChannels; i++)
3049 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3050 sizeof(*pixel_list->lists[i].nodes));
3051 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3052 return(DestroyPixelList(pixel_list));
3053 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3054 sizeof(*pixel_list->lists[i].nodes));
3056 pixel_list->signature=MagickCoreSignature;
3060 static PixelList **AcquirePixelListTLS(
const size_t width,
3061 const size_t height)
3072 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3073 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3074 sizeof(*pixel_list));
3077 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3078 for (i=0; i < (ssize_t) number_threads; i++)
3080 pixel_list[i]=AcquirePixelList(width,height);
3081 if (pixel_list[i] == (
PixelList *) NULL)
3082 return(DestroyPixelListTLS(pixel_list));
3087 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3103 list=pixel_list->lists+channel;
3104 list->nodes[color].signature=pixel_list->signature;
3105 list->nodes[color].count=1;
3110 for (level=list->level; level >= 0; level--)
3112 while (list->nodes[search].next[level] < color)
3113 search=list->nodes[search].next[level];
3114 update[level]=search;
3119 for (level=0; ; level++)
3121 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3122 if ((pixel_list->seed & 0x300) != 0x300)
3127 if (level > (list->level+2))
3128 level=list->level+2;
3132 while (level > list->level)
3135 update[list->level]=65536UL;
3142 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3143 list->nodes[update[level]].next[level]=color;
3144 }
while (level-- > 0);
3163 channels[ListChannels];
3168 for (channel=0; channel < 5; channel++)
3170 list=pixel_list->lists+channel;
3173 maximum=list->nodes[color].next[0];
3176 color=list->nodes[color].next[0];
3177 if (color > maximum)
3179 count+=list->nodes[color].count;
3180 }
while (count < (ssize_t) pixel_list->length);
3181 channels[channel]=(
unsigned short) maximum;
3183 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3184 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3185 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3186 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3187 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3208 channels[ListChannels];
3213 for (channel=0; channel < 5; channel++)
3215 list=pixel_list->lists+channel;
3221 color=list->nodes[color].next[0];
3222 sum+=(MagickRealType) list->nodes[color].count*color;
3223 count+=list->nodes[color].count;
3224 }
while (count < (ssize_t) pixel_list->length);
3225 sum/=pixel_list->length;
3226 channels[channel]=(
unsigned short) sum;
3228 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3229 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3230 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3231 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3232 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3250 channels[ListChannels];
3255 for (channel=0; channel < 5; channel++)
3257 list=pixel_list->lists+channel;
3262 color=list->nodes[color].next[0];
3263 count+=list->nodes[color].count;
3264 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3265 channels[channel]=(
unsigned short) color;
3267 GetMagickPixelPacket((
const Image *) NULL,pixel);
3268 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3269 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3270 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3271 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3272 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3291 channels[ListChannels];
3296 for (channel=0; channel < 5; channel++)
3298 list=pixel_list->lists+channel;
3301 minimum=list->nodes[color].next[0];
3304 color=list->nodes[color].next[0];
3305 if (color < minimum)
3307 count+=list->nodes[color].count;
3308 }
while (count < (ssize_t) pixel_list->length);
3309 channels[channel]=(
unsigned short) minimum;
3311 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3312 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3313 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3314 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3315 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3340 for (channel=0; channel < 5; channel++)
3342 list=pixel_list->lists+channel;
3345 max_count=list->nodes[mode].count;
3349 color=list->nodes[color].next[0];
3350 if (list->nodes[color].count > max_count)
3353 max_count=list->nodes[mode].count;
3355 count+=list->nodes[color].count;
3356 }
while (count < (ssize_t) pixel_list->length);
3357 channels[channel]=(
unsigned short) mode;
3359 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3360 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3361 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3362 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3363 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3388 for (channel=0; channel < 5; channel++)
3390 list=pixel_list->lists+channel;
3392 next=list->nodes[color].next[0];
3398 next=list->nodes[color].next[0];
3399 count+=list->nodes[color].count;
3400 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3401 if ((previous == 65536UL) && (next != 65536UL))
3404 if ((previous != 65536UL) && (next == 65536UL))
3406 channels[channel]=(
unsigned short) color;
3408 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3409 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3410 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3411 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3412 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3415 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3434 channels[ListChannels];
3439 for (channel=0; channel < 5; channel++)
3441 list=pixel_list->lists+channel;
3447 color=list->nodes[color].next[0];
3448 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3449 count+=list->nodes[color].count;
3450 }
while (count < (ssize_t) pixel_list->length);
3451 sum/=pixel_list->length;
3452 channels[channel]=(
unsigned short) sqrt(sum);
3454 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3455 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3456 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3457 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3458 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3461 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3481 channels[ListChannels];
3486 for (channel=0; channel < 5; channel++)
3488 list=pixel_list->lists+channel;
3498 color=list->nodes[color].next[0];
3499 sum+=(MagickRealType) list->nodes[color].count*color;
3500 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3501 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3502 count+=list->nodes[color].count;
3503 }
while (count < (ssize_t) pixel_list->length);
3504 sum/=pixel_list->length;
3505 sum_squared/=pixel_list->length;
3506 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3508 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3509 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3510 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3511 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3512 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3515 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3516 const IndexPacket *indexes,
PixelList *pixel_list)
3524 index=ScaleQuantumToShort(GetPixelRed(pixel));
3525 signature=pixel_list->lists[0].nodes[index].signature;
3526 if (signature == pixel_list->signature)
3527 pixel_list->lists[0].nodes[index].count++;
3529 AddNodePixelList(pixel_list,0,index);
3530 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3531 signature=pixel_list->lists[1].nodes[index].signature;
3532 if (signature == pixel_list->signature)
3533 pixel_list->lists[1].nodes[index].count++;
3535 AddNodePixelList(pixel_list,1,index);
3536 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3537 signature=pixel_list->lists[2].nodes[index].signature;
3538 if (signature == pixel_list->signature)
3539 pixel_list->lists[2].nodes[index].count++;
3541 AddNodePixelList(pixel_list,2,index);
3542 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3543 signature=pixel_list->lists[3].nodes[index].signature;
3544 if (signature == pixel_list->signature)
3545 pixel_list->lists[3].nodes[index].count++;
3547 AddNodePixelList(pixel_list,3,index);
3548 if (image->colorspace == CMYKColorspace)
3549 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3550 signature=pixel_list->lists[4].nodes[index].signature;
3551 if (signature == pixel_list->signature)
3552 pixel_list->lists[4].nodes[index].count++;
3554 AddNodePixelList(pixel_list,4,index);
3557 static void ResetPixelList(
PixelList *pixel_list)
3574 for (channel=0; channel < 5; channel++)
3576 list=pixel_list->lists+channel;
3577 root=list->nodes+65536UL;
3579 for (level=0; level < 9; level++)
3580 root->next[level]=65536UL;
3582 pixel_list->seed=pixel_list->signature++;
3585 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3586 const size_t width,
const size_t height,
ExceptionInfo *exception)
3591 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3593 return(statistic_image);
3596 MagickExport
Image *StatisticImageChannel(
const Image *image,
3597 const ChannelType channel,
const StatisticType type,
const size_t width,
3600 #define StatisticImageTag "Statistic/Image"
3616 **magick_restrict pixel_list;
3628 assert(image != (
Image *) NULL);
3629 assert(image->signature == MagickCoreSignature);
3630 if (IsEventLogging() != MagickFalse)
3631 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3633 assert(exception->signature == MagickCoreSignature);
3634 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3635 if (statistic_image == (
Image *) NULL)
3636 return((
Image *) NULL);
3637 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3639 InheritException(exception,&statistic_image->exception);
3640 statistic_image=DestroyImage(statistic_image);
3641 return((
Image *) NULL);
3643 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3645 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3647 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3650 statistic_image=DestroyImage(statistic_image);
3651 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3658 image_view=AcquireVirtualCacheView(image,exception);
3659 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3660 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3661 #pragma omp parallel for schedule(static) shared(progress,status) \
3662 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3664 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3667 id = GetOpenMPThreadId();
3670 *magick_restrict indexes;
3676 *magick_restrict statistic_indexes;
3684 if (status == MagickFalse)
3686 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3687 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3688 neighbor_height,exception);
3689 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3695 indexes=GetCacheViewVirtualIndexQueue(image_view);
3696 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3697 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3714 ResetPixelList(pixel_list[
id]);
3715 for (v=0; v < (ssize_t) neighbor_height; v++)
3717 for (u=0; u < (ssize_t) neighbor_width; u++)
3718 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3719 r+=image->columns+neighbor_width;
3720 s+=image->columns+neighbor_width;
3722 GetMagickPixelPacket(image,&pixel);
3723 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3724 neighbor_width*neighbor_height/2,&pixel);
3727 case GradientStatistic:
3733 GetMinimumPixelList(pixel_list[
id],&pixel);
3735 GetMaximumPixelList(pixel_list[
id],&pixel);
3737 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3738 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3739 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3740 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3741 if (image->colorspace == CMYKColorspace)
3742 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3745 case MaximumStatistic:
3747 GetMaximumPixelList(pixel_list[
id],&pixel);
3752 GetMeanPixelList(pixel_list[
id],&pixel);
3755 case MedianStatistic:
3758 GetMedianPixelList(pixel_list[
id],&pixel);
3761 case MinimumStatistic:
3763 GetMinimumPixelList(pixel_list[
id],&pixel);
3768 GetModePixelList(pixel_list[
id],&pixel);
3771 case NonpeakStatistic:
3773 GetNonpeakPixelList(pixel_list[
id],&pixel);
3776 case RootMeanSquareStatistic:
3778 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3781 case StandardDeviationStatistic:
3783 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3787 if ((channel & RedChannel) != 0)
3788 SetPixelRed(q,ClampToQuantum(pixel.red));
3789 if ((channel & GreenChannel) != 0)
3790 SetPixelGreen(q,ClampToQuantum(pixel.green));
3791 if ((channel & BlueChannel) != 0)
3792 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3793 if ((channel & OpacityChannel) != 0)
3794 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3795 if (((channel & IndexChannel) != 0) &&
3796 (image->colorspace == CMYKColorspace))
3797 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3801 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3803 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3808 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3810 if (proceed == MagickFalse)
3814 statistic_view=DestroyCacheView(statistic_view);
3815 image_view=DestroyCacheView(image_view);
3816 pixel_list=DestroyPixelListTLS(pixel_list);
3817 if (status == MagickFalse)
3818 statistic_image=DestroyImage(statistic_image);
3819 return(statistic_image);