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"
139static MagickPixelPacket **DestroyPixelTLS(
const Image *images,
140 MagickPixelPacket **pixels)
148 assert(pixels != (MagickPixelPacket **) NULL);
149 rows=MagickMax(GetImageListLength(images),
150 (
size_t) GetMagickResourceLimit(ThreadResource));
151 for (i=0; i < (ssize_t) rows; i++)
152 if (pixels[i] != (MagickPixelPacket *) NULL)
153 pixels[i]=(MagickPixelPacket *) RelinquishMagickMemory(pixels[i]);
154 pixels=(MagickPixelPacket **) RelinquishMagickMemory(pixels);
158static MagickPixelPacket **AcquirePixelTLS(
const Image *images)
174 rows=MagickMax(GetImageListLength(images),
175 (
size_t) GetMagickResourceLimit(ThreadResource));
176 pixels=(MagickPixelPacket **) AcquireQuantumMemory(rows,
sizeof(*pixels));
177 if (pixels == (MagickPixelPacket **) NULL)
178 return((MagickPixelPacket **) NULL);
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++)
185 pixels[i]=(MagickPixelPacket *) AcquireQuantumMemory(columns,
187 if (pixels[i] == (MagickPixelPacket *) NULL)
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)
208 const MagickPixelPacket
215 color_1=(
const MagickPixelPacket *) x;
216 color_2=(
const MagickPixelPacket *) 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)*MagickSafeReciprocal(value);
304 case LaplacianNoiseEvaluateOperator:
306 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
307 LaplacianNoise,value);
310 case LeftShiftEvaluateOperator:
312 result=(double) pixel;
313 for (i=0; i < (ssize_t) value; i++)
317 case LogEvaluateOperator:
319 if ((QuantumScale*(MagickRealType) pixel) >= MagickEpsilon)
320 result=(MagickRealType) QuantumRange*log((
double) (QuantumScale*value*
321 (MagickRealType) pixel+1.0))/log((
double) (value+1.0));
324 case MaxEvaluateOperator:
326 result=(MagickRealType) EvaluateMax((
double) pixel,value);
329 case MeanEvaluateOperator:
331 result=(MagickRealType) pixel+value;
334 case MedianEvaluateOperator:
336 result=(MagickRealType) pixel+value;
339 case MinEvaluateOperator:
341 result=(MagickRealType) MagickMin((
double) pixel,value);
344 case MultiplicativeNoiseEvaluateOperator:
346 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
347 MultiplicativeGaussianNoise,value);
350 case MultiplyEvaluateOperator:
352 result=(MagickRealType) pixel*value;
355 case OrEvaluateOperator:
357 result=(MagickRealType) ((ssize_t) pixel | (ssize_t) (value+0.5));
360 case PoissonNoiseEvaluateOperator:
362 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
366 case PowEvaluateOperator:
368 if (fabs(value) <= MagickEpsilon)
370 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
371 result=(double) -((MagickRealType) QuantumRange*pow(-(QuantumScale*
372 (
double) pixel),(
double) value));
374 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,
378 case RightShiftEvaluateOperator:
380 result=(MagickRealType) pixel;
381 for (i=0; i < (ssize_t) value; i++)
385 case RootMeanSquareEvaluateOperator:
387 result=((MagickRealType) pixel*(MagickRealType) pixel+value);
390 case SetEvaluateOperator:
395 case SineEvaluateOperator:
397 result=(MagickRealType) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
398 QuantumScale*(MagickRealType) pixel*value))+0.5);
401 case SubtractEvaluateOperator:
403 result=(MagickRealType) pixel-value;
406 case SumEvaluateOperator:
408 result=(MagickRealType) pixel+value;
411 case ThresholdEvaluateOperator:
413 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
417 case ThresholdBlackEvaluateOperator:
419 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
422 case ThresholdWhiteEvaluateOperator:
424 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
428 case UniformNoiseEvaluateOperator:
430 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
434 case XorEvaluateOperator:
436 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
443static Image *AcquireImageCanvas(
const Image *images,ExceptionInfo *exception)
455 columns=images->columns;
458 for (p=images; p != (Image *) NULL; p=p->next)
464 if (p->matte != MagickFalse)
466 if (p->colorspace == CMYKColorspace)
468 if (channels > number_channels)
470 number_channels=channels;
473 if (p->columns > columns)
478 return(CloneImage(q,columns,rows,MagickTrue,exception));
481MagickExport MagickBooleanType EvaluateImage(Image *image,
482 const MagickEvaluateOperator op,
const double value,ExceptionInfo *exception)
487 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
491MagickExport Image *EvaluateImages(
const Image *images,
492 const MagickEvaluateOperator op,ExceptionInfo *exception)
494#define EvaluateImageTag "Evaluate/Image"
509 **magick_restrict evaluate_pixels,
513 **magick_restrict random_info;
521#if defined(MAGICKCORE_OPENMP_SUPPORT)
526 assert(images != (Image *) NULL);
527 assert(images->signature == MagickCoreSignature);
528 assert(exception != (ExceptionInfo *) NULL);
529 assert(exception->signature == MagickCoreSignature);
530 if (IsEventLogging() != MagickFalse)
531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
532 image=AcquireImageCanvas(images,exception);
533 if (image == (Image *) NULL)
534 return((Image *) NULL);
535 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
537 InheritException(exception,&image->exception);
538 image=DestroyImage(image);
539 return((Image *) NULL);
541 evaluate_pixels=AcquirePixelTLS(images);
542 if (evaluate_pixels == (MagickPixelPacket **) NULL)
544 image=DestroyImage(image);
545 (void) ThrowMagickException(exception,GetMagickModule(),
546 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
547 return((Image *) NULL);
554 number_images=GetImageListLength(images);
555 GetMagickPixelPacket(images,&zero);
556 random_info=AcquireRandomInfoTLS();
557 evaluate_view=AcquireAuthenticCacheView(image,exception);
558 if (op == MedianEvaluateOperator)
560#if defined(MAGICKCORE_OPENMP_SUPPORT)
561 key=GetRandomSecretKey(random_info[0]);
562 #pragma omp parallel for schedule(static) shared(progress,status) \
563 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1)
565 for (y=0; y < (ssize_t) image->rows; y++)
574 id = GetOpenMPThreadId();
577 *magick_restrict evaluate_indexes;
588 if (status == MagickFalse)
590 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
592 if (q == (PixelPacket *) NULL)
597 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
598 evaluate_pixel=evaluate_pixels[id];
599 for (x=0; x < (ssize_t) image->columns; x++)
604 for (i=0; i < (ssize_t) number_images; i++)
605 evaluate_pixel[i]=zero;
607 for (i=0; i < (ssize_t) number_images; i++)
615 image_view=AcquireVirtualCacheView(next,exception);
616 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
617 if (p == (
const PixelPacket *) NULL)
619 image_view=DestroyCacheView(image_view);
622 indexes=GetCacheViewVirtualIndexQueue(image_view);
623 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
624 GetPixelRed(p),op,evaluate_pixel[i].red);
625 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
626 GetPixelGreen(p),op,evaluate_pixel[i].green);
627 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
628 GetPixelBlue(p),op,evaluate_pixel[i].blue);
629 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
630 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
631 if (image->colorspace == CMYKColorspace)
632 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
633 *indexes,op,evaluate_pixel[i].index);
634 image_view=DestroyCacheView(image_view);
635 next=GetNextImageInList(next);
637 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
639 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
640 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
641 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
642 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
643 if (image->colorspace == CMYKColorspace)
644 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
645 evaluate_pixel[i/2].index));
648 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
650 if (images->progress_monitor != (MagickProgressMonitor) NULL)
655#if defined(MAGICKCORE_OPENMP_SUPPORT)
659 proceed=SetImageProgress(images,EvaluateImageTag,progress,
661 if (proceed == MagickFalse)
668#if defined(MAGICKCORE_OPENMP_SUPPORT)
669 key=GetRandomSecretKey(random_info[0]);
670 #pragma omp parallel for schedule(static) shared(progress,status) \
671 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1)
673 for (y=0; y < (ssize_t) image->rows; y++)
682 id = GetOpenMPThreadId();
685 *magick_restrict evaluate_indexes;
697 if (status == MagickFalse)
699 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
701 if (q == (PixelPacket *) NULL)
706 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
707 evaluate_pixel=evaluate_pixels[id];
708 for (x=0; x < (ssize_t) image->columns; x++)
709 evaluate_pixel[x]=zero;
711 for (i=0; i < (ssize_t) number_images; i++)
719 image_view=AcquireVirtualCacheView(next,exception);
720 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
722 if (p == (
const PixelPacket *) NULL)
724 image_view=DestroyCacheView(image_view);
727 indexes=GetCacheViewVirtualIndexQueue(image_view);
728 for (x=0; x < (ssize_t) image->columns; x++)
730 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
731 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
732 evaluate_pixel[x].red);
733 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
734 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
735 evaluate_pixel[x].green);
736 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
737 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
738 evaluate_pixel[x].blue);
739 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
740 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
741 evaluate_pixel[x].opacity);
742 if (image->colorspace == CMYKColorspace)
743 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
744 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
745 evaluate_pixel[x].index);
748 image_view=DestroyCacheView(image_view);
749 next=GetNextImageInList(next);
751 if (op == MeanEvaluateOperator)
752 for (x=0; x < (ssize_t) image->columns; x++)
754 evaluate_pixel[x].red/=number_images;
755 evaluate_pixel[x].green/=number_images;
756 evaluate_pixel[x].blue/=number_images;
757 evaluate_pixel[x].opacity/=number_images;
758 evaluate_pixel[x].index/=number_images;
760 if (op == RootMeanSquareEvaluateOperator)
761 for (x=0; x < (ssize_t) image->columns; x++)
763 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
765 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
767 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
769 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
771 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
774 if (op == MultiplyEvaluateOperator)
775 for (x=0; x < (ssize_t) image->columns; x++)
780 for (j=0; j < ((ssize_t) number_images-1); j++)
782 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
785 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
786 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
789 for (x=0; x < (ssize_t) image->columns; x++)
791 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
792 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
793 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
794 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
795 if (image->colorspace == CMYKColorspace)
796 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
797 evaluate_pixel[x].index));
800 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
802 if (images->progress_monitor != (MagickProgressMonitor) NULL)
807 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
809 if (proceed == MagickFalse)
814 evaluate_view=DestroyCacheView(evaluate_view);
815 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
816 random_info=DestroyRandomInfoTLS(random_info);
817 if (status == MagickFalse)
818 image=DestroyImage(image);
822MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
823 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
824 ExceptionInfo *exception)
836 **magick_restrict random_info;
841#if defined(MAGICKCORE_OPENMP_SUPPORT)
846 assert(image != (Image *) NULL);
847 assert(image->signature == MagickCoreSignature);
848 assert(exception != (ExceptionInfo *) NULL);
849 assert(exception->signature == MagickCoreSignature);
850 if (IsEventLogging() != MagickFalse)
851 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
852 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
854 InheritException(exception,&image->exception);
859 random_info=AcquireRandomInfoTLS();
860 image_view=AcquireAuthenticCacheView(image,exception);
861#if defined(MAGICKCORE_OPENMP_SUPPORT)
862 key=GetRandomSecretKey(random_info[0]);
863 #pragma omp parallel for schedule(static) shared(progress,status) \
864 magick_number_threads(image,image,image->rows,key == ~0UL ? 0 : 1)
866 for (y=0; y < (ssize_t) image->rows; y++)
869 id = GetOpenMPThreadId();
872 *magick_restrict indexes;
880 if (status == MagickFalse)
882 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
883 if (q == (PixelPacket *) NULL)
888 indexes=GetCacheViewAuthenticIndexQueue(image_view);
889 for (x=0; x < (ssize_t) image->columns; x++)
894 if ((channel & RedChannel) != 0)
896 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
897 if (op == MeanEvaluateOperator)
899 SetPixelRed(q,ClampToQuantum(result));
901 if ((channel & GreenChannel) != 0)
903 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
905 if (op == MeanEvaluateOperator)
907 SetPixelGreen(q,ClampToQuantum(result));
909 if ((channel & BlueChannel) != 0)
911 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
913 if (op == MeanEvaluateOperator)
915 SetPixelBlue(q,ClampToQuantum(result));
917 if ((channel & OpacityChannel) != 0)
919 if (image->matte == MagickFalse)
921 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
923 if (op == MeanEvaluateOperator)
925 SetPixelOpacity(q,ClampToQuantum(result));
929 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
931 if (op == MeanEvaluateOperator)
933 SetPixelAlpha(q,ClampToQuantum(result));
936 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
938 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
940 if (op == MeanEvaluateOperator)
942 SetPixelIndex(indexes+x,ClampToQuantum(result));
946 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
948 if (image->progress_monitor != (MagickProgressMonitor) NULL)
953 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
954 if (proceed == MagickFalse)
958 image_view=DestroyCacheView(image_view);
959 random_info=DestroyRandomInfoTLS(random_info);
1003static Quantum ApplyFunction(Quantum pixel,
const MagickFunction function,
1004 const size_t number_parameters,
const double *parameters,
1005 ExceptionInfo *exception)
1017 case PolynomialFunction:
1025 for (i=0; i < (ssize_t) number_parameters; i++)
1026 result=result*QuantumScale*(MagickRealType) pixel+parameters[i];
1027 result*=(MagickRealType) QuantumRange;
1030 case SinusoidFunction:
1035 double freq,phase,ampl,bias;
1036 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1037 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1038 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1039 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1040 result=(MagickRealType) QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1041 (freq*QuantumScale*(MagickRealType) pixel+phase/360.0)))+bias);
1044 case ArcsinFunction:
1055 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1056 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1057 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1058 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1059 result=2.0*MagickSafeReciprocal(width)*(QuantumScale*(MagickRealType)
1062 result=bias-range/2.0;
1065 result=bias+range/2.0;
1067 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1068 result*=(MagickRealType) QuantumRange;
1071 case ArctanFunction:
1076 double slope,range,center,bias;
1077 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1078 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1079 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1080 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1081 result=(MagickRealType) (MagickPI*slope*(QuantumScale*(MagickRealType)
1083 result=(MagickRealType) QuantumRange*(range/MagickPI*atan((
double)
1087 case UndefinedFunction:
1090 return(ClampToQuantum(result));
1093MagickExport MagickBooleanType FunctionImage(Image *image,
1094 const MagickFunction function,
const size_t number_parameters,
1095 const double *parameters,ExceptionInfo *exception)
1100 status=FunctionImageChannel(image,CompositeChannels,function,
1101 number_parameters,parameters,exception);
1105MagickExport MagickBooleanType FunctionImageChannel(Image *image,
1106 const ChannelType channel,
const MagickFunction function,
1107 const size_t number_parameters,
const double *parameters,
1108 ExceptionInfo *exception)
1110#define FunctionImageTag "Function/Image "
1124 assert(image != (Image *) NULL);
1125 assert(image->signature == MagickCoreSignature);
1126 assert(exception != (ExceptionInfo *) NULL);
1127 assert(exception->signature == MagickCoreSignature);
1128 if (IsEventLogging() != MagickFalse)
1129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1130 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1132 InheritException(exception,&image->exception);
1133 return(MagickFalse);
1135#if defined(MAGICKCORE_OPENCL_SUPPORT)
1136 status=AccelerateFunctionImage(image,channel,function,number_parameters,
1137 parameters,exception);
1138 if (status != MagickFalse)
1143 image_view=AcquireAuthenticCacheView(image,exception);
1144#if defined(MAGICKCORE_OPENMP_SUPPORT)
1145 #pragma omp parallel for schedule(static) shared(progress,status) \
1146 magick_number_threads(image,image,image->rows,2)
1148 for (y=0; y < (ssize_t) image->rows; y++)
1151 *magick_restrict indexes;
1159 if (status == MagickFalse)
1161 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1162 if (q == (PixelPacket *) NULL)
1167 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1168 for (x=0; x < (ssize_t) image->columns; x++)
1170 if ((channel & RedChannel) != 0)
1171 SetPixelRed(q,ApplyFunction(GetPixelRed(q),function,
1172 number_parameters,parameters,exception));
1173 if ((channel & GreenChannel) != 0)
1174 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),function,
1175 number_parameters,parameters,exception));
1176 if ((channel & BlueChannel) != 0)
1177 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),function,
1178 number_parameters,parameters,exception));
1179 if ((channel & OpacityChannel) != 0)
1181 if (image->matte == MagickFalse)
1182 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),function,
1183 number_parameters,parameters,exception));
1185 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),function,
1186 number_parameters,parameters,exception));
1188 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1189 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),function,
1190 number_parameters,parameters,exception));
1193 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1195 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1200 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1201 if (proceed == MagickFalse)
1205 image_view=DestroyCacheView(image_view);
1239MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1240 double *entropy,ExceptionInfo *exception)
1245 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1249MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1250 const ChannelType channel,
double *entropy,ExceptionInfo *exception)
1253 *channel_statistics;
1258 assert(image != (Image *) NULL);
1259 assert(image->signature == MagickCoreSignature);
1260 if (IsEventLogging() != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1262 channel_statistics=GetImageChannelStatistics(image,exception);
1263 if (channel_statistics == (ChannelStatistics *) NULL)
1264 return(MagickFalse);
1266 channel_statistics[CompositeChannels].entropy=0.0;
1267 if ((channel & RedChannel) != 0)
1269 channel_statistics[CompositeChannels].entropy+=
1270 channel_statistics[RedChannel].entropy;
1273 if ((channel & GreenChannel) != 0)
1275 channel_statistics[CompositeChannels].entropy+=
1276 channel_statistics[GreenChannel].entropy;
1279 if ((channel & BlueChannel) != 0)
1281 channel_statistics[CompositeChannels].entropy+=
1282 channel_statistics[BlueChannel].entropy;
1285 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1287 channel_statistics[CompositeChannels].entropy+=
1288 channel_statistics[OpacityChannel].entropy;
1291 if (((channel & IndexChannel) != 0) &&
1292 (image->colorspace == CMYKColorspace))
1294 channel_statistics[CompositeChannels].entropy+=
1295 channel_statistics[BlackChannel].entropy;
1298 channel_statistics[CompositeChannels].entropy/=channels;
1299 *entropy=channel_statistics[CompositeChannels].entropy;
1300 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1301 channel_statistics);
1338MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1339 size_t *minima,
size_t *maxima,ExceptionInfo *exception)
1344 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1349MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1350 const ChannelType channel,
size_t *minima,
size_t *maxima,
1351 ExceptionInfo *exception)
1360 assert(image != (Image *) NULL);
1361 assert(image->signature == MagickCoreSignature);
1362 if (IsEventLogging() != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1364 status=GetImageChannelRange(image,channel,&min,&max,exception);
1365 *minima=(size_t) ceil(min-0.5);
1366 *maxima=(size_t) floor(max+0.5);
1404MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1405 double *kurtosis,
double *skewness,ExceptionInfo *exception)
1410 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1415MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1416 const ChannelType channel,
double *kurtosis,
double *skewness,
1417 ExceptionInfo *exception)
1430 assert(image != (Image *) NULL);
1431 assert(image->signature == MagickCoreSignature);
1432 if (IsEventLogging() != MagickFalse)
1433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1438 standard_deviation=0.0;
1441 sum_fourth_power=0.0;
1442 for (y=0; y < (ssize_t) image->rows; y++)
1445 *magick_restrict indexes;
1453 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1454 if (p == (
const PixelPacket *) NULL)
1456 indexes=GetVirtualIndexQueue(image);
1457 for (x=0; x < (ssize_t) image->columns; x++)
1459 if ((channel & RedChannel) != 0)
1461 mean+=QuantumScale*GetPixelRed(p);
1462 sum_squares+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
1463 sum_cubes+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
1464 QuantumScale*GetPixelRed(p);
1465 sum_fourth_power+=QuantumScale*GetPixelRed(p)*QuantumScale*
1466 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*
1470 if ((channel & GreenChannel) != 0)
1472 mean+=QuantumScale*GetPixelGreen(p);
1473 sum_squares+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1475 sum_cubes+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1476 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
1477 sum_fourth_power+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1478 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
1482 if ((channel & BlueChannel) != 0)
1484 mean+=QuantumScale*GetPixelBlue(p);
1485 sum_squares+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1487 sum_cubes+=QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*
1488 QuantumScale*GetPixelBlue(p);
1489 sum_fourth_power+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1490 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
1494 if ((channel & OpacityChannel) != 0)
1496 mean+=QuantumScale*GetPixelAlpha(p);
1497 sum_squares+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1499 sum_cubes+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1500 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
1501 sum_fourth_power+=QuantumScale*GetPixelAlpha(p)*QuantumScale*
1502 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*GetPixelAlpha(p);
1505 if (((channel & IndexChannel) != 0) &&
1506 (image->colorspace == CMYKColorspace))
1511 index=QuantumScale*GetPixelIndex(indexes+x);
1513 sum_squares+=index*index;
1514 sum_cubes+=index*index*index;
1515 sum_fourth_power+=index*index*index*index;
1521 if (y < (ssize_t) image->rows)
1522 return(MagickFalse);
1528 sum_fourth_power/=area;
1530 standard_deviation=sqrt(sum_squares-(mean*mean));
1531 if (standard_deviation != 0.0)
1533 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1534 3.0*mean*mean*mean*mean;
1535 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1538 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1539 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1541 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1578MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1579 double *standard_deviation,ExceptionInfo *exception)
1584 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1589MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1590 const ChannelType channel,
double *mean,
double *standard_deviation,
1591 ExceptionInfo *exception)
1594 *channel_statistics;
1599 assert(image != (Image *) NULL);
1600 assert(image->signature == MagickCoreSignature);
1601 if (IsEventLogging() != MagickFalse)
1602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1603 channel_statistics=GetImageChannelStatistics(image,exception);
1604 if (channel_statistics == (ChannelStatistics *) NULL)
1607 *standard_deviation=NAN;
1608 return(MagickFalse);
1611 channel_statistics[CompositeChannels].mean=0.0;
1612 channel_statistics[CompositeChannels].standard_deviation=0.0;
1613 if ((channel & RedChannel) != 0)
1615 channel_statistics[CompositeChannels].mean+=
1616 channel_statistics[RedChannel].mean;
1617 channel_statistics[CompositeChannels].standard_deviation+=
1618 channel_statistics[RedChannel].standard_deviation;
1621 if ((channel & GreenChannel) != 0)
1623 channel_statistics[CompositeChannels].mean+=
1624 channel_statistics[GreenChannel].mean;
1625 channel_statistics[CompositeChannels].standard_deviation+=
1626 channel_statistics[GreenChannel].standard_deviation;
1629 if ((channel & BlueChannel) != 0)
1631 channel_statistics[CompositeChannels].mean+=
1632 channel_statistics[BlueChannel].mean;
1633 channel_statistics[CompositeChannels].standard_deviation+=
1634 channel_statistics[BlueChannel].standard_deviation;
1637 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1639 channel_statistics[CompositeChannels].mean+=
1640 channel_statistics[OpacityChannel].mean;
1641 channel_statistics[CompositeChannels].standard_deviation+=
1642 channel_statistics[OpacityChannel].standard_deviation;
1645 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1647 channel_statistics[CompositeChannels].mean+=
1648 channel_statistics[BlackChannel].mean;
1649 channel_statistics[CompositeChannels].standard_deviation+=
1650 channel_statistics[CompositeChannels].standard_deviation;
1653 channel_statistics[CompositeChannels].mean/=channels;
1654 channel_statistics[CompositeChannels].standard_deviation/=channels;
1655 *mean=channel_statistics[CompositeChannels].mean;
1656 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1657 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1658 channel_statistics);
1688MagickExport ChannelMoments *GetImageChannelMoments(
const Image *image,
1689 ExceptionInfo *exception)
1691#define MaxNumberImageMoments 8
1697 M00[CompositeChannels+1],
1698 M01[CompositeChannels+1],
1699 M02[CompositeChannels+1],
1700 M03[CompositeChannels+1],
1701 M10[CompositeChannels+1],
1702 M11[CompositeChannels+1],
1703 M12[CompositeChannels+1],
1704 M20[CompositeChannels+1],
1705 M21[CompositeChannels+1],
1706 M22[CompositeChannels+1],
1707 M30[CompositeChannels+1];
1713 centroid[CompositeChannels+1];
1723 assert(image != (Image *) NULL);
1724 assert(image->signature == MagickCoreSignature);
1725 if (IsEventLogging() != MagickFalse)
1726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1727 length=CompositeChannels+1UL;
1728 channel_moments=(ChannelMoments *) AcquireQuantumMemory(length,
1729 sizeof(*channel_moments));
1730 if (channel_moments == (ChannelMoments *) NULL)
1731 return(channel_moments);
1732 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1733 (void) memset(centroid,0,
sizeof(centroid));
1734 (void) memset(M00,0,
sizeof(M00));
1735 (void) memset(M01,0,
sizeof(M01));
1736 (void) memset(M02,0,
sizeof(M02));
1737 (void) memset(M03,0,
sizeof(M03));
1738 (void) memset(M10,0,
sizeof(M10));
1739 (void) memset(M11,0,
sizeof(M11));
1740 (void) memset(M12,0,
sizeof(M12));
1741 (void) memset(M20,0,
sizeof(M20));
1742 (void) memset(M21,0,
sizeof(M21));
1743 (void) memset(M22,0,
sizeof(M22));
1744 (void) memset(M30,0,
sizeof(M30));
1745 GetMagickPixelPacket(image,&pixel);
1746 for (y=0; y < (ssize_t) image->rows; y++)
1749 *magick_restrict indexes;
1760 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1761 if (p == (
const PixelPacket *) NULL)
1763 indexes=GetVirtualIndexQueue(image);
1764 for (x=0; x < (ssize_t) image->columns; x++)
1766 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1767 M00[RedChannel]+=QuantumScale*pixel.red;
1768 M10[RedChannel]+=x*QuantumScale*pixel.red;
1769 M01[RedChannel]+=y*QuantumScale*pixel.red;
1770 M00[GreenChannel]+=QuantumScale*pixel.green;
1771 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1772 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1773 M00[BlueChannel]+=QuantumScale*pixel.blue;
1774 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1775 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1776 if (image->matte != MagickFalse)
1778 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1779 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1780 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1782 if (image->colorspace == CMYKColorspace)
1784 M00[IndexChannel]+=QuantumScale*pixel.index;
1785 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1786 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1791 for (channel=0; channel <= CompositeChannels; channel++)
1796 if (M00[channel] < MagickEpsilon)
1798 M00[channel]+=MagickEpsilon;
1799 centroid[channel].x=(double) image->columns/2.0;
1800 centroid[channel].y=(double) image->rows/2.0;
1803 M00[channel]+=MagickEpsilon;
1804 centroid[channel].x=M10[channel]/M00[channel];
1805 centroid[channel].y=M01[channel]/M00[channel];
1807 for (y=0; y < (ssize_t) image->rows; y++)
1810 *magick_restrict indexes;
1821 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1822 if (p == (
const PixelPacket *) NULL)
1824 indexes=GetVirtualIndexQueue(image);
1825 for (x=0; x < (ssize_t) image->columns; x++)
1827 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1828 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1829 centroid[RedChannel].y)*QuantumScale*pixel.red;
1830 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1831 centroid[RedChannel].x)*QuantumScale*pixel.red;
1832 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1833 centroid[RedChannel].y)*QuantumScale*pixel.red;
1834 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1835 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1837 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1838 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1840 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1841 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1842 centroid[RedChannel].y)*QuantumScale*pixel.red;
1843 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1844 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1846 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1847 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1849 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1850 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1851 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1852 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1853 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1854 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1855 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1856 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1858 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1859 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1861 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1862 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1863 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1864 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1865 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1867 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1868 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1870 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1871 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1872 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1873 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1874 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1875 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1876 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1877 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1879 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1880 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1882 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1883 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1884 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1885 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1886 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1888 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1889 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1891 if (image->matte != MagickFalse)
1893 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1894 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1895 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1896 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1897 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1898 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1899 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1900 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1901 QuantumScale*pixel.opacity;
1902 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1903 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1904 QuantumScale*pixel.opacity;
1905 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1906 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1907 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1908 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1909 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1910 QuantumScale*pixel.opacity;
1911 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1912 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1913 QuantumScale*pixel.opacity;
1915 if (image->colorspace == CMYKColorspace)
1917 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1918 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1919 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1920 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1921 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1922 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1923 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1924 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1925 QuantumScale*pixel.index;
1926 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1927 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1928 QuantumScale*pixel.index;
1929 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1930 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1931 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1932 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1933 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1934 QuantumScale*pixel.index;
1935 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1936 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1937 QuantumScale*pixel.index;
1943 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1944 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1945 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1946 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1947 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1948 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1949 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1950 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1951 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1952 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1953 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1954 if (image->matte != MagickFalse)
1957 M00[CompositeChannels]+=M00[OpacityChannel];
1958 M01[CompositeChannels]+=M01[OpacityChannel];
1959 M02[CompositeChannels]+=M02[OpacityChannel];
1960 M03[CompositeChannels]+=M03[OpacityChannel];
1961 M10[CompositeChannels]+=M10[OpacityChannel];
1962 M11[CompositeChannels]+=M11[OpacityChannel];
1963 M12[CompositeChannels]+=M12[OpacityChannel];
1964 M20[CompositeChannels]+=M20[OpacityChannel];
1965 M21[CompositeChannels]+=M21[OpacityChannel];
1966 M22[CompositeChannels]+=M22[OpacityChannel];
1967 M30[CompositeChannels]+=M30[OpacityChannel];
1969 if (image->colorspace == CMYKColorspace)
1972 M00[CompositeChannels]+=M00[IndexChannel];
1973 M01[CompositeChannels]+=M01[IndexChannel];
1974 M02[CompositeChannels]+=M02[IndexChannel];
1975 M03[CompositeChannels]+=M03[IndexChannel];
1976 M10[CompositeChannels]+=M10[IndexChannel];
1977 M11[CompositeChannels]+=M11[IndexChannel];
1978 M12[CompositeChannels]+=M12[IndexChannel];
1979 M20[CompositeChannels]+=M20[IndexChannel];
1980 M21[CompositeChannels]+=M21[IndexChannel];
1981 M22[CompositeChannels]+=M22[IndexChannel];
1982 M30[CompositeChannels]+=M30[IndexChannel];
1984 M00[CompositeChannels]/=(double) channels;
1985 M01[CompositeChannels]/=(double) channels;
1986 M02[CompositeChannels]/=(double) channels;
1987 M03[CompositeChannels]/=(double) channels;
1988 M10[CompositeChannels]/=(double) channels;
1989 M11[CompositeChannels]/=(double) channels;
1990 M12[CompositeChannels]/=(double) channels;
1991 M20[CompositeChannels]/=(double) channels;
1992 M21[CompositeChannels]/=(double) channels;
1993 M22[CompositeChannels]/=(double) channels;
1994 M30[CompositeChannels]/=(double) channels;
1995 for (channel=0; channel <= CompositeChannels; channel++)
2000 channel_moments[channel].centroid=centroid[channel];
2001 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
2002 MagickSafeReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
2003 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2004 (M20[channel]-M02[channel]))));
2005 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
2006 MagickSafeReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
2007 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2008 (M20[channel]-M02[channel]))));
2009 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
2010 M11[channel]*MagickSafeReciprocal(M20[channel]-M02[channel])));
2011 if (fabs(M11[channel]) < 0.0)
2013 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2014 ((M20[channel]-M02[channel]) < 0.0))
2015 channel_moments[channel].ellipse_angle+=90.0;
2018 if (M11[channel] < 0.0)
2020 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2022 if ((M20[channel]-M02[channel]) < 0.0)
2023 channel_moments[channel].ellipse_angle+=90.0;
2025 channel_moments[channel].ellipse_angle+=180.0;
2029 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2030 ((M20[channel]-M02[channel]) < 0.0))
2031 channel_moments[channel].ellipse_angle+=90.0;
2032 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2033 channel_moments[channel].ellipse_axis.y*
2034 channel_moments[channel].ellipse_axis.y*MagickSafeReciprocal(
2035 channel_moments[channel].ellipse_axis.x*
2036 channel_moments[channel].ellipse_axis.x)));
2037 channel_moments[channel].ellipse_intensity=M00[channel]/
2038 (MagickPI*channel_moments[channel].ellipse_axis.x*
2039 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2041 for (channel=0; channel <= CompositeChannels; channel++)
2048 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2049 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2050 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2051 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2052 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2053 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2054 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2055 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2058 for (channel=0; channel <= CompositeChannels; channel++)
2063 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2064 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2065 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2066 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2067 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2068 (3.0*M21[channel]-M03[channel]);
2069 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2070 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2071 (M21[channel]+M03[channel]);
2072 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2073 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2074 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2075 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2076 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2077 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2078 (M21[channel]+M03[channel]));
2079 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2080 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2081 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2082 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2083 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2084 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2085 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2086 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2087 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2088 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2089 (M21[channel]+M03[channel]));
2090 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2091 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2092 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2093 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2095 if (y < (ssize_t) image->rows)
2096 channel_moments=(ChannelMoments *) RelinquishMagickMemory(channel_moments);
2097 return(channel_moments);
2126MagickExport ChannelPerceptualHash *GetImageChannelPerceptualHash(
2127 const Image *image,ExceptionInfo *exception)
2132 ChannelPerceptualHash
2150 hash_image=BlurImage(image,0.0,1.0,exception);
2151 if (hash_image == (Image *) NULL)
2152 return((ChannelPerceptualHash *) NULL);
2153 hash_image->depth=8;
2154 status=TransformImageColorspace(hash_image,xyYColorspace);
2155 if (status == MagickFalse)
2156 return((ChannelPerceptualHash *) NULL);
2157 moments=GetImageChannelMoments(hash_image,exception);
2158 hash_image=DestroyImage(hash_image);
2159 if (moments == (ChannelMoments *) NULL)
2160 return((ChannelPerceptualHash *) NULL);
2161 perceptual_hash=(ChannelPerceptualHash *) AcquireQuantumMemory(
2162 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2163 if (perceptual_hash == (ChannelPerceptualHash *) NULL)
2164 return((ChannelPerceptualHash *) NULL);
2165 for (channel=0; channel <= CompositeChannels; channel++)
2166 for (i=0; i < MaximumNumberOfImageMoments; i++)
2167 perceptual_hash[channel].P[i]=(-MagickSafeLog10(fabs(
2168 moments[channel].I[i])));
2169 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
2173 hash_image=BlurImage(image,0.0,1.0,exception);
2174 if (hash_image == (Image *) NULL)
2176 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2178 return((ChannelPerceptualHash *) NULL);
2180 hash_image->depth=8;
2181 status=TransformImageColorspace(hash_image,HSBColorspace);
2182 if (status == MagickFalse)
2184 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2186 return((ChannelPerceptualHash *) NULL);
2188 moments=GetImageChannelMoments(hash_image,exception);
2189 hash_image=DestroyImage(hash_image);
2190 if (moments == (ChannelMoments *) NULL)
2192 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2194 return((ChannelPerceptualHash *) NULL);
2196 for (channel=0; channel <= CompositeChannels; channel++)
2197 for (i=0; i < MaximumNumberOfImageMoments; i++)
2198 perceptual_hash[channel].Q[i]=(-MagickSafeLog10(fabs(
2199 moments[channel].I[i])));
2200 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
2201 return(perceptual_hash);
2237MagickExport MagickBooleanType GetImageRange(
const Image *image,
2238 double *minima,
double *maxima,ExceptionInfo *exception)
2240 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2243MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2244 const ChannelType channel,
double *minima,
double *maxima,
2245 ExceptionInfo *exception)
2253 assert(image != (Image *) NULL);
2254 assert(image->signature == MagickCoreSignature);
2255 if (IsEventLogging() != MagickFalse)
2256 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2257 *maxima=(-MagickMaximumValue);
2258 *minima=MagickMaximumValue;
2259 GetMagickPixelPacket(image,&pixel);
2260 for (y=0; y < (ssize_t) image->rows; y++)
2263 *magick_restrict indexes;
2271 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2272 if (p == (
const PixelPacket *) NULL)
2274 indexes=GetVirtualIndexQueue(image);
2275 for (x=0; x < (ssize_t) image->columns; x++)
2277 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2278 if ((channel & RedChannel) != 0)
2280 if (pixel.red < *minima)
2281 *minima=(double) pixel.red;
2282 if (pixel.red > *maxima)
2283 *maxima=(double) pixel.red;
2285 if ((channel & GreenChannel) != 0)
2287 if (pixel.green < *minima)
2288 *minima=(double) pixel.green;
2289 if (pixel.green > *maxima)
2290 *maxima=(double) pixel.green;
2292 if ((channel & BlueChannel) != 0)
2294 if (pixel.blue < *minima)
2295 *minima=(double) pixel.blue;
2296 if (pixel.blue > *maxima)
2297 *maxima=(double) pixel.blue;
2299 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2301 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2302 *minima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2304 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2305 *maxima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2308 if (((channel & IndexChannel) != 0) &&
2309 (image->colorspace == CMYKColorspace))
2311 if ((
double) pixel.index < *minima)
2312 *minima=(double) pixel.index;
2313 if ((
double) pixel.index > *maxima)
2314 *maxima=(double) pixel.index;
2319 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2355MagickExport ChannelStatistics *GetImageChannelStatistics(
const Image *image,
2356 ExceptionInfo *exception)
2359 *channel_statistics;
2381 assert(image != (Image *) NULL);
2382 assert(image->signature == MagickCoreSignature);
2383 if (IsEventLogging() != MagickFalse)
2384 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2385 length=CompositeChannels+1UL;
2386 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
2387 sizeof(*channel_statistics));
2388 histogram=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1U,
2389 sizeof(*histogram));
2390 if ((channel_statistics == (ChannelStatistics *) NULL) ||
2391 (histogram == (MagickPixelPacket *) NULL))
2393 if (histogram != (MagickPixelPacket *) NULL)
2394 histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
2395 if (channel_statistics != (ChannelStatistics *) NULL)
2396 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2397 channel_statistics);
2398 return(channel_statistics);
2400 (void) memset(channel_statistics,0,length*
2401 sizeof(*channel_statistics));
2402 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2404 ChannelStatistics *cs = channel_statistics+i;
2406 cs->maxima=(-MagickMaximumValue);
2407 cs->minima=MagickMaximumValue;
2410 cs->standard_deviation=0.0;
2416 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2417 (void) memset(&number_bins,0,
sizeof(number_bins));
2418 for (y=0; y < (ssize_t) image->rows; y++)
2421 *magick_restrict indexes;
2432 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2433 if (p == (
const PixelPacket *) NULL)
2435 indexes=GetVirtualIndexQueue(image);
2436 for (x=0; x < (ssize_t) image->columns; )
2438 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2440 depth=channel_statistics[RedChannel].depth;
2441 range=GetQuantumRange(depth);
2442 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2444 channel_statistics[RedChannel].depth++;
2448 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2450 depth=channel_statistics[GreenChannel].depth;
2451 range=GetQuantumRange(depth);
2452 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2454 channel_statistics[GreenChannel].depth++;
2458 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2460 depth=channel_statistics[BlueChannel].depth;
2461 range=GetQuantumRange(depth);
2462 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2464 channel_statistics[BlueChannel].depth++;
2468 if (image->matte != MagickFalse)
2470 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2472 depth=channel_statistics[OpacityChannel].depth;
2473 range=GetQuantumRange(depth);
2474 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2476 channel_statistics[OpacityChannel].depth++;
2481 if (image->colorspace == CMYKColorspace)
2483 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2485 depth=channel_statistics[BlackChannel].depth;
2486 range=GetQuantumRange(depth);
2487 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2489 channel_statistics[BlackChannel].depth++;
2494 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2495 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2496 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2497 channel_statistics[RedChannel].maxima=(double) GetPixelRed(p);
2498 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2499 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2500 QuantumScale*GetPixelRed(p);
2501 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2502 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2503 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2504 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2505 QuantumScale*GetPixelRed(p);
2506 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2507 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2508 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2509 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(p);
2510 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2511 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2512 QuantumScale*GetPixelGreen(p);
2513 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2514 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2515 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2516 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2517 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2518 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2519 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2520 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2521 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(p);
2522 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2523 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2524 QuantumScale*GetPixelBlue(p);
2525 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2526 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2527 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2528 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2529 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2530 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2531 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2532 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2533 if (image->matte != MagickFalse)
2535 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2536 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2537 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2538 channel_statistics[OpacityChannel].maxima=(double) GetPixelAlpha(p);
2539 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2540 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2541 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2542 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2543 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2545 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2546 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2547 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2548 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2550 if (image->colorspace == CMYKColorspace)
2552 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2553 channel_statistics[BlackChannel].minima=(double)
2554 GetPixelIndex(indexes+x);
2555 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2556 channel_statistics[BlackChannel].maxima=(double)
2557 GetPixelIndex(indexes+x);
2558 channel_statistics[BlackChannel].sum+=QuantumScale*
2559 GetPixelIndex(indexes+x);
2560 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2561 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2562 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2563 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2564 QuantumScale*GetPixelIndex(indexes+x);
2565 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2566 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2567 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2568 GetPixelIndex(indexes+x);
2569 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2575 for (i=0; i < (ssize_t) CompositeChannels; i++)
2585 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2586 mean=channel_statistics[i].sum*area;
2587 channel_statistics[i].sum=mean;
2588 channel_statistics[i].sum_squared*=area;
2589 channel_statistics[i].sum_cubed*=area;
2590 channel_statistics[i].sum_fourth_power*=area;
2591 channel_statistics[i].mean=mean;
2592 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2593 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2594 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2595 ((double) image->columns*image->rows);
2596 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2597 channel_statistics[i].standard_deviation=standard_deviation;
2599 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2601 if (histogram[i].red > 0.0)
2603 if (histogram[i].green > 0.0)
2604 number_bins.green++;
2605 if (histogram[i].blue > 0.0)
2607 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2608 number_bins.opacity++;
2609 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2610 number_bins.index++;
2612 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2613 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2621 histogram[i].red*=area;
2622 entropy=-histogram[i].red*log2(histogram[i].red)*
2623 MagickSafeReciprocal(log2((
double) number_bins.red));
2624 if (IsNaN(entropy) == 0)
2625 channel_statistics[RedChannel].entropy+=entropy;
2626 histogram[i].green*=area;
2627 entropy=-histogram[i].green*log2(histogram[i].green)*
2628 MagickSafeReciprocal(log2((
double) number_bins.green));
2629 if (IsNaN(entropy) == 0)
2630 channel_statistics[GreenChannel].entropy+=entropy;
2631 histogram[i].blue*=area;
2632 entropy=-histogram[i].blue*log2(histogram[i].blue)*
2633 MagickSafeReciprocal(log2((
double) number_bins.blue));
2634 if (IsNaN(entropy) == 0)
2635 channel_statistics[BlueChannel].entropy+=entropy;
2636 if (image->matte != MagickFalse)
2638 histogram[i].opacity*=area;
2639 entropy=-histogram[i].opacity*log2(histogram[i].opacity)*
2640 MagickSafeReciprocal(log2((
double) number_bins.opacity));
2641 if (IsNaN(entropy) == 0)
2642 channel_statistics[OpacityChannel].entropy+=entropy;
2644 if (image->colorspace == CMYKColorspace)
2646 histogram[i].index*=area;
2647 entropy=-histogram[i].index*log2(histogram[i].index)*
2648 MagickSafeReciprocal(log2((
double) number_bins.index));
2649 if (IsNaN(entropy) == 0)
2650 channel_statistics[IndexChannel].entropy+=entropy;
2656 for (i=0; i < (ssize_t) CompositeChannels; i++)
2658 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2659 channel_statistics[CompositeChannels].depth,(
double)
2660 channel_statistics[i].depth);
2661 channel_statistics[CompositeChannels].minima=MagickMin(
2662 channel_statistics[CompositeChannels].minima,
2663 channel_statistics[i].minima);
2664 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2665 channel_statistics[CompositeChannels].maxima,
2666 channel_statistics[i].maxima);
2667 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2668 channel_statistics[CompositeChannels].sum_squared+=
2669 channel_statistics[i].sum_squared;
2670 channel_statistics[CompositeChannels].sum_cubed+=
2671 channel_statistics[i].sum_cubed;
2672 channel_statistics[CompositeChannels].sum_fourth_power+=
2673 channel_statistics[i].sum_fourth_power;
2674 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2675 channel_statistics[CompositeChannels].variance+=
2676 channel_statistics[i].variance-channel_statistics[i].mean*
2677 channel_statistics[i].mean;
2678 standard_deviation=sqrt(channel_statistics[i].variance-
2679 (channel_statistics[i].mean*channel_statistics[i].mean));
2680 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2681 ((double) image->columns*image->rows);
2682 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2683 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2684 channel_statistics[CompositeChannels].entropy+=
2685 channel_statistics[i].entropy;
2688 if (image->matte != MagickFalse)
2690 if (image->colorspace == CMYKColorspace)
2692 channel_statistics[CompositeChannels].sum/=channels;
2693 channel_statistics[CompositeChannels].sum_squared/=channels;
2694 channel_statistics[CompositeChannels].sum_cubed/=channels;
2695 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2696 channel_statistics[CompositeChannels].mean/=channels;
2697 channel_statistics[CompositeChannels].kurtosis/=channels;
2698 channel_statistics[CompositeChannels].skewness/=channels;
2699 channel_statistics[CompositeChannels].entropy/=channels;
2700 i=CompositeChannels;
2701 area=MagickSafeReciprocal((
double) channels*image->columns*image->rows);
2702 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2703 channel_statistics[i].mean=channel_statistics[i].sum;
2704 standard_deviation=sqrt(channel_statistics[i].variance-
2705 (channel_statistics[i].mean*channel_statistics[i].mean));
2706 standard_deviation=sqrt(MagickSafeReciprocal((
double) channels*
2707 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2708 standard_deviation*standard_deviation);
2709 channel_statistics[i].standard_deviation=standard_deviation;
2710 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2715 standard_deviation=MagickSafeReciprocal(
2716 channel_statistics[i].standard_deviation);
2717 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2718 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2719 channel_statistics[i].mean*channel_statistics[i].mean*
2720 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2721 standard_deviation);
2722 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2723 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2724 channel_statistics[i].mean*channel_statistics[i].mean*
2725 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2726 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2727 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2728 standard_deviation*standard_deviation)-3.0;
2730 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2732 channel_statistics[i].mean*=QuantumRange;
2733 channel_statistics[i].variance*=QuantumRange;
2734 channel_statistics[i].standard_deviation*=QuantumRange;
2735 channel_statistics[i].sum*=QuantumRange;
2736 channel_statistics[i].sum_squared*=QuantumRange;
2737 channel_statistics[i].sum_cubed*=QuantumRange;
2738 channel_statistics[i].sum_fourth_power*=QuantumRange;
2740 channel_statistics[CompositeChannels].mean=0.0;
2741 channel_statistics[CompositeChannels].standard_deviation=0.0;
2742 for (i=0; i < (ssize_t) CompositeChannels; i++)
2744 channel_statistics[CompositeChannels].mean+=
2745 channel_statistics[i].mean;
2746 channel_statistics[CompositeChannels].standard_deviation+=
2747 channel_statistics[i].standard_deviation;
2749 channel_statistics[CompositeChannels].mean/=(double) channels;
2750 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2751 histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
2752 if (y < (ssize_t) image->rows)
2753 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2754 channel_statistics);
2755 return(channel_statistics);
2796MagickExport Image *PolynomialImage(
const Image *images,
2797 const size_t number_terms,
const double *terms,ExceptionInfo *exception)
2802 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2804 return(polynomial_image);
2807MagickExport Image *PolynomialImageChannel(
const Image *images,
2808 const ChannelType channel,
const size_t number_terms,
const double *terms,
2809 ExceptionInfo *exception)
2811#define PolynomialImageTag "Polynomial/Image"
2826 **magick_restrict polynomial_pixels,
2832 assert(images != (Image *) NULL);
2833 assert(images->signature == MagickCoreSignature);
2834 if (IsEventLogging() != MagickFalse)
2835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2836 assert(exception != (ExceptionInfo *) NULL);
2837 assert(exception->signature == MagickCoreSignature);
2838 image=AcquireImageCanvas(images,exception);
2839 if (image == (Image *) NULL)
2840 return((Image *) NULL);
2841 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2843 InheritException(exception,&image->exception);
2844 image=DestroyImage(image);
2845 return((Image *) NULL);
2847 polynomial_pixels=AcquirePixelTLS(images);
2848 if (polynomial_pixels == (MagickPixelPacket **) NULL)
2850 image=DestroyImage(image);
2851 (void) ThrowMagickException(exception,GetMagickModule(),
2852 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2853 return((Image *) NULL);
2860 GetMagickPixelPacket(images,&zero);
2861 polynomial_view=AcquireAuthenticCacheView(image,exception);
2862#if defined(MAGICKCORE_OPENMP_SUPPORT)
2863 #pragma omp parallel for schedule(static) shared(progress,status) \
2864 magick_number_threads(image,image,image->rows,1)
2866 for (y=0; y < (ssize_t) image->rows; y++)
2875 id = GetOpenMPThreadId();
2878 *magick_restrict polynomial_indexes;
2893 if (status == MagickFalse)
2895 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2897 if (q == (PixelPacket *) NULL)
2902 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2903 polynomial_pixel=polynomial_pixels[id];
2904 for (x=0; x < (ssize_t) image->columns; x++)
2905 polynomial_pixel[x]=zero;
2907 number_images=GetImageListLength(images);
2908 for (i=0; i < (ssize_t) number_images; i++)
2916 if (i >= (ssize_t) number_terms)
2918 image_view=AcquireVirtualCacheView(next,exception);
2919 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2920 if (p == (
const PixelPacket *) NULL)
2922 image_view=DestroyCacheView(image_view);
2925 indexes=GetCacheViewVirtualIndexQueue(image_view);
2926 for (x=0; x < (ssize_t) image->columns; x++)
2932 coefficient=terms[i << 1];
2933 degree=terms[(i << 1)+1];
2934 if ((channel & RedChannel) != 0)
2935 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2937 if ((channel & GreenChannel) != 0)
2938 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2941 if ((channel & BlueChannel) != 0)
2942 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2944 if ((channel & OpacityChannel) != 0)
2945 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2946 ((
double) QuantumRange-(
double) p->opacity),degree);
2947 if (((channel & IndexChannel) != 0) &&
2948 (image->colorspace == CMYKColorspace))
2949 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2953 image_view=DestroyCacheView(image_view);
2954 next=GetNextImageInList(next);
2956 for (x=0; x < (ssize_t) image->columns; x++)
2958 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2959 polynomial_pixel[x].red));
2960 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2961 polynomial_pixel[x].green));
2962 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2963 polynomial_pixel[x].blue));
2964 if (image->matte == MagickFalse)
2965 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2966 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2968 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2969 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2970 if (image->colorspace == CMYKColorspace)
2971 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2972 QuantumRange*polynomial_pixel[x].index));
2975 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2977 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2982 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2984 if (proceed == MagickFalse)
2988 polynomial_view=DestroyCacheView(polynomial_view);
2989 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2990 if (status == MagickFalse)
2991 image=DestroyImage(image);
3033#define ListChannels 5
3060 lists[ListChannels];
3063static PixelList *DestroyPixelList(PixelList *pixel_list)
3068 if (pixel_list == (PixelList *) NULL)
3069 return((PixelList *) NULL);
3070 for (i=0; i < ListChannels; i++)
3071 if (pixel_list->lists[i].nodes != (ListNode *) NULL)
3072 pixel_list->lists[i].nodes=(ListNode *) RelinquishAlignedMemory(
3073 pixel_list->lists[i].nodes);
3074 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
3078static PixelList **DestroyPixelListTLS(PixelList **pixel_list)
3083 assert(pixel_list != (PixelList **) NULL);
3084 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3085 if (pixel_list[i] != (PixelList *) NULL)
3086 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3087 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
3091static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3099 pixel_list=(PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3100 if (pixel_list == (PixelList *) NULL)
3102 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3103 pixel_list->length=width*height;
3104 for (i=0; i < ListChannels; i++)
3106 pixel_list->lists[i].nodes=(ListNode *) AcquireAlignedMemory(65537UL,
3107 sizeof(*pixel_list->lists[i].nodes));
3108 if (pixel_list->lists[i].nodes == (ListNode *) NULL)
3109 return(DestroyPixelList(pixel_list));
3110 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3111 sizeof(*pixel_list->lists[i].nodes));
3113 pixel_list->signature=MagickCoreSignature;
3117static PixelList **AcquirePixelListTLS(
const size_t width,
const size_t height)
3128 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3129 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
3130 sizeof(*pixel_list));
3131 if (pixel_list == (PixelList **) NULL)
3132 return((PixelList **) NULL);
3133 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3134 for (i=0; i < (ssize_t) number_threads; i++)
3136 pixel_list[i]=AcquirePixelList(width,height);
3137 if (pixel_list[i] == (PixelList *) NULL)
3138 return(DestroyPixelListTLS(pixel_list));
3143static void AddNodePixelList(PixelList *pixel_list,
const ssize_t channel,
3159 list=pixel_list->lists+channel;
3160 list->nodes[color].signature=pixel_list->signature;
3161 list->nodes[color].count=1;
3166 (void) memset(update,0,
sizeof(update));
3167 for (level=list->level; level >= 0; level--)
3169 while (list->nodes[search].next[level] < color)
3170 search=list->nodes[search].next[level];
3171 update[level]=search;
3176 for (level=0; ; level++)
3178 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3179 if ((pixel_list->seed & 0x300) != 0x300)
3184 if (level > (list->level+2))
3185 level=list->level+2;
3189 while (level > list->level)
3192 update[list->level]=65536UL;
3199 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3200 list->nodes[update[level]].next[level]=color;
3201 }
while (level-- > 0);
3204static void GetMaximumPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3220 channels[ListChannels];
3225 for (channel=0; channel < 5; channel++)
3227 list=pixel_list->lists+channel;
3230 maximum=list->nodes[color].next[0];
3233 color=list->nodes[color].next[0];
3234 if (color > maximum)
3236 count+=list->nodes[color].count;
3237 }
while (count < (ssize_t) pixel_list->length);
3238 channels[channel]=(
unsigned short) maximum;
3240 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3241 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3242 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3243 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3244 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3247static void GetMeanPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3265 channels[ListChannels];
3270 for (channel=0; channel < 5; channel++)
3272 list=pixel_list->lists+channel;
3278 color=list->nodes[color].next[0];
3279 sum+=(MagickRealType) list->nodes[color].count*color;
3280 count+=list->nodes[color].count;
3281 }
while (count < (ssize_t) pixel_list->length);
3282 sum/=pixel_list->length;
3283 channels[channel]=(
unsigned short) sum;
3285 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3286 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3287 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3288 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3289 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3292static void GetMedianPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3307 channels[ListChannels];
3312 for (channel=0; channel < 5; channel++)
3314 list=pixel_list->lists+channel;
3319 color=list->nodes[color].next[0];
3320 count+=list->nodes[color].count;
3321 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3322 channels[channel]=(
unsigned short) color;
3324 GetMagickPixelPacket((
const Image *) NULL,pixel);
3325 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3326 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3327 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3328 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3329 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3332static void GetMinimumPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3348 channels[ListChannels];
3353 for (channel=0; channel < 5; channel++)
3355 list=pixel_list->lists+channel;
3358 minimum=list->nodes[color].next[0];
3361 color=list->nodes[color].next[0];
3362 if (color < minimum)
3364 count+=list->nodes[color].count;
3365 }
while (count < (ssize_t) pixel_list->length);
3366 channels[channel]=(
unsigned short) minimum;
3368 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3369 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3370 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3371 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3372 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3375static void GetModePixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3397 for (channel=0; channel < 5; channel++)
3399 list=pixel_list->lists+channel;
3402 max_count=list->nodes[mode].count;
3406 color=list->nodes[color].next[0];
3407 if (list->nodes[color].count > max_count)
3410 max_count=list->nodes[mode].count;
3412 count+=list->nodes[color].count;
3413 }
while (count < (ssize_t) pixel_list->length);
3414 channels[channel]=(
unsigned short) mode;
3416 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3417 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3418 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3419 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3420 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3423static void GetNonpeakPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3445 for (channel=0; channel < 5; channel++)
3447 list=pixel_list->lists+channel;
3449 next=list->nodes[color].next[0];
3455 next=list->nodes[color].next[0];
3456 count+=list->nodes[color].count;
3457 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3458 if ((previous == 65536UL) && (next != 65536UL))
3461 if ((previous != 65536UL) && (next == 65536UL))
3463 channels[channel]=(
unsigned short) color;
3465 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3466 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3467 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3468 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3469 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3472static void GetRootMeanSquarePixelList(PixelList *pixel_list,
3473 MagickPixelPacket *pixel)
3491 channels[ListChannels];
3496 for (channel=0; channel < 5; channel++)
3498 list=pixel_list->lists+channel;
3504 color=list->nodes[color].next[0];
3505 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3506 count+=list->nodes[color].count;
3507 }
while (count < (ssize_t) pixel_list->length);
3508 sum/=pixel_list->length;
3509 channels[channel]=(
unsigned short) sqrt(sum);
3511 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3512 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3513 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3514 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3515 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3518static void GetStandardDeviationPixelList(PixelList *pixel_list,
3519 MagickPixelPacket *pixel)
3536 channels[ListChannels];
3541 for (channel=0; channel < 5; channel++)
3543 list=pixel_list->lists+channel;
3553 color=list->nodes[color].next[0];
3554 sum+=(MagickRealType) list->nodes[color].count*color;
3555 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3556 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3557 count+=list->nodes[color].count;
3558 }
while (count < (ssize_t) pixel_list->length);
3559 sum/=pixel_list->length;
3560 sum_squared/=pixel_list->length;
3561 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3563 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3564 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3565 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3566 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3567 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3570static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3571 const IndexPacket *indexes,PixelList *pixel_list)
3579 index=ScaleQuantumToShort(GetPixelRed(pixel));
3580 signature=pixel_list->lists[0].nodes[index].signature;
3581 if (signature == pixel_list->signature)
3582 pixel_list->lists[0].nodes[index].count++;
3584 AddNodePixelList(pixel_list,0,index);
3585 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3586 signature=pixel_list->lists[1].nodes[index].signature;
3587 if (signature == pixel_list->signature)
3588 pixel_list->lists[1].nodes[index].count++;
3590 AddNodePixelList(pixel_list,1,index);
3591 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3592 signature=pixel_list->lists[2].nodes[index].signature;
3593 if (signature == pixel_list->signature)
3594 pixel_list->lists[2].nodes[index].count++;
3596 AddNodePixelList(pixel_list,2,index);
3597 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3598 signature=pixel_list->lists[3].nodes[index].signature;
3599 if (signature == pixel_list->signature)
3600 pixel_list->lists[3].nodes[index].count++;
3602 AddNodePixelList(pixel_list,3,index);
3603 if (image->colorspace == CMYKColorspace)
3604 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3605 signature=pixel_list->lists[4].nodes[index].signature;
3606 if (signature == pixel_list->signature)
3607 pixel_list->lists[4].nodes[index].count++;
3609 AddNodePixelList(pixel_list,4,index);
3612static void ResetPixelList(PixelList *pixel_list)
3629 for (channel=0; channel < 5; channel++)
3631 list=pixel_list->lists+channel;
3632 root=list->nodes+65536UL;
3634 for (level=0; level < 9; level++)
3635 root->next[level]=65536UL;
3637 pixel_list->seed=pixel_list->signature++;
3640MagickExport Image *StatisticImage(
const Image *image,
const StatisticType type,
3641 const size_t width,
const size_t height,ExceptionInfo *exception)
3646 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3648 return(statistic_image);
3651MagickExport Image *StatisticImageChannel(
const Image *image,
3652 const ChannelType channel,
const StatisticType type,
const size_t width,
3653 const size_t height,ExceptionInfo *exception)
3655#define StatisticImageTag "Statistic/Image"
3671 **magick_restrict pixel_list;
3683 assert(image != (Image *) NULL);
3684 assert(image->signature == MagickCoreSignature);
3685 if (IsEventLogging() != MagickFalse)
3686 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3687 assert(exception != (ExceptionInfo *) NULL);
3688 assert(exception->signature == MagickCoreSignature);
3689 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3690 if (statistic_image == (Image *) NULL)
3691 return((Image *) NULL);
3692 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3694 InheritException(exception,&statistic_image->exception);
3695 statistic_image=DestroyImage(statistic_image);
3696 return((Image *) NULL);
3698 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3700 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3702 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3703 if (pixel_list == (PixelList **) NULL)
3705 statistic_image=DestroyImage(statistic_image);
3706 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3713 image_view=AcquireVirtualCacheView(image,exception);
3714 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3715#if defined(MAGICKCORE_OPENMP_SUPPORT)
3716 #pragma omp parallel for schedule(static) shared(progress,status) \
3717 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3719 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3722 id = GetOpenMPThreadId();
3725 *magick_restrict indexes;
3731 *magick_restrict statistic_indexes;
3739 if (status == MagickFalse)
3741 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3742 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3743 neighbor_height,exception);
3744 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3745 if ((p == (
const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
3750 indexes=GetCacheViewVirtualIndexQueue(image_view);
3751 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3752 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3769 ResetPixelList(pixel_list[
id]);
3770 for (v=0; v < (ssize_t) neighbor_height; v++)
3772 for (u=0; u < (ssize_t) neighbor_width; u++)
3773 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3774 r+=(ptrdiff_t) image->columns+neighbor_width;
3775 s+=(ptrdiff_t) image->columns+neighbor_width;
3777 GetMagickPixelPacket(image,&pixel);
3778 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3779 neighbor_width*neighbor_height/2,&pixel);
3782 case GradientStatistic:
3788 GetMinimumPixelList(pixel_list[
id],&pixel);
3790 GetMaximumPixelList(pixel_list[
id],&pixel);
3792 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3793 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3794 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3795 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3796 if (image->colorspace == CMYKColorspace)
3797 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3800 case MaximumStatistic:
3802 GetMaximumPixelList(pixel_list[
id],&pixel);
3807 GetMeanPixelList(pixel_list[
id],&pixel);
3810 case MedianStatistic:
3813 GetMedianPixelList(pixel_list[
id],&pixel);
3816 case MinimumStatistic:
3818 GetMinimumPixelList(pixel_list[
id],&pixel);
3823 GetModePixelList(pixel_list[
id],&pixel);
3826 case NonpeakStatistic:
3828 GetNonpeakPixelList(pixel_list[
id],&pixel);
3831 case RootMeanSquareStatistic:
3833 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3836 case StandardDeviationStatistic:
3838 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3842 if ((channel & RedChannel) != 0)
3843 SetPixelRed(q,ClampToQuantum(pixel.red));
3844 if ((channel & GreenChannel) != 0)
3845 SetPixelGreen(q,ClampToQuantum(pixel.green));
3846 if ((channel & BlueChannel) != 0)
3847 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3848 if ((channel & OpacityChannel) != 0)
3849 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3850 if (((channel & IndexChannel) != 0) &&
3851 (image->colorspace == CMYKColorspace))
3852 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3856 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3858 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3863 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3865 if (proceed == MagickFalse)
3869 statistic_view=DestroyCacheView(statistic_view);
3870 image_view=DestroyCacheView(image_view);
3871 pixel_list=DestroyPixelListTLS(pixel_list);
3872 if (status == MagickFalse)
3873 statistic_image=DestroyImage(statistic_image);
3874 return(statistic_image);