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]);
195static inline double EvaluateMax(
const double x,
const double y)
202#if defined(__cplusplus) || defined(c_plusplus)
206static 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)
226static 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 (fabs(value) <= MagickEpsilon)
370 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
371 result=(double) -((MagickRealType) QuantumRange*pow(-(QuantumScale*
372 (
double) pixel),(
double) value));
374 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,
378 case RightShiftEvaluateOperator:
380 result=(MagickRealType) pixel;
381 for (i=0; i < (ssize_t) value; i++)
385 case RootMeanSquareEvaluateOperator:
387 result=((MagickRealType) pixel*(MagickRealType) pixel+value);
390 case SetEvaluateOperator:
395 case SineEvaluateOperator:
397 result=(MagickRealType) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
398 QuantumScale*(MagickRealType) pixel*value))+0.5);
401 case SubtractEvaluateOperator:
403 result=(MagickRealType) pixel-value;
406 case SumEvaluateOperator:
408 result=(MagickRealType) pixel+value;
411 case ThresholdEvaluateOperator:
413 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
417 case ThresholdBlackEvaluateOperator:
419 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
422 case ThresholdWhiteEvaluateOperator:
424 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
428 case UniformNoiseEvaluateOperator:
430 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
434 case XorEvaluateOperator:
436 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
455 columns=images->columns;
458 for (p=images; p != (
Image *) NULL; p=p->next)
464 if (p->matte != MagickFalse)
466 if (p->colorspace == CMYKColorspace)
468 if (channels > number_channels)
470 number_channels=channels;
473 if (p->columns > columns)
478 return(CloneImage(q,columns,rows,MagickTrue,exception));
481MagickExport MagickBooleanType EvaluateImage(
Image *image,
482 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
487 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
491MagickExport
Image *EvaluateImages(
const Image *images,
494#define EvaluateImageTag "Evaluate/Image"
509 **magick_restrict evaluate_pixels,
513 **magick_restrict random_info;
521#if defined(MAGICKCORE_OPENMP_SUPPORT)
526 assert(images != (
Image *) NULL);
527 assert(images->signature == MagickCoreSignature);
529 assert(exception->signature == MagickCoreSignature);
530 if (IsEventLogging() != MagickFalse)
531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
532 image=AcquireImageCanvas(images,exception);
533 if (image == (
Image *) NULL)
534 return((
Image *) NULL);
535 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
537 InheritException(exception,&image->exception);
538 image=DestroyImage(image);
539 return((
Image *) NULL);
541 evaluate_pixels=AcquirePixelTLS(images);
544 image=DestroyImage(image);
545 (void) ThrowMagickException(exception,GetMagickModule(),
546 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
547 return((
Image *) NULL);
554 number_images=GetImageListLength(images);
555 GetMagickPixelPacket(images,&zero);
556 random_info=AcquireRandomInfoTLS();
557 evaluate_view=AcquireAuthenticCacheView(image,exception);
558 if (op == MedianEvaluateOperator)
560#if defined(MAGICKCORE_OPENMP_SUPPORT)
561 key=GetRandomSecretKey(random_info[0]);
562 #pragma omp parallel for schedule(static) shared(progress,status) \
563 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1)
565 for (y=0; y < (ssize_t) image->rows; y++)
574 id = GetOpenMPThreadId();
577 *magick_restrict evaluate_indexes;
588 if (status == MagickFalse)
590 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
597 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
598 evaluate_pixel=evaluate_pixels[id];
599 for (x=0; x < (ssize_t) image->columns; x++)
604 for (i=0; i < (ssize_t) number_images; i++)
605 evaluate_pixel[i]=zero;
607 for (i=0; i < (ssize_t) number_images; i++)
615 image_view=AcquireVirtualCacheView(next,exception);
616 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
619 image_view=DestroyCacheView(image_view);
622 indexes=GetCacheViewVirtualIndexQueue(image_view);
623 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
624 GetPixelRed(p),op,evaluate_pixel[i].red);
625 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
626 GetPixelGreen(p),op,evaluate_pixel[i].green);
627 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
628 GetPixelBlue(p),op,evaluate_pixel[i].blue);
629 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
630 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
631 if (image->colorspace == CMYKColorspace)
632 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
633 *indexes,op,evaluate_pixel[i].index);
634 image_view=DestroyCacheView(image_view);
635 next=GetNextImageInList(next);
637 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
639 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
640 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
641 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
642 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
643 if (image->colorspace == CMYKColorspace)
644 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
645 evaluate_pixel[i/2].index));
648 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
650 if (images->progress_monitor != (MagickProgressMonitor) NULL)
655#if defined(MAGICKCORE_OPENMP_SUPPORT)
659 proceed=SetImageProgress(images,EvaluateImageTag,progress,
661 if (proceed == MagickFalse)
668#if defined(MAGICKCORE_OPENMP_SUPPORT)
669 key=GetRandomSecretKey(random_info[0]);
670 #pragma omp parallel for schedule(static) shared(progress,status) \
671 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1)
673 for (y=0; y < (ssize_t) image->rows; y++)
682 id = GetOpenMPThreadId();
685 *magick_restrict evaluate_indexes;
697 if (status == MagickFalse)
699 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
706 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
707 evaluate_pixel=evaluate_pixels[id];
708 for (x=0; x < (ssize_t) image->columns; x++)
709 evaluate_pixel[x]=zero;
711 for (i=0; i < (ssize_t) number_images; i++)
719 image_view=AcquireVirtualCacheView(next,exception);
720 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
724 image_view=DestroyCacheView(image_view);
727 indexes=GetCacheViewVirtualIndexQueue(image_view);
728 for (x=0; x < (ssize_t) image->columns; x++)
730 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
731 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
732 evaluate_pixel[x].red);
733 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
734 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
735 evaluate_pixel[x].green);
736 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
737 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
738 evaluate_pixel[x].blue);
739 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
740 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
741 evaluate_pixel[x].opacity);
742 if (image->colorspace == CMYKColorspace)
743 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
744 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
745 evaluate_pixel[x].index);
748 image_view=DestroyCacheView(image_view);
749 next=GetNextImageInList(next);
751 if (op == MeanEvaluateOperator)
752 for (x=0; x < (ssize_t) image->columns; x++)
754 evaluate_pixel[x].red/=number_images;
755 evaluate_pixel[x].green/=number_images;
756 evaluate_pixel[x].blue/=number_images;
757 evaluate_pixel[x].opacity/=number_images;
758 evaluate_pixel[x].index/=number_images;
760 if (op == RootMeanSquareEvaluateOperator)
761 for (x=0; x < (ssize_t) image->columns; x++)
763 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
765 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
767 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
769 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
771 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
774 if (op == MultiplyEvaluateOperator)
775 for (x=0; x < (ssize_t) image->columns; x++)
780 for (j=0; j < (ssize_t) (number_images-1); j++)
782 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
785 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
786 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
789 for (x=0; x < (ssize_t) image->columns; x++)
791 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
792 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
793 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
794 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
795 if (image->colorspace == CMYKColorspace)
796 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
797 evaluate_pixel[x].index));
800 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
802 if (images->progress_monitor != (MagickProgressMonitor) NULL)
807 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
809 if (proceed == MagickFalse)
814 evaluate_view=DestroyCacheView(evaluate_view);
815 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
816 random_info=DestroyRandomInfoTLS(random_info);
817 if (status == MagickFalse)
818 image=DestroyImage(image);
822MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
823 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
836 **magick_restrict random_info;
841#if defined(MAGICKCORE_OPENMP_SUPPORT)
846 assert(image != (
Image *) NULL);
847 assert(image->signature == MagickCoreSignature);
849 assert(exception->signature == MagickCoreSignature);
850 if (IsEventLogging() != MagickFalse)
851 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
852 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
854 InheritException(exception,&image->exception);
859 random_info=AcquireRandomInfoTLS();
860 image_view=AcquireAuthenticCacheView(image,exception);
861#if defined(MAGICKCORE_OPENMP_SUPPORT)
862 key=GetRandomSecretKey(random_info[0]);
863 #pragma omp parallel for schedule(static) shared(progress,status) \
864 magick_number_threads(image,image,image->rows,key == ~0UL ? 0 : 1)
866 for (y=0; y < (ssize_t) image->rows; y++)
869 id = GetOpenMPThreadId();
872 *magick_restrict indexes;
880 if (status == MagickFalse)
882 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
888 indexes=GetCacheViewAuthenticIndexQueue(image_view);
889 for (x=0; x < (ssize_t) image->columns; x++)
894 if ((channel & RedChannel) != 0)
896 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
897 if (op == MeanEvaluateOperator)
899 SetPixelRed(q,ClampToQuantum(result));
901 if ((channel & GreenChannel) != 0)
903 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
905 if (op == MeanEvaluateOperator)
907 SetPixelGreen(q,ClampToQuantum(result));
909 if ((channel & BlueChannel) != 0)
911 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
913 if (op == MeanEvaluateOperator)
915 SetPixelBlue(q,ClampToQuantum(result));
917 if ((channel & OpacityChannel) != 0)
919 if (image->matte == MagickFalse)
921 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
923 if (op == MeanEvaluateOperator)
925 SetPixelOpacity(q,ClampToQuantum(result));
929 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
931 if (op == MeanEvaluateOperator)
933 SetPixelAlpha(q,ClampToQuantum(result));
936 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
938 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
940 if (op == MeanEvaluateOperator)
942 SetPixelIndex(indexes+x,ClampToQuantum(result));
946 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
948 if (image->progress_monitor != (MagickProgressMonitor) NULL)
953 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
954 if (proceed == MagickFalse)
958 image_view=DestroyCacheView(image_view);
959 random_info=DestroyRandomInfoTLS(random_info);
1003static Quantum ApplyFunction(Quantum pixel,
const MagickFunction function,
1004 const size_t number_parameters,
const double *parameters,
1017 case PolynomialFunction:
1025 for (i=0; i < (ssize_t) number_parameters; i++)
1026 result=result*QuantumScale*(MagickRealType) pixel+parameters[i];
1027 result*=(MagickRealType) QuantumRange;
1030 case SinusoidFunction:
1035 double freq,phase,ampl,bias;
1036 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1037 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1038 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1039 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1040 result=(MagickRealType) QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1041 (freq*QuantumScale*(MagickRealType) pixel+phase/360.0)))+bias);
1044 case ArcsinFunction:
1055 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1056 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1057 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1058 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1059 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*(MagickRealType)
1062 result=bias-range/2.0;
1065 result=bias+range/2.0;
1067 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1068 result*=(MagickRealType) QuantumRange;
1071 case ArctanFunction:
1076 double slope,range,center,bias;
1077 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1078 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1079 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1080 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1081 result=(MagickRealType) (MagickPI*slope*(QuantumScale*(MagickRealType)
1083 result=(MagickRealType) QuantumRange*(range/MagickPI*atan((
double)
1087 case UndefinedFunction:
1090 return(ClampToQuantum(result));
1093MagickExport MagickBooleanType FunctionImage(
Image *image,
1094 const MagickFunction function,
const size_t number_parameters,
1100 status=FunctionImageChannel(image,CompositeChannels,function,
1101 number_parameters,parameters,exception);
1105MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1106 const ChannelType channel,
const MagickFunction function,
1107 const size_t number_parameters,
const double *parameters,
1110#define FunctionImageTag "Function/Image "
1124 assert(image != (
Image *) NULL);
1125 assert(image->signature == MagickCoreSignature);
1127 assert(exception->signature == MagickCoreSignature);
1128 if (IsEventLogging() != MagickFalse)
1129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1130 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1132 InheritException(exception,&image->exception);
1133 return(MagickFalse);
1135#if defined(MAGICKCORE_OPENCL_SUPPORT)
1136 status=AccelerateFunctionImage(image,channel,function,number_parameters,
1137 parameters,exception);
1138 if (status != MagickFalse)
1143 image_view=AcquireAuthenticCacheView(image,exception);
1144#if defined(MAGICKCORE_OPENMP_SUPPORT)
1145 #pragma omp parallel for schedule(static) shared(progress,status) \
1146 magick_number_threads(image,image,image->rows,2)
1148 for (y=0; y < (ssize_t) image->rows; y++)
1151 *magick_restrict indexes;
1159 if (status == MagickFalse)
1161 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1167 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1168 for (x=0; x < (ssize_t) image->columns; x++)
1170 if ((channel & RedChannel) != 0)
1171 SetPixelRed(q,ApplyFunction(GetPixelRed(q),function,
1172 number_parameters,parameters,exception));
1173 if ((channel & GreenChannel) != 0)
1174 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),function,
1175 number_parameters,parameters,exception));
1176 if ((channel & BlueChannel) != 0)
1177 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),function,
1178 number_parameters,parameters,exception));
1179 if ((channel & OpacityChannel) != 0)
1181 if (image->matte == MagickFalse)
1182 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),function,
1183 number_parameters,parameters,exception));
1185 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),function,
1186 number_parameters,parameters,exception));
1188 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1189 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),function,
1190 number_parameters,parameters,exception));
1193 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1195 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1200 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1201 if (proceed == MagickFalse)
1205 image_view=DestroyCacheView(image_view);
1239MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1245 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1249MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1250 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1253 *channel_statistics;
1258 assert(image != (
Image *) NULL);
1259 assert(image->signature == MagickCoreSignature);
1260 if (IsEventLogging() != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1262 channel_statistics=GetImageChannelStatistics(image,exception);
1264 return(MagickFalse);
1266 channel_statistics[CompositeChannels].entropy=0.0;
1267 if ((channel & RedChannel) != 0)
1269 channel_statistics[CompositeChannels].entropy+=
1270 channel_statistics[RedChannel].entropy;
1273 if ((channel & GreenChannel) != 0)
1275 channel_statistics[CompositeChannels].entropy+=
1276 channel_statistics[GreenChannel].entropy;
1279 if ((channel & BlueChannel) != 0)
1281 channel_statistics[CompositeChannels].entropy+=
1282 channel_statistics[BlueChannel].entropy;
1285 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1287 channel_statistics[CompositeChannels].entropy+=
1288 channel_statistics[OpacityChannel].entropy;
1291 if (((channel & IndexChannel) != 0) &&
1292 (image->colorspace == CMYKColorspace))
1294 channel_statistics[CompositeChannels].entropy+=
1295 channel_statistics[BlackChannel].entropy;
1298 channel_statistics[CompositeChannels].entropy/=channels;
1299 *entropy=channel_statistics[CompositeChannels].entropy;
1301 channel_statistics);
1338MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1344 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1349MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1350 const ChannelType channel,
size_t *minima,
size_t *maxima,
1360 assert(image != (
Image *) NULL);
1361 assert(image->signature == MagickCoreSignature);
1362 if (IsEventLogging() != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1364 status=GetImageChannelRange(image,channel,&min,&max,exception);
1365 *minima=(size_t) ceil(min-0.5);
1366 *maxima=(size_t) floor(max+0.5);
1404MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1410 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1415MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1416 const ChannelType channel,
double *kurtosis,
double *skewness,
1430 assert(image != (
Image *) NULL);
1431 assert(image->signature == MagickCoreSignature);
1432 if (IsEventLogging() != MagickFalse)
1433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1438 standard_deviation=0.0;
1441 sum_fourth_power=0.0;
1442 for (y=0; y < (ssize_t) image->rows; y++)
1445 *magick_restrict indexes;
1453 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1456 indexes=GetVirtualIndexQueue(image);
1457 for (x=0; x < (ssize_t) image->columns; x++)
1459 if ((channel & RedChannel) != 0)
1461 mean+=QuantumScale*GetPixelRed(p);
1462 sum_squares+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
1463 sum_cubes+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
1464 QuantumScale*GetPixelRed(p);
1465 sum_fourth_power+=QuantumScale*GetPixelRed(p)*QuantumScale*
1466 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*
1470 if ((channel & GreenChannel) != 0)
1472 mean+=QuantumScale*GetPixelGreen(p);
1473 sum_squares+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1475 sum_cubes+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1476 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
1477 sum_fourth_power+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1478 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
1482 if ((channel & BlueChannel) != 0)
1484 mean+=QuantumScale*GetPixelBlue(p);
1485 sum_squares+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1487 sum_cubes+=QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*
1488 QuantumScale*GetPixelBlue(p);
1489 sum_fourth_power+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1490 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
1494 if ((channel & OpacityChannel) != 0)
1496 mean+=QuantumScale*GetPixelAlpha(p);
1497 sum_squares+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1499 sum_cubes+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1500 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
1501 sum_fourth_power+=QuantumScale*GetPixelAlpha(p)*QuantumScale*
1502 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*GetPixelAlpha(p);
1505 if (((channel & IndexChannel) != 0) &&
1506 (image->colorspace == CMYKColorspace))
1511 index=QuantumScale*GetPixelIndex(indexes+x);
1513 sum_squares+=index*index;
1514 sum_cubes+=index*index*index;
1515 sum_fourth_power+=index*index*index*index;
1521 if (y < (ssize_t) image->rows)
1522 return(MagickFalse);
1528 sum_fourth_power/=area;
1530 standard_deviation=sqrt(sum_squares-(mean*mean));
1531 if (standard_deviation != 0.0)
1533 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1534 3.0*mean*mean*mean*mean;
1535 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1538 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1539 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1541 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1578MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1584 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1589MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1590 const ChannelType channel,
double *mean,
double *standard_deviation,
1594 *channel_statistics;
1599 assert(image != (
Image *) NULL);
1600 assert(image->signature == MagickCoreSignature);
1601 if (IsEventLogging() != MagickFalse)
1602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1603 channel_statistics=GetImageChannelStatistics(image,exception);
1607 *standard_deviation=NAN;
1608 return(MagickFalse);
1611 channel_statistics[CompositeChannels].mean=0.0;
1612 channel_statistics[CompositeChannels].standard_deviation=0.0;
1613 if ((channel & RedChannel) != 0)
1615 channel_statistics[CompositeChannels].mean+=
1616 channel_statistics[RedChannel].mean;
1617 channel_statistics[CompositeChannels].standard_deviation+=
1618 channel_statistics[RedChannel].standard_deviation;
1621 if ((channel & GreenChannel) != 0)
1623 channel_statistics[CompositeChannels].mean+=
1624 channel_statistics[GreenChannel].mean;
1625 channel_statistics[CompositeChannels].standard_deviation+=
1626 channel_statistics[GreenChannel].standard_deviation;
1629 if ((channel & BlueChannel) != 0)
1631 channel_statistics[CompositeChannels].mean+=
1632 channel_statistics[BlueChannel].mean;
1633 channel_statistics[CompositeChannels].standard_deviation+=
1634 channel_statistics[BlueChannel].standard_deviation;
1637 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1639 channel_statistics[CompositeChannels].mean+=
1640 channel_statistics[OpacityChannel].mean;
1641 channel_statistics[CompositeChannels].standard_deviation+=
1642 channel_statistics[OpacityChannel].standard_deviation;
1645 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1647 channel_statistics[CompositeChannels].mean+=
1648 channel_statistics[BlackChannel].mean;
1649 channel_statistics[CompositeChannels].standard_deviation+=
1650 channel_statistics[CompositeChannels].standard_deviation;
1653 channel_statistics[CompositeChannels].mean/=channels;
1654 channel_statistics[CompositeChannels].standard_deviation/=channels;
1655 *mean=channel_statistics[CompositeChannels].mean;
1656 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1658 channel_statistics);
1691#define MaxNumberImageMoments 8
1697 M00[CompositeChannels+1],
1698 M01[CompositeChannels+1],
1699 M02[CompositeChannels+1],
1700 M03[CompositeChannels+1],
1701 M10[CompositeChannels+1],
1702 M11[CompositeChannels+1],
1703 M12[CompositeChannels+1],
1704 M20[CompositeChannels+1],
1705 M21[CompositeChannels+1],
1706 M22[CompositeChannels+1],
1707 M30[CompositeChannels+1];
1713 centroid[CompositeChannels+1];
1723 assert(image != (
Image *) NULL);
1724 assert(image->signature == MagickCoreSignature);
1725 if (IsEventLogging() != MagickFalse)
1726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1727 length=CompositeChannels+1UL;
1729 sizeof(*channel_moments));
1731 return(channel_moments);
1732 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1733 (void) memset(centroid,0,
sizeof(centroid));
1734 (void) memset(M00,0,
sizeof(M00));
1735 (void) memset(M01,0,
sizeof(M01));
1736 (void) memset(M02,0,
sizeof(M02));
1737 (void) memset(M03,0,
sizeof(M03));
1738 (void) memset(M10,0,
sizeof(M10));
1739 (void) memset(M11,0,
sizeof(M11));
1740 (void) memset(M12,0,
sizeof(M12));
1741 (void) memset(M20,0,
sizeof(M20));
1742 (void) memset(M21,0,
sizeof(M21));
1743 (void) memset(M22,0,
sizeof(M22));
1744 (void) memset(M30,0,
sizeof(M30));
1745 GetMagickPixelPacket(image,&pixel);
1746 for (y=0; y < (ssize_t) image->rows; y++)
1749 *magick_restrict indexes;
1760 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1763 indexes=GetVirtualIndexQueue(image);
1764 for (x=0; x < (ssize_t) image->columns; x++)
1766 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1767 M00[RedChannel]+=QuantumScale*pixel.red;
1768 M10[RedChannel]+=x*QuantumScale*pixel.red;
1769 M01[RedChannel]+=y*QuantumScale*pixel.red;
1770 M00[GreenChannel]+=QuantumScale*pixel.green;
1771 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1772 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1773 M00[BlueChannel]+=QuantumScale*pixel.blue;
1774 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1775 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1776 if (image->matte != MagickFalse)
1778 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1779 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1780 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1782 if (image->colorspace == CMYKColorspace)
1784 M00[IndexChannel]+=QuantumScale*pixel.index;
1785 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1786 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1791 for (channel=0; channel <= CompositeChannels; channel++)
1796 if (M00[channel] < MagickEpsilon)
1798 M00[channel]+=MagickEpsilon;
1799 centroid[channel].x=(double) image->columns/2.0;
1800 centroid[channel].y=(double) image->rows/2.0;
1803 M00[channel]+=MagickEpsilon;
1804 centroid[channel].x=M10[channel]/M00[channel];
1805 centroid[channel].y=M01[channel]/M00[channel];
1807 for (y=0; y < (ssize_t) image->rows; y++)
1810 *magick_restrict indexes;
1821 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1824 indexes=GetVirtualIndexQueue(image);
1825 for (x=0; x < (ssize_t) image->columns; x++)
1827 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1828 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1829 centroid[RedChannel].y)*QuantumScale*pixel.red;
1830 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1831 centroid[RedChannel].x)*QuantumScale*pixel.red;
1832 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1833 centroid[RedChannel].y)*QuantumScale*pixel.red;
1834 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1835 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1837 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1838 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1840 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1841 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1842 centroid[RedChannel].y)*QuantumScale*pixel.red;
1843 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1844 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1846 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1847 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1849 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1850 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1851 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1852 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1853 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1854 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1855 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1856 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1858 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1859 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1861 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1862 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1863 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1864 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1865 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1867 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1868 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1870 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1871 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1872 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1873 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1874 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1875 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1876 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1877 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1879 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1880 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1882 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1883 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1884 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1885 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1886 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1888 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1889 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1891 if (image->matte != MagickFalse)
1893 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1894 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1895 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1896 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1897 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1898 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1899 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1900 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1901 QuantumScale*pixel.opacity;
1902 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1903 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1904 QuantumScale*pixel.opacity;
1905 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1906 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1907 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1908 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1909 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1910 QuantumScale*pixel.opacity;
1911 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1912 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1913 QuantumScale*pixel.opacity;
1915 if (image->colorspace == CMYKColorspace)
1917 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1918 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1919 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1920 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1921 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1922 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1923 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1924 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1925 QuantumScale*pixel.index;
1926 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1927 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1928 QuantumScale*pixel.index;
1929 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1930 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1931 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1932 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1933 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1934 QuantumScale*pixel.index;
1935 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1936 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1937 QuantumScale*pixel.index;
1943 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1944 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1945 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1946 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1947 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1948 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1949 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1950 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1951 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1952 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1953 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1954 if (image->matte != MagickFalse)
1957 M00[CompositeChannels]+=M00[OpacityChannel];
1958 M01[CompositeChannels]+=M01[OpacityChannel];
1959 M02[CompositeChannels]+=M02[OpacityChannel];
1960 M03[CompositeChannels]+=M03[OpacityChannel];
1961 M10[CompositeChannels]+=M10[OpacityChannel];
1962 M11[CompositeChannels]+=M11[OpacityChannel];
1963 M12[CompositeChannels]+=M12[OpacityChannel];
1964 M20[CompositeChannels]+=M20[OpacityChannel];
1965 M21[CompositeChannels]+=M21[OpacityChannel];
1966 M22[CompositeChannels]+=M22[OpacityChannel];
1967 M30[CompositeChannels]+=M30[OpacityChannel];
1969 if (image->colorspace == CMYKColorspace)
1972 M00[CompositeChannels]+=M00[IndexChannel];
1973 M01[CompositeChannels]+=M01[IndexChannel];
1974 M02[CompositeChannels]+=M02[IndexChannel];
1975 M03[CompositeChannels]+=M03[IndexChannel];
1976 M10[CompositeChannels]+=M10[IndexChannel];
1977 M11[CompositeChannels]+=M11[IndexChannel];
1978 M12[CompositeChannels]+=M12[IndexChannel];
1979 M20[CompositeChannels]+=M20[IndexChannel];
1980 M21[CompositeChannels]+=M21[IndexChannel];
1981 M22[CompositeChannels]+=M22[IndexChannel];
1982 M30[CompositeChannels]+=M30[IndexChannel];
1984 M00[CompositeChannels]/=(double) channels;
1985 M01[CompositeChannels]/=(double) channels;
1986 M02[CompositeChannels]/=(double) channels;
1987 M03[CompositeChannels]/=(double) channels;
1988 M10[CompositeChannels]/=(double) channels;
1989 M11[CompositeChannels]/=(double) channels;
1990 M12[CompositeChannels]/=(double) channels;
1991 M20[CompositeChannels]/=(double) channels;
1992 M21[CompositeChannels]/=(double) channels;
1993 M22[CompositeChannels]/=(double) channels;
1994 M30[CompositeChannels]/=(double) channels;
1995 for (channel=0; channel <= CompositeChannels; channel++)
2000 channel_moments[channel].centroid=centroid[channel];
2001 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
2002 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
2003 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2004 (M20[channel]-M02[channel]))));
2005 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
2006 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
2007 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2008 (M20[channel]-M02[channel]))));
2009 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
2010 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
2011 if (fabs(M11[channel]) < 0.0)
2013 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2014 ((M20[channel]-M02[channel]) < 0.0))
2015 channel_moments[channel].ellipse_angle+=90.0;
2018 if (M11[channel] < 0.0)
2020 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2022 if ((M20[channel]-M02[channel]) < 0.0)
2023 channel_moments[channel].ellipse_angle+=90.0;
2025 channel_moments[channel].ellipse_angle+=180.0;
2029 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2030 ((M20[channel]-M02[channel]) < 0.0))
2031 channel_moments[channel].ellipse_angle+=90.0;
2032 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2033 channel_moments[channel].ellipse_axis.y*
2034 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2035 channel_moments[channel].ellipse_axis.x*
2036 channel_moments[channel].ellipse_axis.x)));
2037 channel_moments[channel].ellipse_intensity=M00[channel]/
2038 (MagickPI*channel_moments[channel].ellipse_axis.x*
2039 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2041 for (channel=0; channel <= CompositeChannels; channel++)
2048 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2049 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2050 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2051 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2052 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2053 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2054 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2055 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2058 for (channel=0; channel <= CompositeChannels; channel++)
2063 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2064 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2065 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2066 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2067 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2068 (3.0*M21[channel]-M03[channel]);
2069 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2070 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2071 (M21[channel]+M03[channel]);
2072 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2073 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2074 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2075 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2076 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2077 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2078 (M21[channel]+M03[channel]));
2079 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2080 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2081 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2082 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2083 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2084 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2085 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2086 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2087 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2088 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2089 (M21[channel]+M03[channel]));
2090 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2091 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2092 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2093 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2095 if (y < (ssize_t) image->rows)
2096 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2097 return(channel_moments);
2150 hash_image=BlurImage(image,0.0,1.0,exception);
2151 if (hash_image == (
Image *) NULL)
2153 hash_image->depth=8;
2154 status=TransformImageColorspace(hash_image,xyYColorspace);
2155 if (status == MagickFalse)
2157 moments=GetImageChannelMoments(hash_image,exception);
2158 hash_image=DestroyImage(hash_image);
2162 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2165 for (channel=0; channel <= CompositeChannels; channel++)
2166 for (i=0; i < MaximumNumberOfImageMoments; i++)
2167 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2172 hash_image=BlurImage(image,0.0,1.0,exception);
2173 if (hash_image == (
Image *) NULL)
2179 hash_image->depth=8;
2180 status=TransformImageColorspace(hash_image,HSBColorspace);
2181 if (status == MagickFalse)
2187 moments=GetImageChannelMoments(hash_image,exception);
2188 hash_image=DestroyImage(hash_image);
2195 for (channel=0; channel <= CompositeChannels; channel++)
2196 for (i=0; i < MaximumNumberOfImageMoments; i++)
2197 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2199 return(perceptual_hash);
2235MagickExport MagickBooleanType GetImageRange(
const Image *image,
2238 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2241MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2242 const ChannelType channel,
double *minima,
double *maxima,
2251 assert(image != (
Image *) NULL);
2252 assert(image->signature == MagickCoreSignature);
2253 if (IsEventLogging() != MagickFalse)
2254 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2255 *maxima=(-MagickMaximumValue);
2256 *minima=MagickMaximumValue;
2257 GetMagickPixelPacket(image,&pixel);
2258 for (y=0; y < (ssize_t) image->rows; y++)
2261 *magick_restrict indexes;
2269 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2272 indexes=GetVirtualIndexQueue(image);
2273 for (x=0; x < (ssize_t) image->columns; x++)
2275 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2276 if ((channel & RedChannel) != 0)
2278 if (pixel.red < *minima)
2279 *minima=(double) pixel.red;
2280 if (pixel.red > *maxima)
2281 *maxima=(double) pixel.red;
2283 if ((channel & GreenChannel) != 0)
2285 if (pixel.green < *minima)
2286 *minima=(double) pixel.green;
2287 if (pixel.green > *maxima)
2288 *maxima=(double) pixel.green;
2290 if ((channel & BlueChannel) != 0)
2292 if (pixel.blue < *minima)
2293 *minima=(double) pixel.blue;
2294 if (pixel.blue > *maxima)
2295 *maxima=(double) pixel.blue;
2297 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2299 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2300 *minima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2302 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2303 *maxima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2306 if (((channel & IndexChannel) != 0) &&
2307 (image->colorspace == CMYKColorspace))
2309 if ((
double) pixel.index < *minima)
2310 *minima=(double) pixel.index;
2311 if ((
double) pixel.index > *maxima)
2312 *maxima=(double) pixel.index;
2317 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2357 *channel_statistics;
2379 assert(image != (
Image *) NULL);
2380 assert(image->signature == MagickCoreSignature);
2381 if (IsEventLogging() != MagickFalse)
2382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2383 length=CompositeChannels+1UL;
2385 sizeof(*channel_statistics));
2387 sizeof(*histogram));
2395 channel_statistics);
2396 return(channel_statistics);
2398 (void) memset(channel_statistics,0,length*
2399 sizeof(*channel_statistics));
2400 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2402 channel_statistics[i].depth=1;
2403 channel_statistics[i].maxima=(-MagickMaximumValue);
2404 channel_statistics[i].minima=MagickMaximumValue;
2406 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2407 (void) memset(&number_bins,0,
sizeof(number_bins));
2408 for (y=0; y < (ssize_t) image->rows; y++)
2411 *magick_restrict indexes;
2422 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2425 indexes=GetVirtualIndexQueue(image);
2426 for (x=0; x < (ssize_t) image->columns; )
2428 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2430 depth=channel_statistics[RedChannel].depth;
2431 range=GetQuantumRange(depth);
2432 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2434 channel_statistics[RedChannel].depth++;
2438 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2440 depth=channel_statistics[GreenChannel].depth;
2441 range=GetQuantumRange(depth);
2442 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2444 channel_statistics[GreenChannel].depth++;
2448 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2450 depth=channel_statistics[BlueChannel].depth;
2451 range=GetQuantumRange(depth);
2452 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2454 channel_statistics[BlueChannel].depth++;
2458 if (image->matte != MagickFalse)
2460 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2462 depth=channel_statistics[OpacityChannel].depth;
2463 range=GetQuantumRange(depth);
2464 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2466 channel_statistics[OpacityChannel].depth++;
2471 if (image->colorspace == CMYKColorspace)
2473 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2475 depth=channel_statistics[BlackChannel].depth;
2476 range=GetQuantumRange(depth);
2477 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2479 channel_statistics[BlackChannel].depth++;
2484 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2485 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2486 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2487 channel_statistics[RedChannel].maxima=(double) GetPixelRed(p);
2488 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2489 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2490 QuantumScale*GetPixelRed(p);
2491 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2492 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2493 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2494 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2495 QuantumScale*GetPixelRed(p);
2496 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2497 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2498 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2499 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(p);
2500 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2501 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2502 QuantumScale*GetPixelGreen(p);
2503 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2504 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2505 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2506 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2507 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2508 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2509 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2510 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2511 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(p);
2512 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2513 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2514 QuantumScale*GetPixelBlue(p);
2515 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2516 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2517 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2518 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2519 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2520 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2521 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2522 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2523 if (image->matte != MagickFalse)
2525 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2526 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2527 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2528 channel_statistics[OpacityChannel].maxima=(double) GetPixelAlpha(p);
2529 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2530 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2531 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2532 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2533 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2535 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2536 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2537 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2538 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2540 if (image->colorspace == CMYKColorspace)
2542 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2543 channel_statistics[BlackChannel].minima=(double)
2544 GetPixelIndex(indexes+x);
2545 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2546 channel_statistics[BlackChannel].maxima=(double)
2547 GetPixelIndex(indexes+x);
2548 channel_statistics[BlackChannel].sum+=QuantumScale*
2549 GetPixelIndex(indexes+x);
2550 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2551 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2552 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2553 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2554 QuantumScale*GetPixelIndex(indexes+x);
2555 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2556 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2557 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2558 GetPixelIndex(indexes+x);
2559 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2565 for (i=0; i < (ssize_t) CompositeChannels; i++)
2575 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2576 mean=channel_statistics[i].sum*area;
2577 channel_statistics[i].sum=mean;
2578 channel_statistics[i].sum_squared*=area;
2579 channel_statistics[i].sum_cubed*=area;
2580 channel_statistics[i].sum_fourth_power*=area;
2581 channel_statistics[i].mean=mean;
2582 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2583 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2584 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2585 ((double) image->columns*image->rows);
2586 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2587 channel_statistics[i].standard_deviation=standard_deviation;
2589 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2591 if (histogram[i].red > 0.0)
2593 if (histogram[i].green > 0.0)
2594 number_bins.green++;
2595 if (histogram[i].blue > 0.0)
2597 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2598 number_bins.opacity++;
2599 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2600 number_bins.index++;
2602 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2603 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2608 histogram[i].red*=area;
2609 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2610 MagickLog10(histogram[i].red)*
2611 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2612 histogram[i].green*=area;
2613 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2614 MagickLog10(histogram[i].green)*
2615 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2616 histogram[i].blue*=area;
2617 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2618 MagickLog10(histogram[i].blue)*
2619 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2620 if (image->matte != MagickFalse)
2622 histogram[i].opacity*=area;
2623 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2624 MagickLog10(histogram[i].opacity)*
2625 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2627 if (image->colorspace == CMYKColorspace)
2629 histogram[i].index*=area;
2630 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2631 MagickLog10(histogram[i].index)*
2632 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2638 for (i=0; i < (ssize_t) CompositeChannels; i++)
2640 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2641 channel_statistics[CompositeChannels].depth,(
double)
2642 channel_statistics[i].depth);
2643 channel_statistics[CompositeChannels].minima=MagickMin(
2644 channel_statistics[CompositeChannels].minima,
2645 channel_statistics[i].minima);
2646 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2647 channel_statistics[CompositeChannels].maxima,
2648 channel_statistics[i].maxima);
2649 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2650 channel_statistics[CompositeChannels].sum_squared+=
2651 channel_statistics[i].sum_squared;
2652 channel_statistics[CompositeChannels].sum_cubed+=
2653 channel_statistics[i].sum_cubed;
2654 channel_statistics[CompositeChannels].sum_fourth_power+=
2655 channel_statistics[i].sum_fourth_power;
2656 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2657 channel_statistics[CompositeChannels].variance+=
2658 channel_statistics[i].variance-channel_statistics[i].mean*
2659 channel_statistics[i].mean;
2660 standard_deviation=sqrt(channel_statistics[i].variance-
2661 (channel_statistics[i].mean*channel_statistics[i].mean));
2662 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2663 ((double) image->columns*image->rows);
2664 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2665 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2666 channel_statistics[CompositeChannels].entropy+=
2667 channel_statistics[i].entropy;
2670 if (image->matte != MagickFalse)
2672 if (image->colorspace == CMYKColorspace)
2674 channel_statistics[CompositeChannels].sum/=channels;
2675 channel_statistics[CompositeChannels].sum_squared/=channels;
2676 channel_statistics[CompositeChannels].sum_cubed/=channels;
2677 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2678 channel_statistics[CompositeChannels].mean/=channels;
2679 channel_statistics[CompositeChannels].kurtosis/=channels;
2680 channel_statistics[CompositeChannels].skewness/=channels;
2681 channel_statistics[CompositeChannels].entropy/=channels;
2682 i=CompositeChannels;
2683 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2684 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2685 channel_statistics[i].mean=channel_statistics[i].sum;
2686 standard_deviation=sqrt(channel_statistics[i].variance-
2687 (channel_statistics[i].mean*channel_statistics[i].mean));
2688 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2689 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2690 standard_deviation*standard_deviation);
2691 channel_statistics[i].standard_deviation=standard_deviation;
2692 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2697 standard_deviation=PerceptibleReciprocal(
2698 channel_statistics[i].standard_deviation);
2699 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2700 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2701 channel_statistics[i].mean*channel_statistics[i].mean*
2702 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2703 standard_deviation);
2704 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2705 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2706 channel_statistics[i].mean*channel_statistics[i].mean*
2707 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2708 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2709 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2710 standard_deviation*standard_deviation)-3.0;
2712 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2714 channel_statistics[i].mean*=QuantumRange;
2715 channel_statistics[i].variance*=QuantumRange;
2716 channel_statistics[i].standard_deviation*=QuantumRange;
2717 channel_statistics[i].sum*=QuantumRange;
2718 channel_statistics[i].sum_squared*=QuantumRange;
2719 channel_statistics[i].sum_cubed*=QuantumRange;
2720 channel_statistics[i].sum_fourth_power*=QuantumRange;
2722 channel_statistics[CompositeChannels].mean=0.0;
2723 channel_statistics[CompositeChannels].standard_deviation=0.0;
2724 for (i=0; i < (ssize_t) CompositeChannels; i++)
2726 channel_statistics[CompositeChannels].mean+=
2727 channel_statistics[i].mean;
2728 channel_statistics[CompositeChannels].standard_deviation+=
2729 channel_statistics[i].standard_deviation;
2731 channel_statistics[CompositeChannels].mean/=(double) channels;
2732 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2734 if (y < (ssize_t) image->rows)
2736 channel_statistics);
2737 return(channel_statistics);
2778MagickExport
Image *PolynomialImage(
const Image *images,
2779 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2784 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2786 return(polynomial_image);
2789MagickExport
Image *PolynomialImageChannel(
const Image *images,
2790 const ChannelType channel,
const size_t number_terms,
const double *terms,
2793#define PolynomialImageTag "Polynomial/Image"
2808 **magick_restrict polynomial_pixels,
2814 assert(images != (
Image *) NULL);
2815 assert(images->signature == MagickCoreSignature);
2816 if (IsEventLogging() != MagickFalse)
2817 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2819 assert(exception->signature == MagickCoreSignature);
2820 image=AcquireImageCanvas(images,exception);
2821 if (image == (
Image *) NULL)
2822 return((
Image *) NULL);
2823 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2825 InheritException(exception,&image->exception);
2826 image=DestroyImage(image);
2827 return((
Image *) NULL);
2829 polynomial_pixels=AcquirePixelTLS(images);
2832 image=DestroyImage(image);
2833 (void) ThrowMagickException(exception,GetMagickModule(),
2834 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2835 return((
Image *) NULL);
2842 GetMagickPixelPacket(images,&zero);
2843 polynomial_view=AcquireAuthenticCacheView(image,exception);
2844#if defined(MAGICKCORE_OPENMP_SUPPORT)
2845 #pragma omp parallel for schedule(static) shared(progress,status) \
2846 magick_number_threads(image,image,image->rows,1)
2848 for (y=0; y < (ssize_t) image->rows; y++)
2857 id = GetOpenMPThreadId();
2860 *magick_restrict polynomial_indexes;
2875 if (status == MagickFalse)
2877 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2884 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2885 polynomial_pixel=polynomial_pixels[id];
2886 for (x=0; x < (ssize_t) image->columns; x++)
2887 polynomial_pixel[x]=zero;
2889 number_images=GetImageListLength(images);
2890 for (i=0; i < (ssize_t) number_images; i++)
2898 if (i >= (ssize_t) number_terms)
2900 image_view=AcquireVirtualCacheView(next,exception);
2901 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2904 image_view=DestroyCacheView(image_view);
2907 indexes=GetCacheViewVirtualIndexQueue(image_view);
2908 for (x=0; x < (ssize_t) image->columns; x++)
2914 coefficient=terms[i << 1];
2915 degree=terms[(i << 1)+1];
2916 if ((channel & RedChannel) != 0)
2917 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2919 if ((channel & GreenChannel) != 0)
2920 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2923 if ((channel & BlueChannel) != 0)
2924 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2926 if ((channel & OpacityChannel) != 0)
2927 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2928 ((
double) QuantumRange-(
double) p->opacity),degree);
2929 if (((channel & IndexChannel) != 0) &&
2930 (image->colorspace == CMYKColorspace))
2931 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2935 image_view=DestroyCacheView(image_view);
2936 next=GetNextImageInList(next);
2938 for (x=0; x < (ssize_t) image->columns; x++)
2940 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2941 polynomial_pixel[x].red));
2942 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2943 polynomial_pixel[x].green));
2944 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2945 polynomial_pixel[x].blue));
2946 if (image->matte == MagickFalse)
2947 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2948 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2950 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2951 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2952 if (image->colorspace == CMYKColorspace)
2953 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2954 QuantumRange*polynomial_pixel[x].index));
2957 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2959 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2964 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2966 if (proceed == MagickFalse)
2970 polynomial_view=DestroyCacheView(polynomial_view);
2971 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2972 if (status == MagickFalse)
2973 image=DestroyImage(image);
3015#define ListChannels 5
3042 lists[ListChannels];
3052 for (i=0; i < ListChannels; i++)
3053 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3054 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3055 pixel_list->lists[i].nodes);
3056 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3065 assert(pixel_list != (
PixelList **) NULL);
3066 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3067 if (pixel_list[i] != (
PixelList *) NULL)
3068 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3069 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3073static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3081 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3084 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3085 pixel_list->length=width*height;
3086 for (i=0; i < ListChannels; i++)
3088 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3089 sizeof(*pixel_list->lists[i].nodes));
3090 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3091 return(DestroyPixelList(pixel_list));
3092 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3093 sizeof(*pixel_list->lists[i].nodes));
3095 pixel_list->signature=MagickCoreSignature;
3099static PixelList **AcquirePixelListTLS(
const size_t width,
3100 const size_t height)
3111 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3112 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3113 sizeof(*pixel_list));
3116 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3117 for (i=0; i < (ssize_t) number_threads; i++)
3119 pixel_list[i]=AcquirePixelList(width,height);
3120 if (pixel_list[i] == (
PixelList *) NULL)
3121 return(DestroyPixelListTLS(pixel_list));
3126static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3142 list=pixel_list->lists+channel;
3143 list->nodes[color].signature=pixel_list->signature;
3144 list->nodes[color].count=1;
3149 (void) memset(update,0,
sizeof(update));
3150 for (level=list->level; level >= 0; level--)
3152 while (list->nodes[search].next[level] < color)
3153 search=list->nodes[search].next[level];
3154 update[level]=search;
3159 for (level=0; ; level++)
3161 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3162 if ((pixel_list->seed & 0x300) != 0x300)
3167 if (level > (list->level+2))
3168 level=list->level+2;
3172 while (level > list->level)
3175 update[list->level]=65536UL;
3182 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3183 list->nodes[update[level]].next[level]=color;
3184 }
while (level-- > 0);
3203 channels[ListChannels];
3208 for (channel=0; channel < 5; channel++)
3210 list=pixel_list->lists+channel;
3213 maximum=list->nodes[color].next[0];
3216 color=list->nodes[color].next[0];
3217 if (color > maximum)
3219 count+=list->nodes[color].count;
3220 }
while (count < (ssize_t) pixel_list->length);
3221 channels[channel]=(
unsigned short) maximum;
3223 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3224 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3225 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3226 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3227 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3248 channels[ListChannels];
3253 for (channel=0; channel < 5; channel++)
3255 list=pixel_list->lists+channel;
3261 color=list->nodes[color].next[0];
3262 sum+=(MagickRealType) list->nodes[color].count*color;
3263 count+=list->nodes[color].count;
3264 }
while (count < (ssize_t) pixel_list->length);
3265 sum/=pixel_list->length;
3266 channels[channel]=(
unsigned short) sum;
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]);
3290 channels[ListChannels];
3295 for (channel=0; channel < 5; channel++)
3297 list=pixel_list->lists+channel;
3302 color=list->nodes[color].next[0];
3303 count+=list->nodes[color].count;
3304 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3305 channels[channel]=(
unsigned short) color;
3307 GetMagickPixelPacket((
const Image *) NULL,pixel);
3308 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3309 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3310 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3311 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3312 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3331 channels[ListChannels];
3336 for (channel=0; channel < 5; channel++)
3338 list=pixel_list->lists+channel;
3341 minimum=list->nodes[color].next[0];
3344 color=list->nodes[color].next[0];
3345 if (color < minimum)
3347 count+=list->nodes[color].count;
3348 }
while (count < (ssize_t) pixel_list->length);
3349 channels[channel]=(
unsigned short) minimum;
3351 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3352 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3353 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3354 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3355 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3380 for (channel=0; channel < 5; channel++)
3382 list=pixel_list->lists+channel;
3385 max_count=list->nodes[mode].count;
3389 color=list->nodes[color].next[0];
3390 if (list->nodes[color].count > max_count)
3393 max_count=list->nodes[mode].count;
3395 count+=list->nodes[color].count;
3396 }
while (count < (ssize_t) pixel_list->length);
3397 channels[channel]=(
unsigned short) mode;
3399 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3400 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3401 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3402 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3403 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3428 for (channel=0; channel < 5; channel++)
3430 list=pixel_list->lists+channel;
3432 next=list->nodes[color].next[0];
3438 next=list->nodes[color].next[0];
3439 count+=list->nodes[color].count;
3440 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3441 if ((previous == 65536UL) && (next != 65536UL))
3444 if ((previous != 65536UL) && (next == 65536UL))
3446 channels[channel]=(
unsigned short) color;
3448 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3449 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3450 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3451 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3452 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3455static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3474 channels[ListChannels];
3479 for (channel=0; channel < 5; channel++)
3481 list=pixel_list->lists+channel;
3487 color=list->nodes[color].next[0];
3488 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3489 count+=list->nodes[color].count;
3490 }
while (count < (ssize_t) pixel_list->length);
3491 sum/=pixel_list->length;
3492 channels[channel]=(
unsigned short) sqrt(sum);
3494 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3495 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3496 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3497 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3498 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3501static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3519 channels[ListChannels];
3524 for (channel=0; channel < 5; channel++)
3526 list=pixel_list->lists+channel;
3536 color=list->nodes[color].next[0];
3537 sum+=(MagickRealType) list->nodes[color].count*color;
3538 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3539 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3540 count+=list->nodes[color].count;
3541 }
while (count < (ssize_t) pixel_list->length);
3542 sum/=pixel_list->length;
3543 sum_squared/=pixel_list->length;
3544 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3546 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3547 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3548 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3549 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3550 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3553static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3554 const IndexPacket *indexes,
PixelList *pixel_list)
3562 index=ScaleQuantumToShort(GetPixelRed(pixel));
3563 signature=pixel_list->lists[0].nodes[index].signature;
3564 if (signature == pixel_list->signature)
3565 pixel_list->lists[0].nodes[index].count++;
3567 AddNodePixelList(pixel_list,0,index);
3568 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3569 signature=pixel_list->lists[1].nodes[index].signature;
3570 if (signature == pixel_list->signature)
3571 pixel_list->lists[1].nodes[index].count++;
3573 AddNodePixelList(pixel_list,1,index);
3574 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3575 signature=pixel_list->lists[2].nodes[index].signature;
3576 if (signature == pixel_list->signature)
3577 pixel_list->lists[2].nodes[index].count++;
3579 AddNodePixelList(pixel_list,2,index);
3580 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3581 signature=pixel_list->lists[3].nodes[index].signature;
3582 if (signature == pixel_list->signature)
3583 pixel_list->lists[3].nodes[index].count++;
3585 AddNodePixelList(pixel_list,3,index);
3586 if (image->colorspace == CMYKColorspace)
3587 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3588 signature=pixel_list->lists[4].nodes[index].signature;
3589 if (signature == pixel_list->signature)
3590 pixel_list->lists[4].nodes[index].count++;
3592 AddNodePixelList(pixel_list,4,index);
3595static void ResetPixelList(
PixelList *pixel_list)
3612 for (channel=0; channel < 5; channel++)
3614 list=pixel_list->lists+channel;
3615 root=list->nodes+65536UL;
3617 for (level=0; level < 9; level++)
3618 root->next[level]=65536UL;
3620 pixel_list->seed=pixel_list->signature++;
3623MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3624 const size_t width,
const size_t height,
ExceptionInfo *exception)
3629 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3631 return(statistic_image);
3634MagickExport
Image *StatisticImageChannel(
const Image *image,
3635 const ChannelType channel,
const StatisticType type,
const size_t width,
3638#define StatisticImageTag "Statistic/Image"
3654 **magick_restrict pixel_list;
3666 assert(image != (
Image *) NULL);
3667 assert(image->signature == MagickCoreSignature);
3668 if (IsEventLogging() != MagickFalse)
3669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3671 assert(exception->signature == MagickCoreSignature);
3672 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3673 if (statistic_image == (
Image *) NULL)
3674 return((
Image *) NULL);
3675 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3677 InheritException(exception,&statistic_image->exception);
3678 statistic_image=DestroyImage(statistic_image);
3679 return((
Image *) NULL);
3681 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3683 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3685 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3688 statistic_image=DestroyImage(statistic_image);
3689 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3696 image_view=AcquireVirtualCacheView(image,exception);
3697 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3698#if defined(MAGICKCORE_OPENMP_SUPPORT)
3699 #pragma omp parallel for schedule(static) shared(progress,status) \
3700 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3702 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3705 id = GetOpenMPThreadId();
3708 *magick_restrict indexes;
3714 *magick_restrict statistic_indexes;
3722 if (status == MagickFalse)
3724 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3725 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3726 neighbor_height,exception);
3727 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3733 indexes=GetCacheViewVirtualIndexQueue(image_view);
3734 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3735 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3752 ResetPixelList(pixel_list[
id]);
3753 for (v=0; v < (ssize_t) neighbor_height; v++)
3755 for (u=0; u < (ssize_t) neighbor_width; u++)
3756 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3757 r+=(ptrdiff_t) image->columns+neighbor_width;
3758 s+=(ptrdiff_t) image->columns+neighbor_width;
3760 GetMagickPixelPacket(image,&pixel);
3761 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3762 neighbor_width*neighbor_height/2,&pixel);
3765 case GradientStatistic:
3771 GetMinimumPixelList(pixel_list[
id],&pixel);
3773 GetMaximumPixelList(pixel_list[
id],&pixel);
3775 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3776 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3777 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3778 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3779 if (image->colorspace == CMYKColorspace)
3780 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3783 case MaximumStatistic:
3785 GetMaximumPixelList(pixel_list[
id],&pixel);
3790 GetMeanPixelList(pixel_list[
id],&pixel);
3793 case MedianStatistic:
3796 GetMedianPixelList(pixel_list[
id],&pixel);
3799 case MinimumStatistic:
3801 GetMinimumPixelList(pixel_list[
id],&pixel);
3806 GetModePixelList(pixel_list[
id],&pixel);
3809 case NonpeakStatistic:
3811 GetNonpeakPixelList(pixel_list[
id],&pixel);
3814 case RootMeanSquareStatistic:
3816 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3819 case StandardDeviationStatistic:
3821 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3825 if ((channel & RedChannel) != 0)
3826 SetPixelRed(q,ClampToQuantum(pixel.red));
3827 if ((channel & GreenChannel) != 0)
3828 SetPixelGreen(q,ClampToQuantum(pixel.green));
3829 if ((channel & BlueChannel) != 0)
3830 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3831 if ((channel & OpacityChannel) != 0)
3832 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3833 if (((channel & IndexChannel) != 0) &&
3834 (image->colorspace == CMYKColorspace))
3835 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3839 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3841 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3846 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3848 if (proceed == MagickFalse)
3852 statistic_view=DestroyCacheView(statistic_view);
3853 image_view=DestroyCacheView(image_view);
3854 pixel_list=DestroyPixelListTLS(pixel_list);
3855 if (status == MagickFalse)
3856 statistic_image=DestroyImage(statistic_image);
3857 return(statistic_image);