43 #include "magick/studio.h" 44 #include "magick/accelerate-private.h" 45 #include "magick/animate.h" 46 #include "magick/animate.h" 47 #include "magick/blob.h" 48 #include "magick/blob-private.h" 49 #include "magick/cache.h" 50 #include "magick/cache-private.h" 51 #include "magick/cache-view.h" 52 #include "magick/client.h" 53 #include "magick/color.h" 54 #include "magick/color-private.h" 55 #include "magick/colorspace.h" 56 #include "magick/colorspace-private.h" 57 #include "magick/composite.h" 58 #include "magick/composite-private.h" 59 #include "magick/compress.h" 60 #include "magick/constitute.h" 61 #include "magick/deprecate.h" 62 #include "magick/display.h" 63 #include "magick/draw.h" 64 #include "magick/enhance.h" 65 #include "magick/exception.h" 66 #include "magick/exception-private.h" 67 #include "magick/gem.h" 68 #include "magick/geometry.h" 69 #include "magick/list.h" 70 #include "magick/image-private.h" 71 #include "magick/magic.h" 72 #include "magick/magick.h" 73 #include "magick/memory_.h" 74 #include "magick/module.h" 75 #include "magick/monitor.h" 76 #include "magick/monitor-private.h" 77 #include "magick/option.h" 78 #include "magick/paint.h" 79 #include "magick/pixel-private.h" 80 #include "magick/profile.h" 81 #include "magick/property.h" 82 #include "magick/quantize.h" 83 #include "magick/random_.h" 84 #include "magick/random-private.h" 85 #include "magick/resource_.h" 86 #include "magick/segment.h" 87 #include "magick/semaphore.h" 88 #include "magick/signature-private.h" 89 #include "magick/statistic.h" 90 #include "magick/statistic-private.h" 91 #include "magick/string_.h" 92 #include "magick/thread-private.h" 93 #include "magick/timer.h" 94 #include "magick/utility.h" 95 #include "magick/version.h" 149 rows=MagickMax(GetImageListLength(images),
150 (
size_t) GetMagickResourceLimit(ThreadResource));
151 for (i=0; i < (ssize_t) rows; i++)
174 rows=MagickMax(GetImageListLength(images),
175 (
size_t) GetMagickResourceLimit(ThreadResource));
179 (void) memset(pixels,0,rows*
sizeof(*pixels));
180 columns=GetImageListLength(images);
181 for (next=images; next != (
Image *) NULL; next=next->next)
182 columns=MagickMax(next->columns,columns);
183 for (i=0; i < (ssize_t) rows; i++)
188 return(DestroyPixelTLS(images,pixels));
189 for (j=0; j < (ssize_t) columns; j++)
190 GetMagickPixelPacket(images,&pixels[i][j]);
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)*PerceptibleReciprocal(value);
304 case LaplacianNoiseEvaluateOperator:
306 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
307 LaplacianNoise,value);
310 case LeftShiftEvaluateOperator:
312 result=(double) pixel;
313 for (i=0; i < (ssize_t) value; i++)
317 case LogEvaluateOperator:
319 if ((QuantumScale*(MagickRealType) pixel) >= MagickEpsilon)
320 result=(MagickRealType) QuantumRange*log((
double) (QuantumScale*value*
321 (MagickRealType) pixel+1.0))/log((
double) (value+1.0));
324 case MaxEvaluateOperator:
326 result=(MagickRealType) EvaluateMax((
double) pixel,value);
329 case MeanEvaluateOperator:
331 result=(MagickRealType) pixel+value;
334 case MedianEvaluateOperator:
336 result=(MagickRealType) pixel+value;
339 case MinEvaluateOperator:
341 result=(MagickRealType) MagickMin((
double) pixel,value);
344 case MultiplicativeNoiseEvaluateOperator:
346 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
347 MultiplicativeGaussianNoise,value);
350 case MultiplyEvaluateOperator:
352 result=(MagickRealType) pixel*value;
355 case OrEvaluateOperator:
357 result=(MagickRealType) ((ssize_t) pixel | (ssize_t) (value+0.5));
360 case PoissonNoiseEvaluateOperator:
362 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
366 case PowEvaluateOperator:
368 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
369 result=(
double) -((MagickRealType) QuantumRange*pow(-(QuantumScale*
370 (
double) pixel),(
double) value));
372 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,
376 case RightShiftEvaluateOperator:
378 result=(MagickRealType) pixel;
379 for (i=0; i < (ssize_t) value; i++)
383 case RootMeanSquareEvaluateOperator:
385 result=((MagickRealType) pixel*(MagickRealType) pixel+value);
388 case SetEvaluateOperator:
393 case SineEvaluateOperator:
395 result=(MagickRealType) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
396 QuantumScale*(MagickRealType) pixel*value))+0.5);
399 case SubtractEvaluateOperator:
401 result=(MagickRealType) pixel-value;
404 case SumEvaluateOperator:
406 result=(MagickRealType) pixel+value;
409 case ThresholdEvaluateOperator:
411 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
415 case ThresholdBlackEvaluateOperator:
417 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
420 case ThresholdWhiteEvaluateOperator:
422 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
426 case UniformNoiseEvaluateOperator:
428 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
432 case XorEvaluateOperator:
434 result=(MagickRealType) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
453 columns=images->columns;
456 for (p=images; p != (
Image *) NULL; p=p->next)
462 if (p->matte != MagickFalse)
464 if (p->colorspace == CMYKColorspace)
466 if (channels > number_channels)
468 number_channels=channels;
471 if (p->columns > columns)
476 return(CloneImage(q,columns,rows,MagickTrue,exception));
479 MagickExport MagickBooleanType EvaluateImage(
Image *image,
480 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
485 status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
489 MagickExport
Image *EvaluateImages(
const Image *images,
492 #define EvaluateImageTag "Evaluate/Image" 507 **magick_restrict evaluate_pixels,
511 **magick_restrict random_info;
519 #if defined(MAGICKCORE_OPENMP_SUPPORT) 524 assert(images != (
Image *) NULL);
525 assert(images->signature == MagickCoreSignature);
527 assert(exception->signature == MagickCoreSignature);
528 if (IsEventLogging() != MagickFalse)
529 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
530 image=AcquireImageCanvas(images,exception);
531 if (image == (
Image *) NULL)
532 return((
Image *) NULL);
533 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
535 InheritException(exception,&image->exception);
536 image=DestroyImage(image);
537 return((
Image *) NULL);
539 evaluate_pixels=AcquirePixelTLS(images);
542 image=DestroyImage(image);
543 (void) ThrowMagickException(exception,GetMagickModule(),
544 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
545 return((
Image *) NULL);
552 number_images=GetImageListLength(images);
553 GetMagickPixelPacket(images,&zero);
554 random_info=AcquireRandomInfoTLS();
555 evaluate_view=AcquireAuthenticCacheView(image,exception);
556 if (op == MedianEvaluateOperator)
558 #if defined(MAGICKCORE_OPENMP_SUPPORT) 559 key=GetRandomSecretKey(random_info[0]);
560 #pragma omp parallel for schedule(static) shared(progress,status) \ 561 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1) 563 for (y=0; y < (ssize_t) image->rows; y++)
572 id = GetOpenMPThreadId();
575 *magick_restrict evaluate_indexes;
586 if (status == MagickFalse)
588 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
595 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
596 evaluate_pixel=evaluate_pixels[id];
597 for (x=0; x < (ssize_t) image->columns; x++)
602 for (i=0; i < (ssize_t) number_images; i++)
603 evaluate_pixel[i]=zero;
605 for (i=0; i < (ssize_t) number_images; i++)
613 image_view=AcquireVirtualCacheView(next,exception);
614 p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
617 image_view=DestroyCacheView(image_view);
620 indexes=GetCacheViewVirtualIndexQueue(image_view);
621 evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[
id],
622 GetPixelRed(p),op,evaluate_pixel[i].red);
623 evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[
id],
624 GetPixelGreen(p),op,evaluate_pixel[i].green);
625 evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[
id],
626 GetPixelBlue(p),op,evaluate_pixel[i].blue);
627 evaluate_pixel[i].opacity=ApplyEvaluateOperator(random_info[
id],
628 GetPixelAlpha(p),op,evaluate_pixel[i].opacity);
629 if (image->colorspace == CMYKColorspace)
630 evaluate_pixel[i].index=ApplyEvaluateOperator(random_info[
id],
631 *indexes,op,evaluate_pixel[i].index);
632 image_view=DestroyCacheView(image_view);
633 next=GetNextImageInList(next);
635 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
637 SetPixelRed(q,ClampToQuantum(evaluate_pixel[i/2].red));
638 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[i/2].green));
639 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[i/2].blue));
640 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[i/2].opacity));
641 if (image->colorspace == CMYKColorspace)
642 SetPixelIndex(evaluate_indexes+i,ClampToQuantum(
643 evaluate_pixel[i/2].index));
646 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
648 if (images->progress_monitor != (MagickProgressMonitor) NULL)
653 #if defined(MAGICKCORE_OPENMP_SUPPORT) 657 proceed=SetImageProgress(images,EvaluateImageTag,progress,
659 if (proceed == MagickFalse)
666 #if defined(MAGICKCORE_OPENMP_SUPPORT) 667 key=GetRandomSecretKey(random_info[0]);
668 #pragma omp parallel for schedule(static) shared(progress,status) \ 669 magick_number_threads(image,images,image->rows,key == ~0UL ? 0 : 1) 671 for (y=0; y < (ssize_t) image->rows; y++)
680 id = GetOpenMPThreadId();
683 *magick_restrict evaluate_indexes;
695 if (status == MagickFalse)
697 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
704 evaluate_indexes=GetCacheViewAuthenticIndexQueue(evaluate_view);
705 evaluate_pixel=evaluate_pixels[id];
706 for (x=0; x < (ssize_t) image->columns; x++)
707 evaluate_pixel[x]=zero;
709 for (i=0; i < (ssize_t) number_images; i++)
717 image_view=AcquireVirtualCacheView(next,exception);
718 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
722 image_view=DestroyCacheView(image_view);
725 indexes=GetCacheViewVirtualIndexQueue(image_view);
726 for (x=0; x < (ssize_t) image->columns; x++)
728 evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[
id],
729 GetPixelRed(p),i == 0 ? AddEvaluateOperator : op,
730 evaluate_pixel[x].red);
731 evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[
id],
732 GetPixelGreen(p),i == 0 ? AddEvaluateOperator : op,
733 evaluate_pixel[x].green);
734 evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[
id],
735 GetPixelBlue(p),i == 0 ? AddEvaluateOperator : op,
736 evaluate_pixel[x].blue);
737 evaluate_pixel[x].opacity=ApplyEvaluateOperator(random_info[
id],
738 GetPixelAlpha(p),i == 0 ? AddEvaluateOperator : op,
739 evaluate_pixel[x].opacity);
740 if (image->colorspace == CMYKColorspace)
741 evaluate_pixel[x].index=ApplyEvaluateOperator(random_info[
id],
742 GetPixelIndex(indexes+x),i == 0 ? AddEvaluateOperator : op,
743 evaluate_pixel[x].index);
746 image_view=DestroyCacheView(image_view);
747 next=GetNextImageInList(next);
749 if (op == MeanEvaluateOperator)
750 for (x=0; x < (ssize_t) image->columns; x++)
752 evaluate_pixel[x].red/=number_images;
753 evaluate_pixel[x].green/=number_images;
754 evaluate_pixel[x].blue/=number_images;
755 evaluate_pixel[x].opacity/=number_images;
756 evaluate_pixel[x].index/=number_images;
758 if (op == RootMeanSquareEvaluateOperator)
759 for (x=0; x < (ssize_t) image->columns; x++)
761 evaluate_pixel[x].red=sqrt((
double) evaluate_pixel[x].red/
763 evaluate_pixel[x].green=sqrt((
double) evaluate_pixel[x].green/
765 evaluate_pixel[x].blue=sqrt((
double) evaluate_pixel[x].blue/
767 evaluate_pixel[x].opacity=sqrt((
double) evaluate_pixel[x].opacity/
769 evaluate_pixel[x].index=sqrt((
double) evaluate_pixel[x].index/
772 if (op == MultiplyEvaluateOperator)
773 for (x=0; x < (ssize_t) image->columns; x++)
778 for (j=0; j < (ssize_t) (number_images-1); j++)
780 evaluate_pixel[x].red*=(MagickRealType) QuantumScale;
781 evaluate_pixel[x].green*=(MagickRealType) QuantumScale;
782 evaluate_pixel[x].blue*=(MagickRealType) QuantumScale;
783 evaluate_pixel[x].opacity*=(MagickRealType) QuantumScale;
784 evaluate_pixel[x].index*=(MagickRealType) QuantumScale;
787 for (x=0; x < (ssize_t) image->columns; x++)
789 SetPixelRed(q,ClampToQuantum(evaluate_pixel[x].red));
790 SetPixelGreen(q,ClampToQuantum(evaluate_pixel[x].green));
791 SetPixelBlue(q,ClampToQuantum(evaluate_pixel[x].blue));
792 SetPixelAlpha(q,ClampToQuantum(evaluate_pixel[x].opacity));
793 if (image->colorspace == CMYKColorspace)
794 SetPixelIndex(evaluate_indexes+x,ClampToQuantum(
795 evaluate_pixel[x].index));
798 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
800 if (images->progress_monitor != (MagickProgressMonitor) NULL)
805 proceed=SetImageProgress(images,EvaluateImageTag,progress++,
807 if (proceed == MagickFalse)
812 evaluate_view=DestroyCacheView(evaluate_view);
813 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
814 random_info=DestroyRandomInfoTLS(random_info);
815 if (status == MagickFalse)
816 image=DestroyImage(image);
820 MagickExport MagickBooleanType EvaluateImageChannel(
Image *image,
821 const ChannelType channel,
const MagickEvaluateOperator op,
const double value,
834 **magick_restrict random_info;
839 #if defined(MAGICKCORE_OPENMP_SUPPORT) 844 assert(image != (
Image *) NULL);
845 assert(image->signature == MagickCoreSignature);
847 assert(exception->signature == MagickCoreSignature);
848 if (IsEventLogging() != MagickFalse)
849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
850 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
852 InheritException(exception,&image->exception);
857 random_info=AcquireRandomInfoTLS();
858 image_view=AcquireAuthenticCacheView(image,exception);
859 #if defined(MAGICKCORE_OPENMP_SUPPORT) 860 key=GetRandomSecretKey(random_info[0]);
861 #pragma omp parallel for schedule(static) shared(progress,status) \ 862 magick_number_threads(image,image,image->rows,key == ~0UL ? 0 : 1) 864 for (y=0; y < (ssize_t) image->rows; y++)
867 id = GetOpenMPThreadId();
870 *magick_restrict indexes;
878 if (status == MagickFalse)
880 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
886 indexes=GetCacheViewAuthenticIndexQueue(image_view);
887 for (x=0; x < (ssize_t) image->columns; x++)
892 if ((channel & RedChannel) != 0)
894 result=ApplyEvaluateOperator(random_info[
id],GetPixelRed(q),op,value);
895 if (op == MeanEvaluateOperator)
897 SetPixelRed(q,ClampToQuantum(result));
899 if ((channel & GreenChannel) != 0)
901 result=ApplyEvaluateOperator(random_info[
id],GetPixelGreen(q),op,
903 if (op == MeanEvaluateOperator)
905 SetPixelGreen(q,ClampToQuantum(result));
907 if ((channel & BlueChannel) != 0)
909 result=ApplyEvaluateOperator(random_info[
id],GetPixelBlue(q),op,
911 if (op == MeanEvaluateOperator)
913 SetPixelBlue(q,ClampToQuantum(result));
915 if ((channel & OpacityChannel) != 0)
917 if (image->matte == MagickFalse)
919 result=ApplyEvaluateOperator(random_info[
id],GetPixelOpacity(q),
921 if (op == MeanEvaluateOperator)
923 SetPixelOpacity(q,ClampToQuantum(result));
927 result=ApplyEvaluateOperator(random_info[
id],GetPixelAlpha(q),
929 if (op == MeanEvaluateOperator)
931 SetPixelAlpha(q,ClampToQuantum(result));
934 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
936 result=ApplyEvaluateOperator(random_info[
id],GetPixelIndex(indexes+x),
938 if (op == MeanEvaluateOperator)
940 SetPixelIndex(indexes+x,ClampToQuantum(result));
944 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
946 if (image->progress_monitor != (MagickProgressMonitor) NULL)
951 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
952 if (proceed == MagickFalse)
956 image_view=DestroyCacheView(image_view);
957 random_info=DestroyRandomInfoTLS(random_info);
1001 static Quantum ApplyFunction(Quantum pixel,
const MagickFunction
function,
1002 const size_t number_parameters,
const double *parameters,
1015 case PolynomialFunction:
1023 for (i=0; i < (ssize_t) number_parameters; i++)
1024 result=result*QuantumScale*(MagickRealType) pixel+parameters[i];
1025 result*=(MagickRealType) QuantumRange;
1028 case SinusoidFunction:
1033 double freq,phase,ampl,bias;
1034 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1035 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1036 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1037 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1038 result=(MagickRealType) QuantumRange*(ampl*sin((
double) (2.0*MagickPI*
1039 (freq*QuantumScale*(MagickRealType) pixel+phase/360.0)))+bias);
1042 case ArcsinFunction:
1053 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1054 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1055 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1056 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1057 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*(MagickRealType)
1060 result=bias-range/2.0;
1063 result=bias+range/2.0;
1065 result=(MagickRealType) (range/MagickPI*asin((
double) result)+bias);
1066 result*=(MagickRealType) QuantumRange;
1069 case ArctanFunction:
1074 double slope,range,center,bias;
1075 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1076 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1077 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1078 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1079 result=(MagickRealType) (MagickPI*slope*(QuantumScale*(MagickRealType)
1081 result=(MagickRealType) QuantumRange*(range/MagickPI*atan((
double)
1085 case UndefinedFunction:
1088 return(ClampToQuantum(result));
1091 MagickExport MagickBooleanType FunctionImage(
Image *image,
1092 const MagickFunction
function,
const size_t number_parameters,
1098 status=FunctionImageChannel(image,CompositeChannels,
function,
1099 number_parameters,parameters,exception);
1103 MagickExport MagickBooleanType FunctionImageChannel(
Image *image,
1104 const ChannelType channel,
const MagickFunction
function,
1105 const size_t number_parameters,
const double *parameters,
1108 #define FunctionImageTag "Function/Image " 1122 assert(image != (
Image *) NULL);
1123 assert(image->signature == MagickCoreSignature);
1125 assert(exception->signature == MagickCoreSignature);
1126 if (IsEventLogging() != MagickFalse)
1127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1128 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1130 InheritException(exception,&image->exception);
1131 return(MagickFalse);
1133 #if defined(MAGICKCORE_OPENCL_SUPPORT) 1134 status=AccelerateFunctionImage(image,channel,
function,number_parameters,
1135 parameters,exception);
1136 if (status != MagickFalse)
1141 image_view=AcquireAuthenticCacheView(image,exception);
1142 #if defined(MAGICKCORE_OPENMP_SUPPORT) 1143 #pragma omp parallel for schedule(static) shared(progress,status) \ 1144 magick_number_threads(image,image,image->rows,2) 1146 for (y=0; y < (ssize_t) image->rows; y++)
1149 *magick_restrict indexes;
1157 if (status == MagickFalse)
1159 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1165 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1166 for (x=0; x < (ssize_t) image->columns; x++)
1168 if ((channel & RedChannel) != 0)
1169 SetPixelRed(q,ApplyFunction(GetPixelRed(q),
function,
1170 number_parameters,parameters,exception));
1171 if ((channel & GreenChannel) != 0)
1172 SetPixelGreen(q,ApplyFunction(GetPixelGreen(q),
function,
1173 number_parameters,parameters,exception));
1174 if ((channel & BlueChannel) != 0)
1175 SetPixelBlue(q,ApplyFunction(GetPixelBlue(q),
function,
1176 number_parameters,parameters,exception));
1177 if ((channel & OpacityChannel) != 0)
1179 if (image->matte == MagickFalse)
1180 SetPixelOpacity(q,ApplyFunction(GetPixelOpacity(q),
function,
1181 number_parameters,parameters,exception));
1183 SetPixelAlpha(q,ApplyFunction((Quantum) GetPixelAlpha(q),
function,
1184 number_parameters,parameters,exception));
1186 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1187 SetPixelIndex(indexes+x,ApplyFunction(GetPixelIndex(indexes+x),
function,
1188 number_parameters,parameters,exception));
1191 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1193 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1198 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1199 if (proceed == MagickFalse)
1203 image_view=DestroyCacheView(image_view);
1237 MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1243 status=GetImageChannelEntropy(image,CompositeChannels,entropy,exception);
1247 MagickExport MagickBooleanType GetImageChannelEntropy(
const Image *image,
1248 const ChannelType channel,
double *entropy,
ExceptionInfo *exception)
1251 *channel_statistics;
1256 assert(image != (
Image *) NULL);
1257 assert(image->signature == MagickCoreSignature);
1258 if (IsEventLogging() != MagickFalse)
1259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1260 channel_statistics=GetImageChannelStatistics(image,exception);
1262 return(MagickFalse);
1264 channel_statistics[CompositeChannels].entropy=0.0;
1265 if ((channel & RedChannel) != 0)
1267 channel_statistics[CompositeChannels].entropy+=
1268 channel_statistics[RedChannel].entropy;
1271 if ((channel & GreenChannel) != 0)
1273 channel_statistics[CompositeChannels].entropy+=
1274 channel_statistics[GreenChannel].entropy;
1277 if ((channel & BlueChannel) != 0)
1279 channel_statistics[CompositeChannels].entropy+=
1280 channel_statistics[BlueChannel].entropy;
1283 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1285 channel_statistics[CompositeChannels].entropy+=
1286 channel_statistics[OpacityChannel].entropy;
1289 if (((channel & IndexChannel) != 0) &&
1290 (image->colorspace == CMYKColorspace))
1292 channel_statistics[CompositeChannels].entropy+=
1293 channel_statistics[BlackChannel].entropy;
1296 channel_statistics[CompositeChannels].entropy/=channels;
1297 *entropy=channel_statistics[CompositeChannels].entropy;
1299 channel_statistics);
1336 MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1342 status=GetImageChannelExtrema(image,CompositeChannels,minima,maxima,
1347 MagickExport MagickBooleanType GetImageChannelExtrema(
const Image *image,
1348 const ChannelType channel,
size_t *minima,
size_t *maxima,
1358 assert(image != (
Image *) NULL);
1359 assert(image->signature == MagickCoreSignature);
1360 if (IsEventLogging() != MagickFalse)
1361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1362 status=GetImageChannelRange(image,channel,&min,&max,exception);
1363 *minima=(size_t) ceil(min-0.5);
1364 *maxima=(size_t) floor(max+0.5);
1402 MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1408 status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
1413 MagickExport MagickBooleanType GetImageChannelKurtosis(
const Image *image,
1414 const ChannelType channel,
double *kurtosis,
double *skewness,
1428 assert(image != (
Image *) NULL);
1429 assert(image->signature == MagickCoreSignature);
1430 if (IsEventLogging() != MagickFalse)
1431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1436 standard_deviation=0.0;
1439 sum_fourth_power=0.0;
1440 for (y=0; y < (ssize_t) image->rows; y++)
1443 *magick_restrict indexes;
1451 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1454 indexes=GetVirtualIndexQueue(image);
1455 for (x=0; x < (ssize_t) image->columns; x++)
1457 if ((channel & RedChannel) != 0)
1459 mean+=QuantumScale*GetPixelRed(p);
1460 sum_squares+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
1461 sum_cubes+=QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
1462 QuantumScale*GetPixelRed(p);
1463 sum_fourth_power+=QuantumScale*GetPixelRed(p)*QuantumScale*
1464 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*
1468 if ((channel & GreenChannel) != 0)
1470 mean+=QuantumScale*GetPixelGreen(p);
1471 sum_squares+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1473 sum_cubes+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1474 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
1475 sum_fourth_power+=QuantumScale*GetPixelGreen(p)*QuantumScale*
1476 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
1480 if ((channel & BlueChannel) != 0)
1482 mean+=QuantumScale*GetPixelBlue(p);
1483 sum_squares+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1485 sum_cubes+=QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*
1486 QuantumScale*GetPixelBlue(p);
1487 sum_fourth_power+=QuantumScale*GetPixelBlue(p)*QuantumScale*
1488 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
1492 if ((channel & OpacityChannel) != 0)
1494 mean+=QuantumScale*GetPixelAlpha(p);
1495 sum_squares+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1497 sum_cubes+=QuantumScale*GetPixelOpacity(p)*QuantumScale*
1498 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
1499 sum_fourth_power+=QuantumScale*GetPixelAlpha(p)*QuantumScale*
1500 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*GetPixelAlpha(p);
1503 if (((channel & IndexChannel) != 0) &&
1504 (image->colorspace == CMYKColorspace))
1509 index=QuantumScale*GetPixelIndex(indexes+x);
1511 sum_squares+=index*index;
1512 sum_cubes+=index*index*index;
1513 sum_fourth_power+=index*index*index*index;
1519 if (y < (ssize_t) image->rows)
1520 return(MagickFalse);
1526 sum_fourth_power/=area;
1528 standard_deviation=sqrt(sum_squares-(mean*mean));
1529 if (standard_deviation != 0.0)
1531 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
1532 3.0*mean*mean*mean*mean;
1533 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
1536 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
1537 *skewness/=standard_deviation*standard_deviation*standard_deviation;
1539 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
1576 MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1582 status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
1587 MagickExport MagickBooleanType GetImageChannelMean(
const Image *image,
1588 const ChannelType channel,
double *mean,
double *standard_deviation,
1592 *channel_statistics;
1597 assert(image != (
Image *) NULL);
1598 assert(image->signature == MagickCoreSignature);
1599 if (IsEventLogging() != MagickFalse)
1600 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1601 channel_statistics=GetImageChannelStatistics(image,exception);
1603 return(MagickFalse);
1605 channel_statistics[CompositeChannels].mean=0.0;
1606 channel_statistics[CompositeChannels].standard_deviation=0.0;
1607 if ((channel & RedChannel) != 0)
1609 channel_statistics[CompositeChannels].mean+=
1610 channel_statistics[RedChannel].mean;
1611 channel_statistics[CompositeChannels].standard_deviation+=
1612 channel_statistics[RedChannel].standard_deviation;
1615 if ((channel & GreenChannel) != 0)
1617 channel_statistics[CompositeChannels].mean+=
1618 channel_statistics[GreenChannel].mean;
1619 channel_statistics[CompositeChannels].standard_deviation+=
1620 channel_statistics[GreenChannel].standard_deviation;
1623 if ((channel & BlueChannel) != 0)
1625 channel_statistics[CompositeChannels].mean+=
1626 channel_statistics[BlueChannel].mean;
1627 channel_statistics[CompositeChannels].standard_deviation+=
1628 channel_statistics[BlueChannel].standard_deviation;
1631 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1633 channel_statistics[CompositeChannels].mean+=
1634 channel_statistics[OpacityChannel].mean;
1635 channel_statistics[CompositeChannels].standard_deviation+=
1636 channel_statistics[OpacityChannel].standard_deviation;
1639 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
1641 channel_statistics[CompositeChannels].mean+=
1642 channel_statistics[BlackChannel].mean;
1643 channel_statistics[CompositeChannels].standard_deviation+=
1644 channel_statistics[CompositeChannels].standard_deviation;
1647 channel_statistics[CompositeChannels].mean/=channels;
1648 channel_statistics[CompositeChannels].standard_deviation/=channels;
1649 *mean=channel_statistics[CompositeChannels].mean;
1650 *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
1652 channel_statistics);
1685 #define MaxNumberImageMoments 8 1691 M00[CompositeChannels+1],
1692 M01[CompositeChannels+1],
1693 M02[CompositeChannels+1],
1694 M03[CompositeChannels+1],
1695 M10[CompositeChannels+1],
1696 M11[CompositeChannels+1],
1697 M12[CompositeChannels+1],
1698 M20[CompositeChannels+1],
1699 M21[CompositeChannels+1],
1700 M22[CompositeChannels+1],
1701 M30[CompositeChannels+1];
1707 centroid[CompositeChannels+1];
1717 assert(image != (
Image *) NULL);
1718 assert(image->signature == MagickCoreSignature);
1719 if (IsEventLogging() != MagickFalse)
1720 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1721 length=CompositeChannels+1UL;
1723 sizeof(*channel_moments));
1725 return(channel_moments);
1726 (void) memset(channel_moments,0,length*
sizeof(*channel_moments));
1727 (void) memset(centroid,0,
sizeof(centroid));
1728 (void) memset(M00,0,
sizeof(M00));
1729 (void) memset(M01,0,
sizeof(M01));
1730 (void) memset(M02,0,
sizeof(M02));
1731 (void) memset(M03,0,
sizeof(M03));
1732 (void) memset(M10,0,
sizeof(M10));
1733 (void) memset(M11,0,
sizeof(M11));
1734 (void) memset(M12,0,
sizeof(M12));
1735 (void) memset(M20,0,
sizeof(M20));
1736 (void) memset(M21,0,
sizeof(M21));
1737 (void) memset(M22,0,
sizeof(M22));
1738 (void) memset(M30,0,
sizeof(M30));
1739 GetMagickPixelPacket(image,&pixel);
1740 for (y=0; y < (ssize_t) image->rows; y++)
1743 *magick_restrict indexes;
1754 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1757 indexes=GetVirtualIndexQueue(image);
1758 for (x=0; x < (ssize_t) image->columns; x++)
1760 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1761 M00[RedChannel]+=QuantumScale*pixel.red;
1762 M10[RedChannel]+=x*QuantumScale*pixel.red;
1763 M01[RedChannel]+=y*QuantumScale*pixel.red;
1764 M00[GreenChannel]+=QuantumScale*pixel.green;
1765 M10[GreenChannel]+=x*QuantumScale*pixel.green;
1766 M01[GreenChannel]+=y*QuantumScale*pixel.green;
1767 M00[BlueChannel]+=QuantumScale*pixel.blue;
1768 M10[BlueChannel]+=x*QuantumScale*pixel.blue;
1769 M01[BlueChannel]+=y*QuantumScale*pixel.blue;
1770 if (image->matte != MagickFalse)
1772 M00[OpacityChannel]+=QuantumScale*pixel.opacity;
1773 M10[OpacityChannel]+=x*QuantumScale*pixel.opacity;
1774 M01[OpacityChannel]+=y*QuantumScale*pixel.opacity;
1776 if (image->colorspace == CMYKColorspace)
1778 M00[IndexChannel]+=QuantumScale*pixel.index;
1779 M10[IndexChannel]+=x*QuantumScale*pixel.index;
1780 M01[IndexChannel]+=y*QuantumScale*pixel.index;
1785 for (channel=0; channel <= CompositeChannels; channel++)
1790 if (M00[channel] < MagickEpsilon)
1792 M00[channel]+=MagickEpsilon;
1793 centroid[channel].x=(double) image->columns/2.0;
1794 centroid[channel].y=(
double) image->rows/2.0;
1797 M00[channel]+=MagickEpsilon;
1798 centroid[channel].x=M10[channel]/M00[channel];
1799 centroid[channel].y=M01[channel]/M00[channel];
1801 for (y=0; y < (ssize_t) image->rows; y++)
1804 *magick_restrict indexes;
1815 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1818 indexes=GetVirtualIndexQueue(image);
1819 for (x=0; x < (ssize_t) image->columns; x++)
1821 SetMagickPixelPacket(image,p,indexes+x,&pixel);
1822 M11[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1823 centroid[RedChannel].y)*QuantumScale*pixel.red;
1824 M20[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1825 centroid[RedChannel].x)*QuantumScale*pixel.red;
1826 M02[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1827 centroid[RedChannel].y)*QuantumScale*pixel.red;
1828 M21[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1829 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*QuantumScale*
1831 M12[RedChannel]+=(x-centroid[RedChannel].x)*(y-
1832 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1834 M22[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1835 centroid[RedChannel].x)*(y-centroid[RedChannel].y)*(y-
1836 centroid[RedChannel].y)*QuantumScale*pixel.red;
1837 M30[RedChannel]+=(x-centroid[RedChannel].x)*(x-
1838 centroid[RedChannel].x)*(x-centroid[RedChannel].x)*QuantumScale*
1840 M03[RedChannel]+=(y-centroid[RedChannel].y)*(y-
1841 centroid[RedChannel].y)*(y-centroid[RedChannel].y)*QuantumScale*
1843 M11[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1844 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1845 M20[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1846 centroid[GreenChannel].x)*QuantumScale*pixel.green;
1847 M02[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1848 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1849 M21[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1850 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*QuantumScale*
1852 M12[GreenChannel]+=(x-centroid[GreenChannel].x)*(y-
1853 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1855 M22[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1856 centroid[GreenChannel].x)*(y-centroid[GreenChannel].y)*(y-
1857 centroid[GreenChannel].y)*QuantumScale*pixel.green;
1858 M30[GreenChannel]+=(x-centroid[GreenChannel].x)*(x-
1859 centroid[GreenChannel].x)*(x-centroid[GreenChannel].x)*QuantumScale*
1861 M03[GreenChannel]+=(y-centroid[GreenChannel].y)*(y-
1862 centroid[GreenChannel].y)*(y-centroid[GreenChannel].y)*QuantumScale*
1864 M11[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1865 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1866 M20[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1867 centroid[BlueChannel].x)*QuantumScale*pixel.blue;
1868 M02[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1869 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1870 M21[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1871 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*QuantumScale*
1873 M12[BlueChannel]+=(x-centroid[BlueChannel].x)*(y-
1874 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1876 M22[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1877 centroid[BlueChannel].x)*(y-centroid[BlueChannel].y)*(y-
1878 centroid[BlueChannel].y)*QuantumScale*pixel.blue;
1879 M30[BlueChannel]+=(x-centroid[BlueChannel].x)*(x-
1880 centroid[BlueChannel].x)*(x-centroid[BlueChannel].x)*QuantumScale*
1882 M03[BlueChannel]+=(y-centroid[BlueChannel].y)*(y-
1883 centroid[BlueChannel].y)*(y-centroid[BlueChannel].y)*QuantumScale*
1885 if (image->matte != MagickFalse)
1887 M11[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1888 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1889 M20[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1890 centroid[OpacityChannel].x)*QuantumScale*pixel.opacity;
1891 M02[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1892 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1893 M21[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1894 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*
1895 QuantumScale*pixel.opacity;
1896 M12[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(y-
1897 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1898 QuantumScale*pixel.opacity;
1899 M22[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1900 centroid[OpacityChannel].x)*(y-centroid[OpacityChannel].y)*(y-
1901 centroid[OpacityChannel].y)*QuantumScale*pixel.opacity;
1902 M30[OpacityChannel]+=(x-centroid[OpacityChannel].x)*(x-
1903 centroid[OpacityChannel].x)*(x-centroid[OpacityChannel].x)*
1904 QuantumScale*pixel.opacity;
1905 M03[OpacityChannel]+=(y-centroid[OpacityChannel].y)*(y-
1906 centroid[OpacityChannel].y)*(y-centroid[OpacityChannel].y)*
1907 QuantumScale*pixel.opacity;
1909 if (image->colorspace == CMYKColorspace)
1911 M11[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1912 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1913 M20[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1914 centroid[IndexChannel].x)*QuantumScale*pixel.index;
1915 M02[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1916 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1917 M21[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1918 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*
1919 QuantumScale*pixel.index;
1920 M12[IndexChannel]+=(x-centroid[IndexChannel].x)*(y-
1921 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1922 QuantumScale*pixel.index;
1923 M22[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1924 centroid[IndexChannel].x)*(y-centroid[IndexChannel].y)*(y-
1925 centroid[IndexChannel].y)*QuantumScale*pixel.index;
1926 M30[IndexChannel]+=(x-centroid[IndexChannel].x)*(x-
1927 centroid[IndexChannel].x)*(x-centroid[IndexChannel].x)*
1928 QuantumScale*pixel.index;
1929 M03[IndexChannel]+=(y-centroid[IndexChannel].y)*(y-
1930 centroid[IndexChannel].y)*(y-centroid[IndexChannel].y)*
1931 QuantumScale*pixel.index;
1937 M00[CompositeChannels]+=(M00[RedChannel]+M00[GreenChannel]+M00[BlueChannel]);
1938 M01[CompositeChannels]+=(M01[RedChannel]+M01[GreenChannel]+M01[BlueChannel]);
1939 M02[CompositeChannels]+=(M02[RedChannel]+M02[GreenChannel]+M02[BlueChannel]);
1940 M03[CompositeChannels]+=(M03[RedChannel]+M03[GreenChannel]+M03[BlueChannel]);
1941 M10[CompositeChannels]+=(M10[RedChannel]+M10[GreenChannel]+M10[BlueChannel]);
1942 M11[CompositeChannels]+=(M11[RedChannel]+M11[GreenChannel]+M11[BlueChannel]);
1943 M12[CompositeChannels]+=(M12[RedChannel]+M12[GreenChannel]+M12[BlueChannel]);
1944 M20[CompositeChannels]+=(M20[RedChannel]+M20[GreenChannel]+M20[BlueChannel]);
1945 M21[CompositeChannels]+=(M21[RedChannel]+M21[GreenChannel]+M21[BlueChannel]);
1946 M22[CompositeChannels]+=(M22[RedChannel]+M22[GreenChannel]+M22[BlueChannel]);
1947 M30[CompositeChannels]+=(M30[RedChannel]+M30[GreenChannel]+M30[BlueChannel]);
1948 if (image->matte != MagickFalse)
1951 M00[CompositeChannels]+=M00[OpacityChannel];
1952 M01[CompositeChannels]+=M01[OpacityChannel];
1953 M02[CompositeChannels]+=M02[OpacityChannel];
1954 M03[CompositeChannels]+=M03[OpacityChannel];
1955 M10[CompositeChannels]+=M10[OpacityChannel];
1956 M11[CompositeChannels]+=M11[OpacityChannel];
1957 M12[CompositeChannels]+=M12[OpacityChannel];
1958 M20[CompositeChannels]+=M20[OpacityChannel];
1959 M21[CompositeChannels]+=M21[OpacityChannel];
1960 M22[CompositeChannels]+=M22[OpacityChannel];
1961 M30[CompositeChannels]+=M30[OpacityChannel];
1963 if (image->colorspace == CMYKColorspace)
1966 M00[CompositeChannels]+=M00[IndexChannel];
1967 M01[CompositeChannels]+=M01[IndexChannel];
1968 M02[CompositeChannels]+=M02[IndexChannel];
1969 M03[CompositeChannels]+=M03[IndexChannel];
1970 M10[CompositeChannels]+=M10[IndexChannel];
1971 M11[CompositeChannels]+=M11[IndexChannel];
1972 M12[CompositeChannels]+=M12[IndexChannel];
1973 M20[CompositeChannels]+=M20[IndexChannel];
1974 M21[CompositeChannels]+=M21[IndexChannel];
1975 M22[CompositeChannels]+=M22[IndexChannel];
1976 M30[CompositeChannels]+=M30[IndexChannel];
1978 M00[CompositeChannels]/=(double) channels;
1979 M01[CompositeChannels]/=(double) channels;
1980 M02[CompositeChannels]/=(double) channels;
1981 M03[CompositeChannels]/=(double) channels;
1982 M10[CompositeChannels]/=(double) channels;
1983 M11[CompositeChannels]/=(double) channels;
1984 M12[CompositeChannels]/=(double) channels;
1985 M20[CompositeChannels]/=(double) channels;
1986 M21[CompositeChannels]/=(double) channels;
1987 M22[CompositeChannels]/=(double) channels;
1988 M30[CompositeChannels]/=(double) channels;
1989 for (channel=0; channel <= CompositeChannels; channel++)
1994 channel_moments[channel].centroid=centroid[channel];
1995 channel_moments[channel].ellipse_axis.x=sqrt((2.0*
1996 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])+
1997 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
1998 (M20[channel]-M02[channel]))));
1999 channel_moments[channel].ellipse_axis.y=sqrt((2.0*
2000 PerceptibleReciprocal(M00[channel]))*((M20[channel]+M02[channel])-
2001 sqrt(4.0*M11[channel]*M11[channel]+(M20[channel]-M02[channel])*
2002 (M20[channel]-M02[channel]))));
2003 channel_moments[channel].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
2004 M11[channel]*PerceptibleReciprocal(M20[channel]-M02[channel])));
2005 if (fabs(M11[channel]) < 0.0)
2007 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2008 ((M20[channel]-M02[channel]) < 0.0))
2009 channel_moments[channel].ellipse_angle+=90.0;
2012 if (M11[channel] < 0.0)
2014 if (fabs(M20[channel]-M02[channel]) >= 0.0)
2016 if ((M20[channel]-M02[channel]) < 0.0)
2017 channel_moments[channel].ellipse_angle+=90.0;
2019 channel_moments[channel].ellipse_angle+=180.0;
2023 if ((fabs(M20[channel]-M02[channel]) >= 0.0) &&
2024 ((M20[channel]-M02[channel]) < 0.0))
2025 channel_moments[channel].ellipse_angle+=90.0;
2026 channel_moments[channel].ellipse_eccentricity=sqrt(1.0-(
2027 channel_moments[channel].ellipse_axis.y*
2028 channel_moments[channel].ellipse_axis.y*PerceptibleReciprocal(
2029 channel_moments[channel].ellipse_axis.x*
2030 channel_moments[channel].ellipse_axis.x)));
2031 channel_moments[channel].ellipse_intensity=M00[channel]/
2032 (MagickPI*channel_moments[channel].ellipse_axis.x*
2033 channel_moments[channel].ellipse_axis.y+MagickEpsilon);
2035 for (channel=0; channel <= CompositeChannels; channel++)
2042 M11[channel]/=pow(M00[channel],1.0+(1.0+1.0)/2.0);
2043 M20[channel]/=pow(M00[channel],1.0+(2.0+0.0)/2.0);
2044 M02[channel]/=pow(M00[channel],1.0+(0.0+2.0)/2.0);
2045 M21[channel]/=pow(M00[channel],1.0+(2.0+1.0)/2.0);
2046 M12[channel]/=pow(M00[channel],1.0+(1.0+2.0)/2.0);
2047 M22[channel]/=pow(M00[channel],1.0+(2.0+2.0)/2.0);
2048 M30[channel]/=pow(M00[channel],1.0+(3.0+0.0)/2.0);
2049 M03[channel]/=pow(M00[channel],1.0+(0.0+3.0)/2.0);
2052 for (channel=0; channel <= CompositeChannels; channel++)
2057 channel_moments[channel].I[0]=M20[channel]+M02[channel];
2058 channel_moments[channel].I[1]=(M20[channel]-M02[channel])*
2059 (M20[channel]-M02[channel])+4.0*M11[channel]*M11[channel];
2060 channel_moments[channel].I[2]=(M30[channel]-3.0*M12[channel])*
2061 (M30[channel]-3.0*M12[channel])+(3.0*M21[channel]-M03[channel])*
2062 (3.0*M21[channel]-M03[channel]);
2063 channel_moments[channel].I[3]=(M30[channel]+M12[channel])*
2064 (M30[channel]+M12[channel])+(M21[channel]+M03[channel])*
2065 (M21[channel]+M03[channel]);
2066 channel_moments[channel].I[4]=(M30[channel]-3.0*M12[channel])*
2067 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2068 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2069 (M21[channel]+M03[channel]))+(3.0*M21[channel]-M03[channel])*
2070 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2071 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2072 (M21[channel]+M03[channel]));
2073 channel_moments[channel].I[5]=(M20[channel]-M02[channel])*
2074 ((M30[channel]+M12[channel])*(M30[channel]+M12[channel])-
2075 (M21[channel]+M03[channel])*(M21[channel]+M03[channel]))+
2076 4.0*M11[channel]*(M30[channel]+M12[channel])*(M21[channel]+M03[channel]);
2077 channel_moments[channel].I[6]=(3.0*M21[channel]-M03[channel])*
2078 (M30[channel]+M12[channel])*((M30[channel]+M12[channel])*
2079 (M30[channel]+M12[channel])-3.0*(M21[channel]+M03[channel])*
2080 (M21[channel]+M03[channel]))-(M30[channel]-3*M12[channel])*
2081 (M21[channel]+M03[channel])*(3.0*(M30[channel]+M12[channel])*
2082 (M30[channel]+M12[channel])-(M21[channel]+M03[channel])*
2083 (M21[channel]+M03[channel]));
2084 channel_moments[channel].I[7]=M11[channel]*((M30[channel]+M12[channel])*
2085 (M30[channel]+M12[channel])-(M03[channel]+M21[channel])*
2086 (M03[channel]+M21[channel]))-(M20[channel]-M02[channel])*
2087 (M30[channel]+M12[channel])*(M03[channel]+M21[channel]);
2089 if (y < (ssize_t) image->rows)
2090 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
2091 return(channel_moments);
2144 hash_image=BlurImage(image,0.0,1.0,exception);
2145 if (hash_image == (
Image *) NULL)
2147 hash_image->depth=8;
2148 status=TransformImageColorspace(hash_image,xyYColorspace);
2149 if (status == MagickFalse)
2151 moments=GetImageChannelMoments(hash_image,exception);
2152 hash_image=DestroyImage(hash_image);
2156 CompositeChannels+1UL,
sizeof(*perceptual_hash));
2159 for (channel=0; channel <= CompositeChannels; channel++)
2160 for (i=0; i < MaximumNumberOfImageMoments; i++)
2161 perceptual_hash[channel].P[i]=(-MagickLog10(moments[channel].I[i]));
2166 hash_image=BlurImage(image,0.0,1.0,exception);
2167 if (hash_image == (
Image *) NULL)
2173 hash_image->depth=8;
2174 status=TransformImageColorspace(hash_image,HSBColorspace);
2175 if (status == MagickFalse)
2181 moments=GetImageChannelMoments(hash_image,exception);
2182 hash_image=DestroyImage(hash_image);
2189 for (channel=0; channel <= CompositeChannels; channel++)
2190 for (i=0; i < MaximumNumberOfImageMoments; i++)
2191 perceptual_hash[channel].Q[i]=(-MagickLog10(moments[channel].I[i]));
2193 return(perceptual_hash);
2229 MagickExport MagickBooleanType GetImageRange(
const Image *image,
2232 return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
2235 MagickExport MagickBooleanType GetImageChannelRange(
const Image *image,
2236 const ChannelType channel,
double *minima,
double *maxima,
2245 assert(image != (
Image *) NULL);
2246 assert(image->signature == MagickCoreSignature);
2247 if (IsEventLogging() != MagickFalse)
2248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2249 *maxima=(-MagickMaximumValue);
2250 *minima=MagickMaximumValue;
2251 GetMagickPixelPacket(image,&pixel);
2252 for (y=0; y < (ssize_t) image->rows; y++)
2255 *magick_restrict indexes;
2263 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2266 indexes=GetVirtualIndexQueue(image);
2267 for (x=0; x < (ssize_t) image->columns; x++)
2269 SetMagickPixelPacket(image,p,indexes+x,&pixel);
2270 if ((channel & RedChannel) != 0)
2272 if (pixel.red < *minima)
2273 *minima=(double) pixel.red;
2274 if (pixel.red > *maxima)
2275 *maxima=(double) pixel.red;
2277 if ((channel & GreenChannel) != 0)
2279 if (pixel.green < *minima)
2280 *minima=(double) pixel.green;
2281 if (pixel.green > *maxima)
2282 *maxima=(double) pixel.green;
2284 if ((channel & BlueChannel) != 0)
2286 if (pixel.blue < *minima)
2287 *minima=(double) pixel.blue;
2288 if (pixel.blue > *maxima)
2289 *maxima=(double) pixel.blue;
2291 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
2293 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) < *minima)
2294 *minima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2296 if (((MagickRealType) QuantumRange-(MagickRealType) pixel.opacity) > *maxima)
2297 *maxima=(
double) ((MagickRealType) QuantumRange-(MagickRealType)
2300 if (((channel & IndexChannel) != 0) &&
2301 (image->colorspace == CMYKColorspace))
2303 if ((
double) pixel.index < *minima)
2304 *minima=(
double) pixel.index;
2305 if ((
double) pixel.index > *maxima)
2306 *maxima=(
double) pixel.index;
2311 return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
2351 *channel_statistics;
2373 assert(image != (
Image *) NULL);
2374 assert(image->signature == MagickCoreSignature);
2375 if (IsEventLogging() != MagickFalse)
2376 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2377 length=CompositeChannels+1UL;
2379 sizeof(*channel_statistics));
2381 sizeof(*histogram));
2389 channel_statistics);
2390 return(channel_statistics);
2392 (void) memset(channel_statistics,0,length*
2393 sizeof(*channel_statistics));
2394 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2396 channel_statistics[i].depth=1;
2397 channel_statistics[i].maxima=(-MagickMaximumValue);
2398 channel_statistics[i].minima=MagickMaximumValue;
2400 (void) memset(histogram,0,(MaxMap+1U)*
sizeof(*histogram));
2401 (void) memset(&number_bins,0,
sizeof(number_bins));
2402 for (y=0; y < (ssize_t) image->rows; y++)
2405 *magick_restrict indexes;
2416 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2419 indexes=GetVirtualIndexQueue(image);
2420 for (x=0; x < (ssize_t) image->columns; )
2422 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2424 depth=channel_statistics[RedChannel].depth;
2425 range=GetQuantumRange(depth);
2426 if (IsPixelAtDepth(GetPixelRed(p),range) == MagickFalse)
2428 channel_statistics[RedChannel].depth++;
2432 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2434 depth=channel_statistics[GreenChannel].depth;
2435 range=GetQuantumRange(depth);
2436 if (IsPixelAtDepth(GetPixelGreen(p),range) == MagickFalse)
2438 channel_statistics[GreenChannel].depth++;
2442 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2444 depth=channel_statistics[BlueChannel].depth;
2445 range=GetQuantumRange(depth);
2446 if (IsPixelAtDepth(GetPixelBlue(p),range) == MagickFalse)
2448 channel_statistics[BlueChannel].depth++;
2452 if (image->matte != MagickFalse)
2454 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2456 depth=channel_statistics[OpacityChannel].depth;
2457 range=GetQuantumRange(depth);
2458 if (IsPixelAtDepth(GetPixelAlpha(p),range) == MagickFalse)
2460 channel_statistics[OpacityChannel].depth++;
2465 if (image->colorspace == CMYKColorspace)
2467 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
2469 depth=channel_statistics[BlackChannel].depth;
2470 range=GetQuantumRange(depth);
2471 if (IsPixelAtDepth(GetPixelIndex(indexes+x),range) == MagickFalse)
2473 channel_statistics[BlackChannel].depth++;
2478 if ((
double) GetPixelRed(p) < channel_statistics[RedChannel].minima)
2479 channel_statistics[RedChannel].minima=(double) GetPixelRed(p);
2480 if ((
double) GetPixelRed(p) > channel_statistics[RedChannel].maxima)
2481 channel_statistics[RedChannel].maxima=(
double) GetPixelRed(p);
2482 channel_statistics[RedChannel].sum+=QuantumScale*GetPixelRed(p);
2483 channel_statistics[RedChannel].sum_squared+=QuantumScale*GetPixelRed(p)*
2484 QuantumScale*GetPixelRed(p);
2485 channel_statistics[RedChannel].sum_cubed+=QuantumScale*GetPixelRed(p)*
2486 QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p);
2487 channel_statistics[RedChannel].sum_fourth_power+=QuantumScale*
2488 GetPixelRed(p)*QuantumScale*GetPixelRed(p)*QuantumScale*GetPixelRed(p)*
2489 QuantumScale*GetPixelRed(p);
2490 if ((
double) GetPixelGreen(p) < channel_statistics[GreenChannel].minima)
2491 channel_statistics[GreenChannel].minima=(double) GetPixelGreen(p);
2492 if ((
double) GetPixelGreen(p) > channel_statistics[GreenChannel].maxima)
2493 channel_statistics[GreenChannel].maxima=(
double) GetPixelGreen(p);
2494 channel_statistics[GreenChannel].sum+=QuantumScale*GetPixelGreen(p);
2495 channel_statistics[GreenChannel].sum_squared+=QuantumScale*GetPixelGreen(p)*
2496 QuantumScale*GetPixelGreen(p);
2497 channel_statistics[GreenChannel].sum_cubed+=QuantumScale*GetPixelGreen(p)*
2498 QuantumScale*GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2499 channel_statistics[GreenChannel].sum_fourth_power+=QuantumScale*
2500 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p)*QuantumScale*
2501 GetPixelGreen(p)*QuantumScale*GetPixelGreen(p);
2502 if ((
double) GetPixelBlue(p) < channel_statistics[BlueChannel].minima)
2503 channel_statistics[BlueChannel].minima=(double) GetPixelBlue(p);
2504 if ((
double) GetPixelBlue(p) > channel_statistics[BlueChannel].maxima)
2505 channel_statistics[BlueChannel].maxima=(
double) GetPixelBlue(p);
2506 channel_statistics[BlueChannel].sum+=QuantumScale*GetPixelBlue(p);
2507 channel_statistics[BlueChannel].sum_squared+=QuantumScale*GetPixelBlue(p)*
2508 QuantumScale*GetPixelBlue(p);
2509 channel_statistics[BlueChannel].sum_cubed+=QuantumScale*GetPixelBlue(p)*
2510 QuantumScale*GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2511 channel_statistics[BlueChannel].sum_fourth_power+=QuantumScale*
2512 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p)*QuantumScale*
2513 GetPixelBlue(p)*QuantumScale*GetPixelBlue(p);
2514 histogram[ScaleQuantumToMap(GetPixelRed(p))].red++;
2515 histogram[ScaleQuantumToMap(GetPixelGreen(p))].green++;
2516 histogram[ScaleQuantumToMap(GetPixelBlue(p))].blue++;
2517 if (image->matte != MagickFalse)
2519 if ((
double) GetPixelAlpha(p) < channel_statistics[OpacityChannel].minima)
2520 channel_statistics[OpacityChannel].minima=(double) GetPixelAlpha(p);
2521 if ((
double) GetPixelAlpha(p) > channel_statistics[OpacityChannel].maxima)
2522 channel_statistics[OpacityChannel].maxima=(
double) GetPixelAlpha(p);
2523 channel_statistics[OpacityChannel].sum+=QuantumScale*GetPixelAlpha(p);
2524 channel_statistics[OpacityChannel].sum_squared+=QuantumScale*
2525 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2526 channel_statistics[OpacityChannel].sum_cubed+=QuantumScale*
2527 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2529 channel_statistics[OpacityChannel].sum_fourth_power+=QuantumScale*
2530 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p)*QuantumScale*
2531 GetPixelAlpha(p)*QuantumScale*GetPixelAlpha(p);
2532 histogram[ScaleQuantumToMap(GetPixelAlpha(p))].opacity++;
2534 if (image->colorspace == CMYKColorspace)
2536 if ((
double) GetPixelIndex(indexes+x) < channel_statistics[BlackChannel].minima)
2537 channel_statistics[BlackChannel].minima=(double)
2538 GetPixelIndex(indexes+x);
2539 if ((
double) GetPixelIndex(indexes+x) > channel_statistics[BlackChannel].maxima)
2540 channel_statistics[BlackChannel].maxima=(
double)
2541 GetPixelIndex(indexes+x);
2542 channel_statistics[BlackChannel].sum+=QuantumScale*
2543 GetPixelIndex(indexes+x);
2544 channel_statistics[BlackChannel].sum_squared+=QuantumScale*
2545 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x);
2546 channel_statistics[BlackChannel].sum_cubed+=QuantumScale*
2547 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2548 QuantumScale*GetPixelIndex(indexes+x);
2549 channel_statistics[BlackChannel].sum_fourth_power+=QuantumScale*
2550 GetPixelIndex(indexes+x)*QuantumScale*GetPixelIndex(indexes+x)*
2551 QuantumScale*GetPixelIndex(indexes+x)*QuantumScale*
2552 GetPixelIndex(indexes+x);
2553 histogram[ScaleQuantumToMap(GetPixelIndex(indexes+x))].index++;
2559 for (i=0; i < (ssize_t) CompositeChannels; i++)
2569 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2570 mean=channel_statistics[i].sum*area;
2571 channel_statistics[i].sum=mean;
2572 channel_statistics[i].sum_squared*=area;
2573 channel_statistics[i].sum_cubed*=area;
2574 channel_statistics[i].sum_fourth_power*=area;
2575 channel_statistics[i].mean=mean;
2576 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2577 standard_deviation=sqrt(channel_statistics[i].variance-(mean*mean));
2578 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2579 ((double) image->columns*image->rows);
2580 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2581 channel_statistics[i].standard_deviation=standard_deviation;
2583 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2585 if (histogram[i].red > 0.0)
2587 if (histogram[i].green > 0.0)
2588 number_bins.green++;
2589 if (histogram[i].blue > 0.0)
2591 if ((image->matte != MagickFalse) && (histogram[i].opacity > 0.0))
2592 number_bins.opacity++;
2593 if ((image->colorspace == CMYKColorspace) && (histogram[i].index > 0.0))
2594 number_bins.index++;
2596 area=PerceptibleReciprocal((
double) image->columns*image->rows);
2597 for (i=0; i < (ssize_t) (MaxMap+1U); i++)
2602 histogram[i].red*=area;
2603 channel_statistics[RedChannel].entropy+=-histogram[i].red*
2604 MagickLog10(histogram[i].red)*
2605 PerceptibleReciprocal(MagickLog10((
double) number_bins.red));
2606 histogram[i].green*=area;
2607 channel_statistics[GreenChannel].entropy+=-histogram[i].green*
2608 MagickLog10(histogram[i].green)*
2609 PerceptibleReciprocal(MagickLog10((
double) number_bins.green));
2610 histogram[i].blue*=area;
2611 channel_statistics[BlueChannel].entropy+=-histogram[i].blue*
2612 MagickLog10(histogram[i].blue)*
2613 PerceptibleReciprocal(MagickLog10((
double) number_bins.blue));
2614 if (image->matte != MagickFalse)
2616 histogram[i].opacity*=area;
2617 channel_statistics[OpacityChannel].entropy+=-histogram[i].opacity*
2618 MagickLog10(histogram[i].opacity)*
2619 PerceptibleReciprocal(MagickLog10((
double) number_bins.opacity));
2621 if (image->colorspace == CMYKColorspace)
2623 histogram[i].index*=area;
2624 channel_statistics[IndexChannel].entropy+=-histogram[i].index*
2625 MagickLog10(histogram[i].index)*
2626 PerceptibleReciprocal(MagickLog10((
double) number_bins.index));
2632 for (i=0; i < (ssize_t) CompositeChannels; i++)
2634 channel_statistics[CompositeChannels].depth=(size_t) EvaluateMax((
double)
2635 channel_statistics[CompositeChannels].depth,(double)
2636 channel_statistics[i].depth);
2637 channel_statistics[CompositeChannels].minima=MagickMin(
2638 channel_statistics[CompositeChannels].minima,
2639 channel_statistics[i].minima);
2640 channel_statistics[CompositeChannels].maxima=EvaluateMax(
2641 channel_statistics[CompositeChannels].maxima,
2642 channel_statistics[i].maxima);
2643 channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
2644 channel_statistics[CompositeChannels].sum_squared+=
2645 channel_statistics[i].sum_squared;
2646 channel_statistics[CompositeChannels].sum_cubed+=
2647 channel_statistics[i].sum_cubed;
2648 channel_statistics[CompositeChannels].sum_fourth_power+=
2649 channel_statistics[i].sum_fourth_power;
2650 channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
2651 channel_statistics[CompositeChannels].variance+=
2652 channel_statistics[i].variance-channel_statistics[i].mean*
2653 channel_statistics[i].mean;
2654 standard_deviation=sqrt(channel_statistics[i].variance-
2655 (channel_statistics[i].mean*channel_statistics[i].mean));
2656 area=PerceptibleReciprocal((
double) image->columns*image->rows-1.0)*
2657 ((double) image->columns*image->rows);
2658 standard_deviation=sqrt(area*standard_deviation*standard_deviation);
2659 channel_statistics[CompositeChannels].standard_deviation=standard_deviation;
2660 channel_statistics[CompositeChannels].entropy+=
2661 channel_statistics[i].entropy;
2664 if (image->matte != MagickFalse)
2666 if (image->colorspace == CMYKColorspace)
2668 channel_statistics[CompositeChannels].sum/=channels;
2669 channel_statistics[CompositeChannels].sum_squared/=channels;
2670 channel_statistics[CompositeChannels].sum_cubed/=channels;
2671 channel_statistics[CompositeChannels].sum_fourth_power/=channels;
2672 channel_statistics[CompositeChannels].mean/=channels;
2673 channel_statistics[CompositeChannels].kurtosis/=channels;
2674 channel_statistics[CompositeChannels].skewness/=channels;
2675 channel_statistics[CompositeChannels].entropy/=channels;
2676 i=CompositeChannels;
2677 area=PerceptibleReciprocal((
double) channels*image->columns*image->rows);
2678 channel_statistics[i].variance=channel_statistics[i].sum_squared;
2679 channel_statistics[i].mean=channel_statistics[i].sum;
2680 standard_deviation=sqrt(channel_statistics[i].variance-
2681 (channel_statistics[i].mean*channel_statistics[i].mean));
2682 standard_deviation=sqrt(PerceptibleReciprocal((
double) channels*
2683 image->columns*image->rows-1.0)*channels*image->columns*image->rows*
2684 standard_deviation*standard_deviation);
2685 channel_statistics[i].standard_deviation=standard_deviation;
2686 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2691 standard_deviation=PerceptibleReciprocal(
2692 channel_statistics[i].standard_deviation);
2693 channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-3.0*
2694 channel_statistics[i].mean*channel_statistics[i].sum_squared+2.0*
2695 channel_statistics[i].mean*channel_statistics[i].mean*
2696 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2697 standard_deviation);
2698 channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-4.0*
2699 channel_statistics[i].mean*channel_statistics[i].sum_cubed+6.0*
2700 channel_statistics[i].mean*channel_statistics[i].mean*
2701 channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
2702 channel_statistics[i].mean*1.0*channel_statistics[i].mean*
2703 channel_statistics[i].mean)*(standard_deviation*standard_deviation*
2704 standard_deviation*standard_deviation)-3.0;
2706 for (i=0; i <= (ssize_t) CompositeChannels; i++)
2708 channel_statistics[i].mean*=QuantumRange;
2709 channel_statistics[i].variance*=QuantumRange;
2710 channel_statistics[i].standard_deviation*=QuantumRange;
2711 channel_statistics[i].sum*=QuantumRange;
2712 channel_statistics[i].sum_squared*=QuantumRange;
2713 channel_statistics[i].sum_cubed*=QuantumRange;
2714 channel_statistics[i].sum_fourth_power*=QuantumRange;
2716 channel_statistics[CompositeChannels].mean=0.0;
2717 channel_statistics[CompositeChannels].standard_deviation=0.0;
2718 for (i=0; i < (ssize_t) CompositeChannels; i++)
2720 channel_statistics[CompositeChannels].mean+=
2721 channel_statistics[i].mean;
2722 channel_statistics[CompositeChannels].standard_deviation+=
2723 channel_statistics[i].standard_deviation;
2725 channel_statistics[CompositeChannels].mean/=(double) channels;
2726 channel_statistics[CompositeChannels].standard_deviation/=(double) channels;
2728 if (y < (ssize_t) image->rows)
2730 channel_statistics);
2731 return(channel_statistics);
2772 MagickExport
Image *PolynomialImage(
const Image *images,
2773 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2778 polynomial_image=PolynomialImageChannel(images,DefaultChannels,number_terms,
2780 return(polynomial_image);
2783 MagickExport
Image *PolynomialImageChannel(
const Image *images,
2784 const ChannelType channel,
const size_t number_terms,
const double *terms,
2787 #define PolynomialImageTag "Polynomial/Image" 2802 **magick_restrict polynomial_pixels,
2808 assert(images != (
Image *) NULL);
2809 assert(images->signature == MagickCoreSignature);
2810 if (IsEventLogging() != MagickFalse)
2811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2813 assert(exception->signature == MagickCoreSignature);
2814 image=AcquireImageCanvas(images,exception);
2815 if (image == (
Image *) NULL)
2816 return((
Image *) NULL);
2817 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2819 InheritException(exception,&image->exception);
2820 image=DestroyImage(image);
2821 return((
Image *) NULL);
2823 polynomial_pixels=AcquirePixelTLS(images);
2826 image=DestroyImage(image);
2827 (void) ThrowMagickException(exception,GetMagickModule(),
2828 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2829 return((
Image *) NULL);
2836 GetMagickPixelPacket(images,&zero);
2837 polynomial_view=AcquireAuthenticCacheView(image,exception);
2838 #if defined(MAGICKCORE_OPENMP_SUPPORT) 2839 #pragma omp parallel for schedule(static) shared(progress,status) \ 2840 magick_number_threads(image,image,image->rows,1) 2842 for (y=0; y < (ssize_t) image->rows; y++)
2851 id = GetOpenMPThreadId();
2854 *magick_restrict polynomial_indexes;
2869 if (status == MagickFalse)
2871 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2878 polynomial_indexes=GetCacheViewAuthenticIndexQueue(polynomial_view);
2879 polynomial_pixel=polynomial_pixels[id];
2880 for (x=0; x < (ssize_t) image->columns; x++)
2881 polynomial_pixel[x]=zero;
2883 number_images=GetImageListLength(images);
2884 for (i=0; i < (ssize_t) number_images; i++)
2892 if (i >= (ssize_t) number_terms)
2894 image_view=AcquireVirtualCacheView(next,exception);
2895 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2898 image_view=DestroyCacheView(image_view);
2901 indexes=GetCacheViewVirtualIndexQueue(image_view);
2902 for (x=0; x < (ssize_t) image->columns; x++)
2908 coefficient=terms[i << 1];
2909 degree=terms[(i << 1)+1];
2910 if ((channel & RedChannel) != 0)
2911 polynomial_pixel[x].red+=coefficient*pow(QuantumScale*(
double)
2913 if ((channel & GreenChannel) != 0)
2914 polynomial_pixel[x].green+=coefficient*pow(QuantumScale*(
double)
2917 if ((channel & BlueChannel) != 0)
2918 polynomial_pixel[x].blue+=coefficient*pow(QuantumScale*(
double)
2920 if ((channel & OpacityChannel) != 0)
2921 polynomial_pixel[x].opacity+=coefficient*pow(QuantumScale*
2922 ((
double) QuantumRange-(double) p->opacity),degree);
2923 if (((channel & IndexChannel) != 0) &&
2924 (image->colorspace == CMYKColorspace))
2925 polynomial_pixel[x].index+=coefficient*pow(QuantumScale*(
double)
2929 image_view=DestroyCacheView(image_view);
2930 next=GetNextImageInList(next);
2932 for (x=0; x < (ssize_t) image->columns; x++)
2934 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*
2935 polynomial_pixel[x].red));
2936 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*
2937 polynomial_pixel[x].green));
2938 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*
2939 polynomial_pixel[x].blue));
2940 if (image->matte == MagickFalse)
2941 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2942 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2944 SetPixelAlpha(q,ClampToQuantum((MagickRealType) QuantumRange-
2945 (MagickRealType) QuantumRange*polynomial_pixel[x].opacity));
2946 if (image->colorspace == CMYKColorspace)
2947 SetPixelIndex(polynomial_indexes+x,ClampToQuantum((MagickRealType)
2948 QuantumRange*polynomial_pixel[x].index));
2951 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2953 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2958 proceed=SetImageProgress(images,PolynomialImageTag,progress++,
2960 if (proceed == MagickFalse)
2964 polynomial_view=DestroyCacheView(polynomial_view);
2965 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2966 if (status == MagickFalse)
2967 image=DestroyImage(image);
3009 #define ListChannels 5 3036 lists[ListChannels];
3046 for (i=0; i < ListChannels; i++)
3047 if (pixel_list->lists[i].nodes != (
ListNode *) NULL)
3048 pixel_list->lists[i].nodes=(
ListNode *) RelinquishAlignedMemory(
3049 pixel_list->lists[i].nodes);
3050 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
3059 assert(pixel_list != (
PixelList **) NULL);
3060 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3061 if (pixel_list[i] != (
PixelList *) NULL)
3062 pixel_list[i]=DestroyPixelList(pixel_list[i]);
3063 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
3067 static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
3075 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
3078 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
3079 pixel_list->length=width*height;
3080 for (i=0; i < ListChannels; i++)
3082 pixel_list->lists[i].nodes=(
ListNode *) AcquireAlignedMemory(65537UL,
3083 sizeof(*pixel_list->lists[i].nodes));
3084 if (pixel_list->lists[i].nodes == (
ListNode *) NULL)
3085 return(DestroyPixelList(pixel_list));
3086 (void) memset(pixel_list->lists[i].nodes,0,65537UL*
3087 sizeof(*pixel_list->lists[i].nodes));
3089 pixel_list->signature=MagickCoreSignature;
3093 static PixelList **AcquirePixelListTLS(
const size_t width,
3094 const size_t height)
3105 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3106 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
3107 sizeof(*pixel_list));
3110 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
3111 for (i=0; i < (ssize_t) number_threads; i++)
3113 pixel_list[i]=AcquirePixelList(width,height);
3114 if (pixel_list[i] == (
PixelList *) NULL)
3115 return(DestroyPixelListTLS(pixel_list));
3120 static void AddNodePixelList(
PixelList *pixel_list,
const ssize_t channel,
3136 list=pixel_list->lists+channel;
3137 list->nodes[color].signature=pixel_list->signature;
3138 list->nodes[color].count=1;
3143 (void) memset(update,0,
sizeof(update));
3144 for (level=list->level; level >= 0; level--)
3146 while (list->nodes[search].next[level] < color)
3147 search=list->nodes[search].next[level];
3148 update[level]=search;
3153 for (level=0; ; level++)
3155 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
3156 if ((pixel_list->seed & 0x300) != 0x300)
3161 if (level > (list->level+2))
3162 level=list->level+2;
3166 while (level > list->level)
3169 update[list->level]=65536UL;
3176 list->nodes[color].next[level]=list->nodes[update[level]].next[level];
3177 list->nodes[update[level]].next[level]=color;
3178 }
while (level-- > 0);
3197 channels[ListChannels];
3202 for (channel=0; channel < 5; channel++)
3204 list=pixel_list->lists+channel;
3207 maximum=list->nodes[color].next[0];
3210 color=list->nodes[color].next[0];
3211 if (color > maximum)
3213 count+=list->nodes[color].count;
3214 }
while (count < (ssize_t) pixel_list->length);
3215 channels[channel]=(
unsigned short) maximum;
3217 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3218 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3219 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3220 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3221 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3242 channels[ListChannels];
3247 for (channel=0; channel < 5; channel++)
3249 list=pixel_list->lists+channel;
3255 color=list->nodes[color].next[0];
3256 sum+=(MagickRealType) list->nodes[color].count*color;
3257 count+=list->nodes[color].count;
3258 }
while (count < (ssize_t) pixel_list->length);
3259 sum/=pixel_list->length;
3260 channels[channel]=(
unsigned short) sum;
3262 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3263 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3264 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3265 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3266 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3284 channels[ListChannels];
3289 for (channel=0; channel < 5; channel++)
3291 list=pixel_list->lists+channel;
3296 color=list->nodes[color].next[0];
3297 count+=list->nodes[color].count;
3298 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3299 channels[channel]=(
unsigned short) color;
3301 GetMagickPixelPacket((
const Image *) NULL,pixel);
3302 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3303 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3304 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3305 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3306 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3325 channels[ListChannels];
3330 for (channel=0; channel < 5; channel++)
3332 list=pixel_list->lists+channel;
3335 minimum=list->nodes[color].next[0];
3338 color=list->nodes[color].next[0];
3339 if (color < minimum)
3341 count+=list->nodes[color].count;
3342 }
while (count < (ssize_t) pixel_list->length);
3343 channels[channel]=(
unsigned short) minimum;
3345 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3346 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3347 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3348 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3349 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3374 for (channel=0; channel < 5; channel++)
3376 list=pixel_list->lists+channel;
3379 max_count=list->nodes[mode].count;
3383 color=list->nodes[color].next[0];
3384 if (list->nodes[color].count > max_count)
3387 max_count=list->nodes[mode].count;
3389 count+=list->nodes[color].count;
3390 }
while (count < (ssize_t) pixel_list->length);
3391 channels[channel]=(
unsigned short) mode;
3393 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3394 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3395 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3396 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3397 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3422 for (channel=0; channel < 5; channel++)
3424 list=pixel_list->lists+channel;
3426 next=list->nodes[color].next[0];
3432 next=list->nodes[color].next[0];
3433 count+=list->nodes[color].count;
3434 }
while (count <= (ssize_t) (pixel_list->length >> 1));
3435 if ((previous == 65536UL) && (next != 65536UL))
3438 if ((previous != 65536UL) && (next == 65536UL))
3440 channels[channel]=(
unsigned short) color;
3442 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3443 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3444 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3445 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3446 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3449 static void GetRootMeanSquarePixelList(
PixelList *pixel_list,
3468 channels[ListChannels];
3473 for (channel=0; channel < 5; channel++)
3475 list=pixel_list->lists+channel;
3481 color=list->nodes[color].next[0];
3482 sum+=(MagickRealType) (list->nodes[color].count*color*color);
3483 count+=list->nodes[color].count;
3484 }
while (count < (ssize_t) pixel_list->length);
3485 sum/=pixel_list->length;
3486 channels[channel]=(
unsigned short) sqrt(sum);
3488 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3489 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3490 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3491 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3492 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3495 static void GetStandardDeviationPixelList(
PixelList *pixel_list,
3513 channels[ListChannels];
3518 for (channel=0; channel < 5; channel++)
3520 list=pixel_list->lists+channel;
3530 color=list->nodes[color].next[0];
3531 sum+=(MagickRealType) list->nodes[color].count*color;
3532 for (i=0; i < (ssize_t) list->nodes[color].count; i++)
3533 sum_squared+=((MagickRealType) color)*((MagickRealType) color);
3534 count+=list->nodes[color].count;
3535 }
while (count < (ssize_t) pixel_list->length);
3536 sum/=pixel_list->length;
3537 sum_squared/=pixel_list->length;
3538 channels[channel]=(
unsigned short) sqrt(sum_squared-(sum*sum));
3540 pixel->red=(MagickRealType) ScaleShortToQuantum(channels[0]);
3541 pixel->green=(MagickRealType) ScaleShortToQuantum(channels[1]);
3542 pixel->blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
3543 pixel->opacity=(MagickRealType) ScaleShortToQuantum(channels[3]);
3544 pixel->index=(MagickRealType) ScaleShortToQuantum(channels[4]);
3547 static inline void InsertPixelList(
const Image *image,
const PixelPacket *pixel,
3548 const IndexPacket *indexes,
PixelList *pixel_list)
3556 index=ScaleQuantumToShort(GetPixelRed(pixel));
3557 signature=pixel_list->lists[0].nodes[index].signature;
3558 if (signature == pixel_list->signature)
3559 pixel_list->lists[0].nodes[index].count++;
3561 AddNodePixelList(pixel_list,0,index);
3562 index=ScaleQuantumToShort(GetPixelGreen(pixel));
3563 signature=pixel_list->lists[1].nodes[index].signature;
3564 if (signature == pixel_list->signature)
3565 pixel_list->lists[1].nodes[index].count++;
3567 AddNodePixelList(pixel_list,1,index);
3568 index=ScaleQuantumToShort(GetPixelBlue(pixel));
3569 signature=pixel_list->lists[2].nodes[index].signature;
3570 if (signature == pixel_list->signature)
3571 pixel_list->lists[2].nodes[index].count++;
3573 AddNodePixelList(pixel_list,2,index);
3574 index=ScaleQuantumToShort(GetPixelOpacity(pixel));
3575 signature=pixel_list->lists[3].nodes[index].signature;
3576 if (signature == pixel_list->signature)
3577 pixel_list->lists[3].nodes[index].count++;
3579 AddNodePixelList(pixel_list,3,index);
3580 if (image->colorspace == CMYKColorspace)
3581 index=ScaleQuantumToShort(GetPixelIndex(indexes));
3582 signature=pixel_list->lists[4].nodes[index].signature;
3583 if (signature == pixel_list->signature)
3584 pixel_list->lists[4].nodes[index].count++;
3586 AddNodePixelList(pixel_list,4,index);
3589 static void ResetPixelList(
PixelList *pixel_list)
3606 for (channel=0; channel < 5; channel++)
3608 list=pixel_list->lists+channel;
3609 root=list->nodes+65536UL;
3611 for (level=0; level < 9; level++)
3612 root->next[level]=65536UL;
3614 pixel_list->seed=pixel_list->signature++;
3617 MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
3618 const size_t width,
const size_t height,
ExceptionInfo *exception)
3623 statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
3625 return(statistic_image);
3628 MagickExport
Image *StatisticImageChannel(
const Image *image,
3629 const ChannelType channel,
const StatisticType type,
const size_t width,
3632 #define StatisticImageTag "Statistic/Image" 3648 **magick_restrict pixel_list;
3660 assert(image != (
Image *) NULL);
3661 assert(image->signature == MagickCoreSignature);
3662 if (IsEventLogging() != MagickFalse)
3663 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3665 assert(exception->signature == MagickCoreSignature);
3666 statistic_image=CloneImage(image,0,0,MagickTrue,exception);
3667 if (statistic_image == (
Image *) NULL)
3668 return((
Image *) NULL);
3669 if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
3671 InheritException(exception,&statistic_image->exception);
3672 statistic_image=DestroyImage(statistic_image);
3673 return((
Image *) NULL);
3675 neighbor_width=width == 0 ? GetOptimalKernelWidth2D((
double) width,0.5) :
3677 neighbor_height=height == 0 ? GetOptimalKernelWidth2D((
double) height,0.5) :
3679 pixel_list=AcquirePixelListTLS(neighbor_width,neighbor_height);
3682 statistic_image=DestroyImage(statistic_image);
3683 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3690 image_view=AcquireVirtualCacheView(image,exception);
3691 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
3692 #if defined(MAGICKCORE_OPENMP_SUPPORT) 3693 #pragma omp parallel for schedule(static) shared(progress,status) \ 3694 magick_number_threads(image,statistic_image,statistic_image->rows,1) 3696 for (y=0; y < (ssize_t) statistic_image->rows; y++)
3699 id = GetOpenMPThreadId();
3702 *magick_restrict indexes;
3708 *magick_restrict statistic_indexes;
3716 if (status == MagickFalse)
3718 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) neighbor_width/2L),y-
3719 (ssize_t) (neighbor_height/2L),image->columns+neighbor_width,
3720 neighbor_height,exception);
3721 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3727 indexes=GetCacheViewVirtualIndexQueue(image_view);
3728 statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
3729 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3746 ResetPixelList(pixel_list[
id]);
3747 for (v=0; v < (ssize_t) neighbor_height; v++)
3749 for (u=0; u < (ssize_t) neighbor_width; u++)
3750 InsertPixelList(image,r+u,s+u,pixel_list[
id]);
3751 r+=image->columns+neighbor_width;
3752 s+=image->columns+neighbor_width;
3754 GetMagickPixelPacket(image,&pixel);
3755 SetMagickPixelPacket(image,p+neighbor_width*neighbor_height/2,indexes+x+
3756 neighbor_width*neighbor_height/2,&pixel);
3759 case GradientStatistic:
3765 GetMinimumPixelList(pixel_list[
id],&pixel);
3767 GetMaximumPixelList(pixel_list[
id],&pixel);
3769 pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
3770 pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
3771 pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
3772 pixel.opacity=MagickAbsoluteValue(maximum.opacity-minimum.opacity);
3773 if (image->colorspace == CMYKColorspace)
3774 pixel.index=MagickAbsoluteValue(maximum.index-minimum.index);
3777 case MaximumStatistic:
3779 GetMaximumPixelList(pixel_list[
id],&pixel);
3784 GetMeanPixelList(pixel_list[
id],&pixel);
3787 case MedianStatistic:
3790 GetMedianPixelList(pixel_list[
id],&pixel);
3793 case MinimumStatistic:
3795 GetMinimumPixelList(pixel_list[
id],&pixel);
3800 GetModePixelList(pixel_list[
id],&pixel);
3803 case NonpeakStatistic:
3805 GetNonpeakPixelList(pixel_list[
id],&pixel);
3808 case RootMeanSquareStatistic:
3810 GetRootMeanSquarePixelList(pixel_list[
id],&pixel);
3813 case StandardDeviationStatistic:
3815 GetStandardDeviationPixelList(pixel_list[
id],&pixel);
3819 if ((channel & RedChannel) != 0)
3820 SetPixelRed(q,ClampToQuantum(pixel.red));
3821 if ((channel & GreenChannel) != 0)
3822 SetPixelGreen(q,ClampToQuantum(pixel.green));
3823 if ((channel & BlueChannel) != 0)
3824 SetPixelBlue(q,ClampToQuantum(pixel.blue));
3825 if ((channel & OpacityChannel) != 0)
3826 SetPixelOpacity(q,ClampToQuantum(pixel.opacity));
3827 if (((channel & IndexChannel) != 0) &&
3828 (image->colorspace == CMYKColorspace))
3829 SetPixelIndex(statistic_indexes+x,ClampToQuantum(pixel.index));
3833 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3835 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3840 proceed=SetImageProgress(image,StatisticImageTag,progress++,
3842 if (proceed == MagickFalse)
3846 statistic_view=DestroyCacheView(statistic_view);
3847 image_view=DestroyCacheView(image_view);
3848 pixel_list=DestroyPixelListTLS(pixel_list);
3849 if (status == MagickFalse)
3850 statistic_image=DestroyImage(statistic_image);
3851 return(statistic_image);