43 #include "magick/studio.h" 44 #include "magick/accelerate-private.h" 45 #include "magick/animate.h" 46 #include "magick/attribute.h" 47 #include "magick/blob.h" 48 #include "magick/blob-private.h" 49 #include "magick/cache.h" 50 #include "magick/cache-private.h" 51 #include "magick/cache-view.h" 52 #include "magick/client.h" 53 #include "magick/color.h" 54 #include "magick/color-private.h" 55 #include "magick/colorspace.h" 56 #include "magick/colorspace-private.h" 57 #include "magick/composite.h" 58 #include "magick/composite-private.h" 59 #include "magick/compress.h" 60 #include "magick/constitute.h" 61 #include "magick/deprecate.h" 62 #include "magick/display.h" 63 #include "magick/draw.h" 64 #include "magick/enhance.h" 65 #include "magick/exception.h" 66 #include "magick/exception-private.h" 67 #include "magick/gem.h" 68 #include "magick/geometry.h" 69 #include "magick/list.h" 70 #include "magick/image-private.h" 71 #include "magick/magic.h" 72 #include "magick/magick.h" 73 #include "magick/memory_.h" 74 #include "magick/module.h" 75 #include "magick/monitor.h" 76 #include "magick/monitor-private.h" 77 #include "magick/option.h" 78 #include "magick/paint.h" 79 #include "magick/pixel-private.h" 80 #include "magick/profile.h" 81 #include "magick/property.h" 82 #include "magick/quantize.h" 83 #include "magick/random_.h" 84 #include "magick/random-private.h" 85 #include "magick/resource_.h" 86 #include "magick/segment.h" 87 #include "magick/semaphore.h" 88 #include "magick/signature-private.h" 89 #include "magick/statistic.h" 90 #include "magick/statistic-private.h" 91 #include "magick/string_.h" 92 #include "magick/thread-private.h" 93 #include "magick/timer.h" 94 #include "magick/utility.h" 95 #include "magick/version.h" 149 rows=MagickMax(GetImageListLength(images),
150 (
size_t) GetMagickResourceLimit(ThreadResource));
151 for (i=0; i < (ssize_t) rows; i++)
174 rows=MagickMax(GetImageListLength(images),
175 (
size_t) GetMagickResourceLimit(ThreadResource));
179 (void) memset(pixels,0,rows*
sizeof(*pixels));
180 columns=GetImageListLength(images);
181 for (next=images; next != (
Image *) NULL; next=next->next)
182 columns=MagickMax(next->columns,columns);
183 for (i=0; i < (ssize_t) rows; i++)
188 return(DestroyPixelTLS(images,pixels));
189 for (j=0; j < (ssize_t) columns; j++)
190 GetMagickPixelPacket(images,&pixels[i][j]);
195 static inline double EvaluateMax(
const double x,
const double y)
202 #if defined(__cplusplus) || defined(c_plusplus) 206 static int IntensityCompare(
const void *x,
const void *y)
217 intensity=(int) MagickPixelIntensity(color_2)-(int)
218 MagickPixelIntensity(color_1);
222 #if defined(__cplusplus) || defined(c_plusplus) 226 static 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));
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));
481 MagickExport MagickBooleanType EvaluateImage(
Image *image,
482 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
487 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
491 MagickExport
Image *EvaluateImages(
const Image *images,
494 #define EvaluateImageTag "Evaluate/Image" 509 **magick_restrict evaluate_pixels,
513 **magick_restrict random_info;
521 #if defined(MAGICKCORE_OPENMP_SUPPORT) 526 assert(images != (
Image *) NULL);
527 assert(images->signature == MagickCoreSignature);
529 assert(exception->signature == MagickCoreSignature);
530 if (IsEventLogging() != MagickFalse)
531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
532 image=AcquireImageCanvas(images,exception);
533 if (image == (
Image *) NULL)
534 return((
Image *) NULL);
535 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
537 InheritException(exception,&image->exception);
538 image=DestroyImage(image);
539 return((
Image *) NULL);
541 evaluate_pixels=AcquirePixelTLS(images);
544 image=DestroyImage(image);
545 (void) ThrowMagickException(exception,GetMagickModule(),
546 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
547 return((
Image *) NULL);
554 number_images=GetImageListLength(images);
555 GetMagickPixelPacket(images,&zero);
556 random_info=AcquireRandomInfoTLS();
557 evaluate_view=AcquireAuthenticCacheView(image,exception);
558 if (op == MedianEvaluateOperator)
560 #if defined(MAGICKCORE_OPENMP_SUPPORT) 561 key=GetRandomSecretKey(random_info[0]);
562 #pragma omp parallel for schedule(static) shared(progress,status) \ 563 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1) 565 for (y=0; y < (ssize_t) image->rows; y++)
574 id = GetOpenMPThreadId();
577 *magick_restrict evaluate_indexes;
588 if (status == MagickFalse)
590 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
597 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
598 evaluate_pixel=evaluate_pixels[id];
599 for (x=0; x < (ssize_t) image->columns; x++)
604 for (i=0; i < (ssize_t) number_images; i++)
605 evaluate_pixel[i]=zero;
607 for (i=0; i < (ssize_t) number_images; i++)
615 image_view=AcquireVirtualCacheView(next,exception);
616 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
619 image_view=DestroyCacheView(image_view);
622 indexes=GetCacheViewVirtualIndexQueue(image_view);
623 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
624 GetPixelRed(p),op,evaluate_pixel[i].red);
625 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
626 GetPixelGreen(p),op,evaluate_pixel[i].green);
627 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
628 GetPixelBlue(p),op,evaluate_pixel[i].blue);
629 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
630 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
631 if (image->colorspace == CMYKColorspace)
632 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
633 *indexes,op,evaluate_pixel[i].index);
634 image_view=DestroyCacheView(image_view);
635 next=GetNextImageInList(next);
637 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
639 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
640 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
641 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
642 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
643 if (image->colorspace == CMYKColorspace)
644 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
645 evaluate_pixel[i/2].index));
648 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
650 if (images->progress_monitor != (MagickProgressMonitor) NULL)
655 #if defined(MAGICKCORE_OPENMP_SUPPORT) 659 proceed=SetImageProgress(images,EvaluateImageTag,progress,
661 if (proceed == MagickFalse)
668 #if defined(MAGICKCORE_OPENMP_SUPPORT) 669 key=GetRandomSecretKey(random_info[0]);
670 #pragma omp parallel for schedule(static) shared(progress,status) \ 671 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1) 673 for (y=0; y < (ssize_t) image->rows; y++)
682 id = GetOpenMPThreadId();
685 *magick_restrict evaluate_indexes;
697 if (status == MagickFalse)
699 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
706 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
707 evaluate_pixel=evaluate_pixels[id];
708 for (x=0; x < (ssize_t) image->columns; x++)
709 evaluate_pixel[x]=zero;
711 for (i=0; i < (ssize_t) number_images; i++)
719 image_view=AcquireVirtualCacheView(next,exception);
720 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
724 image_view=DestroyCacheView(image_view);
727 indexes=GetCacheViewVirtualIndexQueue(image_view);
728 for (x=0; x < (ssize_t) image->columns; x++)
730 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
731 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
732 evaluate_pixel[x].red);
733 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
734 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
735 evaluate_pixel[x].green);
736 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
737 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
738 evaluate_pixel[x].blue);
739 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
740 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
741 evaluate_pixel[x].opacity);
742 if (image->colorspace == CMYKColorspace)
743 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
744 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
745 evaluate_pixel[x].index);
748 image_view=DestroyCacheView(image_view);
749 next=GetNextImageInList(next);
751 if (op == MeanEvaluateOperator)
752 for (x=0; x < (ssize_t) image->columns; x++)
754 evaluate_pixel[x].red/=number_images;
755 evaluate_pixel[x].green/=number_images;
756 evaluate_pixel[x].blue/=number_images;
757 evaluate_pixel[x].opacity/=number_images;
758 evaluate_pixel[x].index/=number_images;
760 if (op == RootMeanSquareEvaluateOperator)
761 for (x=0; x < (ssize_t) image->columns; x++)
763 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
765 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
767 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
769 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
771 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
774 if (op == MultiplyEvaluateOperator)
775 for (x=0; x < (ssize_t) image->columns; x++)
780 for (j=0; j < ((ssize_t) number_images-1); j++)
782 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
785 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
786 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
789 for (x=0; x < (ssize_t) image->columns; x++)
791 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
792 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
793 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
794 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
795 if (image->colorspace == CMYKColorspace)
796 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
797 evaluate_pixel[x].index));
800 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
802 if (images->progress_monitor != (MagickProgressMonitor) NULL)
807 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
809 if (proceed == MagickFalse)
814 evaluate_view=DestroyCacheView(evaluate_view);
815 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
816 random_info=DestroyRandomInfoTLS(random_info);
817 if (status == MagickFalse)
818 image=DestroyImage(image);
822 MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
823 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
836 **magick_restrict random_info;
841 #if defined(MAGICKCORE_OPENMP_SUPPORT) 846 assert(image != (
Image *) NULL);
847 assert(image->signature == MagickCoreSignature);
849 assert(exception->signature == MagickCoreSignature);
850 if (IsEventLogging() != MagickFalse)
851 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
852 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
854 InheritException(exception,&image->exception);
859 random_info=AcquireRandomInfoTLS();
860 image_view=AcquireAuthenticCacheView(image,exception);
861 #if defined(MAGICKCORE_OPENMP_SUPPORT) 862 key=GetRandomSecretKey(random_info[0]);
863 #pragma omp parallel for schedule(static) shared(progress,status) \ 864 magick_number_threads(image,image,image->rows,key == ~0UL ? 0 : 1) 866 for (y=0; y < (ssize_t) image->rows; y++)
869 id = GetOpenMPThreadId();
872 *magick_restrict indexes;
880 if (status == MagickFalse)
882 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
888 indexes=GetCacheViewAuthenticIndexQueue(image_view);
889 for (x=0; x < (ssize_t) image->columns; x++)
894 if ((channel & RedChannel) != 0)
896 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
897 if (op == MeanEvaluateOperator)
899 SetPixelRed(q,ClampToQuantum(result));
901 if ((channel & GreenChannel) != 0)
903 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
905 if (op == MeanEvaluateOperator)
907 SetPixelGreen(q,ClampToQuantum(result));
909 if ((channel & BlueChannel) != 0)
911 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
913 if (op == MeanEvaluateOperator)
915 SetPixelBlue(q,ClampToQuantum(result));
917 if ((channel & OpacityChannel) != 0)
919 if (image->matte == MagickFalse)
921 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
923 if (op == MeanEvaluateOperator)
925 SetPixelOpacity(q,ClampToQuantum(result));
929 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
931 if (op == MeanEvaluateOperator)
933 SetPixelAlpha(q,ClampToQuantum(result));
936 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
938 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
940 if (op == MeanEvaluateOperator)
942 SetPixelIndex(indexes+x,ClampToQuantum(result));
946 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
948 if (image->progress_monitor != (MagickProgressMonitor) NULL)
953 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
954 if (proceed == MagickFalse)
958 image_view=DestroyCacheView(image_view);
959 random_info=DestroyRandomInfoTLS(random_info);
1003 static Quantum ApplyFunction(Quantum pixel,
const MagickFunction
function,
1004 const size_t number_parameters,
const double *parameters,
1017 case PolynomialFunction:
1025 for (i=0; i < (ssize_t) number_parameters; i++)
1026 result=result*QuantumScale*(MagickRealType) pixel+parameters[i];
1027 result*=(MagickRealType) QuantumRange;
1030 case SinusoidFunction:
1035 double freq,phase,ampl,bias;
1036 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1037 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1038 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1039 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1040 result=(MagickRealType) QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1041 (freq*QuantumScale*(MagickRealType) pixel+phase/360.0)))+bias);
1044 case ArcsinFunction:
1055 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1056 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1057 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1058 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1059 result=2.0*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));
1093 MagickExport MagickBooleanType FunctionImage(
Image *image,
1094 const MagickFunction
function,
const size_t number_parameters,
1100 status=FunctionImageChannel(image,CompositeChannels,
function,
1101 number_parameters,parameters,exception);
1105 MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1106 const ChannelType channel,
const MagickFunction
function,
1107 const size_t number_parameters,
const double *parameters,
1110 #define FunctionImageTag "Function/Image " 1124 assert(image != (
Image *) NULL);
1125 assert(image->signature == MagickCoreSignature);
1127 assert(exception->signature == MagickCoreSignature);
1128 if (IsEventLogging() != MagickFalse)
1129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1130 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1132 InheritException(exception,&image->exception);
1133 return(MagickFalse);
1135 #if defined(MAGICKCORE_OPENCL_SUPPORT) 1136 status=AccelerateFunctionImage(image,channel,
function,number_parameters,
1137 parameters,exception);
1138 if (status != MagickFalse)
1143 image_view=AcquireAuthenticCacheView(image,exception);
1144 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1145 #pragma omp parallel for schedule(static) shared(progress,status) \ 1146 magick_number_threads(image,image,image->rows,2) 1148 for (y=0; y < (ssize_t) image->rows; y++)
1151 *magick_restrict indexes;
1159 if (status == MagickFalse)
1161 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1167 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1168 for (x=0; x < (ssize_t) image->columns; x++)
1170 if ((channel & RedChannel) != 0)
1171 SetPixelRed(q,ApplyFunction(GetPixelRed(q),
function,
1172 number_parameters,parameters,exception));
1173 if ((channel & GreenChannel) != 0)
1174 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),
function,
1175 number_parameters,parameters,exception));
1176 if ((channel & BlueChannel) != 0)
1177 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),
function,
1178 number_parameters,parameters,exception));
1179 if ((channel & OpacityChannel) != 0)
1181 if (image->matte == MagickFalse)
1182 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),
function,
1183 number_parameters,parameters,exception));
1185 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),
function,
1186 number_parameters,parameters,exception));
1188 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1189 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),
function,
1190 number_parameters,parameters,exception));
1193 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1195 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1200 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1201 if (proceed == MagickFalse)
1205 image_view=DestroyCacheView(image_view);
1239 MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1245 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1249 MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1250 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1253 *channel_statistics;
1258 assert(image != (
Image *) NULL);
1259 assert(image->signature == MagickCoreSignature);
1260 if (IsEventLogging() != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1262 channel_statistics=GetImageChannelStatistics(image,exception);
1264 return(MagickFalse);
1266 channel_statistics[CompositeChannels].entropy=0.0;
1267 if ((channel & RedChannel) != 0)
1269 channel_statistics[CompositeChannels].entropy+=
1270 channel_statistics[RedChannel].entropy;
1273 if ((channel & GreenChannel) != 0)
1275 channel_statistics[CompositeChannels].entropy+=
1276 channel_statistics[GreenChannel].entropy;
1279 if ((channel & BlueChannel) != 0)
1281 channel_statistics[CompositeChannels].entropy+=
1282 channel_statistics[BlueChannel].entropy;
1285 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1287 channel_statistics[CompositeChannels].entropy+=
1288 channel_statistics[OpacityChannel].entropy;
1291 if (((channel & IndexChannel) != 0) &&
1292 (image->colorspace == CMYKColorspace))
1294 channel_statistics[CompositeChannels].entropy+=
1295 channel_statistics[BlackChannel].entropy;
1298 channel_statistics[CompositeChannels].entropy/=channels;
1299 *entropy=channel_statistics[CompositeChannels].entropy;
1301 channel_statistics);
1338 MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1344 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1349 MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1350 const ChannelType channel,
size_t *minima,
size_t *maxima,
1360 assert(image != (
Image *) NULL);
1361 assert(image->signature == MagickCoreSignature);
1362 if (IsEventLogging() != MagickFalse)
1363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1364 status=GetImageChannelRange(image,channel,&min,&max,exception);
1365 *minima=(size_t) ceil(min-0.5);
1366 *maxima=(size_t) floor(max+0.5);
1404 MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1410 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1415 MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1416 const ChannelType channel,
double *kurtosis,
double *skewness,
1430 assert(image != (
Image *) NULL);
1431 assert(image->signature == MagickCoreSignature);
1432 if (IsEventLogging() != MagickFalse)
1433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1438 standard_deviation=0.0;
1441 sum_fourth_power=0.0;
1442 for (y=0; y < (ssize_t) image->rows; y++)
1445 *magick_restrict indexes;
1453 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1456 indexes=GetVirtualIndexQueue(image);
1457 for (x=0; x < (ssize_t) image->columns; x++)
1459 if ((channel & RedChannel) != 0)
1461 mean+=QuantumScale*GetPixelRed(p);
1462 sum_squares+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
1463 sum_cubes+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
1464 QuantumScale*GetPixelRed(p);
1465 sum_fourth_power+=QuantumScale*GetPixelRed(p)*QuantumScale*
1466 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*
1470 if ((channel & GreenChannel) != 0)
1472 mean+=QuantumScale*GetPixelGreen(p);
1473 sum_squares+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1475 sum_cubes+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1476 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
1477 sum_fourth_power+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1478 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
1482 if ((channel & BlueChannel) != 0)
1484 mean+=QuantumScale*GetPixelBlue(p);
1485 sum_squares+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1487 sum_cubes+=QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*
1488 QuantumScale*GetPixelBlue(p);
1489 sum_fourth_power+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1490 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
1494 if ((channel & OpacityChannel) != 0)
1496 mean+=QuantumScale*GetPixelAlpha(p);
1497 sum_squares+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1499 sum_cubes+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1500 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
1501 sum_fourth_power+=QuantumScale*GetPixelAlpha(p)*QuantumScale*
1502 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*GetPixelAlpha(p);
1505 if (((channel & IndexChannel) != 0) &&
1506 (image->colorspace == CMYKColorspace))
1511 index=QuantumScale*GetPixelIndex(indexes+x);
1513 sum_squares+=index*index;
1514 sum_cubes+=index*index*index;
1515 sum_fourth_power+=index*index*index*index;
1521 if (y < (ssize_t) image->rows)
1522 return(MagickFalse);
1528 sum_fourth_power/=area;
1530 standard_deviation=sqrt(sum_squares-(mean*mean));
1531 if (standard_deviation != 0.0)
1533 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1534 3.0*mean*mean*mean*mean;
1535 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1538 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1539 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1541 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1578 MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1584 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1589 MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1590 const ChannelType channel,
double *mean,
double *standard_deviation,
1594 *channel_statistics;
1599 assert(image != (
Image *) NULL);
1600 assert(image->signature == MagickCoreSignature);
1601 if (IsEventLogging() != MagickFalse)
1602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1603 channel_statistics=GetImageChannelStatistics(image,exception);
1607 *standard_deviation=NAN;
1608 return(MagickFalse);
1611 channel_statistics[CompositeChannels].mean=0.0;
1612 channel_statistics[CompositeChannels].standard_deviation=0.0;
1613 if ((channel & RedChannel) != 0)
1615 channel_statistics[CompositeChannels].mean+=
1616 channel_statistics[RedChannel].mean;
1617 channel_statistics[CompositeChannels].standard_deviation+=
1618 channel_statistics[RedChannel].standard_deviation;
1621 if ((channel & GreenChannel) != 0)
1623 channel_statistics[CompositeChannels].mean+=
1624 channel_statistics[GreenChannel].mean;
1625 channel_statistics[CompositeChannels].standard_deviation+=
1626 channel_statistics[GreenChannel].standard_deviation;
1629 if ((channel & BlueChannel) != 0)
1631 channel_statistics[CompositeChannels].mean+=
1632 channel_statistics[BlueChannel].mean;
1633 channel_statistics[CompositeChannels].standard_deviation+=
1634 channel_statistics[BlueChannel].standard_deviation;
1637 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1639 channel_statistics[CompositeChannels].mean+=
1640 channel_statistics[OpacityChannel].mean;
1641 channel_statistics[CompositeChannels].standard_deviation+=
1642 channel_statistics[OpacityChannel].standard_deviation;
1645 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1647 channel_statistics[CompositeChannels].mean+=
1648 channel_statistics[BlackChannel].mean;
1649 channel_statistics[CompositeChannels].standard_deviation+=
1650 channel_statistics[CompositeChannels].standard_deviation;
1653 channel_statistics[CompositeChannels].mean/=channels;
1654 channel_statistics[CompositeChannels].standard_deviation/=channels;
1655 *mean=channel_statistics[CompositeChannels].mean;
1656 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1658 channel_statistics);
1691 #define MaxNumberImageMoments 8 1697 M00[CompositeChannels+1],
1698 M01[CompositeChannels+1],
1699 M02[CompositeChannels+1],
1700 M03[CompositeChannels+1],
1701 M10[CompositeChannels+1],
1702 M11[CompositeChannels+1],
1703 M12[CompositeChannels+1],
1704 M20[CompositeChannels+1],
1705 M21[CompositeChannels+1],
1706 M22[CompositeChannels+1],
1707 M30[CompositeChannels+1];
1713 centroid[CompositeChannels+1];
1723 assert(image != (
Image *) NULL);
1724 assert(image->signature == MagickCoreSignature);
1725 if (IsEventLogging() != MagickFalse)
1726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1727 length=CompositeChannels+1UL;
1729 sizeof(*channel_moments));
1731 return(channel_moments);
1732 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1733 (void) memset(centroid,0,
sizeof(centroid));
1734 (void) memset(M00,0,
sizeof(M00));
1735 (void) memset(M01,0,
sizeof(M01));
1736 (void) memset(M02,0,
sizeof(M02));
1737 (void) memset(M03,0,
sizeof(M03));
1738 (void) memset(M10,0,
sizeof(M10));
1739 (void) memset(M11,0,
sizeof(M11));
1740 (void) memset(M12,0,
sizeof(M12));
1741 (void) memset(M20,0,
sizeof(M20));
1742 (void) memset(M21,0,
sizeof(M21));
1743 (void) memset(M22,0,
sizeof(M22));
1744 (void) memset(M30,0,
sizeof(M30));
1745 GetMagickPixelPacket(image,&pixel);
1746 for (y=0; y < (ssize_t) image->rows; y++)
1749 *magick_restrict indexes;
1760 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1763 indexes=GetVirtualIndexQueue(image);
1764 for (x=0; x < (ssize_t) image->columns; x++)
1766 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1767 M00[RedChannel]+=QuantumScale*pixel.red;
1768 M10[RedChannel]+=x*QuantumScale*pixel.red;
1769 M01[RedChannel]+=y*QuantumScale*pixel.red;
1770 M00[GreenChannel]+=QuantumScale*pixel.green;
1771 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1772 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1773 M00[BlueChannel]+=QuantumScale*pixel.blue;
1774 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1775 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1776 if (image->matte != MagickFalse)
1778 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1779 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1780 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1782 if (image->colorspace == CMYKColorspace)
1784 M00[IndexChannel]+=QuantumScale*pixel.index;
1785 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1786 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1791 for (channel=0; channel <= CompositeChannels; channel++)
1796 if (M00[channel] < MagickEpsilon)
1798 M00[channel]+=MagickEpsilon;
1799 centroid[channel].x=(double) image->columns/2.0;
1800 centroid[channel].y=(
double) image->rows/2.0;
1803 M00[channel]+=MagickEpsilon;
1804 centroid[channel].x=M10[channel]/M00[channel];
1805 centroid[channel].y=M01[channel]/M00[channel];
1807 for (y=0; y < (ssize_t) image->rows; y++)
1810 *magick_restrict indexes;
1821 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1824 indexes=GetVirtualIndexQueue(image);
1825 for (x=0; x < (ssize_t) image->columns; x++)
1827 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1828 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1829 centroid[RedChannel].y)*QuantumScale*pixel.red;
1830 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1831 centroid[RedChannel].x)*QuantumScale*pixel.red;
1832 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1833 centroid[RedChannel].y)*QuantumScale*pixel.red;
1834 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1835 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1837 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1838 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1840 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1841 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1842 centroid[RedChannel].y)*QuantumScale*pixel.red;
1843 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1844 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1846 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1847 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1849 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1850 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1851 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1852 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1853 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1854 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1855 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1856 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1858 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1859 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1861 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1862 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1863 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1864 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1865 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1867 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1868 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1870 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1871 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1872 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1873 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1874 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1875 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1876 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1877 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1879 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1880 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1882 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1883 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1884 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1885 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1886 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1888 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1889 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1891 if (image->matte != MagickFalse)
1893 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1894 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1895 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1896 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1897 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1898 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1899 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1900 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1901 QuantumScale*pixel.opacity;
1902 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1903 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1904 QuantumScale*pixel.opacity;
1905 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1906 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1907 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1908 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1909 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1910 QuantumScale*pixel.opacity;
1911 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1912 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1913 QuantumScale*pixel.opacity;
1915 if (image->colorspace == CMYKColorspace)
1917 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1918 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1919 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1920 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1921 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1922 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1923 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1924 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1925 QuantumScale*pixel.index;
1926 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1927 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1928 QuantumScale*pixel.index;
1929 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1930 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1931 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1932 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1933 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1934 QuantumScale*pixel.index;
1935 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1936 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1937 QuantumScale*pixel.index;
1943 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1944 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1945 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1946 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1947 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1948 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1949 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1950 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1951 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1952 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1953 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1954 if (image->matte != MagickFalse)
1957 M00[CompositeChannels]+=M00[OpacityChannel];
1958 M01[CompositeChannels]+=M01[OpacityChannel];
1959 M02[CompositeChannels]+=M02[OpacityChannel];
1960 M03[CompositeChannels]+=M03[OpacityChannel];
1961 M10[CompositeChannels]+=M10[OpacityChannel];
1962 M11[CompositeChannels]+=M11[OpacityChannel];
1963 M12[CompositeChannels]+=M12[OpacityChannel];
1964 M20[CompositeChannels]+=M20[OpacityChannel];
1965 M21[CompositeChannels]+=M21[OpacityChannel];
1966 M22[CompositeChannels]+=M22[OpacityChannel];
1967 M30[CompositeChannels]+=M30[OpacityChannel];
1969 if (image->colorspace == CMYKColorspace)
1972 M00[CompositeChannels]+=M00[IndexChannel];
1973 M01[CompositeChannels]+=M01[IndexChannel];
1974 M02[CompositeChannels]+=M02[IndexChannel];
1975 M03[CompositeChannels]+=M03[IndexChannel];
1976 M10[CompositeChannels]+=M10[IndexChannel];
1977 M11[CompositeChannels]+=M11[IndexChannel];
1978 M12[CompositeChannels]+=M12[IndexChannel];
1979 M20[CompositeChannels]+=M20[IndexChannel];
1980 M21[CompositeChannels]+=M21[IndexChannel];
1981 M22[CompositeChannels]+=M22[IndexChannel];
1982 M30[CompositeChannels]+=M30[IndexChannel];
1984 M00[CompositeChannels]/=(double) channels;
1985 M01[CompositeChannels]/=(double) channels;
1986 M02[CompositeChannels]/=(double) channels;
1987 M03[CompositeChannels]/=(double) channels;
1988 M10[CompositeChannels]/=(double) channels;
1989 M11[CompositeChannels]/=(double) channels;
1990 M12[CompositeChannels]/=(double) channels;
1991 M20[CompositeChannels]/=(double) channels;
1992 M21[CompositeChannels]/=(double) channels;
1993 M22[CompositeChannels]/=(double) channels;
1994 M30[CompositeChannels]/=(double) channels;
1995 for (channel=0; channel <= CompositeChannels; channel++)
2000 channel_moments[channel].centroid=centroid[channel];
2001 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
2002 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);
2148 hash_image=BlurImage(image,0.0,1.0,exception);
2149 if (hash_image == (
Image *) NULL)
2151 status=TransformImageColorspace(hash_image,xyYColorspace);
2152 if (status == MagickFalse)
2154 hash_image=DestroyImage(hash_image);
2157 status=SetImageDepth(hash_image,8);
2158 if (status == MagickFalse)
2160 hash_image=DestroyImage(hash_image);
2163 moments=GetImageChannelMoments(hash_image,exception);
2164 hash_image=DestroyImage(hash_image);
2168 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2171 (void) memset(perceptual_hash,0,(CompositeChannels+1UL)*
2172 sizeof(*perceptual_hash));
2173 for (channel=0; channel <= CompositeChannels; channel++)
2174 for (i=0; i < MaximumNumberOfPerceptualHashes; i++)
2175 perceptual_hash[channel].P[i]=(-MagickSafeLog10(fabs(
2176 moments[channel].I[i])));
2181 hash_image=BlurImage(image,0.0,1.0,exception);
2182 if (hash_image == (
Image *) NULL)
2188 status=TransformImageColorspace(hash_image,HSBColorspace);
2189 if (status == MagickFalse)
2191 hash_image=DestroyImage(hash_image);
2196 status=SetImageDepth(hash_image,8);
2197 if (status == MagickFalse)
2199 hash_image=DestroyImage(hash_image);
2204 moments=GetImageChannelMoments(hash_image,exception);
2205 hash_image=DestroyImage(hash_image);
2212 for (channel=0; channel <= CompositeChannels; channel++)
2213 for (i=0; i < MaximumNumberOfPerceptualHashes; i++)
2214 perceptual_hash[channel].Q[i]=(-MagickSafeLog10(fabs(
2215 moments[channel].I[i])));
2217 return(perceptual_hash);
2253 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2256 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2259 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2260 const ChannelType channel,
double *minima,
double *maxima,
2269 assert(image != (
Image *) NULL);
2270 assert(image->signature == MagickCoreSignature);
2271 if (IsEventLogging() != MagickFalse)
2272 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2273 *maxima=(-MagickMaximumValue);
2274 *minima=MagickMaximumValue;
2275 GetMagickPixelPacket(image,&pixel);
2276 for (y=0; y < (ssize_t) image->rows; y++)
2279 *magick_restrict indexes;
2287 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2290 indexes=GetVirtualIndexQueue(image);
2291 for (x=0; x < (ssize_t) image->columns; x++)
2293 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2294 if ((channel & RedChannel) != 0)
2296 if (pixel.red < *minima)
2297 *minima=(double) pixel.red;
2298 if (pixel.red > *maxima)
2299 *maxima=(double) pixel.red;
2301 if ((channel & GreenChannel) != 0)
2303 if (pixel.green < *minima)
2304 *minima=(double) pixel.green;
2305 if (pixel.green > *maxima)
2306 *maxima=(double) pixel.green;
2308 if ((channel & BlueChannel) != 0)
2310 if (pixel.blue < *minima)
2311 *minima=(double) pixel.blue;
2312 if (pixel.blue > *maxima)
2313 *maxima=(double) pixel.blue;
2315 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2317 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2318 *minima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2320 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2321 *maxima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2324 if (((channel & IndexChannel) != 0) &&
2325 (image->colorspace == CMYKColorspace))
2327 if ((
double) pixel.index < *minima)
2328 *minima=(
double) pixel.index;
2329 if ((
double) pixel.index > *maxima)
2330 *maxima=(
double) pixel.index;
2335 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2375 *channel_statistics;
2397 assert(image != (
Image *) NULL);
2398 assert(image->signature == MagickCoreSignature);
2399 if (IsEventLogging() != MagickFalse)
2400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2401 length=CompositeChannels+1UL;
2403 sizeof(*channel_statistics));
2405 sizeof(*histogram));
2413 channel_statistics);
2414 return(channel_statistics);
2416 (void) memset(channel_statistics,0,length*
2417 sizeof(*channel_statistics));
2418 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2422 cs->maxima=(-MagickMaximumValue);
2423 cs->minima=MagickMaximumValue;
2426 cs->standard_deviation=0.0;
2432 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2433 (void) memset(&number_bins,0,
sizeof(number_bins));
2434 for (y=0; y < (ssize_t) image->rows; y++)
2437 *magick_restrict indexes;
2448 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2451 indexes=GetVirtualIndexQueue(image);
2452 for (x=0; x < (ssize_t) image->columns; )
2454 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2456 depth=channel_statistics[RedChannel].depth;
2457 range=GetQuantumRange(depth);
2458 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2460 channel_statistics[RedChannel].depth++;
2464 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2466 depth=channel_statistics[GreenChannel].depth;
2467 range=GetQuantumRange(depth);
2468 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2470 channel_statistics[GreenChannel].depth++;
2474 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2476 depth=channel_statistics[BlueChannel].depth;
2477 range=GetQuantumRange(depth);
2478 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2480 channel_statistics[BlueChannel].depth++;
2484 if (image->matte != MagickFalse)
2486 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2488 depth=channel_statistics[OpacityChannel].depth;
2489 range=GetQuantumRange(depth);
2490 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2492 channel_statistics[OpacityChannel].depth++;
2497 if (image->colorspace == CMYKColorspace)
2499 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2501 depth=channel_statistics[BlackChannel].depth;
2502 range=GetQuantumRange(depth);
2503 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2505 channel_statistics[BlackChannel].depth++;
2510 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2511 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2512 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2513 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2514 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2515 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2516 QuantumScale*GetPixelRed(p);
2517 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2518 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2519 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2520 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2521 QuantumScale*GetPixelRed(p);
2522 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2523 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2524 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2525 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2526 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2527 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2528 QuantumScale*GetPixelGreen(p);
2529 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2530 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2531 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2532 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2533 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2534 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2535 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2536 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2537 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2538 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2539 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2540 QuantumScale*GetPixelBlue(p);
2541 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2542 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2543 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2544 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2545 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2546 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2547 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2548 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2549 if (image->matte != MagickFalse)
2551 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2552 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2553 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2554 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2555 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2556 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2557 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2558 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2559 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2561 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2562 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2563 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2564 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2566 if (image->colorspace == CMYKColorspace)
2568 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2569 channel_statistics[BlackChannel].minima=(double)
2570 GetPixelIndex(indexes+x);
2571 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2572 channel_statistics[BlackChannel].maxima=(
double)
2573 GetPixelIndex(indexes+x);
2574 channel_statistics[BlackChannel].sum+=QuantumScale*
2575 GetPixelIndex(indexes+x);
2576 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2577 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2578 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2579 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2580 QuantumScale*GetPixelIndex(indexes+x);
2581 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2582 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2583 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2584 GetPixelIndex(indexes+x);
2585 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2591 for (i=0; i < (ssize_t) CompositeChannels; i++)
2601 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2602 mean=channel_statistics[i].sum*area;
2603 channel_statistics[i].sum=mean;
2604 channel_statistics[i].sum_squared*=area;
2605 channel_statistics[i].sum_cubed*=area;
2606 channel_statistics[i].sum_fourth_power*=area;
2607 channel_statistics[i].mean=mean;
2608 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2609 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2610 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2611 ((double) image->columns*image->rows);
2612 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2613 channel_statistics[i].standard_deviation=standard_deviation;
2615 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2617 if (histogram[i].red > 0.0)
2619 if (histogram[i].green > 0.0)
2620 number_bins.green++;
2621 if (histogram[i].blue > 0.0)
2623 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2624 number_bins.opacity++;
2625 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2626 number_bins.index++;
2628 area=MagickSafeReciprocal((
double) image->columns*image->rows);
2629 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2637 histogram[i].red*=area;
2638 entropy=-histogram[i].red*log2(histogram[i].red)*
2639 MagickSafeReciprocal(log2((
double) number_bins.red));
2640 if (IsNaN(entropy) == 0)
2641 channel_statistics[RedChannel].entropy+=entropy;
2642 histogram[i].green*=area;
2643 entropy=-histogram[i].green*log2(histogram[i].green)*
2644 MagickSafeReciprocal(log2((
double) number_bins.green));
2645 if (IsNaN(entropy) == 0)
2646 channel_statistics[GreenChannel].entropy+=entropy;
2647 histogram[i].blue*=area;
2648 entropy=-histogram[i].blue*log2(histogram[i].blue)*
2649 MagickSafeReciprocal(log2((
double) number_bins.blue));
2650 if (IsNaN(entropy) == 0)
2651 channel_statistics[BlueChannel].entropy+=entropy;
2652 if (image->matte != MagickFalse)
2654 histogram[i].opacity*=area;
2655 entropy=-histogram[i].opacity*log2(histogram[i].opacity)*
2656 MagickSafeReciprocal(log2((
double) number_bins.opacity));
2657 if (IsNaN(entropy) == 0)
2658 channel_statistics[OpacityChannel].entropy+=entropy;
2660 if (image->colorspace == CMYKColorspace)
2662 histogram[i].index*=area;
2663 entropy=-histogram[i].index*log2(histogram[i].index)*
2664 MagickSafeReciprocal(log2((
double) number_bins.index));
2665 if (IsNaN(entropy) == 0)
2666 channel_statistics[IndexChannel].entropy+=entropy;
2672 for (i=0; i < (ssize_t) CompositeChannels; i++)
2674 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2675 channel_statistics[CompositeChannels].depth,(double)
2676 channel_statistics[i].depth);
2677 channel_statistics[CompositeChannels].minima=MagickMin(
2678 channel_statistics[CompositeChannels].minima,
2679 channel_statistics[i].minima);
2680 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2681 channel_statistics[CompositeChannels].maxima,
2682 channel_statistics[i].maxima);
2683 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2684 channel_statistics[CompositeChannels].sum_squared+=
2685 channel_statistics[i].sum_squared;
2686 channel_statistics[CompositeChannels].sum_cubed+=
2687 channel_statistics[i].sum_cubed;
2688 channel_statistics[CompositeChannels].sum_fourth_power+=
2689 channel_statistics[i].sum_fourth_power;
2690 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2691 channel_statistics[CompositeChannels].variance+=
2692 channel_statistics[i].variance-channel_statistics[i].mean*
2693 channel_statistics[i].mean;
2694 standard_deviation=sqrt(channel_statistics[i].variance-
2695 (channel_statistics[i].mean*channel_statistics[i].mean));
2696 area=MagickSafeReciprocal((
double) image->columns*image->rows-1.0)*
2697 ((double) image->columns*image->rows);
2698 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2699 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2700 channel_statistics[CompositeChannels].entropy+=
2701 channel_statistics[i].entropy;
2704 if (image->matte != MagickFalse)
2706 if (image->colorspace == CMYKColorspace)
2708 channel_statistics[CompositeChannels].sum/=channels;
2709 channel_statistics[CompositeChannels].sum_squared/=channels;
2710 channel_statistics[CompositeChannels].sum_cubed/=channels;
2711 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2712 channel_statistics[CompositeChannels].mean/=channels;
2713 channel_statistics[CompositeChannels].kurtosis/=channels;
2714 channel_statistics[CompositeChannels].skewness/=channels;
2715 channel_statistics[CompositeChannels].entropy/=channels;
2716 i=CompositeChannels;
2717 area=MagickSafeReciprocal((
double) channels*image->columns*image->rows);
2718 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2719 channel_statistics[i].mean=channel_statistics[i].sum;
2720 standard_deviation=sqrt(channel_statistics[i].variance-
2721 (channel_statistics[i].mean*channel_statistics[i].mean));
2722 standard_deviation=sqrt(MagickSafeReciprocal((
double) channels*
2723 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2724 standard_deviation*standard_deviation);
2725 channel_statistics[i].standard_deviation=standard_deviation;
2726 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2731 standard_deviation=MagickSafeReciprocal(
2732 channel_statistics[i].standard_deviation);
2733 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2734 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2735 channel_statistics[i].mean*channel_statistics[i].mean*
2736 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2737 standard_deviation);
2738 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2739 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2740 channel_statistics[i].mean*channel_statistics[i].mean*
2741 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2742 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2743 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2744 standard_deviation*standard_deviation)-3.0;
2746 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2748 channel_statistics[i].mean*=QuantumRange;
2749 channel_statistics[i].variance*=QuantumRange;
2750 channel_statistics[i].standard_deviation*=QuantumRange;
2751 channel_statistics[i].sum*=QuantumRange;
2752 channel_statistics[i].sum_squared*=QuantumRange;
2753 channel_statistics[i].sum_cubed*=QuantumRange;
2754 channel_statistics[i].sum_fourth_power*=QuantumRange;
2756 channel_statistics[CompositeChannels].mean=0.0;
2757 channel_statistics[CompositeChannels].standard_deviation=0.0;
2758 for (i=0; i < (ssize_t) CompositeChannels; i++)
2760 channel_statistics[CompositeChannels].mean+=
2761 channel_statistics[i].mean;
2762 channel_statistics[CompositeChannels].standard_deviation+=
2763 channel_statistics[i].standard_deviation;
2765 channel_statistics[CompositeChannels].mean/=(double) channels;
2766 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2768 if (y < (ssize_t) image->rows)
2770 channel_statistics);
2771 return(channel_statistics);
2812 MagickExport
Image *PolynomialImage(
const Image *images,
2813 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2818 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2820 return(polynomial_image);
2823 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2824 const ChannelType channel,
const size_t number_terms,
const double *terms,
2827 #define PolynomialImageTag "Polynomial/Image" 2842 **magick_restrict polynomial_pixels,
2848 assert(images != (
Image *) NULL);
2849 assert(images->signature == MagickCoreSignature);
2850 if (IsEventLogging() != MagickFalse)
2851 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2853 assert(exception->signature == MagickCoreSignature);
2854 image=AcquireImageCanvas(images,exception);
2855 if (image == (
Image *) NULL)
2856 return((
Image *) NULL);
2857 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2859 InheritException(exception,&image->exception);
2860 image=DestroyImage(image);
2861 return((
Image *) NULL);
2863 polynomial_pixels=AcquirePixelTLS(images);
2866 image=DestroyImage(image);
2867 (void) ThrowMagickException(exception,GetMagickModule(),
2868 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2869 return((
Image *) NULL);
2876 GetMagickPixelPacket(images,&zero);
2877 polynomial_view=AcquireAuthenticCacheView(image,exception);
2878 #if defined(MAGICKCORE_OPENMP_SUPPORT) 2879 #pragma omp parallel for schedule(static) shared(progress,status) \ 2880 magick_number_threads(image,image,image->rows,1) 2882 for (y=0; y < (ssize_t) image->rows; y++)
2891 id = GetOpenMPThreadId();
2894 *magick_restrict polynomial_indexes;
2909 if (status == MagickFalse)
2911 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2918 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2919 polynomial_pixel=polynomial_pixels[id];
2920 for (x=0; x < (ssize_t) image->columns; x++)
2921 polynomial_pixel[x]=zero;
2923 number_images=GetImageListLength(images);
2924 for (i=0; i < (ssize_t) number_images; i++)
2932 if (i >= (ssize_t) number_terms)
2934 image_view=AcquireVirtualCacheView(next,exception);
2935 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2938 image_view=DestroyCacheView(image_view);
2941 indexes=GetCacheViewVirtualIndexQueue(image_view);
2942 for (x=0; x < (ssize_t) image->columns; x++)
2948 coefficient=terms[i << 1];
2949 degree=terms[(i << 1)+1];
2950 if ((channel & RedChannel) != 0)
2951 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2953 if ((channel & GreenChannel) != 0)
2954 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2957 if ((channel & BlueChannel) != 0)
2958 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2960 if ((channel & OpacityChannel) != 0)
2961 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2962 ((
double) QuantumRange-(double) p->opacity),degree);
2963 if (((channel & IndexChannel) != 0) &&
2964 (image->colorspace == CMYKColorspace))
2965 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2969 image_view=DestroyCacheView(image_view);
2970 next=GetNextImageInList(next);
2972 for (x=0; x < (ssize_t) image->columns; x++)
2974 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2975 polynomial_pixel[x].red));
2976 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2977 polynomial_pixel[x].green));
2978 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2979 polynomial_pixel[x].blue));
2980 if (image->matte == MagickFalse)
2981 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2982 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2984 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2985 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2986 if (image->colorspace == CMYKColorspace)
2987 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2988 QuantumRange*polynomial_pixel[x].index));
2991 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2993 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2998 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
3000 if (proceed == MagickFalse)
3004 polynomial_view=DestroyCacheView(polynomial_view);
3005 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
3006 if (status == MagickFalse)
3007 image=DestroyImage(image);
3049 #define ListChannels 5 3076 lists[ListChannels];
3086 for (i=0; i < ListChannels; i++)
3087 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3088 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3089 pixel_list->lists[i].nodes);
3090 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3099 assert(pixel_list != (
PixelList **) NULL);
3100 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3101 if (pixel_list[i] != (
PixelList *) NULL)
3102 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3103 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3107 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3115 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3118 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3119 pixel_list->length=width*height;
3120 for (i=0; i < ListChannels; i++)
3122 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3123 sizeof(*pixel_list->lists[i].nodes));
3124 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3125 return(DestroyPixelList(pixel_list));
3126 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3127 sizeof(*pixel_list->lists[i].nodes));
3129 pixel_list->signature=MagickCoreSignature;
3133 static PixelList **AcquirePixelListTLS(
const size_t width,
const size_t height)
3144 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3145 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3146 sizeof(*pixel_list));
3149 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3150 for (i=0; i < (ssize_t) number_threads; i++)
3152 pixel_list[i]=AcquirePixelList(width,height);
3153 if (pixel_list[i] == (
PixelList *) NULL)
3154 return(DestroyPixelListTLS(pixel_list));
3159 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3175 list=pixel_list->lists+channel;
3176 list->nodes[color].signature=pixel_list->signature;
3177 list->nodes[color].count=1;
3182 (void) memset(update,0,
sizeof(update));
3183 for (level=list->level; level >= 0; level--)
3185 while (list->nodes[search].next[level] < color)
3186 search=list->nodes[search].next[level];
3187 update[level]=search;
3192 for (level=0; ; level++)
3194 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3195 if ((pixel_list->seed & 0x300) != 0x300)
3200 if (level > (list->level+2))
3201 level=list->level+2;
3205 while (level > list->level)
3208 update[list->level]=65536UL;
3215 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3216 list->nodes[update[level]].next[level]=color;
3217 }
while (level-- > 0);
3236 channels[ListChannels];
3241 for (channel=0; channel < 5; channel++)
3243 list=pixel_list->lists+channel;
3246 maximum=list->nodes[color].next[0];
3249 color=list->nodes[color].next[0];
3250 if (color > maximum)
3252 count+=list->nodes[color].count;
3253 }
while (count < (ssize_t) pixel_list->length);
3254 channels[channel]=(
unsigned short) maximum;
3256 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3257 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3258 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3259 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3260 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3281 channels[ListChannels];
3286 for (channel=0; channel < 5; channel++)
3288 list=pixel_list->lists+channel;
3294 color=list->nodes[color].next[0];
3295 sum+=(MagickRealType) list->nodes[color].count*color;
3296 count+=list->nodes[color].count;
3297 }
while (count < (ssize_t) pixel_list->length);
3298 sum/=pixel_list->length;
3299 channels[channel]=(
unsigned short) sum;
3301 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3302 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3303 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3304 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3305 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3323 channels[ListChannels];
3328 for (channel=0; channel < 5; channel++)
3330 list=pixel_list->lists+channel;
3335 color=list->nodes[color].next[0];
3336 count+=list->nodes[color].count;
3337 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3338 channels[channel]=(
unsigned short) color;
3340 GetMagickPixelPacket((
const Image *) NULL,pixel);
3341 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3342 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3343 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3344 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3345 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3364 channels[ListChannels];
3369 for (channel=0; channel < 5; channel++)
3371 list=pixel_list->lists+channel;
3374 minimum=list->nodes[color].next[0];
3377 color=list->nodes[color].next[0];
3378 if (color < minimum)
3380 count+=list->nodes[color].count;
3381 }
while (count < (ssize_t) pixel_list->length);
3382 channels[channel]=(
unsigned short) minimum;
3384 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3385 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3386 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3387 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3388 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3413 for (channel=0; channel < 5; channel++)
3415 list=pixel_list->lists+channel;
3418 max_count=list->nodes[mode].count;
3422 color=list->nodes[color].next[0];
3423 if (list->nodes[color].count > max_count)
3426 max_count=list->nodes[mode].count;
3428 count+=list->nodes[color].count;
3429 }
while (count < (ssize_t) pixel_list->length);
3430 channels[channel]=(
unsigned short) mode;
3432 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3433 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3434 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3435 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3436 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3461 for (channel=0; channel < 5; channel++)
3463 list=pixel_list->lists+channel;
3465 next=list->nodes[color].next[0];
3471 next=list->nodes[color].next[0];
3472 count+=list->nodes[color].count;
3473 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3474 if ((previous == 65536UL) && (next != 65536UL))
3477 if ((previous != 65536UL) && (next == 65536UL))
3479 channels[channel]=(
unsigned short) color;
3481 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3482 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3483 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3484 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3485 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3488 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3507 channels[ListChannels];
3512 for (channel=0; channel < 5; channel++)
3514 list=pixel_list->lists+channel;
3520 color=list->nodes[color].next[0];
3521 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3522 count+=list->nodes[color].count;
3523 }
while (count < (ssize_t) pixel_list->length);
3524 sum/=pixel_list->length;
3525 channels[channel]=(
unsigned short) sqrt(sum);
3527 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3528 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3529 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3530 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3531 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3534 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3552 channels[ListChannels];
3557 for (channel=0; channel < 5; channel++)
3559 list=pixel_list->lists+channel;
3569 color=list->nodes[color].next[0];
3570 sum+=(MagickRealType) list->nodes[color].count*color;
3571 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3572 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3573 count+=list->nodes[color].count;
3574 }
while (count < (ssize_t) pixel_list->length);
3575 sum/=pixel_list->length;
3576 sum_squared/=pixel_list->length;
3577 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3579 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3580 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3581 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3582 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3583 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3586 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3587 const IndexPacket *indexes,
PixelList *pixel_list)
3595 index=ScaleQuantumToShort(GetPixelRed(pixel));
3596 signature=pixel_list->lists[0].nodes[index].signature;
3597 if (signature == pixel_list->signature)
3598 pixel_list->lists[0].nodes[index].count++;
3600 AddNodePixelList(pixel_list,0,index);
3601 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3602 signature=pixel_list->lists[1].nodes[index].signature;
3603 if (signature == pixel_list->signature)
3604 pixel_list->lists[1].nodes[index].count++;
3606 AddNodePixelList(pixel_list,1,index);
3607 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3608 signature=pixel_list->lists[2].nodes[index].signature;
3609 if (signature == pixel_list->signature)
3610 pixel_list->lists[2].nodes[index].count++;
3612 AddNodePixelList(pixel_list,2,index);
3613 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3614 signature=pixel_list->lists[3].nodes[index].signature;
3615 if (signature == pixel_list->signature)
3616 pixel_list->lists[3].nodes[index].count++;
3618 AddNodePixelList(pixel_list,3,index);
3619 if (image->colorspace == CMYKColorspace)
3620 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3621 signature=pixel_list->lists[4].nodes[index].signature;
3622 if (signature == pixel_list->signature)
3623 pixel_list->lists[4].nodes[index].count++;
3625 AddNodePixelList(pixel_list,4,index);
3628 static void ResetPixelList(
PixelList *pixel_list)
3645 for (channel=0; channel < 5; channel++)
3647 list=pixel_list->lists+channel;
3648 root=list->nodes+65536UL;
3650 for (level=0; level < 9; level++)
3651 root->next[level]=65536UL;
3653 pixel_list->seed=pixel_list->signature++;
3656 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3657 const size_t width,
const size_t height,
ExceptionInfo *exception)
3662 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3664 return(statistic_image);
3667 MagickExport
Image *StatisticImageChannel(
const Image *image,
3668 const ChannelType channel,
const StatisticType type,
const size_t width,
3671 #define StatisticImageTag "Statistic/Image" 3687 **magick_restrict pixel_list;
3699 assert(image != (
Image *) NULL);
3700 assert(image->signature == MagickCoreSignature);
3701 if (IsEventLogging() != MagickFalse)
3702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3704 assert(exception->signature == MagickCoreSignature);
3705 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3706 if (statistic_image == (
Image *) NULL)
3707 return((
Image *) NULL);
3708 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3710 InheritException(exception,&statistic_image->exception);
3711 statistic_image=DestroyImage(statistic_image);
3712 return((
Image *) NULL);
3714 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3716 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3718 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3721 statistic_image=DestroyImage(statistic_image);
3722 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3729 image_view=AcquireVirtualCacheView(image,exception);
3730 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3731 #if defined(MAGICKCORE_OPENMP_SUPPORT) 3732 #pragma omp parallel for schedule(static) shared(progress,status) \ 3733 magick_number_threads(image,statistic_image,statistic_image->rows,1) 3735 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3738 id = GetOpenMPThreadId();
3741 *magick_restrict indexes;
3747 *magick_restrict statistic_indexes;
3755 if (status == MagickFalse)
3757 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3758 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3759 neighbor_height,exception);
3760 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3766 indexes=GetCacheViewVirtualIndexQueue(image_view);
3767 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3768 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3785 ResetPixelList(pixel_list[
id]);
3786 for (v=0; v < (ssize_t) neighbor_height; v++)
3788 for (u=0; u < (ssize_t) neighbor_width; u++)
3789 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3790 r+=(ptrdiff_t) image->columns+neighbor_width;
3791 s+=(ptrdiff_t) image->columns+neighbor_width;
3793 GetMagickPixelPacket(image,&pixel);
3794 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3795 neighbor_width*neighbor_height/2,&pixel);
3798 case GradientStatistic:
3804 GetMinimumPixelList(pixel_list[
id],&pixel);
3806 GetMaximumPixelList(pixel_list[
id],&pixel);
3808 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3809 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3810 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3811 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3812 if (image->colorspace == CMYKColorspace)
3813 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3816 case MaximumStatistic:
3818 GetMaximumPixelList(pixel_list[
id],&pixel);
3823 GetMeanPixelList(pixel_list[
id],&pixel);
3826 case MedianStatistic:
3829 GetMedianPixelList(pixel_list[
id],&pixel);
3832 case MinimumStatistic:
3834 GetMinimumPixelList(pixel_list[
id],&pixel);
3839 GetModePixelList(pixel_list[
id],&pixel);
3842 case NonpeakStatistic:
3844 GetNonpeakPixelList(pixel_list[
id],&pixel);
3847 case RootMeanSquareStatistic:
3849 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3852 case StandardDeviationStatistic:
3854 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3858 if ((channel & RedChannel) != 0)
3859 SetPixelRed(q,ClampToQuantum(pixel.red));
3860 if ((channel & GreenChannel) != 0)
3861 SetPixelGreen(q,ClampToQuantum(pixel.green));
3862 if ((channel & BlueChannel) != 0)
3863 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3864 if ((channel & OpacityChannel) != 0)
3865 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3866 if (((channel & IndexChannel) != 0) &&
3867 (image->colorspace == CMYKColorspace))
3868 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3872 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3874 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3879 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3881 if (proceed == MagickFalse)
3885 statistic_view=DestroyCacheView(statistic_view);
3886 image_view=DestroyCacheView(image_view);
3887 pixel_list=DestroyPixelListTLS(pixel_list);
3888 if (status == MagickFalse)
3889 statistic_image=DestroyImage(statistic_image);
3890 return(statistic_image);