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:
259 result=(MagickRealType) pixel+value;
260 result-=((MagickRealType) QuantumRange+1.0)*floor((
double) result/
261 ((MagickRealType) QuantumRange+1.0));
264 case AndEvaluateOperator:
266 result=(MagickRealType) ((ssize_t) pixel & (ssize_t) (value+0.5));
269 case CosineEvaluateOperator:
271 result=(MagickRealType) QuantumRange*(0.5*cos((
double) (2.0*MagickPI*
272 QuantumScale*(MagickRealType) pixel*value))+0.5);
275 case DivideEvaluateOperator:
277 result=(MagickRealType) pixel/(value == 0.0 ? 1.0 : value);
280 case ExponentialEvaluateOperator:
282 result=(MagickRealType) QuantumRange*exp(value*QuantumScale*(
double)
286 case GaussianNoiseEvaluateOperator:
288 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
289 GaussianNoise,value);
292 case ImpulseNoiseEvaluateOperator:
294 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
298 case InverseLogEvaluateOperator:
300 result=((MagickRealType) QuantumRange*pow((value+1.0),
301 QuantumScale*(MagickRealType) pixel)-1.0)*PerceptibleReciprocal(value);
304 case LaplacianNoiseEvaluateOperator:
306 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
307 LaplacianNoise,value);
310 case LeftShiftEvaluateOperator:
312 result=(double) pixel;
313 for (i=0; i < (ssize_t) value; i++)
317 case LogEvaluateOperator:
319 if ((QuantumScale*(MagickRealType) pixel) >= MagickEpsilon)
320 result=(MagickRealType) QuantumRange*log((
double) (QuantumScale*value*
321 (MagickRealType) pixel+1.0))/log((
double) (value+1.0));
324 case MaxEvaluateOperator:
326 result=(MagickRealType) EvaluateMax((
double) pixel,value);
329 case MeanEvaluateOperator:
331 result=(MagickRealType) pixel+value;
334 case MedianEvaluateOperator:
336 result=(MagickRealType) pixel+value;
339 case MinEvaluateOperator:
341 result=(MagickRealType) MagickMin((
double) pixel,value);
344 case MultiplicativeNoiseEvaluateOperator:
346 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
347 MultiplicativeGaussianNoise,value);
350 case MultiplyEvaluateOperator:
352 result=(MagickRealType) pixel*value;
355 case OrEvaluateOperator:
357 result=(MagickRealType) ((ssize_t) pixel | (ssize_t) (value+0.5));
360 case PoissonNoiseEvaluateOperator:
362 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
366 case PowEvaluateOperator:
368 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
369 result=(
double) -((MagickRealType) QuantumRange*pow(-(QuantumScale*
370 (
double) pixel),(
double) value));
372 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,
376 case RightShiftEvaluateOperator:
378 result=(MagickRealType) pixel;
379 for (i=0; i < (ssize_t) value; i++)
383 case RootMeanSquareEvaluateOperator:
385 result=((MagickRealType) pixel*(MagickRealType) pixel+value);
388 case SetEvaluateOperator:
393 case SineEvaluateOperator:
395 result=(MagickRealType) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
396 QuantumScale*(MagickRealType) pixel*value))+0.5);
399 case SubtractEvaluateOperator:
401 result=(MagickRealType) pixel-value;
404 case SumEvaluateOperator:
406 result=(MagickRealType) pixel+value;
409 case ThresholdEvaluateOperator:
411 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
415 case ThresholdBlackEvaluateOperator:
417 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
420 case ThresholdWhiteEvaluateOperator:
422 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
426 case UniformNoiseEvaluateOperator:
428 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
432 case XorEvaluateOperator:
434 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
453 columns=images->columns;
456 for (p=images; p != (
Image *) NULL; p=p->next)
462 if (p->matte != MagickFalse)
464 if (p->colorspace == CMYKColorspace)
466 if (channels > number_channels)
468 number_channels=channels;
471 if (p->columns > columns)
476 return(CloneImage(q,columns,rows,MagickTrue,exception));
479 MagickExport MagickBooleanType EvaluateImage(
Image *image,
480 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
485 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
489 MagickExport
Image *EvaluateImages(
const Image *images,
492 #define EvaluateImageTag "Evaluate/Image"
507 **magick_restrict evaluate_pixels,
511 **magick_restrict random_info;
519 #if defined(MAGICKCORE_OPENMP_SUPPORT)
524 assert(images != (
Image *) NULL);
525 assert(images->signature == MagickCoreSignature);
527 assert(exception->signature == MagickCoreSignature);
528 if (IsEventLogging() != MagickFalse)
529 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
530 image=AcquireImageCanvas(images,exception);
531 if (image == (
Image *) NULL)
532 return((
Image *) NULL);
533 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
535 InheritException(exception,&image->exception);
536 image=DestroyImage(image);
537 return((
Image *) NULL);
539 evaluate_pixels=AcquirePixelTLS(images);
542 image=DestroyImage(image);
543 (void) ThrowMagickException(exception,GetMagickModule(),
544 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
545 return((
Image *) NULL);
552 number_images=GetImageListLength(images);
553 GetMagickPixelPacket(images,&zero);
554 random_info=AcquireRandomInfoTLS();
555 evaluate_view=AcquireAuthenticCacheView(image,exception);
556 if (op == MedianEvaluateOperator)
558 #if defined(MAGICKCORE_OPENMP_SUPPORT)
559 key=GetRandomSecretKey(random_info[0]);
560 #pragma omp parallel for schedule(static) shared(progress,status) \
561 magick_number_threads(image,images,image->rows,key == ~0UL)
563 for (y=0; y < (ssize_t) image->rows; y++)
572 id = GetOpenMPThreadId();
575 *magick_restrict evaluate_indexes;
586 if (status == MagickFalse)
588 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
595 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
596 evaluate_pixel=evaluate_pixels[id];
597 for (x=0; x < (ssize_t) image->columns; x++)
602 for (i=0; i < (ssize_t) number_images; i++)
603 evaluate_pixel[i]=zero;
605 for (i=0; i < (ssize_t) number_images; i++)
613 image_view=AcquireVirtualCacheView(next,exception);
614 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
617 image_view=DestroyCacheView(image_view);
620 indexes=GetCacheViewVirtualIndexQueue(image_view);
621 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
622 GetPixelRed(p),op,evaluate_pixel[i].red);
623 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
624 GetPixelGreen(p),op,evaluate_pixel[i].green);
625 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
626 GetPixelBlue(p),op,evaluate_pixel[i].blue);
627 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
628 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
629 if (image->colorspace == CMYKColorspace)
630 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
631 *indexes,op,evaluate_pixel[i].index);
632 image_view=DestroyCacheView(image_view);
633 next=GetNextImageInList(next);
635 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
637 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
638 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
639 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
640 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
641 if (image->colorspace == CMYKColorspace)
642 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
643 evaluate_pixel[i/2].index));
646 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
648 if (images->progress_monitor != (MagickProgressMonitor) NULL)
653 #if defined(MAGICKCORE_OPENMP_SUPPORT)
657 proceed=SetImageProgress(images,EvaluateImageTag,progress,
659 if (proceed == MagickFalse)
666 #if defined(MAGICKCORE_OPENMP_SUPPORT)
667 key=GetRandomSecretKey(random_info[0]);
668 #pragma omp parallel for schedule(static) shared(progress,status) \
669 magick_number_threads(image,images,image->rows,key == ~0UL)
671 for (y=0; y < (ssize_t) image->rows; y++)
680 id = GetOpenMPThreadId();
683 *magick_restrict evaluate_indexes;
695 if (status == MagickFalse)
697 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
704 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
705 evaluate_pixel=evaluate_pixels[id];
706 for (x=0; x < (ssize_t) image->columns; x++)
707 evaluate_pixel[x]=zero;
709 for (i=0; i < (ssize_t) number_images; i++)
717 image_view=AcquireVirtualCacheView(next,exception);
718 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
722 image_view=DestroyCacheView(image_view);
725 indexes=GetCacheViewVirtualIndexQueue(image_view);
726 for (x=0; x < (ssize_t) image->columns; x++)
728 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
729 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
730 evaluate_pixel[x].red);
731 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
732 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
733 evaluate_pixel[x].green);
734 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
735 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
736 evaluate_pixel[x].blue);
737 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
738 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
739 evaluate_pixel[x].opacity);
740 if (image->colorspace == CMYKColorspace)
741 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
742 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
743 evaluate_pixel[x].index);
746 image_view=DestroyCacheView(image_view);
747 next=GetNextImageInList(next);
749 if (op == MeanEvaluateOperator)
750 for (x=0; x < (ssize_t) image->columns; x++)
752 evaluate_pixel[x].red/=number_images;
753 evaluate_pixel[x].green/=number_images;
754 evaluate_pixel[x].blue/=number_images;
755 evaluate_pixel[x].opacity/=number_images;
756 evaluate_pixel[x].index/=number_images;
758 if (op == RootMeanSquareEvaluateOperator)
759 for (x=0; x < (ssize_t) image->columns; x++)
761 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
763 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
765 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
767 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
769 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
772 if (op == MultiplyEvaluateOperator)
773 for (x=0; x < (ssize_t) image->columns; x++)
778 for (j=0; j < (ssize_t) (number_images-1); j++)
780 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
781 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
782 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
787 for (x=0; x < (ssize_t) image->columns; x++)
789 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
790 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
791 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
792 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
793 if (image->colorspace == CMYKColorspace)
794 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
795 evaluate_pixel[x].index));
798 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
800 if (images->progress_monitor != (MagickProgressMonitor) NULL)
805 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
807 if (proceed == MagickFalse)
812 evaluate_view=DestroyCacheView(evaluate_view);
813 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
814 random_info=DestroyRandomInfoTLS(random_info);
815 if (status == MagickFalse)
816 image=DestroyImage(image);
820 MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
821 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
834 **magick_restrict random_info;
839 #if defined(MAGICKCORE_OPENMP_SUPPORT)
844 assert(image != (
Image *) NULL);
845 assert(image->signature == MagickCoreSignature);
847 assert(exception->signature == MagickCoreSignature);
848 if (IsEventLogging() != MagickFalse)
849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
850 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
852 InheritException(exception,&image->exception);
857 random_info=AcquireRandomInfoTLS();
858 image_view=AcquireAuthenticCacheView(image,exception);
859 #if defined(MAGICKCORE_OPENMP_SUPPORT)
860 key=GetRandomSecretKey(random_info[0]);
861 #pragma omp parallel for schedule(static) shared(progress,status) \
862 magick_number_threads(image,image,image->rows,key == ~0UL)
864 for (y=0; y < (ssize_t) image->rows; y++)
867 id = GetOpenMPThreadId();
870 *magick_restrict indexes;
878 if (status == MagickFalse)
880 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
886 indexes=GetCacheViewAuthenticIndexQueue(image_view);
887 for (x=0; x < (ssize_t) image->columns; x++)
892 if ((channel & RedChannel) != 0)
894 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
895 if (op == MeanEvaluateOperator)
897 SetPixelRed(q,ClampToQuantum(result));
899 if ((channel & GreenChannel) != 0)
901 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
903 if (op == MeanEvaluateOperator)
905 SetPixelGreen(q,ClampToQuantum(result));
907 if ((channel & BlueChannel) != 0)
909 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
911 if (op == MeanEvaluateOperator)
913 SetPixelBlue(q,ClampToQuantum(result));
915 if ((channel & OpacityChannel) != 0)
917 if (image->matte == MagickFalse)
919 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
921 if (op == MeanEvaluateOperator)
923 SetPixelOpacity(q,ClampToQuantum(result));
927 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
929 if (op == MeanEvaluateOperator)
931 SetPixelAlpha(q,ClampToQuantum(result));
934 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
936 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
938 if (op == MeanEvaluateOperator)
940 SetPixelIndex(indexes+x,ClampToQuantum(result));
944 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
946 if (image->progress_monitor != (MagickProgressMonitor) NULL)
951 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
952 if (proceed == MagickFalse)
956 image_view=DestroyCacheView(image_view);
957 random_info=DestroyRandomInfoTLS(random_info);
1001 static Quantum ApplyFunction(Quantum pixel,
const MagickFunction
function,
1002 const size_t number_parameters,
const double *parameters,
1015 case PolynomialFunction:
1023 for (i=0; i < (ssize_t) number_parameters; i++)
1024 result=result*QuantumScale*(MagickRealType) pixel+parameters[i];
1025 result*=(MagickRealType) QuantumRange;
1028 case SinusoidFunction:
1033 double freq,phase,ampl,bias;
1034 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1035 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1036 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1037 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1038 result=(MagickRealType) QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1039 (freq*QuantumScale*(MagickRealType) pixel+phase/360.0)))+bias);
1042 case ArcsinFunction:
1053 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1054 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1055 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1056 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1057 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*(MagickRealType)
1060 result=bias-range/2.0;
1063 result=bias+range/2.0;
1065 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1066 result*=(MagickRealType) QuantumRange;
1069 case ArctanFunction:
1074 double slope,range,center,bias;
1075 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1076 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1077 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1078 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1079 result=(MagickRealType) (MagickPI*slope*(QuantumScale*(MagickRealType)
1081 result=(MagickRealType) QuantumRange*(range/MagickPI*atan((
double)
1085 case UndefinedFunction:
1088 return(ClampToQuantum(result));
1091 MagickExport MagickBooleanType FunctionImage(
Image *image,
1092 const MagickFunction
function,
const size_t number_parameters,
1098 status=FunctionImageChannel(image,CompositeChannels,
function,
1099 number_parameters,parameters,exception);
1103 MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1104 const ChannelType channel,
const MagickFunction
function,
1105 const size_t number_parameters,
const double *parameters,
1108 #define FunctionImageTag "Function/Image "
1122 assert(image != (
Image *) NULL);
1123 assert(image->signature == MagickCoreSignature);
1125 assert(exception->signature == MagickCoreSignature);
1126 if (IsEventLogging() != MagickFalse)
1127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1128 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1130 InheritException(exception,&image->exception);
1131 return(MagickFalse);
1133 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1134 status=AccelerateFunctionImage(image,channel,
function,number_parameters,
1135 parameters,exception);
1136 if (status != MagickFalse)
1141 image_view=AcquireAuthenticCacheView(image,exception);
1142 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1143 #pragma omp parallel for schedule(static) shared(progress,status) \
1144 magick_number_threads(image,image,image->rows,1)
1146 for (y=0; y < (ssize_t) image->rows; y++)
1149 *magick_restrict indexes;
1157 if (status == MagickFalse)
1159 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1165 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1166 for (x=0; x < (ssize_t) image->columns; x++)
1168 if ((channel & RedChannel) != 0)
1169 SetPixelRed(q,ApplyFunction(GetPixelRed(q),
function,
1170 number_parameters,parameters,exception));
1171 if ((channel & GreenChannel) != 0)
1172 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),
function,
1173 number_parameters,parameters,exception));
1174 if ((channel & BlueChannel) != 0)
1175 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),
function,
1176 number_parameters,parameters,exception));
1177 if ((channel & OpacityChannel) != 0)
1179 if (image->matte == MagickFalse)
1180 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),
function,
1181 number_parameters,parameters,exception));
1183 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),
function,
1184 number_parameters,parameters,exception));
1186 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1187 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),
function,
1188 number_parameters,parameters,exception));
1191 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1193 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1198 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1199 if (proceed == MagickFalse)
1203 image_view=DestroyCacheView(image_view);
1237 MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1243 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1247 MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1248 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1251 *channel_statistics;
1256 assert(image != (
Image *) NULL);
1257 assert(image->signature == MagickCoreSignature);
1258 if (IsEventLogging() != MagickFalse)
1259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1260 channel_statistics=GetImageChannelStatistics(image,exception);
1262 return(MagickFalse);
1264 channel_statistics[CompositeChannels].entropy=0.0;
1265 if ((channel & RedChannel) != 0)
1267 channel_statistics[CompositeChannels].entropy+=
1268 channel_statistics[RedChannel].entropy;
1271 if ((channel & GreenChannel) != 0)
1273 channel_statistics[CompositeChannels].entropy+=
1274 channel_statistics[GreenChannel].entropy;
1277 if ((channel & BlueChannel) != 0)
1279 channel_statistics[CompositeChannels].entropy+=
1280 channel_statistics[BlueChannel].entropy;
1283 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1285 channel_statistics[CompositeChannels].entropy+=
1286 channel_statistics[OpacityChannel].entropy;
1289 if (((channel & IndexChannel) != 0) &&
1290 (image->colorspace == CMYKColorspace))
1292 channel_statistics[CompositeChannels].entropy+=
1293 channel_statistics[BlackChannel].entropy;
1296 channel_statistics[CompositeChannels].entropy/=channels;
1297 *entropy=channel_statistics[CompositeChannels].entropy;
1299 channel_statistics);
1336 MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1342 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1347 MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1348 const ChannelType channel,
size_t *minima,
size_t *maxima,
1358 assert(image != (
Image *) NULL);
1359 assert(image->signature == MagickCoreSignature);
1360 if (IsEventLogging() != MagickFalse)
1361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1362 status=GetImageChannelRange(image,channel,&min,&max,exception);
1363 *minima=(size_t) ceil(min-0.5);
1364 *maxima=(size_t) floor(max+0.5);
1402 MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1408 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1413 MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1414 const ChannelType channel,
double *kurtosis,
double *skewness,
1428 assert(image != (
Image *) NULL);
1429 assert(image->signature == MagickCoreSignature);
1430 if (IsEventLogging() != MagickFalse)
1431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1436 standard_deviation=0.0;
1439 sum_fourth_power=0.0;
1440 for (y=0; y < (ssize_t) image->rows; y++)
1443 *magick_restrict indexes;
1451 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1454 indexes=GetVirtualIndexQueue(image);
1455 for (x=0; x < (ssize_t) image->columns; x++)
1457 if ((channel & RedChannel) != 0)
1459 mean+=QuantumScale*GetPixelRed(p);
1460 sum_squares+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
1461 sum_cubes+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
1462 QuantumScale*GetPixelRed(p);
1463 sum_fourth_power+=QuantumScale*GetPixelRed(p)*QuantumScale*
1464 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*
1468 if ((channel & GreenChannel) != 0)
1470 mean+=QuantumScale*GetPixelGreen(p);
1471 sum_squares+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1473 sum_cubes+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1474 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
1475 sum_fourth_power+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1476 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
1480 if ((channel & BlueChannel) != 0)
1482 mean+=QuantumScale*GetPixelBlue(p);
1483 sum_squares+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1485 sum_cubes+=QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*
1486 QuantumScale*GetPixelBlue(p);
1487 sum_fourth_power+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1488 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
1492 if ((channel & OpacityChannel) != 0)
1494 mean+=QuantumScale*GetPixelAlpha(p);
1495 sum_squares+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1497 sum_cubes+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1498 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
1499 sum_fourth_power+=QuantumScale*GetPixelAlpha(p)*QuantumScale*
1500 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*GetPixelAlpha(p);
1503 if (((channel & IndexChannel) != 0) &&
1504 (image->colorspace == CMYKColorspace))
1509 index=QuantumScale*GetPixelIndex(indexes+x);
1511 sum_squares+=index*index;
1512 sum_cubes+=index*index*index;
1513 sum_fourth_power+=index*index*index*index;
1519 if (y < (ssize_t) image->rows)
1520 return(MagickFalse);
1526 sum_fourth_power/=area;
1528 standard_deviation=sqrt(sum_squares-(mean*mean));
1529 if (standard_deviation != 0.0)
1531 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1532 3.0*mean*mean*mean*mean;
1533 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1536 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1537 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1539 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1576 MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1582 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1587 MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1588 const ChannelType channel,
double *mean,
double *standard_deviation,
1592 *channel_statistics;
1597 assert(image != (
Image *) NULL);
1598 assert(image->signature == MagickCoreSignature);
1599 if (IsEventLogging() != MagickFalse)
1600 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1601 channel_statistics=GetImageChannelStatistics(image,exception);
1603 return(MagickFalse);
1605 channel_statistics[CompositeChannels].mean=0.0;
1606 channel_statistics[CompositeChannels].standard_deviation=0.0;
1607 if ((channel & RedChannel) != 0)
1609 channel_statistics[CompositeChannels].mean+=
1610 channel_statistics[RedChannel].mean;
1611 channel_statistics[CompositeChannels].standard_deviation+=
1612 channel_statistics[RedChannel].standard_deviation;
1615 if ((channel & GreenChannel) != 0)
1617 channel_statistics[CompositeChannels].mean+=
1618 channel_statistics[GreenChannel].mean;
1619 channel_statistics[CompositeChannels].standard_deviation+=
1620 channel_statistics[GreenChannel].standard_deviation;
1623 if ((channel & BlueChannel) != 0)
1625 channel_statistics[CompositeChannels].mean+=
1626 channel_statistics[BlueChannel].mean;
1627 channel_statistics[CompositeChannels].standard_deviation+=
1628 channel_statistics[BlueChannel].standard_deviation;
1631 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1633 channel_statistics[CompositeChannels].mean+=
1634 channel_statistics[OpacityChannel].mean;
1635 channel_statistics[CompositeChannels].standard_deviation+=
1636 channel_statistics[OpacityChannel].standard_deviation;
1639 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1641 channel_statistics[CompositeChannels].mean+=
1642 channel_statistics[BlackChannel].mean;
1643 channel_statistics[CompositeChannels].standard_deviation+=
1644 channel_statistics[CompositeChannels].standard_deviation;
1647 channel_statistics[CompositeChannels].mean/=channels;
1648 channel_statistics[CompositeChannels].standard_deviation/=channels;
1649 *mean=channel_statistics[CompositeChannels].mean;
1650 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1652 channel_statistics);
1685 #define MaxNumberImageMoments 8
1691 M00[CompositeChannels+1],
1692 M01[CompositeChannels+1],
1693 M02[CompositeChannels+1],
1694 M03[CompositeChannels+1],
1695 M10[CompositeChannels+1],
1696 M11[CompositeChannels+1],
1697 M12[CompositeChannels+1],
1698 M20[CompositeChannels+1],
1699 M21[CompositeChannels+1],
1700 M22[CompositeChannels+1],
1701 M30[CompositeChannels+1];
1707 centroid[CompositeChannels+1];
1717 assert(image != (
Image *) NULL);
1718 assert(image->signature == MagickCoreSignature);
1719 if (IsEventLogging() != MagickFalse)
1720 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1721 length=CompositeChannels+1UL;
1723 sizeof(*channel_moments));
1725 return(channel_moments);
1726 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1727 (void) memset(centroid,0,
sizeof(centroid));
1728 (void) memset(M00,0,
sizeof(M00));
1729 (void) memset(M01,0,
sizeof(M01));
1730 (void) memset(M02,0,
sizeof(M02));
1731 (void) memset(M03,0,
sizeof(M03));
1732 (void) memset(M10,0,
sizeof(M10));
1733 (void) memset(M11,0,
sizeof(M11));
1734 (void) memset(M12,0,
sizeof(M12));
1735 (void) memset(M20,0,
sizeof(M20));
1736 (void) memset(M21,0,
sizeof(M21));
1737 (void) memset(M22,0,
sizeof(M22));
1738 (void) memset(M30,0,
sizeof(M30));
1739 GetMagickPixelPacket(image,&pixel);
1740 for (y=0; y < (ssize_t) image->rows; y++)
1743 *magick_restrict indexes;
1754 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1757 indexes=GetVirtualIndexQueue(image);
1758 for (x=0; x < (ssize_t) image->columns; x++)
1760 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1761 M00[RedChannel]+=QuantumScale*pixel.red;
1762 M10[RedChannel]+=x*QuantumScale*pixel.red;
1763 M01[RedChannel]+=y*QuantumScale*pixel.red;
1764 M00[GreenChannel]+=QuantumScale*pixel.green;
1765 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1766 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1767 M00[BlueChannel]+=QuantumScale*pixel.blue;
1768 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1769 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1770 if (image->matte != MagickFalse)
1772 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1773 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1774 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1776 if (image->colorspace == CMYKColorspace)
1778 M00[IndexChannel]+=QuantumScale*pixel.index;
1779 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1780 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1785 for (channel=0; channel <= CompositeChannels; channel++)
1790 if (M00[channel] < MagickEpsilon)
1792 M00[channel]+=MagickEpsilon;
1793 centroid[channel].x=(double) image->columns/2.0;
1794 centroid[channel].y=(
double) image->rows/2.0;
1797 M00[channel]+=MagickEpsilon;
1798 centroid[channel].x=M10[channel]/M00[channel];
1799 centroid[channel].y=M01[channel]/M00[channel];
1801 for (y=0; y < (ssize_t) image->rows; y++)
1804 *magick_restrict indexes;
1815 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1818 indexes=GetVirtualIndexQueue(image);
1819 for (x=0; x < (ssize_t) image->columns; x++)
1821 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1822 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1823 centroid[RedChannel].y)*QuantumScale*pixel.red;
1824 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1825 centroid[RedChannel].x)*QuantumScale*pixel.red;
1826 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1827 centroid[RedChannel].y)*QuantumScale*pixel.red;
1828 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1829 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1831 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1832 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1834 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1835 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1836 centroid[RedChannel].y)*QuantumScale*pixel.red;
1837 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1838 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1840 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1841 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1843 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1844 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1845 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1846 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1847 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1848 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1849 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1850 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1852 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1853 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1855 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1856 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1857 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1858 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1859 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1861 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1862 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1864 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1865 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1866 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1867 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1868 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1869 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1870 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1871 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1873 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1874 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1876 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1877 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1878 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1879 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1880 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1882 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1883 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1885 if (image->matte != MagickFalse)
1887 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1888 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1889 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1890 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1891 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1892 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1893 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1894 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1895 QuantumScale*pixel.opacity;
1896 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1897 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1898 QuantumScale*pixel.opacity;
1899 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1900 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1901 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1902 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1903 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1904 QuantumScale*pixel.opacity;
1905 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1906 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1907 QuantumScale*pixel.opacity;
1909 if (image->colorspace == CMYKColorspace)
1911 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1912 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1913 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1914 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1915 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1916 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1917 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1918 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1919 QuantumScale*pixel.index;
1920 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1921 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1922 QuantumScale*pixel.index;
1923 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1924 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1925 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1926 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1927 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1928 QuantumScale*pixel.index;
1929 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1930 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1931 QuantumScale*pixel.index;
1937 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1938 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1939 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1940 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1941 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1942 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1943 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1944 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1945 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1946 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1947 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1948 if (image->matte != MagickFalse)
1951 M00[CompositeChannels]+=M00[OpacityChannel];
1952 M01[CompositeChannels]+=M01[OpacityChannel];
1953 M02[CompositeChannels]+=M02[OpacityChannel];
1954 M03[CompositeChannels]+=M03[OpacityChannel];
1955 M10[CompositeChannels]+=M10[OpacityChannel];
1956 M11[CompositeChannels]+=M11[OpacityChannel];
1957 M12[CompositeChannels]+=M12[OpacityChannel];
1958 M20[CompositeChannels]+=M20[OpacityChannel];
1959 M21[CompositeChannels]+=M21[OpacityChannel];
1960 M22[CompositeChannels]+=M22[OpacityChannel];
1961 M30[CompositeChannels]+=M30[OpacityChannel];
1963 if (image->colorspace == CMYKColorspace)
1966 M00[CompositeChannels]+=M00[IndexChannel];
1967 M01[CompositeChannels]+=M01[IndexChannel];
1968 M02[CompositeChannels]+=M02[IndexChannel];
1969 M03[CompositeChannels]+=M03[IndexChannel];
1970 M10[CompositeChannels]+=M10[IndexChannel];
1971 M11[CompositeChannels]+=M11[IndexChannel];
1972 M12[CompositeChannels]+=M12[IndexChannel];
1973 M20[CompositeChannels]+=M20[IndexChannel];
1974 M21[CompositeChannels]+=M21[IndexChannel];
1975 M22[CompositeChannels]+=M22[IndexChannel];
1976 M30[CompositeChannels]+=M30[IndexChannel];
1978 M00[CompositeChannels]/=(double) channels;
1979 M01[CompositeChannels]/=(double) channels;
1980 M02[CompositeChannels]/=(double) channels;
1981 M03[CompositeChannels]/=(double) channels;
1982 M10[CompositeChannels]/=(double) channels;
1983 M11[CompositeChannels]/=(double) channels;
1984 M12[CompositeChannels]/=(double) channels;
1985 M20[CompositeChannels]/=(double) channels;
1986 M21[CompositeChannels]/=(double) channels;
1987 M22[CompositeChannels]/=(double) channels;
1988 M30[CompositeChannels]/=(double) channels;
1989 for (channel=0; channel <= CompositeChannels; channel++)
1994 channel_moments[channel].centroid=centroid[channel];
1995 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
1996 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
1997 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1998 (M20[channel]-M02[channel]))));
1999 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
2000 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
2001 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2002 (M20[channel]-M02[channel]))));
2003 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
2004 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
2005 if (fabs(M11[channel]) < 0.0)
2007 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2008 ((M20[channel]-M02[channel]) < 0.0))
2009 channel_moments[channel].ellipse_angle+=90.0;
2012 if (M11[channel] < 0.0)
2014 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2016 if ((M20[channel]-M02[channel]) < 0.0)
2017 channel_moments[channel].ellipse_angle+=90.0;
2019 channel_moments[channel].ellipse_angle+=180.0;
2023 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2024 ((M20[channel]-M02[channel]) < 0.0))
2025 channel_moments[channel].ellipse_angle+=90.0;
2026 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2027 channel_moments[channel].ellipse_axis.y*
2028 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2029 channel_moments[channel].ellipse_axis.x*
2030 channel_moments[channel].ellipse_axis.x)));
2031 channel_moments[channel].ellipse_intensity=M00[channel]/
2032 (MagickPI*channel_moments[channel].ellipse_axis.x*
2033 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2035 for (channel=0; channel <= CompositeChannels; channel++)
2042 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2043 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2044 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2045 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2046 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2047 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2048 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2049 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2052 for (channel=0; channel <= CompositeChannels; channel++)
2057 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2058 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2059 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2060 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2061 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2062 (3.0*M21[channel]-M03[channel]);
2063 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2064 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2065 (M21[channel]+M03[channel]);
2066 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[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]))+(3.0*M21[channel]-M03[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[5]=(M20[channel]-M02[channel])*
2074 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2075 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2076 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2077 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2078 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2079 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2080 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2081 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2082 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2083 (M21[channel]+M03[channel]));
2084 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2085 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2086 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2087 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2089 if (y < (ssize_t) image->rows)
2090 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2091 return(channel_moments);
2144 hash_image=BlurImage(image,0.0,1.0,exception);
2145 if (hash_image == (
Image *) NULL)
2147 hash_image->depth=8;
2148 status=TransformImageColorspace(hash_image,xyYColorspace);
2149 if (status == MagickFalse)
2151 moments=GetImageChannelMoments(hash_image,exception);
2152 hash_image=DestroyImage(hash_image);
2156 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2159 for (channel=0; channel <= CompositeChannels; channel++)
2160 for (i=0; i < MaximumNumberOfImageMoments; i++)
2161 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2166 hash_image=BlurImage(image,0.0,1.0,exception);
2167 if (hash_image == (
Image *) NULL)
2173 hash_image->depth=8;
2174 status=TransformImageColorspace(hash_image,HSBColorspace);
2175 if (status == MagickFalse)
2181 moments=GetImageChannelMoments(hash_image,exception);
2182 hash_image=DestroyImage(hash_image);
2189 for (channel=0; channel <= CompositeChannels; channel++)
2190 for (i=0; i < MaximumNumberOfImageMoments; i++)
2191 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2193 return(perceptual_hash);
2229 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2232 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2235 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2236 const ChannelType channel,
double *minima,
double *maxima,
2245 assert(image != (
Image *) NULL);
2246 assert(image->signature == MagickCoreSignature);
2247 if (IsEventLogging() != MagickFalse)
2248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2249 *maxima=(-MagickMaximumValue);
2250 *minima=MagickMaximumValue;
2251 GetMagickPixelPacket(image,&pixel);
2252 for (y=0; y < (ssize_t) image->rows; y++)
2255 *magick_restrict indexes;
2263 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2266 indexes=GetVirtualIndexQueue(image);
2267 for (x=0; x < (ssize_t) image->columns; x++)
2269 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2270 if ((channel & RedChannel) != 0)
2272 if (pixel.red < *minima)
2273 *minima=(double) pixel.red;
2274 if (pixel.red > *maxima)
2275 *maxima=(double) pixel.red;
2277 if ((channel & GreenChannel) != 0)
2279 if (pixel.green < *minima)
2280 *minima=(double) pixel.green;
2281 if (pixel.green > *maxima)
2282 *maxima=(double) pixel.green;
2284 if ((channel & BlueChannel) != 0)
2286 if (pixel.blue < *minima)
2287 *minima=(double) pixel.blue;
2288 if (pixel.blue > *maxima)
2289 *maxima=(double) pixel.blue;
2291 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2293 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2294 *minima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2296 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2297 *maxima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2300 if (((channel & IndexChannel) != 0) &&
2301 (image->colorspace == CMYKColorspace))
2303 if ((
double) pixel.index < *minima)
2304 *minima=(
double) pixel.index;
2305 if ((
double) pixel.index > *maxima)
2306 *maxima=(
double) pixel.index;
2311 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2351 *channel_statistics;
2375 assert(image != (
Image *) NULL);
2376 assert(image->signature == MagickCoreSignature);
2377 if (IsEventLogging() != MagickFalse)
2378 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2379 length=CompositeChannels+1UL;
2381 sizeof(*channel_statistics));
2383 sizeof(*histogram));
2391 channel_statistics);
2392 return(channel_statistics);
2394 (void) memset(channel_statistics,0,length*
2395 sizeof(*channel_statistics));
2396 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2398 channel_statistics[i].depth=1;
2399 channel_statistics[i].maxima=(-MagickMaximumValue);
2400 channel_statistics[i].minima=MagickMaximumValue;
2402 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2403 (void) memset(&number_bins,0,
sizeof(number_bins));
2404 for (y=0; y < (ssize_t) image->rows; y++)
2407 *magick_restrict indexes;
2418 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2421 indexes=GetVirtualIndexQueue(image);
2422 for (x=0; x < (ssize_t) image->columns; )
2424 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2426 depth=channel_statistics[RedChannel].depth;
2427 range=GetQuantumRange(depth);
2428 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2430 channel_statistics[RedChannel].depth++;
2434 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2436 depth=channel_statistics[GreenChannel].depth;
2437 range=GetQuantumRange(depth);
2438 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2440 channel_statistics[GreenChannel].depth++;
2444 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2446 depth=channel_statistics[BlueChannel].depth;
2447 range=GetQuantumRange(depth);
2448 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2450 channel_statistics[BlueChannel].depth++;
2454 if (image->matte != MagickFalse)
2456 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2458 depth=channel_statistics[OpacityChannel].depth;
2459 range=GetQuantumRange(depth);
2460 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2462 channel_statistics[OpacityChannel].depth++;
2467 if (image->colorspace == CMYKColorspace)
2469 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2471 depth=channel_statistics[BlackChannel].depth;
2472 range=GetQuantumRange(depth);
2473 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2475 channel_statistics[BlackChannel].depth++;
2480 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2481 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2482 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2483 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2484 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2485 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2486 QuantumScale*GetPixelRed(p);
2487 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2488 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2489 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2490 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2491 QuantumScale*GetPixelRed(p);
2492 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2493 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2494 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2495 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2496 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2497 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2498 QuantumScale*GetPixelGreen(p);
2499 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2500 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2501 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2502 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2503 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2504 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2505 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2506 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2507 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2508 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2509 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2510 QuantumScale*GetPixelBlue(p);
2511 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2512 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2513 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2514 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2515 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2516 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2517 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2518 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2519 if (image->matte != MagickFalse)
2521 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2522 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2523 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2524 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2525 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2526 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2527 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2528 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2529 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2531 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2532 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2533 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2534 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2536 if (image->colorspace == CMYKColorspace)
2538 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2539 channel_statistics[BlackChannel].minima=(double)
2540 GetPixelIndex(indexes+x);
2541 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2542 channel_statistics[BlackChannel].maxima=(
double)
2543 GetPixelIndex(indexes+x);
2544 channel_statistics[BlackChannel].sum+=QuantumScale*
2545 GetPixelIndex(indexes+x);
2546 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2547 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2548 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2549 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2550 QuantumScale*GetPixelIndex(indexes+x);
2551 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2552 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2553 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2554 GetPixelIndex(indexes+x);
2555 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2561 for (i=0; i < (ssize_t) CompositeChannels; i++)
2571 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2572 mean=channel_statistics[i].sum*area;
2573 channel_statistics[i].sum=mean;
2574 channel_statistics[i].sum_squared*=area;
2575 channel_statistics[i].sum_cubed*=area;
2576 channel_statistics[i].sum_fourth_power*=area;
2577 channel_statistics[i].mean=mean;
2578 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2579 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2580 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2581 ((double) image->columns*image->rows);
2582 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2583 channel_statistics[i].standard_deviation=standard_deviation;
2585 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2587 if (histogram[i].red > 0.0)
2589 if (histogram[i].green > 0.0)
2590 number_bins.green++;
2591 if (histogram[i].blue > 0.0)
2593 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2594 number_bins.opacity++;
2595 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2596 number_bins.index++;
2598 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2599 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2604 histogram[i].red*=area;
2605 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2606 MagickLog10(histogram[i].red)*
2607 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2608 histogram[i].green*=area;
2609 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2610 MagickLog10(histogram[i].green)*
2611 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2612 histogram[i].blue*=area;
2613 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2614 MagickLog10(histogram[i].blue)*
2615 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2616 if (image->matte != MagickFalse)
2618 histogram[i].opacity*=area;
2619 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2620 MagickLog10(histogram[i].opacity)*
2621 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2623 if (image->colorspace == CMYKColorspace)
2625 histogram[i].index*=area;
2626 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2627 MagickLog10(histogram[i].index)*
2628 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2634 for (i=0; i < (ssize_t) CompositeChannels; i++)
2636 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2637 channel_statistics[CompositeChannels].depth,(double)
2638 channel_statistics[i].depth);
2639 channel_statistics[CompositeChannels].minima=MagickMin(
2640 channel_statistics[CompositeChannels].minima,
2641 channel_statistics[i].minima);
2642 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2643 channel_statistics[CompositeChannels].maxima,
2644 channel_statistics[i].maxima);
2645 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2646 channel_statistics[CompositeChannels].sum_squared+=
2647 channel_statistics[i].sum_squared;
2648 channel_statistics[CompositeChannels].sum_cubed+=
2649 channel_statistics[i].sum_cubed;
2650 channel_statistics[CompositeChannels].sum_fourth_power+=
2651 channel_statistics[i].sum_fourth_power;
2652 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2653 channel_statistics[CompositeChannels].variance+=
2654 channel_statistics[i].variance-channel_statistics[i].mean*
2655 channel_statistics[i].mean;
2656 standard_deviation=sqrt(channel_statistics[i].variance-
2657 (channel_statistics[i].mean*channel_statistics[i].mean));
2658 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2659 ((double) image->columns*image->rows);
2660 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2661 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2662 channel_statistics[CompositeChannels].entropy+=
2663 channel_statistics[i].entropy;
2666 if (image->matte != MagickFalse)
2668 if (image->colorspace == CMYKColorspace)
2670 channel_statistics[CompositeChannels].sum/=channels;
2671 channel_statistics[CompositeChannels].sum_squared/=channels;
2672 channel_statistics[CompositeChannels].sum_cubed/=channels;
2673 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2674 channel_statistics[CompositeChannels].mean/=channels;
2675 channel_statistics[CompositeChannels].kurtosis/=channels;
2676 channel_statistics[CompositeChannels].skewness/=channels;
2677 channel_statistics[CompositeChannels].entropy/=channels;
2678 i=CompositeChannels;
2679 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2680 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2681 channel_statistics[i].mean=channel_statistics[i].sum;
2682 standard_deviation=sqrt(channel_statistics[i].variance-
2683 (channel_statistics[i].mean*channel_statistics[i].mean));
2684 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2685 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2686 standard_deviation*standard_deviation);
2687 channel_statistics[i].standard_deviation=standard_deviation;
2688 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2693 standard_deviation=PerceptibleReciprocal(
2694 channel_statistics[i].standard_deviation);
2695 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2696 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2697 channel_statistics[i].mean*channel_statistics[i].mean*
2698 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2699 standard_deviation);
2700 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2701 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2702 channel_statistics[i].mean*channel_statistics[i].mean*
2703 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2704 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2705 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2706 standard_deviation*standard_deviation)-3.0;
2708 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2710 channel_statistics[i].mean*=QuantumRange;
2711 channel_statistics[i].variance*=QuantumRange;
2712 channel_statistics[i].standard_deviation*=QuantumRange;
2713 channel_statistics[i].sum*=QuantumRange;
2714 channel_statistics[i].sum_squared*=QuantumRange;
2715 channel_statistics[i].sum_cubed*=QuantumRange;
2716 channel_statistics[i].sum_fourth_power*=QuantumRange;
2718 channel_statistics[CompositeChannels].mean=0.0;
2719 channel_statistics[CompositeChannels].standard_deviation=0.0;
2720 for (i=0; i < (ssize_t) CompositeChannels; i++)
2722 channel_statistics[CompositeChannels].mean+=
2723 channel_statistics[i].mean;
2724 channel_statistics[CompositeChannels].standard_deviation+=
2725 channel_statistics[i].standard_deviation;
2727 channel_statistics[CompositeChannels].mean/=(double) channels;
2728 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2730 if (y < (ssize_t) image->rows)
2732 channel_statistics);
2733 return(channel_statistics);
2774 MagickExport
Image *PolynomialImage(
const Image *images,
2775 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2780 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2782 return(polynomial_image);
2785 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2786 const ChannelType channel,
const size_t number_terms,
const double *terms,
2789 #define PolynomialImageTag "Polynomial/Image"
2804 **magick_restrict polynomial_pixels,
2810 assert(images != (
Image *) NULL);
2811 assert(images->signature == MagickCoreSignature);
2812 if (IsEventLogging() != MagickFalse)
2813 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2815 assert(exception->signature == MagickCoreSignature);
2816 image=AcquireImageCanvas(images,exception);
2817 if (image == (
Image *) NULL)
2818 return((
Image *) NULL);
2819 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2821 InheritException(exception,&image->exception);
2822 image=DestroyImage(image);
2823 return((
Image *) NULL);
2825 polynomial_pixels=AcquirePixelTLS(images);
2828 image=DestroyImage(image);
2829 (void) ThrowMagickException(exception,GetMagickModule(),
2830 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2831 return((
Image *) NULL);
2838 GetMagickPixelPacket(images,&zero);
2839 polynomial_view=AcquireAuthenticCacheView(image,exception);
2840 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2841 #pragma omp parallel for schedule(static) shared(progress,status) \
2842 magick_number_threads(image,image,image->rows,1)
2844 for (y=0; y < (ssize_t) image->rows; y++)
2853 id = GetOpenMPThreadId();
2856 *magick_restrict polynomial_indexes;
2871 if (status == MagickFalse)
2873 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2880 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2881 polynomial_pixel=polynomial_pixels[id];
2882 for (x=0; x < (ssize_t) image->columns; x++)
2883 polynomial_pixel[x]=zero;
2885 number_images=GetImageListLength(images);
2886 for (i=0; i < (ssize_t) number_images; i++)
2894 if (i >= (ssize_t) number_terms)
2896 image_view=AcquireVirtualCacheView(next,exception);
2897 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2900 image_view=DestroyCacheView(image_view);
2903 indexes=GetCacheViewVirtualIndexQueue(image_view);
2904 for (x=0; x < (ssize_t) image->columns; x++)
2910 coefficient=terms[i << 1];
2911 degree=terms[(i << 1)+1];
2912 if ((channel & RedChannel) != 0)
2913 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2915 if ((channel & GreenChannel) != 0)
2916 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2919 if ((channel & BlueChannel) != 0)
2920 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2922 if ((channel & OpacityChannel) != 0)
2923 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2924 ((
double) QuantumRange-(double) p->opacity),degree);
2925 if (((channel & IndexChannel) != 0) &&
2926 (image->colorspace == CMYKColorspace))
2927 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2931 image_view=DestroyCacheView(image_view);
2932 next=GetNextImageInList(next);
2934 for (x=0; x < (ssize_t) image->columns; x++)
2936 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2937 polynomial_pixel[x].red));
2938 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2939 polynomial_pixel[x].green));
2940 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2941 polynomial_pixel[x].blue));
2942 if (image->matte == MagickFalse)
2943 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2944 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2946 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2947 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2948 if (image->colorspace == CMYKColorspace)
2949 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2950 QuantumRange*polynomial_pixel[x].index));
2953 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2955 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2960 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2962 if (proceed == MagickFalse)
2966 polynomial_view=DestroyCacheView(polynomial_view);
2967 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2968 if (status == MagickFalse)
2969 image=DestroyImage(image);
3011 #define ListChannels 5
3038 lists[ListChannels];
3048 for (i=0; i < ListChannels; i++)
3049 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3050 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3051 pixel_list->lists[i].nodes);
3052 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3061 assert(pixel_list != (
PixelList **) NULL);
3062 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3063 if (pixel_list[i] != (
PixelList *) NULL)
3064 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3065 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3069 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3077 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3080 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3081 pixel_list->length=width*height;
3082 for (i=0; i < ListChannels; i++)
3084 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3085 sizeof(*pixel_list->lists[i].nodes));
3086 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3087 return(DestroyPixelList(pixel_list));
3088 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3089 sizeof(*pixel_list->lists[i].nodes));
3091 pixel_list->signature=MagickCoreSignature;
3095 static PixelList **AcquirePixelListTLS(
const size_t width,
3096 const size_t height)
3107 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3108 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3109 sizeof(*pixel_list));
3112 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3113 for (i=0; i < (ssize_t) number_threads; i++)
3115 pixel_list[i]=AcquirePixelList(width,height);
3116 if (pixel_list[i] == (
PixelList *) NULL)
3117 return(DestroyPixelListTLS(pixel_list));
3122 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3138 list=pixel_list->lists+channel;
3139 list->nodes[color].signature=pixel_list->signature;
3140 list->nodes[color].count=1;
3145 (void) memset(update,0,
sizeof(update));
3146 for (level=list->level; level >= 0; level--)
3148 while (list->nodes[search].next[level] < color)
3149 search=list->nodes[search].next[level];
3150 update[level]=search;
3155 for (level=0; ; level++)
3157 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3158 if ((pixel_list->seed & 0x300) != 0x300)
3163 if (level > (list->level+2))
3164 level=list->level+2;
3168 while (level > list->level)
3171 update[list->level]=65536UL;
3178 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3179 list->nodes[update[level]].next[level]=color;
3180 }
while (level-- > 0);
3199 channels[ListChannels];
3204 for (channel=0; channel < 5; channel++)
3206 list=pixel_list->lists+channel;
3209 maximum=list->nodes[color].next[0];
3212 color=list->nodes[color].next[0];
3213 if (color > maximum)
3215 count+=list->nodes[color].count;
3216 }
while (count < (ssize_t) pixel_list->length);
3217 channels[channel]=(
unsigned short) maximum;
3219 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3220 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3221 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3222 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3223 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3244 channels[ListChannels];
3249 for (channel=0; channel < 5; channel++)
3251 list=pixel_list->lists+channel;
3257 color=list->nodes[color].next[0];
3258 sum+=(MagickRealType) list->nodes[color].count*color;
3259 count+=list->nodes[color].count;
3260 }
while (count < (ssize_t) pixel_list->length);
3261 sum/=pixel_list->length;
3262 channels[channel]=(
unsigned short) sum;
3264 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3265 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3266 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3267 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3268 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3286 channels[ListChannels];
3291 for (channel=0; channel < 5; channel++)
3293 list=pixel_list->lists+channel;
3298 color=list->nodes[color].next[0];
3299 count+=list->nodes[color].count;
3300 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3301 channels[channel]=(
unsigned short) color;
3303 GetMagickPixelPacket((
const Image *) NULL,pixel);
3304 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3305 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3306 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3307 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3308 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3327 channels[ListChannels];
3332 for (channel=0; channel < 5; channel++)
3334 list=pixel_list->lists+channel;
3337 minimum=list->nodes[color].next[0];
3340 color=list->nodes[color].next[0];
3341 if (color < minimum)
3343 count+=list->nodes[color].count;
3344 }
while (count < (ssize_t) pixel_list->length);
3345 channels[channel]=(
unsigned short) minimum;
3347 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3348 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3349 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3350 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3351 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3376 for (channel=0; channel < 5; channel++)
3378 list=pixel_list->lists+channel;
3381 max_count=list->nodes[mode].count;
3385 color=list->nodes[color].next[0];
3386 if (list->nodes[color].count > max_count)
3389 max_count=list->nodes[mode].count;
3391 count+=list->nodes[color].count;
3392 }
while (count < (ssize_t) pixel_list->length);
3393 channels[channel]=(
unsigned short) mode;
3395 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3396 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3397 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3398 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3399 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3424 for (channel=0; channel < 5; channel++)
3426 list=pixel_list->lists+channel;
3428 next=list->nodes[color].next[0];
3434 next=list->nodes[color].next[0];
3435 count+=list->nodes[color].count;
3436 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3437 if ((previous == 65536UL) && (next != 65536UL))
3440 if ((previous != 65536UL) && (next == 65536UL))
3442 channels[channel]=(
unsigned short) color;
3444 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3445 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3446 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3447 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3448 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3451 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3470 channels[ListChannels];
3475 for (channel=0; channel < 5; channel++)
3477 list=pixel_list->lists+channel;
3483 color=list->nodes[color].next[0];
3484 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3485 count+=list->nodes[color].count;
3486 }
while (count < (ssize_t) pixel_list->length);
3487 sum/=pixel_list->length;
3488 channels[channel]=(
unsigned short) sqrt(sum);
3490 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3491 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3492 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3493 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3494 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3497 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3515 channels[ListChannels];
3520 for (channel=0; channel < 5; channel++)
3522 list=pixel_list->lists+channel;
3532 color=list->nodes[color].next[0];
3533 sum+=(MagickRealType) list->nodes[color].count*color;
3534 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3535 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3536 count+=list->nodes[color].count;
3537 }
while (count < (ssize_t) pixel_list->length);
3538 sum/=pixel_list->length;
3539 sum_squared/=pixel_list->length;
3540 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3542 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3543 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3544 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3545 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3546 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3549 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3550 const IndexPacket *indexes,
PixelList *pixel_list)
3558 index=ScaleQuantumToShort(GetPixelRed(pixel));
3559 signature=pixel_list->lists[0].nodes[index].signature;
3560 if (signature == pixel_list->signature)
3561 pixel_list->lists[0].nodes[index].count++;
3563 AddNodePixelList(pixel_list,0,index);
3564 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3565 signature=pixel_list->lists[1].nodes[index].signature;
3566 if (signature == pixel_list->signature)
3567 pixel_list->lists[1].nodes[index].count++;
3569 AddNodePixelList(pixel_list,1,index);
3570 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3571 signature=pixel_list->lists[2].nodes[index].signature;
3572 if (signature == pixel_list->signature)
3573 pixel_list->lists[2].nodes[index].count++;
3575 AddNodePixelList(pixel_list,2,index);
3576 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3577 signature=pixel_list->lists[3].nodes[index].signature;
3578 if (signature == pixel_list->signature)
3579 pixel_list->lists[3].nodes[index].count++;
3581 AddNodePixelList(pixel_list,3,index);
3582 if (image->colorspace == CMYKColorspace)
3583 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3584 signature=pixel_list->lists[4].nodes[index].signature;
3585 if (signature == pixel_list->signature)
3586 pixel_list->lists[4].nodes[index].count++;
3588 AddNodePixelList(pixel_list,4,index);
3591 static void ResetPixelList(
PixelList *pixel_list)
3608 for (channel=0; channel < 5; channel++)
3610 list=pixel_list->lists+channel;
3611 root=list->nodes+65536UL;
3613 for (level=0; level < 9; level++)
3614 root->next[level]=65536UL;
3616 pixel_list->seed=pixel_list->signature++;
3619 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3620 const size_t width,
const size_t height,
ExceptionInfo *exception)
3625 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3627 return(statistic_image);
3630 MagickExport
Image *StatisticImageChannel(
const Image *image,
3631 const ChannelType channel,
const StatisticType type,
const size_t width,
3634 #define StatisticImageTag "Statistic/Image"
3650 **magick_restrict pixel_list;
3662 assert(image != (
Image *) NULL);
3663 assert(image->signature == MagickCoreSignature);
3664 if (IsEventLogging() != MagickFalse)
3665 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3667 assert(exception->signature == MagickCoreSignature);
3668 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3669 if (statistic_image == (
Image *) NULL)
3670 return((
Image *) NULL);
3671 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3673 InheritException(exception,&statistic_image->exception);
3674 statistic_image=DestroyImage(statistic_image);
3675 return((
Image *) NULL);
3677 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3679 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3681 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3684 statistic_image=DestroyImage(statistic_image);
3685 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3692 image_view=AcquireVirtualCacheView(image,exception);
3693 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3694 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3695 #pragma omp parallel for schedule(static) shared(progress,status) \
3696 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3698 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3701 id = GetOpenMPThreadId();
3704 *magick_restrict indexes;
3710 *magick_restrict statistic_indexes;
3718 if (status == MagickFalse)
3720 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3721 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3722 neighbor_height,exception);
3723 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3729 indexes=GetCacheViewVirtualIndexQueue(image_view);
3730 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3731 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3748 ResetPixelList(pixel_list[
id]);
3749 for (v=0; v < (ssize_t) neighbor_height; v++)
3751 for (u=0; u < (ssize_t) neighbor_width; u++)
3752 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3753 r+=image->columns+neighbor_width;
3754 s+=image->columns+neighbor_width;
3756 GetMagickPixelPacket(image,&pixel);
3757 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3758 neighbor_width*neighbor_height/2,&pixel);
3761 case GradientStatistic:
3767 GetMinimumPixelList(pixel_list[
id],&pixel);
3769 GetMaximumPixelList(pixel_list[
id],&pixel);
3771 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3772 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3773 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3774 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3775 if (image->colorspace == CMYKColorspace)
3776 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3779 case MaximumStatistic:
3781 GetMaximumPixelList(pixel_list[
id],&pixel);
3786 GetMeanPixelList(pixel_list[
id],&pixel);
3789 case MedianStatistic:
3792 GetMedianPixelList(pixel_list[
id],&pixel);
3795 case MinimumStatistic:
3797 GetMinimumPixelList(pixel_list[
id],&pixel);
3802 GetModePixelList(pixel_list[
id],&pixel);
3805 case NonpeakStatistic:
3807 GetNonpeakPixelList(pixel_list[
id],&pixel);
3810 case RootMeanSquareStatistic:
3812 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3815 case StandardDeviationStatistic:
3817 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3821 if ((channel & RedChannel) != 0)
3822 SetPixelRed(q,ClampToQuantum(pixel.red));
3823 if ((channel & GreenChannel) != 0)
3824 SetPixelGreen(q,ClampToQuantum(pixel.green));
3825 if ((channel & BlueChannel) != 0)
3826 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3827 if ((channel & OpacityChannel) != 0)
3828 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3829 if (((channel & IndexChannel) != 0) &&
3830 (image->colorspace == CMYKColorspace))
3831 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3835 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3837 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3842 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3844 if (proceed == MagickFalse)
3848 statistic_view=DestroyCacheView(statistic_view);
3849 image_view=DestroyCacheView(image_view);
3850 pixel_list=DestroyPixelListTLS(pixel_list);
3851 if (status == MagickFalse)
3852 statistic_image=DestroyImage(statistic_image);
3853 return(statistic_image);