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(moments[channel].I[i]));
2168 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
2172 hash_image=BlurImage(image,0.0,1.0,exception);
2173 if (hash_image == (Image *) NULL)
2175 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2177 return((ChannelPerceptualHash *) NULL);
2179 hash_image->depth=8;
2180 status=TransformImageColorspace(hash_image,HSBColorspace);
2181 if (status == MagickFalse)
2183 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2185 return((ChannelPerceptualHash *) NULL);
2187 moments=GetImageChannelMoments(hash_image,exception);
2188 hash_image=DestroyImage(hash_image);
2189 if (moments == (ChannelMoments *) NULL)
2191 perceptual_hash=(ChannelPerceptualHash *) RelinquishMagickMemory(
2193 return((ChannelPerceptualHash *) NULL);
2195 for (channel=0; channel <= CompositeChannels; channel++)
2196 for (i=0; i < MaximumNumberOfImageMoments; i++)
2197 perceptual_hash[channel].Q[i]=(-MagickSafeLog10(moments[channel].I[i]));
2198 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
2199 return(perceptual_hash);
2235MagickExport MagickBooleanType GetImageRange(
const Image *image,
2236 double *minima,
double *maxima,ExceptionInfo *exception)
2238 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2241MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2242 const ChannelType channel,
double *minima,
double *maxima,
2243 ExceptionInfo *exception)
2251 assert(image != (Image *) NULL);
2252 assert(image->signature == MagickCoreSignature);
2253 if (IsEventLogging() != MagickFalse)
2254 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2255 *maxima=(-MagickMaximumValue);
2256 *minima=MagickMaximumValue;
2257 GetMagickPixelPacket(image,&pixel);
2258 for (y=0; y < (ssize_t) image->rows; y++)
2261 *magick_restrict indexes;
2269 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2270 if (p == (
const PixelPacket *) NULL)
2272 indexes=GetVirtualIndexQueue(image);
2273 for (x=0; x < (ssize_t) image->columns; x++)
2275 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2276 if ((channel & RedChannel) != 0)
2278 if (pixel.red < *minima)
2279 *minima=(double) pixel.red;
2280 if (pixel.red > *maxima)
2281 *maxima=(double) pixel.red;
2283 if ((channel & GreenChannel) != 0)
2285 if (pixel.green < *minima)
2286 *minima=(double) pixel.green;
2287 if (pixel.green > *maxima)
2288 *maxima=(double) pixel.green;
2290 if ((channel & BlueChannel) != 0)
2292 if (pixel.blue < *minima)
2293 *minima=(double) pixel.blue;
2294 if (pixel.blue > *maxima)
2295 *maxima=(double) pixel.blue;
2297 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2299 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2300 *minima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2302 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2303 *maxima=(double) ((MagickRealType) QuantumRange-(MagickRealType)
2306 if (((channel & IndexChannel) != 0) &&
2307 (image->colorspace == CMYKColorspace))
2309 if ((
double) pixel.index < *minima)
2310 *minima=(double) pixel.index;
2311 if ((
double) pixel.index > *maxima)
2312 *maxima=(double) pixel.index;
2317 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2353MagickExport ChannelStatistics *GetImageChannelStatistics(
const Image *image,
2354 ExceptionInfo *exception)
2357 *channel_statistics;
2379 assert(image != (Image *) NULL);
2380 assert(image->signature == MagickCoreSignature);
2381 if (IsEventLogging() != MagickFalse)
2382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2383 length=CompositeChannels+1UL;
2384 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
2385 sizeof(*channel_statistics));
2386 histogram=(MagickPixelPacket *) AcquireQuantumMemory(MaxMap+1U,
2387 sizeof(*histogram));
2388 if ((channel_statistics == (ChannelStatistics *) NULL) ||
2389 (histogram == (MagickPixelPacket *) NULL))
2391 if (histogram != (MagickPixelPacket *) NULL)
2392 histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
2393 if (channel_statistics != (ChannelStatistics *) NULL)
2394 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2395 channel_statistics);
2396 return(channel_statistics);
2398 (void) memset(channel_statistics,0,length*
2399 sizeof(*channel_statistics));
2400 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2402 ChannelStatistics *cs = channel_statistics+i;
2404 cs->maxima=(-MagickMaximumValue);
2405 cs->minima=MagickMaximumValue;
2408 cs->standard_deviation=0.0;
2414 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2415 (void) memset(&number_bins,0,
sizeof(number_bins));
2416 for (y=0; y < (ssize_t) image->rows; y++)
2419 *magick_restrict indexes;
2430 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2431 if (p == (
const PixelPacket *) NULL)
2433 indexes=GetVirtualIndexQueue(image);
2434 for (x=0; x < (ssize_t) image->columns; )
2436 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2438 depth=channel_statistics[RedChannel].depth;
2439 range=GetQuantumRange(depth);
2440 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2442 channel_statistics[RedChannel].depth++;
2446 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2448 depth=channel_statistics[GreenChannel].depth;
2449 range=GetQuantumRange(depth);
2450 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2452 channel_statistics[GreenChannel].depth++;
2456 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2458 depth=channel_statistics[BlueChannel].depth;
2459 range=GetQuantumRange(depth);
2460 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2462 channel_statistics[BlueChannel].depth++;
2466 if (image->matte != MagickFalse)
2468 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2470 depth=channel_statistics[OpacityChannel].depth;
2471 range=GetQuantumRange(depth);
2472 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2474 channel_statistics[OpacityChannel].depth++;
2479 if (image->colorspace == CMYKColorspace)
2481 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2483 depth=channel_statistics[BlackChannel].depth;
2484 range=GetQuantumRange(depth);
2485 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2487 channel_statistics[BlackChannel].depth++;
2492 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2493 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2494 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2495 channel_statistics[RedChannel].maxima=(double) GetPixelRed(p);
2496 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2497 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2498 QuantumScale*GetPixelRed(p);
2499 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2500 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2501 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2502 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2503 QuantumScale*GetPixelRed(p);
2504 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2505 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2506 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2507 channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(p);
2508 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2509 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2510 QuantumScale*GetPixelGreen(p);
2511 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2512 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2513 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2514 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2515 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2516 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2517 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2518 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2519 channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(p);
2520 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2521 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2522 QuantumScale*GetPixelBlue(p);
2523 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2524 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2525 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2526 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2527 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2528 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2529 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2530 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2531 if (image->matte != MagickFalse)
2533 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2534 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2535 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2536 channel_statistics[OpacityChannel].maxima=(double) GetPixelAlpha(p);
2537 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2538 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2539 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2540 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2541 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2543 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2544 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2545 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2546 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2548 if (image->colorspace == CMYKColorspace)
2550 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2551 channel_statistics[BlackChannel].minima=(double)
2552 GetPixelIndex(indexes+x);
2553 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2554 channel_statistics[BlackChannel].maxima=(double)
2555 GetPixelIndex(indexes+x);
2556 channel_statistics[BlackChannel].sum+=QuantumScale*
2557 GetPixelIndex(indexes+x);
2558 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2559 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2560 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2561 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2562 QuantumScale*GetPixelIndex(indexes+x);
2563 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2564 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2565 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2566 GetPixelIndex(indexes+x);
2567 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2573 for (i=0; i < (ssize_t) CompositeChannels; i++)
2583 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2584 mean=channel_statistics[i].sum*area;
2585 channel_statistics[i].sum=mean;
2586 channel_statistics[i].sum_squared*=area;
2587 channel_statistics[i].sum_cubed*=area;
2588 channel_statistics[i].sum_fourth_power*=area;
2589 channel_statistics[i].mean=mean;
2590 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2591 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2592 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2593 ((double) image->columns*image->rows);
2594 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2595 channel_statistics[i].standard_deviation=standard_deviation;
2597 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2599 if (histogram[i].red > 0.0)
2601 if (histogram[i].green > 0.0)
2602 number_bins.green++;
2603 if (histogram[i].blue > 0.0)
2605 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2606 number_bins.opacity++;
2607 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2608 number_bins.index++;
2610 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2611 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2619 histogram[i].red*=area;
2620 entropy=-histogram[i].red*log2(histogram[i].red)*
2621 MagickSafeReciprocal(log10((
double) number_bins.red));
2622 if (IsNaN(entropy) == 0)
2623 channel_statistics[RedChannel].entropy+=entropy;
2624 histogram[i].green*=area;
2625 entropy=-histogram[i].green*log2(histogram[i].green)*
2626 MagickSafeReciprocal(log10((
double) number_bins.green));
2627 if (IsNaN(entropy) == 0)
2628 channel_statistics[GreenChannel].entropy+=entropy;
2629 histogram[i].blue*=area;
2630 entropy=-histogram[i].blue*log2(histogram[i].blue)*
2631 MagickSafeReciprocal(log10((
double) number_bins.blue));
2632 if (IsNaN(entropy) == 0)
2633 channel_statistics[BlueChannel].entropy+=entropy;
2634 if (image->matte != MagickFalse)
2636 histogram[i].opacity*=area;
2637 entropy=-histogram[i].opacity*log2(histogram[i].opacity)*
2638 MagickSafeReciprocal(log10((
double) number_bins.opacity));
2639 if (IsNaN(entropy) == 0)
2640 channel_statistics[OpacityChannel].entropy+=entropy;
2642 if (image->colorspace == CMYKColorspace)
2644 histogram[i].index*=area;
2645 entropy=-histogram[i].index*log2(histogram[i].index)*
2646 MagickSafeReciprocal(log10((
double) number_bins.index));
2647 if (IsNaN(entropy) == 0)
2648 channel_statistics[IndexChannel].entropy+=entropy;
2654 for (i=0; i < (ssize_t) CompositeChannels; i++)
2656 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2657 channel_statistics[CompositeChannels].depth,(
double)
2658 channel_statistics[i].depth);
2659 channel_statistics[CompositeChannels].minima=MagickMin(
2660 channel_statistics[CompositeChannels].minima,
2661 channel_statistics[i].minima);
2662 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2663 channel_statistics[CompositeChannels].maxima,
2664 channel_statistics[i].maxima);
2665 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2666 channel_statistics[CompositeChannels].sum_squared+=
2667 channel_statistics[i].sum_squared;
2668 channel_statistics[CompositeChannels].sum_cubed+=
2669 channel_statistics[i].sum_cubed;
2670 channel_statistics[CompositeChannels].sum_fourth_power+=
2671 channel_statistics[i].sum_fourth_power;
2672 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2673 channel_statistics[CompositeChannels].variance+=
2674 channel_statistics[i].variance-channel_statistics[i].mean*
2675 channel_statistics[i].mean;
2676 standard_deviation=sqrt(channel_statistics[i].variance-
2677 (channel_statistics[i].mean*channel_statistics[i].mean));
2678 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2679 ((double) image->columns*image->rows);
2680 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2681 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2682 channel_statistics[CompositeChannels].entropy+=
2683 channel_statistics[i].entropy;
2686 if (image->matte != MagickFalse)
2688 if (image->colorspace == CMYKColorspace)
2690 channel_statistics[CompositeChannels].sum/=channels;
2691 channel_statistics[CompositeChannels].sum_squared/=channels;
2692 channel_statistics[CompositeChannels].sum_cubed/=channels;
2693 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2694 channel_statistics[CompositeChannels].mean/=channels;
2695 channel_statistics[CompositeChannels].kurtosis/=channels;
2696 channel_statistics[CompositeChannels].skewness/=channels;
2697 channel_statistics[CompositeChannels].entropy/=channels;
2698 i=CompositeChannels;
2699 area=MagickSafeReciprocal((
double) channels*image->columns*image->rows);
2700 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2701 channel_statistics[i].mean=channel_statistics[i].sum;
2702 standard_deviation=sqrt(channel_statistics[i].variance-
2703 (channel_statistics[i].mean*channel_statistics[i].mean));
2704 standard_deviation=sqrt(MagickSafeReciprocal((
double) channels*
2705 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2706 standard_deviation*standard_deviation);
2707 channel_statistics[i].standard_deviation=standard_deviation;
2708 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2713 standard_deviation=MagickSafeReciprocal(
2714 channel_statistics[i].standard_deviation);
2715 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2716 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2717 channel_statistics[i].mean*channel_statistics[i].mean*
2718 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2719 standard_deviation);
2720 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2721 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2722 channel_statistics[i].mean*channel_statistics[i].mean*
2723 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2724 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2725 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2726 standard_deviation*standard_deviation)-3.0;
2728 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2730 channel_statistics[i].mean*=QuantumRange;
2731 channel_statistics[i].variance*=QuantumRange;
2732 channel_statistics[i].standard_deviation*=QuantumRange;
2733 channel_statistics[i].sum*=QuantumRange;
2734 channel_statistics[i].sum_squared*=QuantumRange;
2735 channel_statistics[i].sum_cubed*=QuantumRange;
2736 channel_statistics[i].sum_fourth_power*=QuantumRange;
2738 channel_statistics[CompositeChannels].mean=0.0;
2739 channel_statistics[CompositeChannels].standard_deviation=0.0;
2740 for (i=0; i < (ssize_t) CompositeChannels; i++)
2742 channel_statistics[CompositeChannels].mean+=
2743 channel_statistics[i].mean;
2744 channel_statistics[CompositeChannels].standard_deviation+=
2745 channel_statistics[i].standard_deviation;
2747 channel_statistics[CompositeChannels].mean/=(double) channels;
2748 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2749 histogram=(MagickPixelPacket *) RelinquishMagickMemory(histogram);
2750 if (y < (ssize_t) image->rows)
2751 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2752 channel_statistics);
2753 return(channel_statistics);
2794MagickExport Image *PolynomialImage(
const Image *images,
2795 const size_t number_terms,
const double *terms,ExceptionInfo *exception)
2800 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2802 return(polynomial_image);
2805MagickExport Image *PolynomialImageChannel(
const Image *images,
2806 const ChannelType channel,
const size_t number_terms,
const double *terms,
2807 ExceptionInfo *exception)
2809#define PolynomialImageTag "Polynomial/Image"
2824 **magick_restrict polynomial_pixels,
2830 assert(images != (Image *) NULL);
2831 assert(images->signature == MagickCoreSignature);
2832 if (IsEventLogging() != MagickFalse)
2833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2834 assert(exception != (ExceptionInfo *) NULL);
2835 assert(exception->signature == MagickCoreSignature);
2836 image=AcquireImageCanvas(images,exception);
2837 if (image == (Image *) NULL)
2838 return((Image *) NULL);
2839 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2841 InheritException(exception,&image->exception);
2842 image=DestroyImage(image);
2843 return((Image *) NULL);
2845 polynomial_pixels=AcquirePixelTLS(images);
2846 if (polynomial_pixels == (MagickPixelPacket **) NULL)
2848 image=DestroyImage(image);
2849 (void) ThrowMagickException(exception,GetMagickModule(),
2850 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2851 return((Image *) NULL);
2858 GetMagickPixelPacket(images,&zero);
2859 polynomial_view=AcquireAuthenticCacheView(image,exception);
2860#if defined(MAGICKCORE_OPENMP_SUPPORT)
2861 #pragma omp parallel for schedule(static) shared(progress,status) \
2862 magick_number_threads(image,image,image->rows,1)
2864 for (y=0; y < (ssize_t) image->rows; y++)
2873 id = GetOpenMPThreadId();
2876 *magick_restrict polynomial_indexes;
2891 if (status == MagickFalse)
2893 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2895 if (q == (PixelPacket *) NULL)
2900 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2901 polynomial_pixel=polynomial_pixels[id];
2902 for (x=0; x < (ssize_t) image->columns; x++)
2903 polynomial_pixel[x]=zero;
2905 number_images=GetImageListLength(images);
2906 for (i=0; i < (ssize_t) number_images; i++)
2914 if (i >= (ssize_t) number_terms)
2916 image_view=AcquireVirtualCacheView(next,exception);
2917 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2918 if (p == (
const PixelPacket *) NULL)
2920 image_view=DestroyCacheView(image_view);
2923 indexes=GetCacheViewVirtualIndexQueue(image_view);
2924 for (x=0; x < (ssize_t) image->columns; x++)
2930 coefficient=terms[i << 1];
2931 degree=terms[(i << 1)+1];
2932 if ((channel & RedChannel) != 0)
2933 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2935 if ((channel & GreenChannel) != 0)
2936 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2939 if ((channel & BlueChannel) != 0)
2940 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2942 if ((channel & OpacityChannel) != 0)
2943 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2944 ((
double) QuantumRange-(
double) p->opacity),degree);
2945 if (((channel & IndexChannel) != 0) &&
2946 (image->colorspace == CMYKColorspace))
2947 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2951 image_view=DestroyCacheView(image_view);
2952 next=GetNextImageInList(next);
2954 for (x=0; x < (ssize_t) image->columns; x++)
2956 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2957 polynomial_pixel[x].red));
2958 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2959 polynomial_pixel[x].green));
2960 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2961 polynomial_pixel[x].blue));
2962 if (image->matte == MagickFalse)
2963 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2964 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2966 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2967 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2968 if (image->colorspace == CMYKColorspace)
2969 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2970 QuantumRange*polynomial_pixel[x].index));
2973 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2975 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2980 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2982 if (proceed == MagickFalse)
2986 polynomial_view=DestroyCacheView(polynomial_view);
2987 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2988 if (status == MagickFalse)
2989 image=DestroyImage(image);
3031#define ListChannels 5
3058 lists[ListChannels];
3061static PixelList *DestroyPixelList(PixelList *pixel_list)
3066 if (pixel_list == (PixelList *) NULL)
3067 return((PixelList *) NULL);
3068 for (i=0; i < ListChannels; i++)
3069 if (pixel_list->lists[i].nodes != (ListNode *) NULL)
3070 pixel_list->lists[i].nodes=(ListNode *) RelinquishAlignedMemory(
3071 pixel_list->lists[i].nodes);
3072 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
3076static PixelList **DestroyPixelListTLS(PixelList **pixel_list)
3081 assert(pixel_list != (PixelList **) NULL);
3082 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3083 if (pixel_list[i] != (PixelList *) NULL)
3084 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3085 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
3089static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3097 pixel_list=(PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3098 if (pixel_list == (PixelList *) NULL)
3100 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3101 pixel_list->length=width*height;
3102 for (i=0; i < ListChannels; i++)
3104 pixel_list->lists[i].nodes=(ListNode *) AcquireAlignedMemory(65537UL,
3105 sizeof(*pixel_list->lists[i].nodes));
3106 if (pixel_list->lists[i].nodes == (ListNode *) NULL)
3107 return(DestroyPixelList(pixel_list));
3108 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3109 sizeof(*pixel_list->lists[i].nodes));
3111 pixel_list->signature=MagickCoreSignature;
3115static PixelList **AcquirePixelListTLS(
const size_t width,
3116 const size_t height)
3127 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3128 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
3129 sizeof(*pixel_list));
3130 if (pixel_list == (PixelList **) NULL)
3131 return((PixelList **) NULL);
3132 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3133 for (i=0; i < (ssize_t) number_threads; i++)
3135 pixel_list[i]=AcquirePixelList(width,height);
3136 if (pixel_list[i] == (PixelList *) NULL)
3137 return(DestroyPixelListTLS(pixel_list));
3142static void AddNodePixelList(PixelList *pixel_list,
const ssize_t channel,
3158 list=pixel_list->lists+channel;
3159 list->nodes[color].signature=pixel_list->signature;
3160 list->nodes[color].count=1;
3165 (void) memset(update,0,
sizeof(update));
3166 for (level=list->level; level >= 0; level--)
3168 while (list->nodes[search].next[level] < color)
3169 search=list->nodes[search].next[level];
3170 update[level]=search;
3175 for (level=0; ; level++)
3177 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3178 if ((pixel_list->seed & 0x300) != 0x300)
3183 if (level > (list->level+2))
3184 level=list->level+2;
3188 while (level > list->level)
3191 update[list->level]=65536UL;
3198 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3199 list->nodes[update[level]].next[level]=color;
3200 }
while (level-- > 0);
3203static void GetMaximumPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3219 channels[ListChannels];
3224 for (channel=0; channel < 5; channel++)
3226 list=pixel_list->lists+channel;
3229 maximum=list->nodes[color].next[0];
3232 color=list->nodes[color].next[0];
3233 if (color > maximum)
3235 count+=list->nodes[color].count;
3236 }
while (count < (ssize_t) pixel_list->length);
3237 channels[channel]=(
unsigned short) maximum;
3239 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3240 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3241 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3242 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3243 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3246static void GetMeanPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3264 channels[ListChannels];
3269 for (channel=0; channel < 5; channel++)
3271 list=pixel_list->lists+channel;
3277 color=list->nodes[color].next[0];
3278 sum+=(MagickRealType) list->nodes[color].count*color;
3279 count+=list->nodes[color].count;
3280 }
while (count < (ssize_t) pixel_list->length);
3281 sum/=pixel_list->length;
3282 channels[channel]=(
unsigned short) sum;
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]);
3291static void GetMedianPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3306 channels[ListChannels];
3311 for (channel=0; channel < 5; channel++)
3313 list=pixel_list->lists+channel;
3318 color=list->nodes[color].next[0];
3319 count+=list->nodes[color].count;
3320 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3321 channels[channel]=(
unsigned short) color;
3323 GetMagickPixelPacket((
const Image *) NULL,pixel);
3324 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3325 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3326 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3327 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3328 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3331static void GetMinimumPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3347 channels[ListChannels];
3352 for (channel=0; channel < 5; channel++)
3354 list=pixel_list->lists+channel;
3357 minimum=list->nodes[color].next[0];
3360 color=list->nodes[color].next[0];
3361 if (color < minimum)
3363 count+=list->nodes[color].count;
3364 }
while (count < (ssize_t) pixel_list->length);
3365 channels[channel]=(
unsigned short) minimum;
3367 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3368 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3369 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3370 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3371 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3374static void GetModePixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3396 for (channel=0; channel < 5; channel++)
3398 list=pixel_list->lists+channel;
3401 max_count=list->nodes[mode].count;
3405 color=list->nodes[color].next[0];
3406 if (list->nodes[color].count > max_count)
3409 max_count=list->nodes[mode].count;
3411 count+=list->nodes[color].count;
3412 }
while (count < (ssize_t) pixel_list->length);
3413 channels[channel]=(
unsigned short) mode;
3415 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3416 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3417 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3418 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3419 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3422static void GetNonpeakPixelList(PixelList *pixel_list,MagickPixelPacket *pixel)
3444 for (channel=0; channel < 5; channel++)
3446 list=pixel_list->lists+channel;
3448 next=list->nodes[color].next[0];
3454 next=list->nodes[color].next[0];
3455 count+=list->nodes[color].count;
3456 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3457 if ((previous == 65536UL) && (next != 65536UL))
3460 if ((previous != 65536UL) && (next == 65536UL))
3462 channels[channel]=(
unsigned short) color;
3464 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3465 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3466 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3467 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3468 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3471static void GetRootMeanSquarePixelList(PixelList *pixel_list,
3472 MagickPixelPacket *pixel)
3490 channels[ListChannels];
3495 for (channel=0; channel < 5; channel++)
3497 list=pixel_list->lists+channel;
3503 color=list->nodes[color].next[0];
3504 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3505 count+=list->nodes[color].count;
3506 }
while (count < (ssize_t) pixel_list->length);
3507 sum/=pixel_list->length;
3508 channels[channel]=(
unsigned short) sqrt(sum);
3510 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3511 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3512 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3513 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3514 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3517static void GetStandardDeviationPixelList(PixelList *pixel_list,
3518 MagickPixelPacket *pixel)
3535 channels[ListChannels];
3540 for (channel=0; channel < 5; channel++)
3542 list=pixel_list->lists+channel;
3552 color=list->nodes[color].next[0];
3553 sum+=(MagickRealType) list->nodes[color].count*color;
3554 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3555 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3556 count+=list->nodes[color].count;
3557 }
while (count < (ssize_t) pixel_list->length);
3558 sum/=pixel_list->length;
3559 sum_squared/=pixel_list->length;
3560 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3562 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3563 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3564 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3565 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3566 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3569static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3570 const IndexPacket *indexes,PixelList *pixel_list)
3578 index=ScaleQuantumToShort(GetPixelRed(pixel));
3579 signature=pixel_list->lists[0].nodes[index].signature;
3580 if (signature == pixel_list->signature)
3581 pixel_list->lists[0].nodes[index].count++;
3583 AddNodePixelList(pixel_list,0,index);
3584 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3585 signature=pixel_list->lists[1].nodes[index].signature;
3586 if (signature == pixel_list->signature)
3587 pixel_list->lists[1].nodes[index].count++;
3589 AddNodePixelList(pixel_list,1,index);
3590 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3591 signature=pixel_list->lists[2].nodes[index].signature;
3592 if (signature == pixel_list->signature)
3593 pixel_list->lists[2].nodes[index].count++;
3595 AddNodePixelList(pixel_list,2,index);
3596 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3597 signature=pixel_list->lists[3].nodes[index].signature;
3598 if (signature == pixel_list->signature)
3599 pixel_list->lists[3].nodes[index].count++;
3601 AddNodePixelList(pixel_list,3,index);
3602 if (image->colorspace == CMYKColorspace)
3603 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3604 signature=pixel_list->lists[4].nodes[index].signature;
3605 if (signature == pixel_list->signature)
3606 pixel_list->lists[4].nodes[index].count++;
3608 AddNodePixelList(pixel_list,4,index);
3611static void ResetPixelList(PixelList *pixel_list)
3628 for (channel=0; channel < 5; channel++)
3630 list=pixel_list->lists+channel;
3631 root=list->nodes+65536UL;
3633 for (level=0; level < 9; level++)
3634 root->next[level]=65536UL;
3636 pixel_list->seed=pixel_list->signature++;
3639MagickExport Image *StatisticImage(
const Image *image,
const StatisticType type,
3640 const size_t width,
const size_t height,ExceptionInfo *exception)
3645 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3647 return(statistic_image);
3650MagickExport Image *StatisticImageChannel(
const Image *image,
3651 const ChannelType channel,
const StatisticType type,
const size_t width,
3652 const size_t height,ExceptionInfo *exception)
3654#define StatisticImageTag "Statistic/Image"
3670 **magick_restrict pixel_list;
3682 assert(image != (Image *) NULL);
3683 assert(image->signature == MagickCoreSignature);
3684 if (IsEventLogging() != MagickFalse)
3685 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3686 assert(exception != (ExceptionInfo *) NULL);
3687 assert(exception->signature == MagickCoreSignature);
3688 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3689 if (statistic_image == (Image *) NULL)
3690 return((Image *) NULL);
3691 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3693 InheritException(exception,&statistic_image->exception);
3694 statistic_image=DestroyImage(statistic_image);
3695 return((Image *) NULL);
3697 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3699 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3701 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3702 if (pixel_list == (PixelList **) NULL)
3704 statistic_image=DestroyImage(statistic_image);
3705 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3712 image_view=AcquireVirtualCacheView(image,exception);
3713 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3714#if defined(MAGICKCORE_OPENMP_SUPPORT)
3715 #pragma omp parallel for schedule(static) shared(progress,status) \
3716 magick_number_threads(image,statistic_image,statistic_image->rows,1)
3718 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3721 id = GetOpenMPThreadId();
3724 *magick_restrict indexes;
3730 *magick_restrict statistic_indexes;
3738 if (status == MagickFalse)
3740 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3741 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3742 neighbor_height,exception);
3743 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3744 if ((p == (
const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
3749 indexes=GetCacheViewVirtualIndexQueue(image_view);
3750 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3751 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3768 ResetPixelList(pixel_list[
id]);
3769 for (v=0; v < (ssize_t) neighbor_height; v++)
3771 for (u=0; u < (ssize_t) neighbor_width; u++)
3772 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3773 r+=(ptrdiff_t) image->columns+neighbor_width;
3774 s+=(ptrdiff_t) image->columns+neighbor_width;
3776 GetMagickPixelPacket(image,&pixel);
3777 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3778 neighbor_width*neighbor_height/2,&pixel);
3781 case GradientStatistic:
3787 GetMinimumPixelList(pixel_list[
id],&pixel);
3789 GetMaximumPixelList(pixel_list[
id],&pixel);
3791 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3792 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3793 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3794 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3795 if (image->colorspace == CMYKColorspace)
3796 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3799 case MaximumStatistic:
3801 GetMaximumPixelList(pixel_list[
id],&pixel);
3806 GetMeanPixelList(pixel_list[
id],&pixel);
3809 case MedianStatistic:
3812 GetMedianPixelList(pixel_list[
id],&pixel);
3815 case MinimumStatistic:
3817 GetMinimumPixelList(pixel_list[
id],&pixel);
3822 GetModePixelList(pixel_list[
id],&pixel);
3825 case NonpeakStatistic:
3827 GetNonpeakPixelList(pixel_list[
id],&pixel);
3830 case RootMeanSquareStatistic:
3832 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3835 case StandardDeviationStatistic:
3837 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3841 if ((channel & RedChannel) != 0)
3842 SetPixelRed(q,ClampToQuantum(pixel.red));
3843 if ((channel & GreenChannel) != 0)
3844 SetPixelGreen(q,ClampToQuantum(pixel.green));
3845 if ((channel & BlueChannel) != 0)
3846 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3847 if ((channel & OpacityChannel) != 0)
3848 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3849 if (((channel & IndexChannel) != 0) &&
3850 (image->colorspace == CMYKColorspace))
3851 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3855 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3857 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3862 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3864 if (proceed == MagickFalse)
3868 statistic_view=DestroyCacheView(statistic_view);
3869 image_view=DestroyCacheView(image_view);
3870 pixel_list=DestroyPixelListTLS(pixel_list);
3871 if (status == MagickFalse)
3872 statistic_image=DestroyImage(statistic_image);
3873 return(statistic_image);