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)
563 for (y=0; y < (ssize_t) image->rows; y++)
572 id = GetOpenMPThreadId();
575 *magick_restrict evaluate_indexes;
586 if (status == MagickFalse)
588 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
595 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
596 evaluate_pixel=evaluate_pixels[id];
597 for (x=0; x < (ssize_t) image->columns; x++)
602 for (i=0; i < (ssize_t) number_images; i++)
603 evaluate_pixel[i]=zero;
605 for (i=0; i < (ssize_t) number_images; i++)
613 image_view=AcquireVirtualCacheView(next,exception);
614 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
617 image_view=DestroyCacheView(image_view);
620 indexes=GetCacheViewVirtualIndexQueue(image_view);
621 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
622 GetPixelRed(p),op,evaluate_pixel[i].red);
623 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
624 GetPixelGreen(p),op,evaluate_pixel[i].green);
625 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
626 GetPixelBlue(p),op,evaluate_pixel[i].blue);
627 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
628 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
629 if (image->colorspace == CMYKColorspace)
630 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
631 *indexes,op,evaluate_pixel[i].index);
632 image_view=DestroyCacheView(image_view);
633 next=GetNextImageInList(next);
635 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
637 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
638 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
639 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
640 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
641 if (image->colorspace == CMYKColorspace)
642 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
643 evaluate_pixel[i/2].index));
646 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
648 if (images->progress_monitor != (MagickProgressMonitor) NULL)
653#if defined(MAGICKCORE_OPENMP_SUPPORT)
657 proceed=SetImageProgress(images,EvaluateImageTag,progress,
659 if (proceed == MagickFalse)
666#if defined(MAGICKCORE_OPENMP_SUPPORT)
667 key=GetRandomSecretKey(random_info[0]);
668 #pragma omp parallel for schedule(static) shared(progress,status) \
669 magick_number_threads(image,images,image->rows,key == ~0UL)
671 for (y=0; y < (ssize_t) image->rows; y++)
680 id = GetOpenMPThreadId();
683 *magick_restrict evaluate_indexes;
695 if (status == MagickFalse)
697 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
704 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
705 evaluate_pixel=evaluate_pixels[id];
706 for (x=0; x < (ssize_t) image->columns; x++)
707 evaluate_pixel[x]=zero;
709 for (i=0; i < (ssize_t) number_images; i++)
717 image_view=AcquireVirtualCacheView(next,exception);
718 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
722 image_view=DestroyCacheView(image_view);
725 indexes=GetCacheViewVirtualIndexQueue(image_view);
726 for (x=0; x < (ssize_t) image->columns; x++)
728 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
729 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
730 evaluate_pixel[x].red);
731 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
732 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
733 evaluate_pixel[x].green);
734 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
735 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
736 evaluate_pixel[x].blue);
737 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
738 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
739 evaluate_pixel[x].opacity);
740 if (image->colorspace == CMYKColorspace)
741 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
742 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
743 evaluate_pixel[x].index);
746 image_view=DestroyCacheView(image_view);
747 next=GetNextImageInList(next);
749 if (op == MeanEvaluateOperator)
750 for (x=0; x < (ssize_t) image->columns; x++)
752 evaluate_pixel[x].red/=number_images;
753 evaluate_pixel[x].green/=number_images;
754 evaluate_pixel[x].blue/=number_images;
755 evaluate_pixel[x].opacity/=number_images;
756 evaluate_pixel[x].index/=number_images;
758 if (op == RootMeanSquareEvaluateOperator)
759 for (x=0; x < (ssize_t) image->columns; x++)
761 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
763 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
765 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
767 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
769 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
772 if (op == MultiplyEvaluateOperator)
773 for (x=0; x < (ssize_t) image->columns; x++)
778 for (j=0; j < (ssize_t) (number_images-1); j++)
780 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
781 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
782 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
787 for (x=0; x < (ssize_t) image->columns; x++)
789 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
790 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
791 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
792 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
793 if (image->colorspace == CMYKColorspace)
794 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
795 evaluate_pixel[x].index));
798 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
800 if (images->progress_monitor != (MagickProgressMonitor) NULL)
805 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
807 if (proceed == MagickFalse)
812 evaluate_view=DestroyCacheView(evaluate_view);
813 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
814 random_info=DestroyRandomInfoTLS(random_info);
815 if (status == MagickFalse)
816 image=DestroyImage(image);
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)
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,1)
1146 for (y=0; y < (ssize_t) image->rows; y++)
1149 *magick_restrict indexes;
1157 if (status == MagickFalse)
1159 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1165 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1166 for (x=0; x < (ssize_t) image->columns; x++)
1168 if ((channel & RedChannel) != 0)
1169 SetPixelRed(q,ApplyFunction(GetPixelRed(q),function,
1170 number_parameters,parameters,exception));
1171 if ((channel & GreenChannel) != 0)
1172 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),function,
1173 number_parameters,parameters,exception));
1174 if ((channel & BlueChannel) != 0)
1175 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),function,
1176 number_parameters,parameters,exception));
1177 if ((channel & OpacityChannel) != 0)
1179 if (image->matte == MagickFalse)
1180 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),function,
1181 number_parameters,parameters,exception));
1183 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),function,
1184 number_parameters,parameters,exception));
1186 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1187 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),function,
1188 number_parameters,parameters,exception));
1191 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1193 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1198 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1199 if (proceed == MagickFalse)
1203 image_view=DestroyCacheView(image_view);
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+=(MagickRealType) GetPixelRed(p);
1460 sum_squares+=(double) GetPixelRed(p)*(double) GetPixelRed(p);
1461 sum_cubes+=(double) GetPixelRed(p)*(double) GetPixelRed(p)*(double)
1463 sum_fourth_power+=(double) GetPixelRed(p)*(double) GetPixelRed(p)*
1464 (double) GetPixelRed(p)*(double) GetPixelRed(p);
1467 if ((channel & GreenChannel) != 0)
1469 mean+=(MagickRealType) GetPixelGreen(p);
1470 sum_squares+=(double) GetPixelGreen(p)*(double) GetPixelGreen(p);
1471 sum_cubes+=(double) GetPixelGreen(p)*(double) GetPixelGreen(p)*
1472 (double) GetPixelGreen(p);
1473 sum_fourth_power+=(double) GetPixelGreen(p)*(double) GetPixelGreen(p)*
1474 (double) GetPixelGreen(p)*(double) GetPixelGreen(p);
1477 if ((channel & BlueChannel) != 0)
1479 mean+=(MagickRealType) GetPixelBlue(p);
1480 sum_squares+=(double) GetPixelBlue(p)*(double) GetPixelBlue(p);
1481 sum_cubes+=(double) GetPixelBlue(p)*(double) GetPixelBlue(p)*(double)
1483 sum_fourth_power+=(double) GetPixelBlue(p)*(double) GetPixelBlue(p)*
1484 (double) GetPixelBlue(p)*(double) GetPixelBlue(p);
1487 if ((channel & OpacityChannel) != 0)
1489 mean+=(MagickRealType) GetPixelAlpha(p);
1490 sum_squares+=(double) GetPixelOpacity(p)*(double) GetPixelAlpha(p);
1491 sum_cubes+=(double) GetPixelOpacity(p)*(double) GetPixelAlpha(p)*
1492 (double) GetPixelAlpha(p);
1493 sum_fourth_power+=(double) GetPixelAlpha(p)*(double) GetPixelAlpha(p)*
1494 (double) GetPixelAlpha(p)*GetPixelAlpha(p);
1497 if (((channel & IndexChannel) != 0) &&
1498 (image->colorspace == CMYKColorspace))
1503 index=(double) GetPixelIndex(indexes+x);
1505 sum_squares+=index*index;
1506 sum_cubes+=index*index*index;
1507 sum_fourth_power+=index*index*index*index;
1513 if (y < (ssize_t) image->rows)
1514 return(MagickFalse);
1520 sum_fourth_power/=area;
1522 standard_deviation=sqrt(sum_squares-(mean*mean));
1523 if (standard_deviation != 0.0)
1525 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1526 3.0*mean*mean*mean*mean;
1527 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1530 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1531 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1533 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1570MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1576 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1581MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1582 const ChannelType channel,
double *mean,
double *standard_deviation,
1586 *channel_statistics;
1591 assert(image != (
Image *) NULL);
1592 assert(image->signature == MagickCoreSignature);
1593 if (IsEventLogging() != MagickFalse)
1594 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1595 channel_statistics=GetImageChannelStatistics(image,exception);
1597 return(MagickFalse);
1599 channel_statistics[CompositeChannels].mean=0.0;
1600 channel_statistics[CompositeChannels].standard_deviation=0.0;
1601 if ((channel & RedChannel) != 0)
1603 channel_statistics[CompositeChannels].mean+=
1604 channel_statistics[RedChannel].mean;
1605 channel_statistics[CompositeChannels].standard_deviation+=
1606 channel_statistics[RedChannel].standard_deviation;
1609 if ((channel & GreenChannel) != 0)
1611 channel_statistics[CompositeChannels].mean+=
1612 channel_statistics[GreenChannel].mean;
1613 channel_statistics[CompositeChannels].standard_deviation+=
1614 channel_statistics[GreenChannel].standard_deviation;
1617 if ((channel & BlueChannel) != 0)
1619 channel_statistics[CompositeChannels].mean+=
1620 channel_statistics[BlueChannel].mean;
1621 channel_statistics[CompositeChannels].standard_deviation+=
1622 channel_statistics[BlueChannel].standard_deviation;
1625 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1627 channel_statistics[CompositeChannels].mean+=
1628 channel_statistics[OpacityChannel].mean;
1629 channel_statistics[CompositeChannels].standard_deviation+=
1630 channel_statistics[OpacityChannel].standard_deviation;
1633 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1635 channel_statistics[CompositeChannels].mean+=
1636 channel_statistics[BlackChannel].mean;
1637 channel_statistics[CompositeChannels].standard_deviation+=
1638 channel_statistics[CompositeChannels].standard_deviation;
1641 channel_statistics[CompositeChannels].mean/=channels;
1642 channel_statistics[CompositeChannels].standard_deviation/=channels;
1643 *mean=channel_statistics[CompositeChannels].mean;
1644 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1646 channel_statistics);
1679#define MaxNumberImageMoments 8
1685 M00[CompositeChannels+1],
1686 M01[CompositeChannels+1],
1687 M02[CompositeChannels+1],
1688 M03[CompositeChannels+1],
1689 M10[CompositeChannels+1],
1690 M11[CompositeChannels+1],
1691 M12[CompositeChannels+1],
1692 M20[CompositeChannels+1],
1693 M21[CompositeChannels+1],
1694 M22[CompositeChannels+1],
1695 M30[CompositeChannels+1];
1701 centroid[CompositeChannels+1];
1711 assert(image != (
Image *) NULL);
1712 assert(image->signature == MagickCoreSignature);
1713 if (IsEventLogging() != MagickFalse)
1714 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1715 length=CompositeChannels+1UL;
1717 sizeof(*channel_moments));
1719 return(channel_moments);
1720 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1721 (void) memset(centroid,0,
sizeof(centroid));
1722 (void) memset(M00,0,
sizeof(M00));
1723 (void) memset(M01,0,
sizeof(M01));
1724 (void) memset(M02,0,
sizeof(M02));
1725 (void) memset(M03,0,
sizeof(M03));
1726 (void) memset(M10,0,
sizeof(M10));
1727 (void) memset(M11,0,
sizeof(M11));
1728 (void) memset(M12,0,
sizeof(M12));
1729 (void) memset(M20,0,
sizeof(M20));
1730 (void) memset(M21,0,
sizeof(M21));
1731 (void) memset(M22,0,
sizeof(M22));
1732 (void) memset(M30,0,
sizeof(M30));
1733 GetMagickPixelPacket(image,&pixel);
1734 for (y=0; y < (ssize_t) image->rows; y++)
1737 *magick_restrict indexes;
1748 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1751 indexes=GetVirtualIndexQueue(image);
1752 for (x=0; x < (ssize_t) image->columns; x++)
1754 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1755 M00[RedChannel]+=QuantumScale*pixel.red;
1756 M10[RedChannel]+=x*QuantumScale*pixel.red;
1757 M01[RedChannel]+=y*QuantumScale*pixel.red;
1758 M00[GreenChannel]+=QuantumScale*pixel.green;
1759 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1760 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1761 M00[BlueChannel]+=QuantumScale*pixel.blue;
1762 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1763 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1764 if (image->matte != MagickFalse)
1766 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1767 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1768 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1770 if (image->colorspace == CMYKColorspace)
1772 M00[IndexChannel]+=QuantumScale*pixel.index;
1773 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1774 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1779 for (channel=0; channel <= CompositeChannels; channel++)
1784 if (M00[channel] < MagickEpsilon)
1786 M00[channel]+=MagickEpsilon;
1787 centroid[channel].x=(double) image->columns/2.0;
1788 centroid[channel].y=(double) image->rows/2.0;
1791 M00[channel]+=MagickEpsilon;
1792 centroid[channel].x=M10[channel]/M00[channel];
1793 centroid[channel].y=M01[channel]/M00[channel];
1795 for (y=0; y < (ssize_t) image->rows; y++)
1798 *magick_restrict indexes;
1809 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1812 indexes=GetVirtualIndexQueue(image);
1813 for (x=0; x < (ssize_t) image->columns; x++)
1815 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1816 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1817 centroid[RedChannel].y)*QuantumScale*pixel.red;
1818 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1819 centroid[RedChannel].x)*QuantumScale*pixel.red;
1820 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1821 centroid[RedChannel].y)*QuantumScale*pixel.red;
1822 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1823 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1825 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1826 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1828 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1829 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1830 centroid[RedChannel].y)*QuantumScale*pixel.red;
1831 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1832 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1834 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1835 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1837 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1838 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1839 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1840 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1841 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1842 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1843 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1844 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1846 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1847 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1849 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1850 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1851 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1852 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1853 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1855 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1856 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1858 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1859 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1860 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1861 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1862 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1863 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1864 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1865 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1867 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1868 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1870 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1871 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1872 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1873 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1874 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1876 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1877 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1879 if (image->matte != MagickFalse)
1881 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1882 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1883 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1884 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1885 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1886 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1887 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1888 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1889 QuantumScale*pixel.opacity;
1890 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1891 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1892 QuantumScale*pixel.opacity;
1893 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1894 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1895 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1896 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1897 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1898 QuantumScale*pixel.opacity;
1899 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1900 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1901 QuantumScale*pixel.opacity;
1903 if (image->colorspace == CMYKColorspace)
1905 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1906 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1907 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1908 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1909 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1910 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1911 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1912 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1913 QuantumScale*pixel.index;
1914 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1915 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1916 QuantumScale*pixel.index;
1917 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1918 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1919 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1920 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1921 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1922 QuantumScale*pixel.index;
1923 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1924 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1925 QuantumScale*pixel.index;
1931 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1932 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1933 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1934 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1935 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1936 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1937 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1938 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1939 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1940 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1941 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1942 if (image->matte != MagickFalse)
1945 M00[CompositeChannels]+=M00[OpacityChannel];
1946 M01[CompositeChannels]+=M01[OpacityChannel];
1947 M02[CompositeChannels]+=M02[OpacityChannel];
1948 M03[CompositeChannels]+=M03[OpacityChannel];
1949 M10[CompositeChannels]+=M10[OpacityChannel];
1950 M11[CompositeChannels]+=M11[OpacityChannel];
1951 M12[CompositeChannels]+=M12[OpacityChannel];
1952 M20[CompositeChannels]+=M20[OpacityChannel];
1953 M21[CompositeChannels]+=M21[OpacityChannel];
1954 M22[CompositeChannels]+=M22[OpacityChannel];
1955 M30[CompositeChannels]+=M30[OpacityChannel];
1957 if (image->colorspace == CMYKColorspace)
1960 M00[CompositeChannels]+=M00[IndexChannel];
1961 M01[CompositeChannels]+=M01[IndexChannel];
1962 M02[CompositeChannels]+=M02[IndexChannel];
1963 M03[CompositeChannels]+=M03[IndexChannel];
1964 M10[CompositeChannels]+=M10[IndexChannel];
1965 M11[CompositeChannels]+=M11[IndexChannel];
1966 M12[CompositeChannels]+=M12[IndexChannel];
1967 M20[CompositeChannels]+=M20[IndexChannel];
1968 M21[CompositeChannels]+=M21[IndexChannel];
1969 M22[CompositeChannels]+=M22[IndexChannel];
1970 M30[CompositeChannels]+=M30[IndexChannel];
1972 M00[CompositeChannels]/=(double) channels;
1973 M01[CompositeChannels]/=(double) channels;
1974 M02[CompositeChannels]/=(double) channels;
1975 M03[CompositeChannels]/=(double) channels;
1976 M10[CompositeChannels]/=(double) channels;
1977 M11[CompositeChannels]/=(double) channels;
1978 M12[CompositeChannels]/=(double) channels;
1979 M20[CompositeChannels]/=(double) channels;
1980 M21[CompositeChannels]/=(double) channels;
1981 M22[CompositeChannels]/=(double) channels;
1982 M30[CompositeChannels]/=(double) channels;
1983 for (channel=0; channel <= CompositeChannels; channel++)
1988 channel_moments[channel].centroid=centroid[channel];
1989 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
1990 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
1991 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1992 (M20[channel]-M02[channel]))));
1993 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
1994 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
1995 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1996 (M20[channel]-M02[channel]))));
1997 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
1998 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
1999 if (fabs(M11[channel]) < 0.0)
2001 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2002 ((M20[channel]-M02[channel]) < 0.0))
2003 channel_moments[channel].ellipse_angle+=90.0;
2006 if (M11[channel] < 0.0)
2008 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2010 if ((M20[channel]-M02[channel]) < 0.0)
2011 channel_moments[channel].ellipse_angle+=90.0;
2013 channel_moments[channel].ellipse_angle+=180.0;
2017 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2018 ((M20[channel]-M02[channel]) < 0.0))
2019 channel_moments[channel].ellipse_angle+=90.0;
2020 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2021 channel_moments[channel].ellipse_axis.y*
2022 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2023 channel_moments[channel].ellipse_axis.x*
2024 channel_moments[channel].ellipse_axis.x)));
2025 channel_moments[channel].ellipse_intensity=M00[channel]/
2026 (MagickPI*channel_moments[channel].ellipse_axis.x*
2027 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2029 for (channel=0; channel <= CompositeChannels; channel++)
2036 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2037 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2038 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2039 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2040 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2041 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2042 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2043 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2046 for (channel=0; channel <= CompositeChannels; channel++)
2051 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2052 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2053 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2054 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2055 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2056 (3.0*M21[channel]-M03[channel]);
2057 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2058 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2059 (M21[channel]+M03[channel]);
2060 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2061 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2062 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2063 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2064 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2065 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2066 (M21[channel]+M03[channel]));
2067 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2068 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2069 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2070 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2071 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2072 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2073 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2074 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2075 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2076 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2077 (M21[channel]+M03[channel]));
2078 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2079 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2080 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2081 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2083 if (y < (ssize_t) image->rows)
2084 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2085 return(channel_moments);
2138 hash_image=BlurImage(image,0.0,1.0,exception);
2139 if (hash_image == (
Image *) NULL)
2141 hash_image->depth=8;
2142 status=TransformImageColorspace(hash_image,xyYColorspace);
2143 if (status == MagickFalse)
2145 moments=GetImageChannelMoments(hash_image,exception);
2146 hash_image=DestroyImage(hash_image);
2150 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2153 for (channel=0; channel <= CompositeChannels; channel++)
2154 for (i=0; i < MaximumNumberOfImageMoments; i++)
2155 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2160 hash_image=BlurImage(image,0.0,1.0,exception);
2161 if (hash_image == (
Image *) NULL)
2167 hash_image->depth=8;
2168 status=TransformImageColorspace(hash_image,HSBColorspace);
2169 if (status == MagickFalse)
2175 moments=GetImageChannelMoments(hash_image,exception);
2176 hash_image=DestroyImage(hash_image);
2183 for (channel=0; channel <= CompositeChannels; channel++)
2184 for (i=0; i < MaximumNumberOfImageMoments; i++)
2185 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2187 return(perceptual_hash);
2223MagickExport MagickBooleanType GetImageRange(
const Image *image,
2226 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2229MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2230 const ChannelType channel,
double *minima,
double *maxima,
2239 assert(image != (
Image *) NULL);
2240 assert(image->signature == MagickCoreSignature);
2241 if (IsEventLogging() != MagickFalse)
2242 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2243 *maxima=(-MagickMaximumValue);
2244 *minima=MagickMaximumValue;
2245 GetMagickPixelPacket(image,&pixel);
2246 for (y=0; y < (ssize_t) image->rows; y++)
2249 *magick_restrict indexes;
2257 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2260 indexes=GetVirtualIndexQueue(image);
2261 for (x=0; x < (ssize_t) image->columns; x++)
2263 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2264 if ((channel & RedChannel) != 0)
2266 if (pixel.red < *minima)
2267 *minima=(double) pixel.red;
2268 if (pixel.red > *maxima)
2269 *maxima=(double) pixel.red;
2271 if ((channel & GreenChannel) != 0)
2273 if (pixel.green < *minima)
2274 *minima=(double) pixel.green;
2275 if (pixel.green > *maxima)
2276 *maxima=(double) pixel.green;
2278 if ((channel & BlueChannel) != 0)
2280 if (pixel.blue < *minima)
2281 *minima=(double) pixel.blue;
2282 if (pixel.blue > *maxima)
2283 *maxima=(double) pixel.blue;
2285 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2287 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2288 *minima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2290 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2291 *maxima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2294 if (((channel & IndexChannel) != 0) &&
2295 (image->colorspace == CMYKColorspace))
2297 if ((
double) pixel.index < *minima)
2298 *minima=(
double) pixel.index;
2299 if ((
double) pixel.index > *maxima)
2300 *maxima=(
double) pixel.index;
2305 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2345 *channel_statistics;
2369 assert(image != (
Image *) NULL);
2370 assert(image->signature == MagickCoreSignature);
2371 if (IsEventLogging() != MagickFalse)
2372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2373 length=CompositeChannels+1UL;
2375 sizeof(*channel_statistics));
2377 sizeof(*histogram));
2385 channel_statistics);
2386 return(channel_statistics);
2388 (void) memset(channel_statistics,0,length*
2389 sizeof(*channel_statistics));
2390 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2392 channel_statistics[i].depth=1;
2393 channel_statistics[i].maxima=(-MagickMaximumValue);
2394 channel_statistics[i].minima=MagickMaximumValue;
2396 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2397 (void) memset(&number_bins,0,
sizeof(number_bins));
2398 for (y=0; y < (ssize_t) image->rows; y++)
2401 *magick_restrict indexes;
2412 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2415 indexes=GetVirtualIndexQueue(image);
2416 for (x=0; x < (ssize_t) image->columns; )
2418 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2420 depth=channel_statistics[RedChannel].depth;
2421 range=GetQuantumRange(depth);
2422 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2424 channel_statistics[RedChannel].depth++;
2428 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2430 depth=channel_statistics[GreenChannel].depth;
2431 range=GetQuantumRange(depth);
2432 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2434 channel_statistics[GreenChannel].depth++;
2438 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2440 depth=channel_statistics[BlueChannel].depth;
2441 range=GetQuantumRange(depth);
2442 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2444 channel_statistics[BlueChannel].depth++;
2448 if (image->matte != MagickFalse)
2450 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2452 depth=channel_statistics[OpacityChannel].depth;
2453 range=GetQuantumRange(depth);
2454 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2456 channel_statistics[OpacityChannel].depth++;
2461 if (image->colorspace == CMYKColorspace)
2463 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2465 depth=channel_statistics[BlackChannel].depth;
2466 range=GetQuantumRange(depth);
2467 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2469 channel_statistics[BlackChannel].depth++;
2474 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2475 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2476 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2477 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2478 channel_statistics[RedChannel].sum+=(double) GetPixelRed(p);
2479 channel_statistics[RedChannel].sum_squared+=(double) GetPixelRed(p)*
2480 (double) GetPixelRed(p);
2481 channel_statistics[RedChannel].sum_cubed+=(double) GetPixelRed(p)*
2482 (double) GetPixelRed(p)*(double) GetPixelRed(p);
2483 channel_statistics[RedChannel].sum_fourth_power+=(double)
2484 GetPixelRed(p)*(double) GetPixelRed(p)*(double) GetPixelRed(p)*
2485 (double) GetPixelRed(p);
2486 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2487 channel_statistics[GreenChannel].minima=(
double) GetPixelGreen(p);
2488 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2489 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(p);
2490 channel_statistics[GreenChannel].sum+=(double) GetPixelGreen(p);
2491 channel_statistics[GreenChannel].sum_squared+=(double) GetPixelGreen(p)*
2492 (double) GetPixelGreen(p);
2493 channel_statistics[GreenChannel].sum_cubed+=(double) GetPixelGreen(p)*
2494 (double) GetPixelGreen(p)*(double) GetPixelGreen(p);
2495 channel_statistics[GreenChannel].sum_fourth_power+=(double)
2496 GetPixelGreen(p)*(double) GetPixelGreen(p)*(double) GetPixelGreen(p)*
2497 (double) GetPixelGreen(p);
2498 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2499 channel_statistics[BlueChannel].minima=(
double) GetPixelBlue(p);
2500 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2501 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(p);
2502 channel_statistics[BlueChannel].sum+=(double) GetPixelBlue(p);
2503 channel_statistics[BlueChannel].sum_squared+=(double) GetPixelBlue(p)*
2504 (double) GetPixelBlue(p);
2505 channel_statistics[BlueChannel].sum_cubed+=(double) GetPixelBlue(p)*
2506 (double) GetPixelBlue(p)*(double) GetPixelBlue(p);
2507 channel_statistics[BlueChannel].sum_fourth_power+=(double)
2508 GetPixelBlue(p)*(double) GetPixelBlue(p)*(double) GetPixelBlue(p)*
2509 (double) GetPixelBlue(p);
2510 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2511 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2512 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2513 if (image->matte != MagickFalse)
2515 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2516 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2517 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2518 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2519 channel_statistics[OpacityChannel].sum+=GetPixelAlpha(p);
2520 channel_statistics[OpacityChannel].sum_squared+=(double)
2521 GetPixelAlpha(p)*GetPixelAlpha(p);
2522 channel_statistics[OpacityChannel].sum_cubed+=(double)
2523 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2524 channel_statistics[OpacityChannel].sum_fourth_power+=(double)
2525 GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p)*GetPixelAlpha(p);
2526 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2528 if (image->colorspace == CMYKColorspace)
2530 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2531 channel_statistics[BlackChannel].minima=(double)
2532 GetPixelIndex(indexes+x);
2533 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2534 channel_statistics[BlackChannel].maxima=(
double)
2535 GetPixelIndex(indexes+x);
2536 channel_statistics[BlackChannel].sum+=(double)
2537 GetPixelIndex(indexes+x);
2538 channel_statistics[BlackChannel].sum_squared+=(double)
2539 GetPixelIndex(indexes+x)*(double) GetPixelIndex(indexes+x);
2540 channel_statistics[BlackChannel].sum_cubed+=(double)
2541 GetPixelIndex(indexes+x)*(double) GetPixelIndex(indexes+x)*
2542 (double) GetPixelIndex(indexes+x);
2543 channel_statistics[BlackChannel].sum_fourth_power+=(double)
2544 GetPixelIndex(indexes+x)*(double) GetPixelIndex(indexes+x)*
2545 (double) GetPixelIndex(indexes+x)*(double) GetPixelIndex(indexes+x);
2546 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2552 for (i=0; i < (ssize_t) CompositeChannels; i++)
2562 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2563 mean=channel_statistics[i].sum*area;
2564 channel_statistics[i].sum=mean;
2565 channel_statistics[i].sum_squared*=area;
2566 channel_statistics[i].sum_cubed*=area;
2567 channel_statistics[i].sum_fourth_power*=area;
2568 channel_statistics[i].mean=mean;
2569 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2570 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2571 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2572 ((double) image->columns*image->rows);
2573 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2574 channel_statistics[i].standard_deviation=standard_deviation;
2576 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2578 if (histogram[i].red > 0.0)
2580 if (histogram[i].green > 0.0)
2581 number_bins.green++;
2582 if (histogram[i].blue > 0.0)
2584 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2585 number_bins.opacity++;
2586 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2587 number_bins.index++;
2589 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2590 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2595 histogram[i].red*=area;
2596 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2597 MagickLog10(histogram[i].red)*
2598 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2599 histogram[i].green*=area;
2600 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2601 MagickLog10(histogram[i].green)*
2602 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2603 histogram[i].blue*=area;
2604 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2605 MagickLog10(histogram[i].blue)*
2606 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2607 if (image->matte != MagickFalse)
2609 histogram[i].opacity*=area;
2610 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2611 MagickLog10(histogram[i].opacity)*
2612 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2614 if (image->colorspace == CMYKColorspace)
2616 histogram[i].index*=area;
2617 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2618 MagickLog10(histogram[i].index)*
2619 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2625 for (i=0; i < (ssize_t) CompositeChannels; i++)
2627 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2628 channel_statistics[CompositeChannels].depth,(double)
2629 channel_statistics[i].depth);
2630 channel_statistics[CompositeChannels].minima=MagickMin(
2631 channel_statistics[CompositeChannels].minima,
2632 channel_statistics[i].minima);
2633 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2634 channel_statistics[CompositeChannels].maxima,
2635 channel_statistics[i].maxima);
2636 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2637 channel_statistics[CompositeChannels].sum_squared+=
2638 channel_statistics[i].sum_squared;
2639 channel_statistics[CompositeChannels].sum_cubed+=
2640 channel_statistics[i].sum_cubed;
2641 channel_statistics[CompositeChannels].sum_fourth_power+=
2642 channel_statistics[i].sum_fourth_power;
2643 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2644 channel_statistics[CompositeChannels].variance+=
2645 channel_statistics[i].variance-channel_statistics[i].mean*
2646 channel_statistics[i].mean;
2647 standard_deviation=sqrt(channel_statistics[i].variance-
2648 (channel_statistics[i].mean*channel_statistics[i].mean));
2649 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2650 ((double) image->columns*image->rows);
2651 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2652 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2653 channel_statistics[CompositeChannels].entropy+=
2654 channel_statistics[i].entropy;
2657 if (image->matte != MagickFalse)
2659 if (image->colorspace == CMYKColorspace)
2661 channel_statistics[CompositeChannels].sum/=channels;
2662 channel_statistics[CompositeChannels].sum_squared/=channels;
2663 channel_statistics[CompositeChannels].sum_cubed/=channels;
2664 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2665 channel_statistics[CompositeChannels].mean/=channels;
2666 channel_statistics[CompositeChannels].kurtosis/=channels;
2667 channel_statistics[CompositeChannels].skewness/=channels;
2668 channel_statistics[CompositeChannels].entropy/=channels;
2669 i=CompositeChannels;
2670 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2671 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2672 channel_statistics[i].mean=channel_statistics[i].sum;
2673 standard_deviation=sqrt(channel_statistics[i].variance-
2674 (channel_statistics[i].mean*channel_statistics[i].mean));
2675 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2676 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2677 standard_deviation*standard_deviation);
2678 channel_statistics[i].standard_deviation=standard_deviation;
2679 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2684 standard_deviation=PerceptibleReciprocal(
2685 channel_statistics[i].standard_deviation);
2686 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2687 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2688 channel_statistics[i].mean*channel_statistics[i].mean*
2689 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2690 standard_deviation);
2691 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2692 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2693 channel_statistics[i].mean*channel_statistics[i].mean*
2694 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2695 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2696 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2697 standard_deviation*standard_deviation)-3.0;
2699 channel_statistics[CompositeChannels].mean=0.0;
2700 channel_statistics[CompositeChannels].standard_deviation=0.0;
2701 for (i=0; i < (ssize_t) CompositeChannels; i++)
2703 channel_statistics[CompositeChannels].mean+=
2704 channel_statistics[i].mean;
2705 channel_statistics[CompositeChannels].standard_deviation+=
2706 channel_statistics[i].standard_deviation;
2708 channel_statistics[CompositeChannels].mean/=(double) channels;
2709 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2711 if (y < (ssize_t) image->rows)
2713 channel_statistics);
2714 return(channel_statistics);
2755MagickExport
Image *PolynomialImage(
const Image *images,
2756 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2761 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2763 return(polynomial_image);
2766MagickExport
Image *PolynomialImageChannel(
const Image *images,
2767 const ChannelType channel,
const size_t number_terms,
const double *terms,
2770#define PolynomialImageTag "Polynomial/Image"
2785 **magick_restrict polynomial_pixels,
2791 assert(images != (
Image *) NULL);
2792 assert(images->signature == MagickCoreSignature);
2793 if (IsEventLogging() != MagickFalse)
2794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2796 assert(exception->signature == MagickCoreSignature);
2797 image=AcquireImageCanvas(images,exception);
2798 if (image == (
Image *) NULL)
2799 return((
Image *) NULL);
2800 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2802 InheritException(exception,&image->exception);
2803 image=DestroyImage(image);
2804 return((
Image *) NULL);
2806 polynomial_pixels=AcquirePixelTLS(images);
2809 image=DestroyImage(image);
2810 (void) ThrowMagickException(exception,GetMagickModule(),
2811 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2812 return((
Image *) NULL);
2819 GetMagickPixelPacket(images,&zero);
2820 polynomial_view=AcquireAuthenticCacheView(image,exception);
2821#if defined(MAGICKCORE_OPENMP_SUPPORT)
2822 #pragma omp parallel for schedule(static) shared(progress,status) \
2823 magick_number_threads(image,image,image->rows,1)
2825 for (y=0; y < (ssize_t) image->rows; y++)
2834 id = GetOpenMPThreadId();
2837 *magick_restrict polynomial_indexes;
2852 if (status == MagickFalse)
2854 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2861 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2862 polynomial_pixel=polynomial_pixels[id];
2863 for (x=0; x < (ssize_t) image->columns; x++)
2864 polynomial_pixel[x]=zero;
2866 number_images=GetImageListLength(images);
2867 for (i=0; i < (ssize_t) number_images; i++)
2875 if (i >= (ssize_t) number_terms)
2877 image_view=AcquireVirtualCacheView(next,exception);
2878 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2881 image_view=DestroyCacheView(image_view);
2884 indexes=GetCacheViewVirtualIndexQueue(image_view);
2885 for (x=0; x < (ssize_t) image->columns; x++)
2891 coefficient=terms[i << 1];
2892 degree=terms[(i << 1)+1];
2893 if ((channel & RedChannel) != 0)
2894 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2896 if ((channel & GreenChannel) != 0)
2897 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2900 if ((channel & BlueChannel) != 0)
2901 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2903 if ((channel & OpacityChannel) != 0)
2904 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2905 ((
double) QuantumRange-(double) p->opacity),degree);
2906 if (((channel & IndexChannel) != 0) &&
2907 (image->colorspace == CMYKColorspace))
2908 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2912 image_view=DestroyCacheView(image_view);
2913 next=GetNextImageInList(next);
2915 for (x=0; x < (ssize_t) image->columns; x++)
2917 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2918 polynomial_pixel[x].red));
2919 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2920 polynomial_pixel[x].green));
2921 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2922 polynomial_pixel[x].blue));
2923 if (image->matte == MagickFalse)
2924 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2925 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2927 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2928 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2929 if (image->colorspace == CMYKColorspace)
2930 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2931 QuantumRange*polynomial_pixel[x].index));
2934 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2936 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2941 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2943 if (proceed == MagickFalse)
2947 polynomial_view=DestroyCacheView(polynomial_view);
2948 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2949 if (status == MagickFalse)
2950 image=DestroyImage(image);
2992#define ListChannels 5
3019 lists[ListChannels];
3029 for (i=0; i < ListChannels; i++)
3030 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3031 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3032 pixel_list->lists[i].nodes);
3033 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3042 assert(pixel_list != (
PixelList **) NULL);
3043 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3044 if (pixel_list[i] != (
PixelList *) NULL)
3045 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3046 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3050static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3058 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3061 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3062 pixel_list->length=width*height;
3063 for (i=0; i < ListChannels; i++)
3065 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3066 sizeof(*pixel_list->lists[i].nodes));
3067 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3068 return(DestroyPixelList(pixel_list));
3069 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3070 sizeof(*pixel_list->lists[i].nodes));
3072 pixel_list->signature=MagickCoreSignature;
3076static PixelList **AcquirePixelListTLS(
const size_t width,
3077 const size_t height)
3088 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3089 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3090 sizeof(*pixel_list));
3093 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3094 for (i=0; i < (ssize_t) number_threads; i++)
3096 pixel_list[i]=AcquirePixelList(width,height);
3097 if (pixel_list[i] == (
PixelList *) NULL)
3098 return(DestroyPixelListTLS(pixel_list));
3103static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3119 list=pixel_list->lists+channel;
3120 list->nodes[color].signature=pixel_list->signature;
3121 list->nodes[color].count=1;
3126 for (level=list->level; level >= 0; level--)
3128 while (list->nodes[search].next[level] < color)
3129 search=list->nodes[search].next[level];
3130 update[level]=search;
3135 for (level=0; ; level++)
3137 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3138 if ((pixel_list->seed & 0x300) != 0x300)
3143 if (level > (list->level+2))
3144 level=list->level+2;
3148 while (level > list->level)
3151 update[list->level]=65536UL;
3158 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3159 list->nodes[update[level]].next[level]=color;
3160 }
while (level-- > 0);
3179 channels[ListChannels];
3184 for (channel=0; channel < 5; channel++)
3186 list=pixel_list->lists+channel;
3189 maximum=list->nodes[color].next[0];
3192 color=list->nodes[color].next[0];
3193 if (color > maximum)
3195 count+=list->nodes[color].count;
3196 }
while (count < (ssize_t) pixel_list->length);
3197 channels[channel]=(
unsigned short) maximum;
3199 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3200 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3201 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3202 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3203 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3224 channels[ListChannels];
3229 for (channel=0; channel < 5; channel++)
3231 list=pixel_list->lists+channel;
3237 color=list->nodes[color].next[0];
3238 sum+=(MagickRealType) list->nodes[color].count*color;
3239 count+=list->nodes[color].count;
3240 }
while (count < (ssize_t) pixel_list->length);
3241 sum/=pixel_list->length;
3242 channels[channel]=(
unsigned short) sum;
3244 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3245 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3246 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3247 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3248 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3266 channels[ListChannels];
3271 for (channel=0; channel < 5; channel++)
3273 list=pixel_list->lists+channel;
3278 color=list->nodes[color].next[0];
3279 count+=list->nodes[color].count;
3280 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3281 channels[channel]=(
unsigned short) color;
3283 GetMagickPixelPacket((
const Image *) NULL,pixel);
3284 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3285 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3286 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3287 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3288 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3307 channels[ListChannels];
3312 for (channel=0; channel < 5; channel++)
3314 list=pixel_list->lists+channel;
3317 minimum=list->nodes[color].next[0];
3320 color=list->nodes[color].next[0];
3321 if (color < minimum)
3323 count+=list->nodes[color].count;
3324 }
while (count < (ssize_t) pixel_list->length);
3325 channels[channel]=(
unsigned short) minimum;
3327 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3328 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3329 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3330 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3331 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3356 for (channel=0; channel < 5; channel++)
3358 list=pixel_list->lists+channel;
3361 max_count=list->nodes[mode].count;
3365 color=list->nodes[color].next[0];
3366 if (list->nodes[color].count > max_count)
3369 max_count=list->nodes[mode].count;
3371 count+=list->nodes[color].count;
3372 }
while (count < (ssize_t) pixel_list->length);
3373 channels[channel]=(
unsigned short) mode;
3375 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3376 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3377 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3378 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3379 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3404 for (channel=0; channel < 5; channel++)
3406 list=pixel_list->lists+channel;
3408 next=list->nodes[color].next[0];
3414 next=list->nodes[color].next[0];
3415 count+=list->nodes[color].count;
3416 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3417 if ((previous == 65536UL) && (next != 65536UL))
3420 if ((previous != 65536UL) && (next == 65536UL))
3422 channels[channel]=(
unsigned short) color;
3424 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3425 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3426 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3427 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3428 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3431static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3450 channels[ListChannels];
3455 for (channel=0; channel < 5; channel++)
3457 list=pixel_list->lists+channel;
3463 color=list->nodes[color].next[0];
3464 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3465 count+=list->nodes[color].count;
3466 }
while (count < (ssize_t) pixel_list->length);
3467 sum/=pixel_list->length;
3468 channels[channel]=(
unsigned short) sqrt(sum);
3470 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3471 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3472 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3473 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3474 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3477static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3495 channels[ListChannels];
3500 for (channel=0; channel < 5; channel++)
3502 list=pixel_list->lists+channel;
3512 color=list->nodes[color].next[0];
3513 sum+=(MagickRealType) list->nodes[color].count*color;
3514 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3515 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3516 count+=list->nodes[color].count;
3517 }
while (count < (ssize_t) pixel_list->length);
3518 sum/=pixel_list->length;
3519 sum_squared/=pixel_list->length;
3520 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3522 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3523 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3524 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3525 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3526 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3529static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3530 const IndexPacket *indexes,
PixelList *pixel_list)
3538 index=ScaleQuantumToShort(GetPixelRed(pixel));
3539 signature=pixel_list->lists[0].nodes[index].signature;
3540 if (signature == pixel_list->signature)
3541 pixel_list->lists[0].nodes[index].count++;
3543 AddNodePixelList(pixel_list,0,index);
3544 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3545 signature=pixel_list->lists[1].nodes[index].signature;
3546 if (signature == pixel_list->signature)
3547 pixel_list->lists[1].nodes[index].count++;
3549 AddNodePixelList(pixel_list,1,index);
3550 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3551 signature=pixel_list->lists[2].nodes[index].signature;
3552 if (signature == pixel_list->signature)
3553 pixel_list->lists[2].nodes[index].count++;
3555 AddNodePixelList(pixel_list,2,index);
3556 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3557 signature=pixel_list->lists[3].nodes[index].signature;
3558 if (signature == pixel_list->signature)
3559 pixel_list->lists[3].nodes[index].count++;
3561 AddNodePixelList(pixel_list,3,index);
3562 if (image->colorspace == CMYKColorspace)
3563 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3564 signature=pixel_list->lists[4].nodes[index].signature;
3565 if (signature == pixel_list->signature)
3566 pixel_list->lists[4].nodes[index].count++;
3568 AddNodePixelList(pixel_list,4,index);
3571static void ResetPixelList(
PixelList *pixel_list)
3588 for (channel=0; channel < 5; channel++)
3590 list=pixel_list->lists+channel;
3591 root=list->nodes+65536UL;
3593 for (level=0; level < 9; level++)
3594 root->next[level]=65536UL;
3596 pixel_list->seed=pixel_list->signature++;
3599MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3600 const size_t width,
const size_t height,
ExceptionInfo *exception)
3605 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3607 return(statistic_image);
3610MagickExport
Image *StatisticImageChannel(
const Image *image,
3611 const ChannelType channel,
const StatisticType type,
const size_t width,
3614#define StatisticImageTag "Statistic/Image"
3630 **magick_restrict pixel_list;
3642 assert(image != (
Image *) NULL);
3643 assert(image->signature == MagickCoreSignature);
3644 if (IsEventLogging() != MagickFalse)
3645 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3647 assert(exception->signature == MagickCoreSignature);
3648 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3649 if (statistic_image == (
Image *) NULL)
3650 return((
Image *) NULL);
3651 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3653 InheritException(exception,&statistic_image->exception);
3654 statistic_image=DestroyImage(statistic_image);
3655 return((
Image *) NULL);
3657 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3659 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3661 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3664 statistic_image=DestroyImage(statistic_image);
3665 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3672 image_view=AcquireVirtualCacheView(image,exception);
3673 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3674#if defined(MAGICKCORE_OPENMP_SUPPORT)
3675 #pragma omp parallel for schedule(static) shared(progress,status) \
3676 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3678 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3681 id = GetOpenMPThreadId();
3684 *magick_restrict indexes;
3690 *magick_restrict statistic_indexes;
3698 if (status == MagickFalse)
3700 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3701 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3702 neighbor_height,exception);
3703 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3709 indexes=GetCacheViewVirtualIndexQueue(image_view);
3710 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3711 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3728 ResetPixelList(pixel_list[
id]);
3729 for (v=0; v < (ssize_t) neighbor_height; v++)
3731 for (u=0; u < (ssize_t) neighbor_width; u++)
3732 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3733 r+=image->columns+neighbor_width;
3734 s+=image->columns+neighbor_width;
3736 GetMagickPixelPacket(image,&pixel);
3737 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3738 neighbor_width*neighbor_height/2,&pixel);
3741 case GradientStatistic:
3747 GetMinimumPixelList(pixel_list[
id],&pixel);
3749 GetMaximumPixelList(pixel_list[
id],&pixel);
3751 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3752 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3753 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3754 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3755 if (image->colorspace == CMYKColorspace)
3756 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3759 case MaximumStatistic:
3761 GetMaximumPixelList(pixel_list[
id],&pixel);
3766 GetMeanPixelList(pixel_list[
id],&pixel);
3769 case MedianStatistic:
3772 GetMedianPixelList(pixel_list[
id],&pixel);
3775 case MinimumStatistic:
3777 GetMinimumPixelList(pixel_list[
id],&pixel);
3782 GetModePixelList(pixel_list[
id],&pixel);
3785 case NonpeakStatistic:
3787 GetNonpeakPixelList(pixel_list[
id],&pixel);
3790 case RootMeanSquareStatistic:
3792 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3795 case StandardDeviationStatistic:
3797 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3801 if ((channel & RedChannel) != 0)
3802 SetPixelRed(q,ClampToQuantum(pixel.red));
3803 if ((channel & GreenChannel) != 0)
3804 SetPixelGreen(q,ClampToQuantum(pixel.green));
3805 if ((channel & BlueChannel) != 0)
3806 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3807 if ((channel & OpacityChannel) != 0)
3808 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3809 if (((channel & IndexChannel) != 0) &&
3810 (image->colorspace == CMYKColorspace))
3811 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3815 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3817 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3822 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3824 if (proceed == MagickFalse)
3828 statistic_view=DestroyCacheView(statistic_view);
3829 image_view=DestroyCacheView(image_view);
3830 pixel_list=DestroyPixelListTLS(pixel_list);
3831 if (status == MagickFalse)
3832 statistic_image=DestroyImage(statistic_image);
3833 return(statistic_image);