43#include "MagickCore/studio.h"
44#include "MagickCore/accelerate-private.h"
45#include "MagickCore/animate.h"
46#include "MagickCore/artifact.h"
47#include "MagickCore/attribute.h"
48#include "MagickCore/blob.h"
49#include "MagickCore/blob-private.h"
50#include "MagickCore/cache.h"
51#include "MagickCore/cache-private.h"
52#include "MagickCore/cache-view.h"
53#include "MagickCore/client.h"
54#include "MagickCore/color.h"
55#include "MagickCore/color-private.h"
56#include "MagickCore/colorspace.h"
57#include "MagickCore/colorspace-private.h"
58#include "MagickCore/composite.h"
59#include "MagickCore/composite-private.h"
60#include "MagickCore/compress.h"
61#include "MagickCore/constitute.h"
62#include "MagickCore/display.h"
63#include "MagickCore/draw.h"
64#include "MagickCore/enhance.h"
65#include "MagickCore/exception.h"
66#include "MagickCore/exception-private.h"
67#include "MagickCore/gem.h"
68#include "MagickCore/gem-private.h"
69#include "MagickCore/geometry.h"
70#include "MagickCore/list.h"
71#include "MagickCore/image-private.h"
72#include "MagickCore/magic.h"
73#include "MagickCore/magick.h"
74#include "MagickCore/memory_.h"
75#include "MagickCore/module.h"
76#include "MagickCore/monitor.h"
77#include "MagickCore/monitor-private.h"
78#include "MagickCore/option.h"
79#include "MagickCore/paint.h"
80#include "MagickCore/pixel-accessor.h"
81#include "MagickCore/profile.h"
82#include "MagickCore/property.h"
83#include "MagickCore/quantize.h"
84#include "MagickCore/quantum-private.h"
85#include "MagickCore/random_.h"
86#include "MagickCore/random-private.h"
87#include "MagickCore/resource_.h"
88#include "MagickCore/segment.h"
89#include "MagickCore/semaphore.h"
90#include "MagickCore/signature-private.h"
91#include "MagickCore/statistic.h"
92#include "MagickCore/statistic-private.h"
93#include "MagickCore/string_.h"
94#include "MagickCore/thread-private.h"
95#include "MagickCore/timer.h"
96#include "MagickCore/utility.h"
97#include "MagickCore/version.h"
139 channel[MaxPixelChannels];
142static PixelChannels **DestroyPixelTLS(
const Image *images,
143 PixelChannels **pixels)
151 assert(pixels != (PixelChannels **) NULL);
152 rows=MagickMax(GetImageListLength(images),(
size_t)
153 GetMagickResourceLimit(ThreadResource));
154 for (i=0; i < (ssize_t) rows; i++)
155 if (pixels[i] != (PixelChannels *) NULL)
156 pixels[i]=(PixelChannels *) RelinquishMagickMemory(pixels[i]);
157 pixels=(PixelChannels **) RelinquishMagickMemory(pixels);
161static PixelChannels **AcquirePixelTLS(
const Image *images)
177 number_images=GetImageListLength(images);
178 rows=MagickMax(number_images,(
size_t) GetMagickResourceLimit(ThreadResource));
179 pixels=(PixelChannels **) AcquireQuantumMemory(rows,
sizeof(*pixels));
180 if (pixels == (PixelChannels **) NULL)
181 return((PixelChannels **) NULL);
182 (void) memset(pixels,0,rows*
sizeof(*pixels));
183 columns=MagickMax(number_images,MaxPixelChannels);
184 for (next=images; next != (Image *) NULL; next=next->next)
185 columns=MagickMax(next->columns,columns);
186 for (i=0; i < (ssize_t) rows; i++)
191 pixels[i]=(PixelChannels *) AcquireQuantumMemory(columns,
sizeof(**pixels));
192 if (pixels[i] == (PixelChannels *) NULL)
193 return(DestroyPixelTLS(images,pixels));
194 for (j=0; j < (ssize_t) columns; j++)
199 for (k=0; k < MaxPixelChannels; k++)
200 pixels[i][j].channel[k]=0.0;
206static inline double EvaluateMax(
const double x,
const double y)
213#if defined(__cplusplus) || defined(c_plusplus)
217static int IntensityCompare(
const void *x,
const void *y)
229 color_1=(
const PixelChannels *) x;
230 color_2=(
const PixelChannels *) y;
232 for (i=0; i < MaxPixelChannels; i++)
233 distance+=color_1->channel[i]-(
double) color_2->channel[i];
234 return(distance < 0.0 ? -1 : distance > 0.0 ? 1 : 0);
237#if defined(__cplusplus) || defined(c_plusplus)
241static double ApplyEvaluateOperator(RandomInfo *random_info,
const Quantum pixel,
242 const MagickEvaluateOperator op,
const double value)
253 case UndefinedEvaluateOperator:
255 case AbsEvaluateOperator:
257 result=(double) fabs((
double) pixel+value);
260 case AddEvaluateOperator:
262 result=(double) pixel+value;
265 case AddModulusEvaluateOperator:
273 result=(double) pixel+value;
274 result-=((double) QuantumRange+1.0)*floor(result/((
double)
278 case AndEvaluateOperator:
280 result=(double) ((ssize_t) pixel & (ssize_t) (value+0.5));
283 case CosineEvaluateOperator:
285 result=(double) QuantumRange*(0.5*cos((
double) (2.0*MagickPI*
286 QuantumScale*(
double) pixel*value))+0.5);
289 case DivideEvaluateOperator:
291 result=(double) pixel/(value == 0.0 ? 1.0 : value);
294 case ExponentialEvaluateOperator:
296 result=(double) QuantumRange*exp(value*QuantumScale*(
double) pixel);
299 case GaussianNoiseEvaluateOperator:
301 result=(double) GenerateDifferentialNoise(random_info,pixel,GaussianNoise,
305 case ImpulseNoiseEvaluateOperator:
307 result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
311 case InverseLogEvaluateOperator:
313 result=(double) QuantumRange*pow((value+1.0),QuantumScale*(
double)
314 pixel-1.0)*MagickSafeReciprocal(value);
317 case LaplacianNoiseEvaluateOperator:
319 result=(double) GenerateDifferentialNoise(random_info,pixel,
320 LaplacianNoise,value);
323 case LeftShiftEvaluateOperator:
325 result=(double) pixel;
326 for (i=0; i < (ssize_t) value; i++)
330 case LogEvaluateOperator:
332 if ((QuantumScale*(
double) pixel) >= MagickEpsilon)
333 result=(double) QuantumRange*log(QuantumScale*value*
334 (
double) pixel+1.0)/log((
double) (value+1.0));
337 case MaxEvaluateOperator:
339 result=(double) EvaluateMax((
double) pixel,value);
342 case MeanEvaluateOperator:
344 result=(double) pixel+value;
347 case MedianEvaluateOperator:
349 result=(double) pixel+value;
352 case MinEvaluateOperator:
354 result=MagickMin((
double) pixel,value);
357 case MultiplicativeNoiseEvaluateOperator:
359 result=(double) GenerateDifferentialNoise(random_info,pixel,
360 MultiplicativeGaussianNoise,value);
363 case MultiplyEvaluateOperator:
365 result=(double) pixel*value;
368 case OrEvaluateOperator:
370 result=(double) ((ssize_t) pixel | (ssize_t) (value+0.5));
373 case PoissonNoiseEvaluateOperator:
375 result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
379 case PowEvaluateOperator:
381 if (fabs(value) <= MagickEpsilon)
383 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
384 result=(double) -((
double) QuantumRange*pow(-(QuantumScale*(
double)
387 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,value);
390 case RightShiftEvaluateOperator:
392 result=(double) pixel;
393 for (i=0; i < (ssize_t) value; i++)
397 case RootMeanSquareEvaluateOperator:
399 result=((double) pixel*(double) pixel+value);
402 case SetEvaluateOperator:
407 case SineEvaluateOperator:
409 result=(double) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
410 QuantumScale*(
double) pixel*value))+0.5);
413 case SubtractEvaluateOperator:
415 result=(double) pixel-value;
418 case SumEvaluateOperator:
420 result=(double) pixel+value;
423 case ThresholdEvaluateOperator:
425 result=(double) (((
double) pixel <= value) ? 0 : QuantumRange);
428 case ThresholdBlackEvaluateOperator:
430 result=(double) (((
double) pixel <= value) ? 0 : pixel);
433 case ThresholdWhiteEvaluateOperator:
435 result=(double) (((
double) pixel > value) ? QuantumRange : pixel);
438 case UniformNoiseEvaluateOperator:
440 result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
444 case XorEvaluateOperator:
446 result=(double) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
453static Image *AcquireImageCanvas(
const Image *images,ExceptionInfo *exception)
464 columns=images->columns;
466 for (p=images; p != (Image *) NULL; p=p->next)
468 if (p->number_channels > q->number_channels)
470 if (p->columns > columns)
475 return(CloneImage(q,columns,rows,MagickTrue,exception));
478MagickExport Image *EvaluateImages(
const Image *images,
479 const MagickEvaluateOperator op,ExceptionInfo *exception)
481#define EvaluateImageTag "Evaluate/Image"
500 **magick_restrict evaluate_pixels;
503 **magick_restrict random_info;
512#if defined(MAGICKCORE_OPENMP_SUPPORT)
517 assert(images != (Image *) NULL);
518 assert(images->signature == MagickCoreSignature);
519 assert(exception != (ExceptionInfo *) NULL);
520 assert(exception->signature == MagickCoreSignature);
521 if (IsEventLogging() != MagickFalse)
522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
523 image=AcquireImageCanvas(images,exception);
524 if (image == (Image *) NULL)
525 return((Image *) NULL);
526 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
528 image=DestroyImage(image);
529 return((Image *) NULL);
531 number_images=GetImageListLength(images);
532 evaluate_pixels=AcquirePixelTLS(images);
533 if (evaluate_pixels == (PixelChannels **) NULL)
535 image=DestroyImage(image);
536 (void) ThrowMagickException(exception,GetMagickModule(),
537 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
538 return((Image *) NULL);
540 image_view=(CacheView **) AcquireQuantumMemory(number_images,
541 sizeof(*image_view));
542 if (image_view == (CacheView **) NULL)
544 image=DestroyImage(image);
545 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
546 (void) ThrowMagickException(exception,GetMagickModule(),
547 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
551 for (n=0; n < (ssize_t) number_images; n++)
553 image_view[n]=AcquireVirtualCacheView(view,exception);
554 view=GetNextImageInList(view);
561 random_info=AcquireRandomInfoTLS();
562 evaluate_view=AcquireAuthenticCacheView(image,exception);
563 if (op == MedianEvaluateOperator)
565#if defined(MAGICKCORE_OPENMP_SUPPORT)
566 key=GetRandomSecretKey(random_info[0]);
567 #pragma omp parallel for schedule(static) shared(progress,status) \
568 magick_number_threads(image,images,image->rows,key == ~0UL)
570 for (y=0; y < (ssize_t) image->rows; y++)
573 id = GetOpenMPThreadId();
590 if (status == MagickFalse)
592 p=(
const Quantum **) AcquireQuantumMemory(number_images,
sizeof(*p));
593 if (p == (
const Quantum **) NULL)
596 (void) ThrowMagickException(exception,GetMagickModule(),
597 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
601 for (j=0; j < (ssize_t) number_images; j++)
603 p[j]=GetCacheViewVirtualPixels(image_view[j],0,y,image->columns,1,
605 if (p[j] == (
const Quantum *) NULL)
608 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
610 if ((j < (ssize_t) number_images) || (q == (Quantum *) NULL))
615 evaluate_pixel=evaluate_pixels[id];
616 for (x=0; x < (ssize_t) image->columns; x++)
625 for (j=0; j < (ssize_t) number_images; j++)
627 for (i=0; i < MaxPixelChannels; i++)
628 evaluate_pixel[j].channel[i]=0.0;
629 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
631 PixelChannel channel = GetPixelChannelChannel(image,i);
632 PixelTrait traits = GetPixelChannelTraits(next,channel);
633 PixelTrait evaluate_traits = GetPixelChannelTraits(image,channel);
634 if (((traits & UpdatePixelTrait) == 0) ||
635 ((evaluate_traits & UpdatePixelTrait) == 0))
637 evaluate_pixel[j].channel[i]=ApplyEvaluateOperator(
638 random_info[
id],GetPixelChannel(next,channel,p[j]),op,
639 evaluate_pixel[j].channel[i]);
641 p[j]+=(ptrdiff_t) GetPixelChannels(next);
642 next=GetNextImageInList(next);
644 qsort((
void *) evaluate_pixel,number_images,
sizeof(*evaluate_pixel),
646 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
648 PixelChannel channel = GetPixelChannelChannel(image,i);
649 PixelTrait traits = GetPixelChannelTraits(image,channel);
650 if ((traits & UpdatePixelTrait) == 0)
652 q[i]=ClampToQuantum(evaluate_pixel[number_images/2].channel[i]);
654 q+=(ptrdiff_t) GetPixelChannels(image);
656 p=(
const Quantum **) RelinquishMagickMemory((
void *) p);
657 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
659 if (images->progress_monitor != (MagickProgressMonitor) NULL)
664#if defined(MAGICKCORE_OPENMP_SUPPORT)
668 proceed=SetImageProgress(images,EvaluateImageTag,progress,
670 if (proceed == MagickFalse)
677#if defined(MAGICKCORE_OPENMP_SUPPORT)
678 key=GetRandomSecretKey(random_info[0]);
679 #pragma omp parallel for schedule(static) shared(progress,status) \
680 magick_number_threads(image,images,image->rows,key == ~0UL)
682 for (y=0; y < (ssize_t) image->rows; y++)
688 id = GetOpenMPThreadId();
706 if (status == MagickFalse)
708 p=(
const Quantum **) AcquireQuantumMemory(number_images,
sizeof(*p));
709 if (p == (
const Quantum **) NULL)
712 (void) ThrowMagickException(exception,GetMagickModule(),
713 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
717 for (j=0; j < (ssize_t) number_images; j++)
719 p[j]=GetCacheViewVirtualPixels(image_view[j],0,y,image->columns,1,
721 if (p[j] == (
const Quantum *) NULL)
724 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
726 if ((j < (ssize_t) number_images) || (q == (Quantum *) NULL))
731 evaluate_pixel=evaluate_pixels[id];
732 for (j=0; j < (ssize_t) image->columns; j++)
733 for (i=0; i < MaxPixelChannels; i++)
734 evaluate_pixel[j].channel[i]=0.0;
736 for (j=0; j < (ssize_t) number_images; j++)
738 for (x=0; x < (ssize_t) image->columns; x++)
740 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
742 PixelChannel channel = GetPixelChannelChannel(image,i);
743 PixelTrait traits = GetPixelChannelTraits(next,channel);
744 PixelTrait evaluate_traits = GetPixelChannelTraits(image,channel);
745 if (((traits & UpdatePixelTrait) == 0) ||
746 ((evaluate_traits & UpdatePixelTrait) == 0))
748 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
749 random_info[
id],GetPixelChannel(next,channel,p[j]),j == 0 ?
750 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
752 p[j]+=(ptrdiff_t) GetPixelChannels(next);
754 next=GetNextImageInList(next);
756 for (x=0; x < (ssize_t) image->columns; x++)
760 case MeanEvaluateOperator:
762 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
763 evaluate_pixel[x].channel[i]/=(
double) number_images;
766 case MultiplyEvaluateOperator:
768 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
770 for (j=0; j < ((ssize_t) number_images-1); j++)
771 evaluate_pixel[x].channel[i]*=QuantumScale;
775 case RootMeanSquareEvaluateOperator:
777 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
778 evaluate_pixel[x].channel[i]=sqrt(evaluate_pixel[x].channel[i]/
786 for (x=0; x < (ssize_t) image->columns; x++)
788 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
790 PixelChannel channel = GetPixelChannelChannel(image,i);
791 PixelTrait traits = GetPixelChannelTraits(image,channel);
792 if ((traits & UpdatePixelTrait) == 0)
794 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
796 q+=(ptrdiff_t) GetPixelChannels(image);
798 p=(
const Quantum **) RelinquishMagickMemory((
void *) p);
799 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
801 if (images->progress_monitor != (MagickProgressMonitor) NULL)
806#if defined(MAGICKCORE_OPENMP_SUPPORT)
810 proceed=SetImageProgress(images,EvaluateImageTag,progress,
812 if (proceed == MagickFalse)
817 for (n=0; n < (ssize_t) number_images; n++)
818 image_view[n]=DestroyCacheView(image_view[n]);
819 image_view=(CacheView **) RelinquishMagickMemory(image_view);
820 evaluate_view=DestroyCacheView(evaluate_view);
821 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
822 random_info=DestroyRandomInfoTLS(random_info);
823 if (status == MagickFalse)
824 image=DestroyImage(image);
828MagickExport MagickBooleanType EvaluateImage(Image *image,
829 const MagickEvaluateOperator op,
const double value,ExceptionInfo *exception)
845 **magick_restrict random_info;
850#if defined(MAGICKCORE_OPENMP_SUPPORT)
855 assert(image != (Image *) NULL);
856 assert(image->signature == MagickCoreSignature);
857 assert(exception != (ExceptionInfo *) NULL);
858 assert(exception->signature == MagickCoreSignature);
859 if (IsEventLogging() != MagickFalse)
860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
861 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
866 artifact=GetImageArtifact(image,
"evaluate:clamp");
867 if (artifact != (
const char *) NULL)
868 clamp=IsStringTrue(artifact);
869 random_info=AcquireRandomInfoTLS();
870 image_view=AcquireAuthenticCacheView(image,exception);
871#if defined(MAGICKCORE_OPENMP_SUPPORT)
872 key=GetRandomSecretKey(random_info[0]);
873 #pragma omp parallel for schedule(static) shared(progress,status) \
874 magick_number_threads(image,image,image->rows,key == ~0UL)
876 for (y=0; y < (ssize_t) image->rows; y++)
879 id = GetOpenMPThreadId();
887 if (status == MagickFalse)
889 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
890 if (q == (Quantum *) NULL)
895 for (x=0; x < (ssize_t) image->columns; x++)
903 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
905 PixelChannel channel = GetPixelChannelChannel(image,i);
906 PixelTrait traits = GetPixelChannelTraits(image,channel);
907 if ((traits & UpdatePixelTrait) == 0)
909 result=ApplyEvaluateOperator(random_info[
id],q[i],op,value);
910 if (op == MeanEvaluateOperator)
912 q[i]=clamp != MagickFalse ? ClampPixel(result) : ClampToQuantum(result);
914 q+=(ptrdiff_t) GetPixelChannels(image);
916 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
918 if (image->progress_monitor != (MagickProgressMonitor) NULL)
923#if defined(MAGICKCORE_OPENMP_SUPPORT)
927 proceed=SetImageProgress(image,EvaluateImageTag,progress,image->rows);
928 if (proceed == MagickFalse)
932 image_view=DestroyCacheView(image_view);
933 random_info=DestroyRandomInfoTLS(random_info);
971static Quantum ApplyFunction(Quantum pixel,
const MagickFunction function,
972 const size_t number_parameters,
const double *parameters,
973 ExceptionInfo *exception)
985 case PolynomialFunction:
992 for (i=0; i < (ssize_t) number_parameters; i++)
993 result=result*QuantumScale*(
double) pixel+parameters[i];
994 result*=(double) QuantumRange;
997 case SinusoidFunction:
1008 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
1009 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
1010 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
1011 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1012 result=(double) QuantumRange*(amplitude*sin((
double) (2.0*
1013 MagickPI*(frequency*QuantumScale*(
double) pixel+phase/360.0)))+bias);
1016 case ArcsinFunction:
1028 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1029 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1030 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1031 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1032 result=2.0*MagickSafeReciprocal(width)*(QuantumScale*(double) pixel-
1035 result=bias-range/2.0;
1038 result=bias+range/2.0;
1040 result=(double) (range/MagickPI*asin((
double) result)+bias);
1041 result*=(double) QuantumRange;
1044 case ArctanFunction:
1055 slope=(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=MagickPI*slope*(QuantumScale*(double) pixel-center);
1060 result=(double) QuantumRange*(range/MagickPI*atan((
double) result)+bias);
1063 case UndefinedFunction:
1066 return(ClampToQuantum(result));
1069MagickExport MagickBooleanType FunctionImage(Image *image,
1070 const MagickFunction function,
const size_t number_parameters,
1071 const double *parameters,ExceptionInfo *exception)
1073#define FunctionImageTag "Function/Image "
1087 assert(image != (Image *) NULL);
1088 assert(image->signature == MagickCoreSignature);
1089 assert(exception != (ExceptionInfo *) NULL);
1090 assert(exception->signature == MagickCoreSignature);
1091 if (IsEventLogging() != MagickFalse)
1092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1093#if defined(MAGICKCORE_OPENCL_SUPPORT)
1094 if (AccelerateFunctionImage(image,function,number_parameters,parameters,
1095 exception) != MagickFalse)
1098 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1099 return(MagickFalse);
1102 image_view=AcquireAuthenticCacheView(image,exception);
1103#if defined(MAGICKCORE_OPENMP_SUPPORT)
1104 #pragma omp parallel for schedule(static) shared(progress,status) \
1105 magick_number_threads(image,image,image->rows,1)
1107 for (y=0; y < (ssize_t) image->rows; y++)
1115 if (status == MagickFalse)
1117 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1118 if (q == (Quantum *) NULL)
1123 for (x=0; x < (ssize_t) image->columns; x++)
1128 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1130 PixelChannel channel = GetPixelChannelChannel(image,i);
1131 PixelTrait traits = GetPixelChannelTraits(image,channel);
1132 if ((traits & UpdatePixelTrait) == 0)
1134 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1137 q+=(ptrdiff_t) GetPixelChannels(image);
1139 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1141 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1146#if defined(MAGICKCORE_OPENMP_SUPPORT)
1150 proceed=SetImageProgress(image,FunctionImageTag,progress,image->rows);
1151 if (proceed == MagickFalse)
1155 image_view=DestroyCacheView(image_view);
1186MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1187 double *entropy,ExceptionInfo *exception)
1190 *channel_statistics;
1192 assert(image != (Image *) NULL);
1193 assert(image->signature == MagickCoreSignature);
1194 if (IsEventLogging() != MagickFalse)
1195 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1196 channel_statistics=GetImageStatistics(image,exception);
1197 if (channel_statistics == (ChannelStatistics *) NULL)
1200 return(MagickFalse);
1202 *entropy=channel_statistics[CompositePixelChannel].entropy;
1203 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1204 channel_statistics);
1237MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1238 size_t *minima,
size_t *maxima,ExceptionInfo *exception)
1247 assert(image != (Image *) NULL);
1248 assert(image->signature == MagickCoreSignature);
1249 if (IsEventLogging() != MagickFalse)
1250 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1251 status=GetImageRange(image,&min,&max,exception);
1252 *minima=(size_t) ceil(min-0.5);
1253 *maxima=(size_t) floor(max+0.5);
1287MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1288 double *kurtosis,
double *skewness,ExceptionInfo *exception)
1291 *channel_statistics;
1293 assert(image != (Image *) NULL);
1294 assert(image->signature == MagickCoreSignature);
1295 if (IsEventLogging() != MagickFalse)
1296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1297 channel_statistics=GetImageStatistics(image,exception);
1298 if (channel_statistics == (ChannelStatistics *) NULL)
1302 return(MagickFalse);
1304 *kurtosis=channel_statistics[CompositePixelChannel].kurtosis;
1305 *skewness=channel_statistics[CompositePixelChannel].skewness;
1306 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1307 channel_statistics);
1341MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1342 double *standard_deviation,ExceptionInfo *exception)
1345 *channel_statistics;
1347 assert(image != (Image *) NULL);
1348 assert(image->signature == MagickCoreSignature);
1349 if (IsEventLogging() != MagickFalse)
1350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1351 channel_statistics=GetImageStatistics(image,exception);
1352 if (channel_statistics == (ChannelStatistics *) NULL)
1355 *standard_deviation=NAN;
1356 return(MagickFalse);
1358 *mean=channel_statistics[CompositePixelChannel].mean;
1359 *standard_deviation=
1360 channel_statistics[CompositePixelChannel].standard_deviation;
1361 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1362 channel_statistics);
1393MagickExport MagickBooleanType GetImageMedian(
const Image *image,
double *median,
1394 ExceptionInfo *exception)
1397 *channel_statistics;
1399 assert(image != (Image *) NULL);
1400 assert(image->signature == MagickCoreSignature);
1401 if (IsEventLogging() != MagickFalse)
1402 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1403 channel_statistics=GetImageStatistics(image,exception);
1404 if (channel_statistics == (ChannelStatistics *) NULL)
1407 return(MagickFalse);
1409 *median=channel_statistics[CompositePixelChannel].median;
1410 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
1411 channel_statistics);
1441MagickExport ChannelMoments *GetImageMoments(
const Image *image,
1442 ExceptionInfo *exception)
1444#define MaxNumberImageMoments 8
1454 M00[2*MaxPixelChannels+1] = { 0.0 },
1455 M01[2*MaxPixelChannels+1] = { 0.0 },
1456 M02[2*MaxPixelChannels+1] = { 0.0 },
1457 M03[2*MaxPixelChannels+1] = { 0.0 },
1458 M10[2*MaxPixelChannels+1] = { 0.0 },
1459 M11[2*MaxPixelChannels+1] = { 0.0 },
1460 M12[2*MaxPixelChannels+1] = { 0.0 },
1461 M20[2*MaxPixelChannels+1] = { 0.0 },
1462 M21[2*MaxPixelChannels+1] = { 0.0 },
1463 M22[2*MaxPixelChannels+1] = { 0.0 },
1464 M30[2*MaxPixelChannels+1] = { 0.0 };
1467 centroid[2*MaxPixelChannels+1] = {{ 0 }};
1473 assert(image != (Image *) NULL);
1474 assert(image->signature == MagickCoreSignature);
1475 if (IsEventLogging() != MagickFalse)
1476 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1477 channel_moments=(ChannelMoments *) AcquireQuantumMemory(MaxPixelChannels+1,
1478 sizeof(*channel_moments));
1479 if (channel_moments == (ChannelMoments *) NULL)
1480 return(channel_moments);
1481 (void) memset(channel_moments,0,(MaxPixelChannels+1)*
1482 sizeof(*channel_moments));
1483 image_view=AcquireVirtualCacheView(image,exception);
1484 for (y=0; y < (ssize_t) image->rows; y++)
1495 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1496 if (p == (
const Quantum *) NULL)
1498 for (x=0; x < (ssize_t) image->columns; x++)
1503 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1508 PixelChannel channel = GetPixelChannelChannel(image,i);
1509 PixelTrait traits = GetPixelChannelTraits(image,channel);
1510 if ((traits & UpdatePixelTrait) == 0)
1512 pixel=QuantumScale*p[i];
1513 M00[channel]+=pixel;
1514 M00[CompositePixelChannel]+=pixel;
1515 M10[channel]+=x*pixel;
1516 M10[CompositePixelChannel]+=x*pixel;
1517 M01[channel]+=y*pixel;
1518 M01[CompositePixelChannel]+=y*pixel;
1520 p+=(ptrdiff_t) GetPixelChannels(image);
1523 for (c=0; c <= MaxPixelChannels; c++)
1528 centroid[c].x=M10[c]*MagickSafeReciprocal(M00[c]);
1529 centroid[c].y=M01[c]*MagickSafeReciprocal(M00[c]);
1531 for (y=0; y < (ssize_t) image->rows; y++)
1542 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1543 if (p == (
const Quantum *) NULL)
1545 for (x=0; x < (ssize_t) image->columns; x++)
1550 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1552 PixelChannel channel = GetPixelChannelChannel(image,i);
1553 PixelTrait traits = GetPixelChannelTraits(image,channel);
1554 if ((traits & UpdatePixelTrait) == 0)
1556 M11[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1557 QuantumScale*(double) p[i];
1558 M11[CompositePixelChannel]+=(x-centroid[channel].x)*(y-
1559 centroid[channel].y)*QuantumScale*(double) p[i];
1560 M20[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1561 QuantumScale*(double) p[i];
1562 M20[CompositePixelChannel]+=(x-centroid[channel].x)*(x-
1563 centroid[channel].x)*QuantumScale*(double) p[i];
1564 M02[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1565 QuantumScale*(double) p[i];
1566 M02[CompositePixelChannel]+=(y-centroid[channel].y)*(y-
1567 centroid[channel].y)*QuantumScale*(double) p[i];
1568 M21[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1569 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1570 M21[CompositePixelChannel]+=(x-centroid[channel].x)*(x-
1571 centroid[channel].x)*(y-centroid[channel].y)*QuantumScale*(
double)
1573 M12[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1574 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1575 M12[CompositePixelChannel]+=(x-centroid[channel].x)*(y-
1576 centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*(
double)
1578 M22[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1579 (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*(double)
1581 M22[CompositePixelChannel]+=(x-centroid[channel].x)*(x-
1582 centroid[channel].x)*(y-centroid[channel].y)*(y-centroid[channel].y)*
1583 QuantumScale*(double) p[i];
1584 M30[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1585 (x-centroid[channel].x)*QuantumScale*(
double) p[i];
1586 M30[CompositePixelChannel]+=(x-centroid[channel].x)*(x-
1587 centroid[channel].x)*(x-centroid[channel].x)*QuantumScale*(
double)
1589 M03[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1590 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1591 M03[CompositePixelChannel]+=(y-centroid[channel].y)*(y-
1592 centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*(
double)
1595 p+=(ptrdiff_t) GetPixelChannels(image);
1598 channels=(double) GetImageChannels(image);
1599 M00[CompositePixelChannel]/=channels;
1600 M01[CompositePixelChannel]/=channels;
1601 M02[CompositePixelChannel]/=channels;
1602 M03[CompositePixelChannel]/=channels;
1603 M10[CompositePixelChannel]/=channels;
1604 M11[CompositePixelChannel]/=channels;
1605 M12[CompositePixelChannel]/=channels;
1606 M20[CompositePixelChannel]/=channels;
1607 M21[CompositePixelChannel]/=channels;
1608 M22[CompositePixelChannel]/=channels;
1609 M30[CompositePixelChannel]/=channels;
1610 for (c=0; c <= MaxPixelChannels; c++)
1615 channel_moments[c].centroid=centroid[c];
1616 channel_moments[c].ellipse_axis.x=sqrt((2.0*MagickSafeReciprocal(M00[c]))*
1617 ((M20[c]+M02[c])+sqrt(4.0*M11[c]*M11[c]+(M20[c]-M02[c])*
1619 channel_moments[c].ellipse_axis.y=sqrt((2.0*MagickSafeReciprocal(M00[c]))*
1620 ((M20[c]+M02[c])-sqrt(4.0*M11[c]*M11[c]+(M20[c]-M02[c])*
1622 channel_moments[c].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
1623 M11[c]*MagickSafeReciprocal(M20[c]-M02[c])));
1624 if (fabs(M11[c]) < 0.0)
1626 if ((fabs(M20[c]-M02[c]) >= 0.0) && ((M20[c]-M02[c]) < 0.0))
1627 channel_moments[c].ellipse_angle+=90.0;
1632 if (fabs(M20[c]-M02[c]) >= 0.0)
1634 if ((M20[c]-M02[c]) < 0.0)
1635 channel_moments[c].ellipse_angle+=90.0;
1637 channel_moments[c].ellipse_angle+=180.0;
1641 if ((fabs(M20[c]-M02[c]) >= 0.0) && ((M20[c]-M02[c]) < 0.0))
1642 channel_moments[c].ellipse_angle+=90.0;
1643 channel_moments[c].ellipse_eccentricity=sqrt(1.0-(
1644 channel_moments[c].ellipse_axis.y*
1645 channel_moments[c].ellipse_axis.y*MagickSafeReciprocal(
1646 channel_moments[c].ellipse_axis.x*
1647 channel_moments[c].ellipse_axis.x)));
1648 channel_moments[c].ellipse_intensity=M00[c]*
1649 MagickSafeReciprocal(MagickPI*channel_moments[c].ellipse_axis.x*
1650 channel_moments[c].ellipse_axis.y+MagickEpsilon);
1652 for (c=0; c <= MaxPixelChannels; c++)
1659 M11[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(1.0+1.0)/2.0));
1660 M20[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(2.0+0.0)/2.0));
1661 M02[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(0.0+2.0)/2.0));
1662 M21[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(2.0+1.0)/2.0));
1663 M12[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(1.0+2.0)/2.0));
1664 M22[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(2.0+2.0)/2.0));
1665 M30[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(3.0+0.0)/2.0));
1666 M03[c]*=MagickSafeReciprocal(pow(M00[c],1.0+(0.0+3.0)/2.0));
1669 image_view=DestroyCacheView(image_view);
1670 for (c=0; c <= MaxPixelChannels; c++)
1675 channel_moments[c].invariant[0]=M20[c]+M02[c];
1676 channel_moments[c].invariant[1]=(M20[c]-M02[c])*(M20[c]-M02[c])+4.0*M11[c]*
1678 channel_moments[c].invariant[2]=(M30[c]-3.0*M12[c])*(M30[c]-3.0*M12[c])+
1679 (3.0*M21[c]-M03[c])*(3.0*M21[c]-M03[c]);
1680 channel_moments[c].invariant[3]=(M30[c]+M12[c])*(M30[c]+M12[c])+(M21[c]+
1681 M03[c])*(M21[c]+M03[c]);
1682 channel_moments[c].invariant[4]=(M30[c]-3.0*M12[c])*(M30[c]+M12[c])*
1683 ((M30[c]+M12[c])*(M30[c]+M12[c])-3.0*(M21[c]+M03[c])*(M21[c]+M03[c]))+
1684 (3.0*M21[c]-M03[c])*(M21[c]+M03[c])*(3.0*(M30[c]+M12[c])*(M30[c]+M12[c])-
1685 (M21[c]+M03[c])*(M21[c]+M03[c]));
1686 channel_moments[c].invariant[5]=(M20[c]-M02[c])*((M30[c]+M12[c])*(M30[c]+
1687 M12[c])-(M21[c]+M03[c])*(M21[c]+M03[c]))+4.0*M11[c]*(M30[c]+M12[c])*
1689 channel_moments[c].invariant[6]=(3.0*M21[c]-M03[c])*(M30[c]+M12[c])*
1690 ((M30[c]+M12[c])*(M30[c]+M12[c])-3.0*(M21[c]+M03[c])*(M21[c]+M03[c]))-
1691 (M30[c]-3*M12[c])*(M21[c]+M03[c])*(3.0*(M30[c]+M12[c])*(M30[c]+M12[c])-
1692 (M21[c]+M03[c])*(M21[c]+M03[c]));
1693 channel_moments[c].invariant[7]=M11[c]*((M30[c]+M12[c])*(M30[c]+M12[c])-
1694 (M03[c]+M21[c])*(M03[c]+M21[c]))-(M20[c]-M02[c])*(M30[c]+M12[c])*
1697 if (y < (ssize_t) image->rows)
1698 channel_moments=(ChannelMoments *) RelinquishMagickMemory(channel_moments);
1699 return(channel_moments);
1728MagickExport ChannelPerceptualHash *GetImagePerceptualHash(
const Image *image,
1729 ExceptionInfo *exception)
1731 ChannelPerceptualHash
1748 perceptual_hash=(ChannelPerceptualHash *) AcquireQuantumMemory(
1749 MaxPixelChannels+1UL,
sizeof(*perceptual_hash));
1750 if (perceptual_hash == (ChannelPerceptualHash *) NULL)
1751 return((ChannelPerceptualHash *) NULL);
1752 (void) memset(perceptual_hash,0,(MaxPixelChannels+1UL)*
1753 sizeof(*perceptual_hash));
1754 artifact=GetImageArtifact(image,
"phash:colorspaces");
1755 if (artifact != (
const char *) NULL)
1756 colorspaces=AcquireString(artifact);
1758 colorspaces=AcquireString(
"xyY,HSB");
1759 perceptual_hash[0].number_colorspaces=0;
1760 perceptual_hash[0].number_channels=0;
1762 for (i=0; (p=StringToken(
",",&q)) != (
char *) NULL; i++)
1777 if (i >= MaximumNumberOfPerceptualColorspaces)
1779 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,p);
1782 perceptual_hash[0].colorspace[i]=(ColorspaceType) colorspace;
1783 hash_image=BlurImage(image,0.0,1.0,exception);
1784 if (hash_image == (Image *) NULL)
1786 status=TransformImageColorspace(hash_image,(ColorspaceType) colorspace,
1788 if (status == MagickFalse)
1790 hash_image=DestroyImage(hash_image);
1793 status=SetImageDepth(hash_image,8,exception);
1794 if (status == MagickFalse)
1796 hash_image=DestroyImage(hash_image);
1799 moments=GetImageMoments(hash_image,exception);
1800 if (moments == (ChannelMoments *) NULL)
1802 hash_image=DestroyImage(hash_image);
1805 perceptual_hash[0].number_colorspaces++;
1806 perceptual_hash[0].number_channels+=GetImageChannels(hash_image);
1807 for (channel=0; channel <= MaxPixelChannels; channel++)
1808 for (j=0; j < MaximumNumberOfPerceptualHashes; j++)
1809 perceptual_hash[channel].phash[i][j]=(-MagickSafeLog10(fabs(
1810 moments[channel].invariant[j])));
1811 hash_image=DestroyImage(hash_image);
1812 moments=(ChannelMoments *) RelinquishMagickMemory(moments);
1814 colorspaces=DestroyString(colorspaces);
1815 return(perceptual_hash);
1847MagickExport MagickBooleanType GetImageRange(
const Image *image,
double *minima,
1848 double *maxima,ExceptionInfo *exception)
1864 range_info = { -MagickMaximumValue, MagickMaximumValue };
1869 assert(image != (Image *) NULL);
1870 assert(image->signature == MagickCoreSignature);
1871 if (IsEventLogging() != MagickFalse)
1872 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1874 image_view=AcquireVirtualCacheView(image,exception);
1875#if defined(MAGICKCORE_OPENMP_SUPPORT)
1876 #pragma omp parallel for schedule(static) shared(range_info,status) \
1877 magick_number_threads(image,image,image->rows,1)
1879 for (y=0; y < (ssize_t) image->rows; y++)
1890 if (status == MagickFalse)
1892 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1893 if (p == (
const Quantum *) NULL)
1898 channel_range=range_info;
1899 for (x=0; x < (ssize_t) image->columns; x++)
1904 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1906 PixelChannel channel = GetPixelChannelChannel(image,i);
1907 PixelTrait traits = GetPixelChannelTraits(image,channel);
1908 if ((traits & UpdatePixelTrait) == 0)
1910 if ((
double) p[i] > channel_range.maxima)
1911 channel_range.maxima=(double) p[i];
1912 if ((
double) p[i] < channel_range.minima)
1913 channel_range.minima=(double) p[i];
1915 p+=(ptrdiff_t) GetPixelChannels(image);
1917#if defined(MAGICKCORE_OPENMP_SUPPORT)
1918 #pragma omp critical (MagickCore_GetImageRange)
1921 if (channel_range.maxima > range_info.maxima)
1922 range_info.maxima=channel_range.maxima;
1923 if (channel_range.minima < range_info.minima)
1924 range_info.minima=channel_range.minima;
1927 image_view=DestroyCacheView(image_view);
1928 *maxima=range_info.maxima;
1929 *minima=range_info.minima;
1967static ssize_t GetMedianPixel(Quantum *pixels,
const size_t n)
1969#define SwapPixels(alpha,beta) \
1971 Quantum gamma=(alpha); \
1972 (alpha)=(beta);(beta)=gamma; \
1977 high = (ssize_t) n-1,
1978 median = (low+high)/2;
1989 if (high == (low+1))
1991 if (pixels[low] > pixels[high])
1992 SwapPixels(pixels[low],pixels[high]);
1995 if (pixels[mid] > pixels[high])
1996 SwapPixels(pixels[mid],pixels[high]);
1997 if (pixels[low] > pixels[high])
1998 SwapPixels(pixels[low], pixels[high]);
1999 if (pixels[mid] > pixels[low])
2000 SwapPixels(pixels[mid],pixels[low]);
2001 SwapPixels(pixels[mid],pixels[low+1]);
2004 do l++;
while (pixels[low] > pixels[l]);
2005 do h--;
while (pixels[h] > pixels[low]);
2008 SwapPixels(pixels[l],pixels[h]);
2010 SwapPixels(pixels[low],pixels[h]);
2018static inline long double MagickSafeReciprocalLD(
const long double x)
2026 sign=x < 0.0 ? -1.0 : 1.0;
2027 if ((sign*x) >= MagickEpsilon)
2029 return(sign/MagickEpsilon);
2032MagickExport ChannelStatistics *GetImageStatistics(
const Image *image,
2033 ExceptionInfo *exception)
2036 *channel_statistics;
2064 assert(image != (Image *) NULL);
2065 assert(image->signature == MagickCoreSignature);
2066 if (IsEventLogging() != MagickFalse)
2067 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2068 histogram=(
double *) AcquireQuantumMemory(MaxMap+1UL,
2069 MagickMax(GetPixelChannels(image),1)*
sizeof(*histogram));
2070 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
2071 MaxPixelChannels+1,
sizeof(*channel_statistics));
2072 if ((channel_statistics == (ChannelStatistics *) NULL) ||
2073 (histogram == (
double *) NULL))
2075 if (histogram != (
double *) NULL)
2076 histogram=(
double *) RelinquishMagickMemory(histogram);
2077 if (channel_statistics != (ChannelStatistics *) NULL)
2078 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2079 channel_statistics);
2080 (void) ThrowMagickException(exception,GetMagickModule(),
2081 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2082 return(channel_statistics);
2084 (void) memset(channel_statistics,0,(MaxPixelChannels+1)*
2085 sizeof(*channel_statistics));
2086 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
2088 ChannelStatistics *cs = channel_statistics+i;
2091 cs->maxima=(-MagickMaximumValue);
2092 cs->minima=MagickMaximumValue;
2096 cs->standard_deviation=0.0;
2102 (void) memset(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
2103 sizeof(*histogram));
2104 for (y=0; y < (ssize_t) image->rows; y++)
2115 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2116 if (p == (
const Quantum *) NULL)
2118 for (x=0; x < (ssize_t) image->columns; x++)
2120 if (GetPixelReadMask(image,p) <= (QuantumRange/2))
2122 p+=(ptrdiff_t) GetPixelChannels(image);
2125 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2130 PixelChannel channel = GetPixelChannelChannel(image,i);
2131 PixelTrait traits = GetPixelChannelTraits(image,channel);
2132 if ((traits & UpdatePixelTrait) == 0)
2134 cs=channel_statistics+channel;
2135 if (cs->depth != MAGICKCORE_QUANTUM_DEPTH)
2138 range=GetQuantumRange(depth);
2139 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
2140 range) ? MagickTrue : MagickFalse;
2141 if (status != MagickFalse)
2144 if (cs->depth > channel_statistics[CompositePixelChannel].depth)
2145 channel_statistics[CompositePixelChannel].depth=cs->depth;
2151 if ((
double) p[i] < cs->minima)
2152 cs->minima=(double) p[i];
2153 if ((
double) p[i] > cs->maxima)
2154 cs->maxima=(double) p[i];
2155 histogram[(ssize_t) GetPixelChannels(image)*ScaleQuantumToMap(
2156 ClampToQuantum((
double) p[i]))+i]++;
2157 cs->sumLD+=(
long double) p[i];
2163 cs->sum_squared+=(double) p[i]*(
double) p[i];
2164 cs->sum_cubed+=(double) p[i]*(
double) p[i]*(double) p[i];
2165 cs->sum_fourth_power+=(double) p[i]*(
double) p[i]*(double) p[i]*
2180 delta=(double) p[i]-cs->M1;
2182 delta_n2=delta_n*delta_n;
2183 term1=delta*delta_n*n1;
2184 cs->M4+=term1*delta_n2*(n*n-3.0*n+3.0)+6.0*delta_n2*cs->M2-4.0*
2186 cs->M3+=term1*delta_n*(n-2.0)-3.0*delta_n*cs->M2;
2191 p+=(ptrdiff_t) GetPixelChannels(image);
2194 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2202 PixelChannel channel = GetPixelChannelChannel(image,i);
2203 PixelTrait traits = GetPixelChannelTraits(image,channel);
2204 if ((traits & UpdatePixelTrait) == 0)
2206 cs=channel_statistics+(ssize_t) channel;
2210 cs->mean=(double) (cs->sumLD/(
long double) cs->area);
2212 adj_area=cs->area/(cs->area-1.0);
2214 cs->sum=(double) cs->sum;
2217 cs->standard_deviation=0.0;
2225 cs->standard_deviation=(double) sqrtl(cs->M2/((
long double)
2228 cs->standard_deviation=(double) sqrtl(cs->M2/((
long double)
2230 cs->variance=cs->standard_deviation*cs->standard_deviation;
2231 cs->skewness=(double) (sqrtl(cs->area)*cs->M3/powl(cs->M2*adj_area,
2233 cs->kurtosis=(double) (cs->area*cs->M4/(cs->M2*cs->M2*adj_area*
2237 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2248 PixelChannel channel = GetPixelChannelChannel(image,i);
2249 PixelTrait traits = GetPixelChannelTraits(image,channel);
2250 if ((traits & UpdatePixelTrait) == 0)
2252 cs=channel_statistics+(ssize_t) channel;
2256 cs->sum_squared/=cs->area;
2257 cs->sum_cubed/=cs->area;
2258 cs->sum_fourth_power/=cs->area;
2264 for (j=0; j <= (ssize_t) MaxMap; j++)
2265 if (histogram[(ssize_t) GetPixelChannels(image)*j+i] > 0.0)
2267 area=MagickSafeReciprocalLD(channel_statistics[channel].area);
2268 number_bins=(double) MagickSafeReciprocalLD((
long double) log2(number_bins));
2269 for (j=0; j <= (ssize_t) MaxMap; j++)
2275 count=(double) (area*histogram[(ssize_t) GetPixelChannels(image)*j+i]);
2276 entropy=-count*log2(count)*number_bins;
2277 if (IsNaN(entropy) != 0)
2279 channel_statistics[channel].entropy+=(double) entropy;
2280 channel_statistics[CompositePixelChannel].entropy+=((double) entropy/
2281 GetPixelChannels(image));
2284 histogram=(
double *) RelinquishMagickMemory(histogram);
2285 median_info=AcquireVirtualMemory(image->columns,image->rows*
sizeof(*median));
2286 if (median_info == (MemoryInfo *) NULL)
2287 (void) ThrowMagickException(exception,GetMagickModule(),
2288 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2291 median=(Quantum *) GetVirtualMemoryBlob(median_info);
2292 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2300 PixelChannel channel = GetPixelChannelChannel(image,i);
2301 PixelTrait traits = GetPixelChannelTraits(image,channel);
2302 if ((traits & UpdatePixelTrait) == 0)
2304 for (y=0; y < (ssize_t) image->rows; y++)
2312 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2313 if (p == (
const Quantum *) NULL)
2315 for (x=0; x < (ssize_t) image->columns; x++)
2317 if (GetPixelReadMask(image,p) <= (QuantumRange/2))
2319 p+=(ptrdiff_t) GetPixelChannels(image);
2323 p+=(ptrdiff_t) GetPixelChannels(image);
2326 channel_statistics[channel].median=(double) median[
2327 GetMedianPixel(median,n)];
2329 median_info=RelinquishVirtualMemory(median_info);
2332 ChannelStatistics *cs_comp = channel_statistics+CompositePixelChannel;
2334 cs_comp->sum_squared=0.0;
2335 cs_comp->sum_cubed=0.0;
2336 cs_comp->sum_fourth_power=0.0;
2337 cs_comp->maxima=(-MagickMaximumValue);
2338 cs_comp->minima=MagickMaximumValue;
2341 cs_comp->median=0.0;
2342 cs_comp->variance=0.0;
2343 cs_comp->standard_deviation=0.0;
2344 cs_comp->entropy=0.0;
2345 cs_comp->skewness=0.0;
2346 cs_comp->kurtosis=0.0;
2347 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2352 PixelChannel channel = GetPixelChannelChannel(image,i);
2353 PixelTrait traits = GetPixelChannelTraits(image,channel);
2354 if ((traits & UpdatePixelTrait) == 0)
2356 cs=channel_statistics+channel;
2357 if (cs_comp->maxima < cs->maxima)
2358 cs_comp->maxima=cs->maxima;
2359 if (cs_comp->minima > cs->minima)
2360 cs_comp->minima=cs->minima;
2361 cs_comp->sum+=cs->sum;
2362 cs_comp->sum_squared+=cs->sum_squared;
2363 cs_comp->sum_cubed+=cs->sum_cubed;
2364 cs_comp->sum_fourth_power+=cs->sum_fourth_power;
2365 cs_comp->median+=cs->median;
2366 cs_comp->area+=cs->area;
2367 cs_comp->mean+=cs->mean;
2368 cs_comp->variance+=cs->variance;
2369 cs_comp->standard_deviation+=cs->standard_deviation;
2370 cs_comp->skewness+=cs->skewness;
2371 cs_comp->kurtosis+=cs->kurtosis;
2372 cs_comp->entropy+=cs->entropy;
2374 channels=(double) GetImageChannels(image);
2375 cs_comp->sum/=channels;
2376 cs_comp->sum_squared/=channels;
2377 cs_comp->sum_cubed/=channels;
2378 cs_comp->sum_fourth_power/=channels;
2379 cs_comp->median/=channels;
2380 cs_comp->area/=channels;
2381 cs_comp->mean/=channels;
2382 cs_comp->variance/=channels;
2383 cs_comp->standard_deviation/=channels;
2384 cs_comp->skewness/=channels;
2385 cs_comp->kurtosis/=channels;
2386 cs_comp->entropy/=channels;
2388 if (y < (ssize_t) image->rows)
2389 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
2390 channel_statistics);
2391 return(channel_statistics);
2427MagickExport Image *PolynomialImage(
const Image *images,
2428 const size_t number_terms,
const double *terms,ExceptionInfo *exception)
2430#define PolynomialImageTag "Polynomial/Image"
2445 **magick_restrict polynomial_pixels;
2453 assert(images != (Image *) NULL);
2454 assert(images->signature == MagickCoreSignature);
2455 if (IsEventLogging() != MagickFalse)
2456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2457 assert(exception != (ExceptionInfo *) NULL);
2458 assert(exception->signature == MagickCoreSignature);
2459 image=AcquireImageCanvas(images,exception);
2460 if (image == (Image *) NULL)
2461 return((Image *) NULL);
2462 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2464 image=DestroyImage(image);
2465 return((Image *) NULL);
2467 number_images=GetImageListLength(images);
2468 polynomial_pixels=AcquirePixelTLS(images);
2469 if (polynomial_pixels == (PixelChannels **) NULL)
2471 image=DestroyImage(image);
2472 (void) ThrowMagickException(exception,GetMagickModule(),
2473 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2474 return((Image *) NULL);
2481 polynomial_view=AcquireAuthenticCacheView(image,exception);
2482#if defined(MAGICKCORE_OPENMP_SUPPORT)
2483 #pragma omp parallel for schedule(static) shared(progress,status) \
2484 magick_number_threads(image,image,image->rows,1)
2486 for (y=0; y < (ssize_t) image->rows; y++)
2495 id = GetOpenMPThreadId();
2508 if (status == MagickFalse)
2510 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2512 if (q == (Quantum *) NULL)
2517 polynomial_pixel=polynomial_pixels[id];
2518 for (j=0; j < (ssize_t) image->columns; j++)
2519 for (i=0; i < MaxPixelChannels; i++)
2520 polynomial_pixel[j].channel[i]=0.0;
2522 for (j=0; j < (ssize_t) number_images; j++)
2527 if (j >= (ssize_t) number_terms)
2529 image_view=AcquireVirtualCacheView(next,exception);
2530 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2531 if (p == (
const Quantum *) NULL)
2533 image_view=DestroyCacheView(image_view);
2536 for (x=0; x < (ssize_t) image->columns; x++)
2538 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
2544 PixelChannel channel = GetPixelChannelChannel(image,i);
2545 PixelTrait traits = GetPixelChannelTraits(next,channel);
2546 PixelTrait polynomial_traits = GetPixelChannelTraits(image,channel);
2547 if (((traits & UpdatePixelTrait) == 0) ||
2548 ((polynomial_traits & UpdatePixelTrait) == 0))
2550 coefficient=(MagickRealType) terms[2*j];
2551 degree=(MagickRealType) terms[(j << 1)+1];
2552 polynomial_pixel[x].channel[i]+=coefficient*
2553 pow(QuantumScale*(
double) GetPixelChannel(image,channel,p),degree);
2555 p+=(ptrdiff_t) GetPixelChannels(next);
2557 image_view=DestroyCacheView(image_view);
2558 next=GetNextImageInList(next);
2560 for (x=0; x < (ssize_t) image->columns; x++)
2562 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2564 PixelChannel channel = GetPixelChannelChannel(image,i);
2565 PixelTrait traits = GetPixelChannelTraits(image,channel);
2566 if ((traits & UpdatePixelTrait) == 0)
2568 q[i]=ClampToQuantum((
double) QuantumRange*
2569 polynomial_pixel[x].channel[i]);
2571 q+=(ptrdiff_t) GetPixelChannels(image);
2573 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2575 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2580#if defined(MAGICKCORE_OPENMP_SUPPORT)
2584 proceed=SetImageProgress(images,PolynomialImageTag,progress,
2586 if (proceed == MagickFalse)
2590 polynomial_view=DestroyCacheView(polynomial_view);
2591 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2592 if (status == MagickFalse)
2593 image=DestroyImage(image);
2660static PixelList *DestroyPixelList(PixelList *pixel_list)
2662 if (pixel_list == (PixelList *) NULL)
2663 return((PixelList *) NULL);
2664 if (pixel_list->skip_list.nodes != (SkipNode *) NULL)
2665 pixel_list->skip_list.nodes=(SkipNode *) RelinquishAlignedMemory(
2666 pixel_list->skip_list.nodes);
2667 pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
2671static PixelList **DestroyPixelListTLS(PixelList **pixel_list)
2676 assert(pixel_list != (PixelList **) NULL);
2677 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2678 if (pixel_list[i] != (PixelList *) NULL)
2679 pixel_list[i]=DestroyPixelList(pixel_list[i]);
2680 pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
2684static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
2689 pixel_list=(PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
2690 if (pixel_list == (PixelList *) NULL)
2692 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
2693 pixel_list->length=width*height;
2694 pixel_list->skip_list.nodes=(SkipNode *) AcquireAlignedMemory(65537UL,
2695 sizeof(*pixel_list->skip_list.nodes));
2696 if (pixel_list->skip_list.nodes == (SkipNode *) NULL)
2697 return(DestroyPixelList(pixel_list));
2698 (void) memset(pixel_list->skip_list.nodes,0,65537UL*
2699 sizeof(*pixel_list->skip_list.nodes));
2700 pixel_list->signature=MagickCoreSignature;
2704static PixelList **AcquirePixelListTLS(
const size_t width,
2705 const size_t height)
2716 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2717 pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
2718 sizeof(*pixel_list));
2719 if (pixel_list == (PixelList **) NULL)
2720 return((PixelList **) NULL);
2721 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
2722 for (i=0; i < (ssize_t) number_threads; i++)
2724 pixel_list[i]=AcquirePixelList(width,height);
2725 if (pixel_list[i] == (PixelList *) NULL)
2726 return(DestroyPixelListTLS(pixel_list));
2731static void AddNodePixelList(PixelList *pixel_list,
const size_t color)
2746 p=(&pixel_list->skip_list);
2747 p->nodes[color].signature=pixel_list->signature;
2748 p->nodes[color].count=1;
2753 (void) memset(update,0,
sizeof(update));
2754 for (level=p->level; level >= 0; level--)
2756 while (p->nodes[search].next[level] < color)
2757 search=p->nodes[search].next[level];
2758 update[level]=search;
2763 for (level=0; ; level++)
2765 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
2766 if ((pixel_list->seed & 0x300) != 0x300)
2771 if (level > (p->level+2))
2776 while (level > p->level)
2779 update[p->level]=65536UL;
2786 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
2787 p->nodes[update[level]].next[level]=color;
2788 }
while (level-- > 0);
2791static inline void GetMedianPixelList(PixelList *pixel_list,Quantum *pixel)
2805 p=(&pixel_list->skip_list);
2810 color=p->nodes[color].next[0];
2811 count+=(ssize_t) p->nodes[color].count;
2812 }
while (count <= (ssize_t) (pixel_list->length >> 1));
2813 *pixel=ScaleShortToQuantum((
unsigned short) color);
2816static inline void GetModePixelList(PixelList *pixel_list,Quantum *pixel)
2832 p=(&pixel_list->skip_list);
2835 max_count=p->nodes[mode].count;
2839 color=p->nodes[color].next[0];
2840 if (p->nodes[color].count > max_count)
2843 max_count=p->nodes[mode].count;
2845 count+=(ssize_t) p->nodes[color].count;
2846 }
while (count < (ssize_t) pixel_list->length);
2847 *pixel=ScaleShortToQuantum((
unsigned short) mode);
2850static inline void GetNonpeakPixelList(PixelList *pixel_list,Quantum *pixel)
2866 p=(&pixel_list->skip_list);
2868 next=p->nodes[color].next[0];
2874 next=p->nodes[color].next[0];
2875 count+=(ssize_t) p->nodes[color].count;
2876 }
while (count <= (ssize_t) (pixel_list->length >> 1));
2877 if ((previous == 65536UL) && (next != 65536UL))
2880 if ((previous != 65536UL) && (next == 65536UL))
2882 *pixel=ScaleShortToQuantum((
unsigned short) color);
2885static inline void InsertPixelList(
const Quantum pixel,PixelList *pixel_list)
2893 index=ScaleQuantumToShort(pixel);
2894 signature=pixel_list->skip_list.nodes[index].signature;
2895 if (signature == pixel_list->signature)
2897 pixel_list->skip_list.nodes[index].count++;
2900 AddNodePixelList(pixel_list,index);
2903static void ResetPixelList(PixelList *pixel_list)
2917 p=(&pixel_list->skip_list);
2918 root=p->nodes+65536UL;
2920 for (level=0; level < 9; level++)
2921 root->next[level]=65536UL;
2922 pixel_list->seed=pixel_list->signature++;
2925MagickExport Image *StatisticImage(
const Image *image,
const StatisticType type,
2926 const size_t width,
const size_t height,ExceptionInfo *exception)
2928#define StatisticImageTag "Statistic/Image"
2944 **magick_restrict pixel_list;
2953 assert(image != (Image *) NULL);
2954 assert(image->signature == MagickCoreSignature);
2955 if (IsEventLogging() != MagickFalse)
2956 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2957 assert(exception != (ExceptionInfo *) NULL);
2958 assert(exception->signature == MagickCoreSignature);
2959 statistic_image=CloneImage(image,0,0,MagickTrue,
2961 if (statistic_image == (Image *) NULL)
2962 return((Image *) NULL);
2963 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2964 if (status == MagickFalse)
2966 statistic_image=DestroyImage(statistic_image);
2967 return((Image *) NULL);
2969 pixel_list=AcquirePixelListTLS(MagickMax(width,1),MagickMax(height,1));
2970 if (pixel_list == (PixelList **) NULL)
2972 statistic_image=DestroyImage(statistic_image);
2973 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2978 center=(ssize_t) GetPixelChannels(image)*((ssize_t) image->columns+
2979 MagickMax((ssize_t) width,1L))*(MagickMax((ssize_t) height,1)/2L)+(ssize_t)
2980 GetPixelChannels(image)*(MagickMax((ssize_t) width,1L)/2L);
2983 image_view=AcquireVirtualCacheView(image,exception);
2984 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2985#if defined(MAGICKCORE_OPENMP_SUPPORT)
2986 #pragma omp parallel for schedule(static) shared(progress,status) \
2987 magick_number_threads(image,statistic_image,statistic_image->rows,1)
2989 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2992 id = GetOpenMPThreadId();
3003 if (status == MagickFalse)
3005 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
3006 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
3007 MagickMax(height,1),exception);
3008 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3009 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3014 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3019 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3032 *magick_restrict pixels;
3040 PixelChannel channel = GetPixelChannelChannel(image,i);
3041 PixelTrait traits = GetPixelChannelTraits(image,channel);
3042 PixelTrait statistic_traits=GetPixelChannelTraits(statistic_image,
3044 if (((traits & UpdatePixelTrait) == 0) ||
3045 ((statistic_traits & UpdatePixelTrait) == 0))
3047 if (((statistic_traits & CopyPixelTrait) != 0) ||
3048 (GetPixelWriteMask(image,p) <= (QuantumRange/2)))
3050 SetPixelChannel(statistic_image,channel,p[center+i],q);
3059 ResetPixelList(pixel_list[
id]);
3060 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
3062 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
3064 if ((type == MedianStatistic) || (type == ModeStatistic) ||
3065 (type == NonpeakStatistic))
3067 InsertPixelList(pixels[i],pixel_list[
id]);
3068 pixels+=(ptrdiff_t) GetPixelChannels(image);
3072 if ((
double) pixels[i] < minimum)
3073 minimum=(double) pixels[i];
3074 if ((
double) pixels[i] > maximum)
3075 maximum=(double) pixels[i];
3076 sum+=(double) pixels[i];
3077 sum_squared+=(double) pixels[i]*(
double) pixels[i];
3078 pixels+=(ptrdiff_t) GetPixelChannels(image);
3080 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3084 case ContrastStatistic:
3086 pixel=ClampToQuantum(MagickAbsoluteValue((maximum-minimum)*
3087 MagickSafeReciprocal(maximum+minimum)));
3090 case GradientStatistic:
3092 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
3095 case MaximumStatistic:
3097 pixel=ClampToQuantum(maximum);
3103 pixel=ClampToQuantum(sum/area);
3106 case MedianStatistic:
3108 GetMedianPixelList(pixel_list[
id],&pixel);
3111 case MinimumStatistic:
3113 pixel=ClampToQuantum(minimum);
3118 GetModePixelList(pixel_list[
id],&pixel);
3121 case NonpeakStatistic:
3123 GetNonpeakPixelList(pixel_list[
id],&pixel);
3126 case RootMeanSquareStatistic:
3128 pixel=ClampToQuantum(sqrt(sum_squared/area));
3131 case StandardDeviationStatistic:
3133 pixel=ClampToQuantum(sqrt(sum_squared/area-(sum/area*sum/area)));
3137 SetPixelChannel(statistic_image,channel,pixel,q);
3139 p+=(ptrdiff_t) GetPixelChannels(image);
3140 q+=(ptrdiff_t) GetPixelChannels(statistic_image);
3142 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3144 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3149#if defined(MAGICKCORE_OPENMP_SUPPORT)
3153 proceed=SetImageProgress(image,StatisticImageTag,progress,image->rows);
3154 if (proceed == MagickFalse)
3158 statistic_view=DestroyCacheView(statistic_view);
3159 image_view=DestroyCacheView(image_view);
3160 pixel_list=DestroyPixelListTLS(pixel_list);
3161 if (status == MagickFalse)
3162 statistic_image=DestroyImage(statistic_image);
3163 return(statistic_image);