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 (((
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));
479MagickExport MagickBooleanType EvaluateImage(
Image *image,
480 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
485 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
489MagickExport
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 ? 0 : 1)
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 ? 0 : 1)
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);
820MagickExport 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 ? 0 : 1)
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);
1001static 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));
1091MagickExport MagickBooleanType FunctionImage(
Image *image,
1092 const MagickFunction function,
const size_t number_parameters,
1098 status=FunctionImageChannel(image,CompositeChannels,function,
1099 number_parameters,parameters,exception);
1103MagickExport 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,2)
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);
1237MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1243 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1247MagickExport 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);
1336MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1342 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1347MagickExport 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);
1402MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1408 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1413MagickExport 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);
1576MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1582 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1587MagickExport 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);
1605 *standard_deviation=NAN;
1606 return(MagickFalse);
1609 channel_statistics[CompositeChannels].mean=0.0;
1610 channel_statistics[CompositeChannels].standard_deviation=0.0;
1611 if ((channel & RedChannel) != 0)
1613 channel_statistics[CompositeChannels].mean+=
1614 channel_statistics[RedChannel].mean;
1615 channel_statistics[CompositeChannels].standard_deviation+=
1616 channel_statistics[RedChannel].standard_deviation;
1619 if ((channel & GreenChannel) != 0)
1621 channel_statistics[CompositeChannels].mean+=
1622 channel_statistics[GreenChannel].mean;
1623 channel_statistics[CompositeChannels].standard_deviation+=
1624 channel_statistics[GreenChannel].standard_deviation;
1627 if ((channel & BlueChannel) != 0)
1629 channel_statistics[CompositeChannels].mean+=
1630 channel_statistics[BlueChannel].mean;
1631 channel_statistics[CompositeChannels].standard_deviation+=
1632 channel_statistics[BlueChannel].standard_deviation;
1635 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1637 channel_statistics[CompositeChannels].mean+=
1638 channel_statistics[OpacityChannel].mean;
1639 channel_statistics[CompositeChannels].standard_deviation+=
1640 channel_statistics[OpacityChannel].standard_deviation;
1643 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1645 channel_statistics[CompositeChannels].mean+=
1646 channel_statistics[BlackChannel].mean;
1647 channel_statistics[CompositeChannels].standard_deviation+=
1648 channel_statistics[CompositeChannels].standard_deviation;
1651 channel_statistics[CompositeChannels].mean/=channels;
1652 channel_statistics[CompositeChannels].standard_deviation/=channels;
1653 *mean=channel_statistics[CompositeChannels].mean;
1654 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1656 channel_statistics);
1689#define MaxNumberImageMoments 8
1695 M00[CompositeChannels+1],
1696 M01[CompositeChannels+1],
1697 M02[CompositeChannels+1],
1698 M03[CompositeChannels+1],
1699 M10[CompositeChannels+1],
1700 M11[CompositeChannels+1],
1701 M12[CompositeChannels+1],
1702 M20[CompositeChannels+1],
1703 M21[CompositeChannels+1],
1704 M22[CompositeChannels+1],
1705 M30[CompositeChannels+1];
1711 centroid[CompositeChannels+1];
1721 assert(image != (
Image *) NULL);
1722 assert(image->signature == MagickCoreSignature);
1723 if (IsEventLogging() != MagickFalse)
1724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1725 length=CompositeChannels+1UL;
1727 sizeof(*channel_moments));
1729 return(channel_moments);
1730 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1731 (void) memset(centroid,0,
sizeof(centroid));
1732 (void) memset(M00,0,
sizeof(M00));
1733 (void) memset(M01,0,
sizeof(M01));
1734 (void) memset(M02,0,
sizeof(M02));
1735 (void) memset(M03,0,
sizeof(M03));
1736 (void) memset(M10,0,
sizeof(M10));
1737 (void) memset(M11,0,
sizeof(M11));
1738 (void) memset(M12,0,
sizeof(M12));
1739 (void) memset(M20,0,
sizeof(M20));
1740 (void) memset(M21,0,
sizeof(M21));
1741 (void) memset(M22,0,
sizeof(M22));
1742 (void) memset(M30,0,
sizeof(M30));
1743 GetMagickPixelPacket(image,&pixel);
1744 for (y=0; y < (ssize_t) image->rows; y++)
1747 *magick_restrict indexes;
1758 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1761 indexes=GetVirtualIndexQueue(image);
1762 for (x=0; x < (ssize_t) image->columns; x++)
1764 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1765 M00[RedChannel]+=QuantumScale*pixel.red;
1766 M10[RedChannel]+=x*QuantumScale*pixel.red;
1767 M01[RedChannel]+=y*QuantumScale*pixel.red;
1768 M00[GreenChannel]+=QuantumScale*pixel.green;
1769 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1770 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1771 M00[BlueChannel]+=QuantumScale*pixel.blue;
1772 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1773 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1774 if (image->matte != MagickFalse)
1776 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1777 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1778 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1780 if (image->colorspace == CMYKColorspace)
1782 M00[IndexChannel]+=QuantumScale*pixel.index;
1783 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1784 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1789 for (channel=0; channel <= CompositeChannels; channel++)
1794 if (M00[channel] < MagickEpsilon)
1796 M00[channel]+=MagickEpsilon;
1797 centroid[channel].x=(double) image->columns/2.0;
1798 centroid[channel].y=(double) image->rows/2.0;
1801 M00[channel]+=MagickEpsilon;
1802 centroid[channel].x=M10[channel]/M00[channel];
1803 centroid[channel].y=M01[channel]/M00[channel];
1805 for (y=0; y < (ssize_t) image->rows; y++)
1808 *magick_restrict indexes;
1819 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1822 indexes=GetVirtualIndexQueue(image);
1823 for (x=0; x < (ssize_t) image->columns; x++)
1825 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1826 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1827 centroid[RedChannel].y)*QuantumScale*pixel.red;
1828 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1829 centroid[RedChannel].x)*QuantumScale*pixel.red;
1830 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1831 centroid[RedChannel].y)*QuantumScale*pixel.red;
1832 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1833 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1835 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1836 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1838 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1839 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1840 centroid[RedChannel].y)*QuantumScale*pixel.red;
1841 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1842 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1844 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1845 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1847 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1848 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1849 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1850 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1851 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1852 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1853 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1854 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1856 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1857 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1859 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1860 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1861 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1862 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1863 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1865 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1866 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1868 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1869 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1870 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1871 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1872 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1873 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1874 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1875 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1877 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1878 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1880 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1881 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1882 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1883 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1884 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1886 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1887 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1889 if (image->matte != MagickFalse)
1891 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1892 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1893 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1894 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1895 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1896 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1897 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1898 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1899 QuantumScale*pixel.opacity;
1900 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1901 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1902 QuantumScale*pixel.opacity;
1903 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1904 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1905 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1906 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1907 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1908 QuantumScale*pixel.opacity;
1909 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1910 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1911 QuantumScale*pixel.opacity;
1913 if (image->colorspace == CMYKColorspace)
1915 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1916 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1917 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1918 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1919 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1920 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1921 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1922 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1923 QuantumScale*pixel.index;
1924 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1925 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1926 QuantumScale*pixel.index;
1927 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1928 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1929 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1930 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1931 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1932 QuantumScale*pixel.index;
1933 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1934 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1935 QuantumScale*pixel.index;
1941 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1942 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1943 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1944 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1945 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1946 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1947 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1948 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1949 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1950 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1951 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1952 if (image->matte != MagickFalse)
1955 M00[CompositeChannels]+=M00[OpacityChannel];
1956 M01[CompositeChannels]+=M01[OpacityChannel];
1957 M02[CompositeChannels]+=M02[OpacityChannel];
1958 M03[CompositeChannels]+=M03[OpacityChannel];
1959 M10[CompositeChannels]+=M10[OpacityChannel];
1960 M11[CompositeChannels]+=M11[OpacityChannel];
1961 M12[CompositeChannels]+=M12[OpacityChannel];
1962 M20[CompositeChannels]+=M20[OpacityChannel];
1963 M21[CompositeChannels]+=M21[OpacityChannel];
1964 M22[CompositeChannels]+=M22[OpacityChannel];
1965 M30[CompositeChannels]+=M30[OpacityChannel];
1967 if (image->colorspace == CMYKColorspace)
1970 M00[CompositeChannels]+=M00[IndexChannel];
1971 M01[CompositeChannels]+=M01[IndexChannel];
1972 M02[CompositeChannels]+=M02[IndexChannel];
1973 M03[CompositeChannels]+=M03[IndexChannel];
1974 M10[CompositeChannels]+=M10[IndexChannel];
1975 M11[CompositeChannels]+=M11[IndexChannel];
1976 M12[CompositeChannels]+=M12[IndexChannel];
1977 M20[CompositeChannels]+=M20[IndexChannel];
1978 M21[CompositeChannels]+=M21[IndexChannel];
1979 M22[CompositeChannels]+=M22[IndexChannel];
1980 M30[CompositeChannels]+=M30[IndexChannel];
1982 M00[CompositeChannels]/=(double) channels;
1983 M01[CompositeChannels]/=(double) channels;
1984 M02[CompositeChannels]/=(double) channels;
1985 M03[CompositeChannels]/=(double) channels;
1986 M10[CompositeChannels]/=(double) channels;
1987 M11[CompositeChannels]/=(double) channels;
1988 M12[CompositeChannels]/=(double) channels;
1989 M20[CompositeChannels]/=(double) channels;
1990 M21[CompositeChannels]/=(double) channels;
1991 M22[CompositeChannels]/=(double) channels;
1992 M30[CompositeChannels]/=(double) channels;
1993 for (channel=0; channel <= CompositeChannels; channel++)
1998 channel_moments[channel].centroid=centroid[channel];
1999 channel_moments[channel].ellipse_axis.x=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_axis.y=sqrt((2.0*
2004 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
2005 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2006 (M20[channel]-M02[channel]))));
2007 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
2008 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
2009 if (fabs(M11[channel]) < 0.0)
2011 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2012 ((M20[channel]-M02[channel]) < 0.0))
2013 channel_moments[channel].ellipse_angle+=90.0;
2016 if (M11[channel] < 0.0)
2018 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2020 if ((M20[channel]-M02[channel]) < 0.0)
2021 channel_moments[channel].ellipse_angle+=90.0;
2023 channel_moments[channel].ellipse_angle+=180.0;
2027 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2028 ((M20[channel]-M02[channel]) < 0.0))
2029 channel_moments[channel].ellipse_angle+=90.0;
2030 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2031 channel_moments[channel].ellipse_axis.y*
2032 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2033 channel_moments[channel].ellipse_axis.x*
2034 channel_moments[channel].ellipse_axis.x)));
2035 channel_moments[channel].ellipse_intensity=M00[channel]/
2036 (MagickPI*channel_moments[channel].ellipse_axis.x*
2037 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2039 for (channel=0; channel <= CompositeChannels; channel++)
2046 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2047 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2048 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2049 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2050 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2051 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2052 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2053 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2056 for (channel=0; channel <= CompositeChannels; channel++)
2061 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2062 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2063 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2064 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2065 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2066 (3.0*M21[channel]-M03[channel]);
2067 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2068 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2069 (M21[channel]+M03[channel]);
2070 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2071 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2072 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2073 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2074 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2075 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2076 (M21[channel]+M03[channel]));
2077 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2078 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2079 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2080 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2081 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2082 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2083 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2084 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2085 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2086 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2087 (M21[channel]+M03[channel]));
2088 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2089 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2090 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2091 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2093 if (y < (ssize_t) image->rows)
2094 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2095 return(channel_moments);
2148 hash_image=BlurImage(image,0.0,1.0,exception);
2149 if (hash_image == (
Image *) NULL)
2151 hash_image->depth=8;
2152 status=TransformImageColorspace(hash_image,xyYColorspace);
2153 if (status == MagickFalse)
2155 moments=GetImageChannelMoments(hash_image,exception);
2156 hash_image=DestroyImage(hash_image);
2160 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2163 for (channel=0; channel <= CompositeChannels; channel++)
2164 for (i=0; i < MaximumNumberOfImageMoments; i++)
2165 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2170 hash_image=BlurImage(image,0.0,1.0,exception);
2171 if (hash_image == (
Image *) NULL)
2177 hash_image->depth=8;
2178 status=TransformImageColorspace(hash_image,HSBColorspace);
2179 if (status == MagickFalse)
2185 moments=GetImageChannelMoments(hash_image,exception);
2186 hash_image=DestroyImage(hash_image);
2193 for (channel=0; channel <= CompositeChannels; channel++)
2194 for (i=0; i < MaximumNumberOfImageMoments; i++)
2195 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2197 return(perceptual_hash);
2233MagickExport MagickBooleanType GetImageRange(
const Image *image,
2236 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2239MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2240 const ChannelType channel,
double *minima,
double *maxima,
2249 assert(image != (
Image *) NULL);
2250 assert(image->signature == MagickCoreSignature);
2251 if (IsEventLogging() != MagickFalse)
2252 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2253 *maxima=(-MagickMaximumValue);
2254 *minima=MagickMaximumValue;
2255 GetMagickPixelPacket(image,&pixel);
2256 for (y=0; y < (ssize_t) image->rows; y++)
2259 *magick_restrict indexes;
2267 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2270 indexes=GetVirtualIndexQueue(image);
2271 for (x=0; x < (ssize_t) image->columns; x++)
2273 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2274 if ((channel & RedChannel) != 0)
2276 if (pixel.red < *minima)
2277 *minima=(double) pixel.red;
2278 if (pixel.red > *maxima)
2279 *maxima=(double) pixel.red;
2281 if ((channel & GreenChannel) != 0)
2283 if (pixel.green < *minima)
2284 *minima=(double) pixel.green;
2285 if (pixel.green > *maxima)
2286 *maxima=(double) pixel.green;
2288 if ((channel & BlueChannel) != 0)
2290 if (pixel.blue < *minima)
2291 *minima=(double) pixel.blue;
2292 if (pixel.blue > *maxima)
2293 *maxima=(double) pixel.blue;
2295 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2297 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2298 *minima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2300 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2301 *maxima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2304 if (((channel & IndexChannel) != 0) &&
2305 (image->colorspace == CMYKColorspace))
2307 if ((
double) pixel.index < *minima)
2308 *minima=(
double) pixel.index;
2309 if ((
double) pixel.index > *maxima)
2310 *maxima=(
double) pixel.index;
2315 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2355 *channel_statistics;
2377 assert(image != (
Image *) NULL);
2378 assert(image->signature == MagickCoreSignature);
2379 if (IsEventLogging() != MagickFalse)
2380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2381 length=CompositeChannels+1UL;
2383 sizeof(*channel_statistics));
2385 sizeof(*histogram));
2393 channel_statistics);
2394 return(channel_statistics);
2396 (void) memset(channel_statistics,0,length*
2397 sizeof(*channel_statistics));
2398 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2400 channel_statistics[i].depth=1;
2401 channel_statistics[i].maxima=(-MagickMaximumValue);
2402 channel_statistics[i].minima=MagickMaximumValue;
2404 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2405 (void) memset(&number_bins,0,
sizeof(number_bins));
2406 for (y=0; y < (ssize_t) image->rows; y++)
2409 *magick_restrict indexes;
2420 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2423 indexes=GetVirtualIndexQueue(image);
2424 for (x=0; x < (ssize_t) image->columns; )
2426 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2428 depth=channel_statistics[RedChannel].depth;
2429 range=GetQuantumRange(depth);
2430 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2432 channel_statistics[RedChannel].depth++;
2436 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2438 depth=channel_statistics[GreenChannel].depth;
2439 range=GetQuantumRange(depth);
2440 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2442 channel_statistics[GreenChannel].depth++;
2446 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2448 depth=channel_statistics[BlueChannel].depth;
2449 range=GetQuantumRange(depth);
2450 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2452 channel_statistics[BlueChannel].depth++;
2456 if (image->matte != MagickFalse)
2458 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2460 depth=channel_statistics[OpacityChannel].depth;
2461 range=GetQuantumRange(depth);
2462 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2464 channel_statistics[OpacityChannel].depth++;
2469 if (image->colorspace == CMYKColorspace)
2471 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2473 depth=channel_statistics[BlackChannel].depth;
2474 range=GetQuantumRange(depth);
2475 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2477 channel_statistics[BlackChannel].depth++;
2482 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2483 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2484 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2485 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2486 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2487 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2488 QuantumScale*GetPixelRed(p);
2489 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2490 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2491 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2492 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2493 QuantumScale*GetPixelRed(p);
2494 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2495 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2496 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2497 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2498 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2499 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2500 QuantumScale*GetPixelGreen(p);
2501 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2502 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2503 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2504 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2505 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2506 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2507 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2508 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2509 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2510 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2511 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2512 QuantumScale*GetPixelBlue(p);
2513 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2514 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2515 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2516 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2517 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2518 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2519 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2520 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2521 if (image->matte != MagickFalse)
2523 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2524 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2525 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2526 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2527 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2528 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2529 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2530 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2531 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2533 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2534 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2535 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2536 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2538 if (image->colorspace == CMYKColorspace)
2540 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2541 channel_statistics[BlackChannel].minima=(double)
2542 GetPixelIndex(indexes+x);
2543 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2544 channel_statistics[BlackChannel].maxima=(
double)
2545 GetPixelIndex(indexes+x);
2546 channel_statistics[BlackChannel].sum+=QuantumScale*
2547 GetPixelIndex(indexes+x);
2548 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2549 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2550 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2551 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2552 QuantumScale*GetPixelIndex(indexes+x);
2553 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2554 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2555 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2556 GetPixelIndex(indexes+x);
2557 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2563 for (i=0; i < (ssize_t) CompositeChannels; i++)
2573 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2574 mean=channel_statistics[i].sum*area;
2575 channel_statistics[i].sum=mean;
2576 channel_statistics[i].sum_squared*=area;
2577 channel_statistics[i].sum_cubed*=area;
2578 channel_statistics[i].sum_fourth_power*=area;
2579 channel_statistics[i].mean=mean;
2580 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2581 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2582 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2583 ((double) image->columns*image->rows);
2584 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2585 channel_statistics[i].standard_deviation=standard_deviation;
2587 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2589 if (histogram[i].red > 0.0)
2591 if (histogram[i].green > 0.0)
2592 number_bins.green++;
2593 if (histogram[i].blue > 0.0)
2595 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2596 number_bins.opacity++;
2597 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2598 number_bins.index++;
2600 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2601 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2606 histogram[i].red*=area;
2607 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2608 MagickLog10(histogram[i].red)*
2609 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2610 histogram[i].green*=area;
2611 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2612 MagickLog10(histogram[i].green)*
2613 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2614 histogram[i].blue*=area;
2615 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2616 MagickLog10(histogram[i].blue)*
2617 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2618 if (image->matte != MagickFalse)
2620 histogram[i].opacity*=area;
2621 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2622 MagickLog10(histogram[i].opacity)*
2623 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2625 if (image->colorspace == CMYKColorspace)
2627 histogram[i].index*=area;
2628 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2629 MagickLog10(histogram[i].index)*
2630 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2636 for (i=0; i < (ssize_t) CompositeChannels; i++)
2638 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2639 channel_statistics[CompositeChannels].depth,(double)
2640 channel_statistics[i].depth);
2641 channel_statistics[CompositeChannels].minima=MagickMin(
2642 channel_statistics[CompositeChannels].minima,
2643 channel_statistics[i].minima);
2644 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2645 channel_statistics[CompositeChannels].maxima,
2646 channel_statistics[i].maxima);
2647 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2648 channel_statistics[CompositeChannels].sum_squared+=
2649 channel_statistics[i].sum_squared;
2650 channel_statistics[CompositeChannels].sum_cubed+=
2651 channel_statistics[i].sum_cubed;
2652 channel_statistics[CompositeChannels].sum_fourth_power+=
2653 channel_statistics[i].sum_fourth_power;
2654 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2655 channel_statistics[CompositeChannels].variance+=
2656 channel_statistics[i].variance-channel_statistics[i].mean*
2657 channel_statistics[i].mean;
2658 standard_deviation=sqrt(channel_statistics[i].variance-
2659 (channel_statistics[i].mean*channel_statistics[i].mean));
2660 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2661 ((double) image->columns*image->rows);
2662 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2663 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2664 channel_statistics[CompositeChannels].entropy+=
2665 channel_statistics[i].entropy;
2668 if (image->matte != MagickFalse)
2670 if (image->colorspace == CMYKColorspace)
2672 channel_statistics[CompositeChannels].sum/=channels;
2673 channel_statistics[CompositeChannels].sum_squared/=channels;
2674 channel_statistics[CompositeChannels].sum_cubed/=channels;
2675 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2676 channel_statistics[CompositeChannels].mean/=channels;
2677 channel_statistics[CompositeChannels].kurtosis/=channels;
2678 channel_statistics[CompositeChannels].skewness/=channels;
2679 channel_statistics[CompositeChannels].entropy/=channels;
2680 i=CompositeChannels;
2681 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2682 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2683 channel_statistics[i].mean=channel_statistics[i].sum;
2684 standard_deviation=sqrt(channel_statistics[i].variance-
2685 (channel_statistics[i].mean*channel_statistics[i].mean));
2686 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2687 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2688 standard_deviation*standard_deviation);
2689 channel_statistics[i].standard_deviation=standard_deviation;
2690 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2695 standard_deviation=PerceptibleReciprocal(
2696 channel_statistics[i].standard_deviation);
2697 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2698 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2699 channel_statistics[i].mean*channel_statistics[i].mean*
2700 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2701 standard_deviation);
2702 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2703 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2704 channel_statistics[i].mean*channel_statistics[i].mean*
2705 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2706 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2707 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2708 standard_deviation*standard_deviation)-3.0;
2710 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2712 channel_statistics[i].mean*=QuantumRange;
2713 channel_statistics[i].variance*=QuantumRange;
2714 channel_statistics[i].standard_deviation*=QuantumRange;
2715 channel_statistics[i].sum*=QuantumRange;
2716 channel_statistics[i].sum_squared*=QuantumRange;
2717 channel_statistics[i].sum_cubed*=QuantumRange;
2718 channel_statistics[i].sum_fourth_power*=QuantumRange;
2720 channel_statistics[CompositeChannels].mean=0.0;
2721 channel_statistics[CompositeChannels].standard_deviation=0.0;
2722 for (i=0; i < (ssize_t) CompositeChannels; i++)
2724 channel_statistics[CompositeChannels].mean+=
2725 channel_statistics[i].mean;
2726 channel_statistics[CompositeChannels].standard_deviation+=
2727 channel_statistics[i].standard_deviation;
2729 channel_statistics[CompositeChannels].mean/=(double) channels;
2730 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2732 if (y < (ssize_t) image->rows)
2734 channel_statistics);
2735 return(channel_statistics);
2776MagickExport
Image *PolynomialImage(
const Image *images,
2777 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2782 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2784 return(polynomial_image);
2787MagickExport
Image *PolynomialImageChannel(
const Image *images,
2788 const ChannelType channel,
const size_t number_terms,
const double *terms,
2791#define PolynomialImageTag "Polynomial/Image"
2806 **magick_restrict polynomial_pixels,
2812 assert(images != (
Image *) NULL);
2813 assert(images->signature == MagickCoreSignature);
2814 if (IsEventLogging() != MagickFalse)
2815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2817 assert(exception->signature == MagickCoreSignature);
2818 image=AcquireImageCanvas(images,exception);
2819 if (image == (
Image *) NULL)
2820 return((
Image *) NULL);
2821 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2823 InheritException(exception,&image->exception);
2824 image=DestroyImage(image);
2825 return((
Image *) NULL);
2827 polynomial_pixels=AcquirePixelTLS(images);
2830 image=DestroyImage(image);
2831 (void) ThrowMagickException(exception,GetMagickModule(),
2832 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2833 return((
Image *) NULL);
2840 GetMagickPixelPacket(images,&zero);
2841 polynomial_view=AcquireAuthenticCacheView(image,exception);
2842#if defined(MAGICKCORE_OPENMP_SUPPORT)
2843 #pragma omp parallel for schedule(static) shared(progress,status) \
2844 magick_number_threads(image,image,image->rows,1)
2846 for (y=0; y < (ssize_t) image->rows; y++)
2855 id = GetOpenMPThreadId();
2858 *magick_restrict polynomial_indexes;
2873 if (status == MagickFalse)
2875 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2882 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2883 polynomial_pixel=polynomial_pixels[id];
2884 for (x=0; x < (ssize_t) image->columns; x++)
2885 polynomial_pixel[x]=zero;
2887 number_images=GetImageListLength(images);
2888 for (i=0; i < (ssize_t) number_images; i++)
2896 if (i >= (ssize_t) number_terms)
2898 image_view=AcquireVirtualCacheView(next,exception);
2899 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2902 image_view=DestroyCacheView(image_view);
2905 indexes=GetCacheViewVirtualIndexQueue(image_view);
2906 for (x=0; x < (ssize_t) image->columns; x++)
2912 coefficient=terms[i << 1];
2913 degree=terms[(i << 1)+1];
2914 if ((channel & RedChannel) != 0)
2915 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2917 if ((channel & GreenChannel) != 0)
2918 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2921 if ((channel & BlueChannel) != 0)
2922 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2924 if ((channel & OpacityChannel) != 0)
2925 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2926 ((
double) QuantumRange-(double) p->opacity),degree);
2927 if (((channel & IndexChannel) != 0) &&
2928 (image->colorspace == CMYKColorspace))
2929 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2933 image_view=DestroyCacheView(image_view);
2934 next=GetNextImageInList(next);
2936 for (x=0; x < (ssize_t) image->columns; x++)
2938 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2939 polynomial_pixel[x].red));
2940 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2941 polynomial_pixel[x].green));
2942 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2943 polynomial_pixel[x].blue));
2944 if (image->matte == MagickFalse)
2945 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2946 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2948 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2949 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2950 if (image->colorspace == CMYKColorspace)
2951 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2952 QuantumRange*polynomial_pixel[x].index));
2955 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2957 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2962 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2964 if (proceed == MagickFalse)
2968 polynomial_view=DestroyCacheView(polynomial_view);
2969 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2970 if (status == MagickFalse)
2971 image=DestroyImage(image);
3013#define ListChannels 5
3040 lists[ListChannels];
3050 for (i=0; i < ListChannels; i++)
3051 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3052 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3053 pixel_list->lists[i].nodes);
3054 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3063 assert(pixel_list != (
PixelList **) NULL);
3064 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3065 if (pixel_list[i] != (
PixelList *) NULL)
3066 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3067 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3071static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3079 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3082 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3083 pixel_list->length=width*height;
3084 for (i=0; i < ListChannels; i++)
3086 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3087 sizeof(*pixel_list->lists[i].nodes));
3088 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3089 return(DestroyPixelList(pixel_list));
3090 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3091 sizeof(*pixel_list->lists[i].nodes));
3093 pixel_list->signature=MagickCoreSignature;
3097static PixelList **AcquirePixelListTLS(
const size_t width,
3098 const size_t height)
3109 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3110 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3111 sizeof(*pixel_list));
3114 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3115 for (i=0; i < (ssize_t) number_threads; i++)
3117 pixel_list[i]=AcquirePixelList(width,height);
3118 if (pixel_list[i] == (
PixelList *) NULL)
3119 return(DestroyPixelListTLS(pixel_list));
3124static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3140 list=pixel_list->lists+channel;
3141 list->nodes[color].signature=pixel_list->signature;
3142 list->nodes[color].count=1;
3147 (void) memset(update,0,
sizeof(update));
3148 for (level=list->level; level >= 0; level--)
3150 while (list->nodes[search].next[level] < color)
3151 search=list->nodes[search].next[level];
3152 update[level]=search;
3157 for (level=0; ; level++)
3159 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3160 if ((pixel_list->seed & 0x300) != 0x300)
3165 if (level > (list->level+2))
3166 level=list->level+2;
3170 while (level > list->level)
3173 update[list->level]=65536UL;
3180 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3181 list->nodes[update[level]].next[level]=color;
3182 }
while (level-- > 0);
3201 channels[ListChannels];
3206 for (channel=0; channel < 5; channel++)
3208 list=pixel_list->lists+channel;
3211 maximum=list->nodes[color].next[0];
3214 color=list->nodes[color].next[0];
3215 if (color > maximum)
3217 count+=list->nodes[color].count;
3218 }
while (count < (ssize_t) pixel_list->length);
3219 channels[channel]=(
unsigned short) maximum;
3221 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3222 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3223 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3224 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3225 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3246 channels[ListChannels];
3251 for (channel=0; channel < 5; channel++)
3253 list=pixel_list->lists+channel;
3259 color=list->nodes[color].next[0];
3260 sum+=(MagickRealType) list->nodes[color].count*color;
3261 count+=list->nodes[color].count;
3262 }
while (count < (ssize_t) pixel_list->length);
3263 sum/=pixel_list->length;
3264 channels[channel]=(
unsigned short) sum;
3266 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3267 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3268 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3269 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3270 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3288 channels[ListChannels];
3293 for (channel=0; channel < 5; channel++)
3295 list=pixel_list->lists+channel;
3300 color=list->nodes[color].next[0];
3301 count+=list->nodes[color].count;
3302 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3303 channels[channel]=(
unsigned short) color;
3305 GetMagickPixelPacket((
const Image *) NULL,pixel);
3306 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3307 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3308 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3309 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3310 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3329 channels[ListChannels];
3334 for (channel=0; channel < 5; channel++)
3336 list=pixel_list->lists+channel;
3339 minimum=list->nodes[color].next[0];
3342 color=list->nodes[color].next[0];
3343 if (color < minimum)
3345 count+=list->nodes[color].count;
3346 }
while (count < (ssize_t) pixel_list->length);
3347 channels[channel]=(
unsigned short) minimum;
3349 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3350 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3351 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3352 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3353 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3378 for (channel=0; channel < 5; channel++)
3380 list=pixel_list->lists+channel;
3383 max_count=list->nodes[mode].count;
3387 color=list->nodes[color].next[0];
3388 if (list->nodes[color].count > max_count)
3391 max_count=list->nodes[mode].count;
3393 count+=list->nodes[color].count;
3394 }
while (count < (ssize_t) pixel_list->length);
3395 channels[channel]=(
unsigned short) mode;
3397 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3398 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3399 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3400 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3401 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3426 for (channel=0; channel < 5; channel++)
3428 list=pixel_list->lists+channel;
3430 next=list->nodes[color].next[0];
3436 next=list->nodes[color].next[0];
3437 count+=list->nodes[color].count;
3438 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3439 if ((previous == 65536UL) && (next != 65536UL))
3442 if ((previous != 65536UL) && (next == 65536UL))
3444 channels[channel]=(
unsigned short) color;
3446 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3447 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3448 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3449 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3450 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3453static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3472 channels[ListChannels];
3477 for (channel=0; channel < 5; channel++)
3479 list=pixel_list->lists+channel;
3485 color=list->nodes[color].next[0];
3486 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3487 count+=list->nodes[color].count;
3488 }
while (count < (ssize_t) pixel_list->length);
3489 sum/=pixel_list->length;
3490 channels[channel]=(
unsigned short) sqrt(sum);
3492 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3493 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3494 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3495 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3496 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3499static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3517 channels[ListChannels];
3522 for (channel=0; channel < 5; channel++)
3524 list=pixel_list->lists+channel;
3534 color=list->nodes[color].next[0];
3535 sum+=(MagickRealType) list->nodes[color].count*color;
3536 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3537 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3538 count+=list->nodes[color].count;
3539 }
while (count < (ssize_t) pixel_list->length);
3540 sum/=pixel_list->length;
3541 sum_squared/=pixel_list->length;
3542 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3544 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3545 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3546 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3547 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3548 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3551static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3552 const IndexPacket *indexes,
PixelList *pixel_list)
3560 index=ScaleQuantumToShort(GetPixelRed(pixel));
3561 signature=pixel_list->lists[0].nodes[index].signature;
3562 if (signature == pixel_list->signature)
3563 pixel_list->lists[0].nodes[index].count++;
3565 AddNodePixelList(pixel_list,0,index);
3566 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3567 signature=pixel_list->lists[1].nodes[index].signature;
3568 if (signature == pixel_list->signature)
3569 pixel_list->lists[1].nodes[index].count++;
3571 AddNodePixelList(pixel_list,1,index);
3572 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3573 signature=pixel_list->lists[2].nodes[index].signature;
3574 if (signature == pixel_list->signature)
3575 pixel_list->lists[2].nodes[index].count++;
3577 AddNodePixelList(pixel_list,2,index);
3578 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3579 signature=pixel_list->lists[3].nodes[index].signature;
3580 if (signature == pixel_list->signature)
3581 pixel_list->lists[3].nodes[index].count++;
3583 AddNodePixelList(pixel_list,3,index);
3584 if (image->colorspace == CMYKColorspace)
3585 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3586 signature=pixel_list->lists[4].nodes[index].signature;
3587 if (signature == pixel_list->signature)
3588 pixel_list->lists[4].nodes[index].count++;
3590 AddNodePixelList(pixel_list,4,index);
3593static void ResetPixelList(
PixelList *pixel_list)
3610 for (channel=0; channel < 5; channel++)
3612 list=pixel_list->lists+channel;
3613 root=list->nodes+65536UL;
3615 for (level=0; level < 9; level++)
3616 root->next[level]=65536UL;
3618 pixel_list->seed=pixel_list->signature++;
3621MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3622 const size_t width,
const size_t height,
ExceptionInfo *exception)
3627 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3629 return(statistic_image);
3632MagickExport
Image *StatisticImageChannel(
const Image *image,
3633 const ChannelType channel,
const StatisticType type,
const size_t width,
3636#define StatisticImageTag "Statistic/Image"
3652 **magick_restrict pixel_list;
3664 assert(image != (
Image *) NULL);
3665 assert(image->signature == MagickCoreSignature);
3666 if (IsEventLogging() != MagickFalse)
3667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3669 assert(exception->signature == MagickCoreSignature);
3670 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3671 if (statistic_image == (
Image *) NULL)
3672 return((
Image *) NULL);
3673 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3675 InheritException(exception,&statistic_image->exception);
3676 statistic_image=DestroyImage(statistic_image);
3677 return((
Image *) NULL);
3679 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3681 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3683 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3686 statistic_image=DestroyImage(statistic_image);
3687 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3694 image_view=AcquireVirtualCacheView(image,exception);
3695 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3696#if defined(MAGICKCORE_OPENMP_SUPPORT)
3697 #pragma omp parallel for schedule(static) shared(progress,status) \
3698 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3700 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3703 id = GetOpenMPThreadId();
3706 *magick_restrict indexes;
3712 *magick_restrict statistic_indexes;
3720 if (status == MagickFalse)
3722 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3723 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3724 neighbor_height,exception);
3725 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3731 indexes=GetCacheViewVirtualIndexQueue(image_view);
3732 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3733 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3750 ResetPixelList(pixel_list[
id]);
3751 for (v=0; v < (ssize_t) neighbor_height; v++)
3753 for (u=0; u < (ssize_t) neighbor_width; u++)
3754 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3755 r+=(ptrdiff_t) image->columns+neighbor_width;
3756 s+=(ptrdiff_t) image->columns+neighbor_width;
3758 GetMagickPixelPacket(image,&pixel);
3759 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3760 neighbor_width*neighbor_height/2,&pixel);
3763 case GradientStatistic:
3769 GetMinimumPixelList(pixel_list[
id],&pixel);
3771 GetMaximumPixelList(pixel_list[
id],&pixel);
3773 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3774 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3775 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3776 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3777 if (image->colorspace == CMYKColorspace)
3778 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3781 case MaximumStatistic:
3783 GetMaximumPixelList(pixel_list[
id],&pixel);
3788 GetMeanPixelList(pixel_list[
id],&pixel);
3791 case MedianStatistic:
3794 GetMedianPixelList(pixel_list[
id],&pixel);
3797 case MinimumStatistic:
3799 GetMinimumPixelList(pixel_list[
id],&pixel);
3804 GetModePixelList(pixel_list[
id],&pixel);
3807 case NonpeakStatistic:
3809 GetNonpeakPixelList(pixel_list[
id],&pixel);
3812 case RootMeanSquareStatistic:
3814 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3817 case StandardDeviationStatistic:
3819 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3823 if ((channel & RedChannel) != 0)
3824 SetPixelRed(q,ClampToQuantum(pixel.red));
3825 if ((channel & GreenChannel) != 0)
3826 SetPixelGreen(q,ClampToQuantum(pixel.green));
3827 if ((channel & BlueChannel) != 0)
3828 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3829 if ((channel & OpacityChannel) != 0)
3830 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3831 if (((channel & IndexChannel) != 0) &&
3832 (image->colorspace == CMYKColorspace))
3833 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3837 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3839 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3844 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3846 if (proceed == MagickFalse)
3850 statistic_view=DestroyCacheView(statistic_view);
3851 image_view=DestroyCacheView(image_view);
3852 pixel_list=DestroyPixelListTLS(pixel_list);
3853 if (status == MagickFalse)
3854 statistic_image=DestroyImage(statistic_image);
3855 return(statistic_image);