43#include "MagickCore/studio.h"
44#include "MagickCore/accelerate-private.h"
45#include "MagickCore/animate.h"
46#include "MagickCore/artifact.h"
47#include "MagickCore/blob.h"
48#include "MagickCore/blob-private.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-private.h"
51#include "MagickCore/cache-view.h"
52#include "MagickCore/client.h"
53#include "MagickCore/color.h"
54#include "MagickCore/color-private.h"
55#include "MagickCore/colorspace.h"
56#include "MagickCore/colorspace-private.h"
57#include "MagickCore/composite.h"
58#include "MagickCore/composite-private.h"
59#include "MagickCore/compress.h"
60#include "MagickCore/constitute.h"
61#include "MagickCore/display.h"
62#include "MagickCore/draw.h"
63#include "MagickCore/enhance.h"
64#include "MagickCore/exception.h"
65#include "MagickCore/exception-private.h"
66#include "MagickCore/gem.h"
67#include "MagickCore/gem-private.h"
68#include "MagickCore/geometry.h"
69#include "MagickCore/list.h"
70#include "MagickCore/image-private.h"
71#include "MagickCore/magic.h"
72#include "MagickCore/magick.h"
73#include "MagickCore/memory_.h"
74#include "MagickCore/module.h"
75#include "MagickCore/monitor.h"
76#include "MagickCore/monitor-private.h"
77#include "MagickCore/option.h"
78#include "MagickCore/paint.h"
79#include "MagickCore/pixel-accessor.h"
80#include "MagickCore/profile.h"
81#include "MagickCore/property.h"
82#include "MagickCore/quantize.h"
83#include "MagickCore/quantum-private.h"
84#include "MagickCore/random_.h"
85#include "MagickCore/random-private.h"
86#include "MagickCore/resource_.h"
87#include "MagickCore/segment.h"
88#include "MagickCore/semaphore.h"
89#include "MagickCore/signature-private.h"
90#include "MagickCore/statistic.h"
91#include "MagickCore/statistic-private.h"
92#include "MagickCore/string_.h"
93#include "MagickCore/thread-private.h"
94#include "MagickCore/timer.h"
95#include "MagickCore/utility.h"
96#include "MagickCore/version.h"
138 channel[MaxPixelChannels];
151 rows=MagickMax(GetImageListLength(images),(
size_t)
152 GetMagickResourceLimit(ThreadResource));
153 for (i=0; i < (ssize_t) rows; i++)
155 pixels[i]=(
PixelChannels *) RelinquishMagickMemory(pixels[i]);
176 number_images=GetImageListLength(images);
177 rows=MagickMax(number_images,(
size_t) GetMagickResourceLimit(ThreadResource));
178 pixels=(
PixelChannels **) AcquireQuantumMemory(rows,
sizeof(*pixels));
181 (void) memset(pixels,0,rows*
sizeof(*pixels));
182 columns=MagickMax(number_images,MaxPixelChannels);
183 for (next=images; next != (
Image *) NULL; next=next->next)
184 columns=MagickMax(next->columns,columns);
185 for (i=0; i < (ssize_t) rows; i++)
190 pixels[i]=(
PixelChannels *) AcquireQuantumMemory(columns,
sizeof(**pixels));
192 return(DestroyPixelTLS(images,pixels));
193 for (j=0; j < (ssize_t) columns; j++)
198 for (k=0; k < MaxPixelChannels; k++)
199 pixels[i][j].channel[k]=0.0;
205static inline double EvaluateMax(
const double x,
const double y)
212#if defined(__cplusplus) || defined(c_plusplus)
216static int IntensityCompare(
const void *x,
const void *y)
231 for (i=0; i < MaxPixelChannels; i++)
232 distance+=color_1->channel[i]-(
double) color_2->channel[i];
233 return(distance < 0.0 ? -1 : distance > 0.0 ? 1 : 0);
236#if defined(__cplusplus) || defined(c_plusplus)
240static double ApplyEvaluateOperator(
RandomInfo *random_info,
const Quantum pixel,
241 const MagickEvaluateOperator op,
const double value)
252 case UndefinedEvaluateOperator:
254 case AbsEvaluateOperator:
256 result=(double) fabs((
double) pixel+value);
259 case AddEvaluateOperator:
261 result=(double) pixel+value;
264 case AddModulusEvaluateOperator:
272 result=(double) pixel+value;
273 result-=((double) QuantumRange+1.0)*floor(result/((
double)
277 case AndEvaluateOperator:
279 result=(double) ((ssize_t) pixel & (ssize_t) (value+0.5));
282 case CosineEvaluateOperator:
284 result=(double) QuantumRange*(0.5*cos((
double) (2.0*MagickPI*
285 QuantumScale*(
double) pixel*value))+0.5);
288 case DivideEvaluateOperator:
290 result=(double) pixel/(value == 0.0 ? 1.0 : value);
293 case ExponentialEvaluateOperator:
295 result=(double) QuantumRange*exp(value*QuantumScale*(
double) pixel);
298 case GaussianNoiseEvaluateOperator:
300 result=(double) GenerateDifferentialNoise(random_info,pixel,GaussianNoise,
304 case ImpulseNoiseEvaluateOperator:
306 result=(double) GenerateDifferentialNoise(random_info,pixel,ImpulseNoise,
310 case InverseLogEvaluateOperator:
312 result=(double) QuantumRange*pow((value+1.0),QuantumScale*(
double)
313 pixel-1.0)*PerceptibleReciprocal(value);
316 case LaplacianNoiseEvaluateOperator:
318 result=(double) GenerateDifferentialNoise(random_info,pixel,
319 LaplacianNoise,value);
322 case LeftShiftEvaluateOperator:
324 result=(double) pixel;
325 for (i=0; i < (ssize_t) value; i++)
329 case LogEvaluateOperator:
331 if ((QuantumScale*(
double) pixel) >= MagickEpsilon)
332 result=(double) QuantumRange*log(QuantumScale*value*
333 (
double) pixel+1.0)/log((
double) (value+1.0));
336 case MaxEvaluateOperator:
338 result=(double) EvaluateMax((
double) pixel,value);
341 case MeanEvaluateOperator:
343 result=(double) pixel+value;
346 case MedianEvaluateOperator:
348 result=(double) pixel+value;
351 case MinEvaluateOperator:
353 result=MagickMin((
double) pixel,value);
356 case MultiplicativeNoiseEvaluateOperator:
358 result=(double) GenerateDifferentialNoise(random_info,pixel,
359 MultiplicativeGaussianNoise,value);
362 case MultiplyEvaluateOperator:
364 result=(double) pixel*value;
367 case OrEvaluateOperator:
369 result=(double) ((ssize_t) pixel | (ssize_t) (value+0.5));
372 case PoissonNoiseEvaluateOperator:
374 result=(double) GenerateDifferentialNoise(random_info,pixel,PoissonNoise,
378 case PowEvaluateOperator:
380 if (fabs(value) <= MagickEpsilon)
382 if (((
double) pixel < 0.0) && ((value-floor(value)) > MagickEpsilon))
383 result=(double) -((
double) QuantumRange*pow(-(QuantumScale*(
double)
386 result=(double) QuantumRange*pow(QuantumScale*(
double) pixel,value);
389 case RightShiftEvaluateOperator:
391 result=(double) pixel;
392 for (i=0; i < (ssize_t) value; i++)
396 case RootMeanSquareEvaluateOperator:
398 result=((double) pixel*(double) pixel+value);
401 case SetEvaluateOperator:
406 case SineEvaluateOperator:
408 result=(double) QuantumRange*(0.5*sin((
double) (2.0*MagickPI*
409 QuantumScale*(
double) pixel*value))+0.5);
412 case SubtractEvaluateOperator:
414 result=(double) pixel-value;
417 case SumEvaluateOperator:
419 result=(double) pixel+value;
422 case ThresholdEvaluateOperator:
424 result=(double) (((
double) pixel <= value) ? 0 : QuantumRange);
427 case ThresholdBlackEvaluateOperator:
429 result=(double) (((
double) pixel <= value) ? 0 : pixel);
432 case ThresholdWhiteEvaluateOperator:
434 result=(double) (((
double) pixel > value) ? QuantumRange : pixel);
437 case UniformNoiseEvaluateOperator:
439 result=(double) GenerateDifferentialNoise(random_info,pixel,UniformNoise,
443 case XorEvaluateOperator:
445 result=(double) ((ssize_t) pixel ^ (ssize_t) (value+0.5));
463 columns=images->columns;
465 for (p=images; p != (
Image *) NULL; p=p->next)
467 if (p->number_channels > q->number_channels)
469 if (p->columns > columns)
474 return(CloneImage(q,columns,rows,MagickTrue,exception));
477MagickExport
Image *EvaluateImages(
const Image *images,
480#define EvaluateImageTag "Evaluate/Image"
499 **magick_restrict evaluate_pixels;
502 **magick_restrict random_info;
511#if defined(MAGICKCORE_OPENMP_SUPPORT)
516 assert(images != (
Image *) NULL);
517 assert(images->signature == MagickCoreSignature);
519 assert(exception->signature == MagickCoreSignature);
520 if (IsEventLogging() != MagickFalse)
521 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
522 image=AcquireImageCanvas(images,exception);
523 if (image == (
Image *) NULL)
524 return((
Image *) NULL);
525 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
527 image=DestroyImage(image);
528 return((
Image *) NULL);
530 number_images=GetImageListLength(images);
531 evaluate_pixels=AcquirePixelTLS(images);
534 image=DestroyImage(image);
535 (void) ThrowMagickException(exception,GetMagickModule(),
536 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
537 return((
Image *) NULL);
539 image_view=(
CacheView **) AcquireQuantumMemory(number_images,
540 sizeof(*image_view));
543 image=DestroyImage(image);
544 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
545 (void) ThrowMagickException(exception,GetMagickModule(),
546 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
550 for (n=0; n < (ssize_t) number_images; n++)
552 image_view[n]=AcquireVirtualCacheView(view,exception);
553 view=GetNextImageInList(view);
560 random_info=AcquireRandomInfoTLS();
561 evaluate_view=AcquireAuthenticCacheView(image,exception);
562 if (op == MedianEvaluateOperator)
564#if defined(MAGICKCORE_OPENMP_SUPPORT)
565 key=GetRandomSecretKey(random_info[0]);
566 #pragma omp parallel for schedule(static) shared(progress,status) \
567 magick_number_threads(image,images,image->rows,key == ~0UL)
569 for (y=0; y < (ssize_t) image->rows; y++)
572 id = GetOpenMPThreadId();
589 if (status == MagickFalse)
591 p=(
const Quantum **) AcquireQuantumMemory(number_images,
sizeof(*p));
592 if (p == (
const Quantum **) NULL)
595 (void) ThrowMagickException(exception,GetMagickModule(),
596 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
600 for (j=0; j < (ssize_t) number_images; j++)
602 p[j]=GetCacheViewVirtualPixels(image_view[j],0,y,image->columns,1,
604 if (p[j] == (
const Quantum *) NULL)
607 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
609 if ((j < (ssize_t) number_images) || (q == (Quantum *) NULL))
614 evaluate_pixel=evaluate_pixels[id];
615 for (x=0; x < (ssize_t) image->columns; x++)
624 for (j=0; j < (ssize_t) number_images; j++)
626 for (i=0; i < MaxPixelChannels; i++)
627 evaluate_pixel[j].channel[i]=0.0;
628 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
630 PixelChannel channel = GetPixelChannelChannel(image,i);
631 PixelTrait traits = GetPixelChannelTraits(next,channel);
632 PixelTrait evaluate_traits = GetPixelChannelTraits(image,channel);
633 if ((traits == UndefinedPixelTrait) ||
634 (evaluate_traits == UndefinedPixelTrait) ||
635 ((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 == UndefinedPixelTrait) ||
651 ((traits & UpdatePixelTrait) == 0))
653 q[i]=ClampToQuantum(evaluate_pixel[number_images/2].channel[i]);
655 q+=(ptrdiff_t) GetPixelChannels(image);
657 p=(
const Quantum **) RelinquishMagickMemory((
void *) p);
658 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
660 if (images->progress_monitor != (MagickProgressMonitor) NULL)
665#if defined(MAGICKCORE_OPENMP_SUPPORT)
669 proceed=SetImageProgress(images,EvaluateImageTag,progress,
671 if (proceed == MagickFalse)
678#if defined(MAGICKCORE_OPENMP_SUPPORT)
679 key=GetRandomSecretKey(random_info[0]);
680 #pragma omp parallel for schedule(static) shared(progress,status) \
681 magick_number_threads(image,images,image->rows,key == ~0UL)
683 for (y=0; y < (ssize_t) image->rows; y++)
689 id = GetOpenMPThreadId();
707 if (status == MagickFalse)
709 p=(
const Quantum **) AcquireQuantumMemory(number_images,
sizeof(*p));
710 if (p == (
const Quantum **) NULL)
713 (void) ThrowMagickException(exception,GetMagickModule(),
714 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
718 for (j=0; j < (ssize_t) number_images; j++)
720 p[j]=GetCacheViewVirtualPixels(image_view[j],0,y,image->columns,1,
722 if (p[j] == (
const Quantum *) NULL)
725 q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,image->columns,1,
727 if ((j < (ssize_t) number_images) || (q == (Quantum *) NULL))
732 evaluate_pixel=evaluate_pixels[id];
733 for (j=0; j < (ssize_t) image->columns; j++)
734 for (i=0; i < MaxPixelChannels; i++)
735 evaluate_pixel[j].channel[i]=0.0;
737 for (j=0; j < (ssize_t) number_images; j++)
739 for (x=0; x < (ssize_t) image->columns; x++)
741 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
743 PixelChannel channel = GetPixelChannelChannel(image,i);
744 PixelTrait traits = GetPixelChannelTraits(next,channel);
745 PixelTrait evaluate_traits = GetPixelChannelTraits(image,channel);
746 if ((traits == UndefinedPixelTrait) ||
747 (evaluate_traits == UndefinedPixelTrait))
749 if ((traits & UpdatePixelTrait) == 0)
751 evaluate_pixel[x].channel[i]=ApplyEvaluateOperator(
752 random_info[
id],GetPixelChannel(next,channel,p[j]),j == 0 ?
753 AddEvaluateOperator : op,evaluate_pixel[x].channel[i]);
755 p[j]+=(ptrdiff_t) GetPixelChannels(next);
757 next=GetNextImageInList(next);
759 for (x=0; x < (ssize_t) image->columns; x++)
763 case MeanEvaluateOperator:
765 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
766 evaluate_pixel[x].channel[i]/=(
double) number_images;
769 case MultiplyEvaluateOperator:
771 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
773 for (j=0; j < (ssize_t) (number_images-1); j++)
774 evaluate_pixel[x].channel[i]*=QuantumScale;
778 case RootMeanSquareEvaluateOperator:
780 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
781 evaluate_pixel[x].channel[i]=sqrt(evaluate_pixel[x].channel[i]/
789 for (x=0; x < (ssize_t) image->columns; x++)
791 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
793 PixelChannel channel = GetPixelChannelChannel(image,i);
794 PixelTrait traits = GetPixelChannelTraits(image,channel);
795 if ((traits == UndefinedPixelTrait) ||
796 ((traits & UpdatePixelTrait) == 0))
798 q[i]=ClampToQuantum(evaluate_pixel[x].channel[i]);
800 q+=(ptrdiff_t) GetPixelChannels(image);
802 p=(
const Quantum **) RelinquishMagickMemory((
void *) p);
803 if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
805 if (images->progress_monitor != (MagickProgressMonitor) NULL)
810#if defined(MAGICKCORE_OPENMP_SUPPORT)
814 proceed=SetImageProgress(images,EvaluateImageTag,progress,
816 if (proceed == MagickFalse)
821 for (n=0; n < (ssize_t) number_images; n++)
822 image_view[n]=DestroyCacheView(image_view[n]);
823 image_view=(
CacheView **) RelinquishMagickMemory(image_view);
824 evaluate_view=DestroyCacheView(evaluate_view);
825 evaluate_pixels=DestroyPixelTLS(images,evaluate_pixels);
826 random_info=DestroyRandomInfoTLS(random_info);
827 if (status == MagickFalse)
828 image=DestroyImage(image);
832MagickExport MagickBooleanType EvaluateImage(
Image *image,
833 const MagickEvaluateOperator op,
const double value,
ExceptionInfo *exception)
849 **magick_restrict random_info;
854#if defined(MAGICKCORE_OPENMP_SUPPORT)
859 assert(image != (
Image *) NULL);
860 assert(image->signature == MagickCoreSignature);
862 assert(exception->signature == MagickCoreSignature);
863 if (IsEventLogging() != MagickFalse)
864 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
865 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
870 artifact=GetImageArtifact(image,
"evaluate:clamp");
871 if (artifact != (
const char *) NULL)
872 clamp=IsStringTrue(artifact);
873 random_info=AcquireRandomInfoTLS();
874 image_view=AcquireAuthenticCacheView(image,exception);
875#if defined(MAGICKCORE_OPENMP_SUPPORT)
876 key=GetRandomSecretKey(random_info[0]);
877 #pragma omp parallel for schedule(static) shared(progress,status) \
878 magick_number_threads(image,image,image->rows,key == ~0UL)
880 for (y=0; y < (ssize_t) image->rows; y++)
883 id = GetOpenMPThreadId();
891 if (status == MagickFalse)
893 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
894 if (q == (Quantum *) NULL)
899 for (x=0; x < (ssize_t) image->columns; x++)
907 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
909 PixelChannel channel = GetPixelChannelChannel(image,i);
910 PixelTrait traits = GetPixelChannelTraits(image,channel);
911 if (traits == UndefinedPixelTrait)
913 if ((traits & CopyPixelTrait) != 0)
915 if ((traits & UpdatePixelTrait) == 0)
917 result=ApplyEvaluateOperator(random_info[
id],q[i],op,value);
918 if (op == MeanEvaluateOperator)
920 q[i]=clamp != MagickFalse ? ClampPixel(result) : ClampToQuantum(result);
922 q+=(ptrdiff_t) GetPixelChannels(image);
924 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
926 if (image->progress_monitor != (MagickProgressMonitor) NULL)
931#if defined(MAGICKCORE_OPENMP_SUPPORT)
935 proceed=SetImageProgress(image,EvaluateImageTag,progress,image->rows);
936 if (proceed == MagickFalse)
940 image_view=DestroyCacheView(image_view);
941 random_info=DestroyRandomInfoTLS(random_info);
979static Quantum ApplyFunction(Quantum pixel,
const MagickFunction function,
980 const size_t number_parameters,
const double *parameters,
993 case PolynomialFunction:
1000 for (i=0; i < (ssize_t) number_parameters; i++)
1001 result=result*QuantumScale*(
double) pixel+parameters[i];
1002 result*=(double) QuantumRange;
1005 case SinusoidFunction:
1016 frequency=(number_parameters >= 1) ? parameters[0] : 1.0;
1017 phase=(number_parameters >= 2) ? parameters[1] : 0.0;
1018 amplitude=(number_parameters >= 3) ? parameters[2] : 0.5;
1019 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1020 result=(double) QuantumRange*(amplitude*sin((
double) (2.0*
1021 MagickPI*(frequency*QuantumScale*(
double) pixel+phase/360.0)))+bias);
1024 case ArcsinFunction:
1036 width=(number_parameters >= 1) ? parameters[0] : 1.0;
1037 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1038 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1039 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1040 result=2.0*PerceptibleReciprocal(width)*(QuantumScale*(double) pixel-
1043 result=bias-range/2.0;
1046 result=bias+range/2.0;
1048 result=(double) (range/MagickPI*asin((
double) result)+bias);
1049 result*=(double) QuantumRange;
1052 case ArctanFunction:
1063 slope=(number_parameters >= 1) ? parameters[0] : 1.0;
1064 center=(number_parameters >= 2) ? parameters[1] : 0.5;
1065 range=(number_parameters >= 3) ? parameters[2] : 1.0;
1066 bias=(number_parameters >= 4) ? parameters[3] : 0.5;
1067 result=MagickPI*slope*(QuantumScale*(double) pixel-center);
1068 result=(double) QuantumRange*(range/MagickPI*atan((
double) result)+bias);
1071 case UndefinedFunction:
1074 return(ClampToQuantum(result));
1077MagickExport MagickBooleanType FunctionImage(
Image *image,
1078 const MagickFunction function,
const size_t number_parameters,
1081#define FunctionImageTag "Function/Image "
1095 assert(image != (
Image *) NULL);
1096 assert(image->signature == MagickCoreSignature);
1098 assert(exception->signature == MagickCoreSignature);
1099 if (IsEventLogging() != MagickFalse)
1100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1101#if defined(MAGICKCORE_OPENCL_SUPPORT)
1102 if (AccelerateFunctionImage(image,function,number_parameters,parameters,
1103 exception) != MagickFalse)
1106 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1107 return(MagickFalse);
1110 image_view=AcquireAuthenticCacheView(image,exception);
1111#if defined(MAGICKCORE_OPENMP_SUPPORT)
1112 #pragma omp parallel for schedule(static) shared(progress,status) \
1113 magick_number_threads(image,image,image->rows,1)
1115 for (y=0; y < (ssize_t) image->rows; y++)
1123 if (status == MagickFalse)
1125 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1126 if (q == (Quantum *) NULL)
1131 for (x=0; x < (ssize_t) image->columns; x++)
1136 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1138 PixelChannel channel = GetPixelChannelChannel(image,i);
1139 PixelTrait traits = GetPixelChannelTraits(image,channel);
1140 if (traits == UndefinedPixelTrait)
1142 if ((traits & UpdatePixelTrait) == 0)
1144 q[i]=ApplyFunction(q[i],function,number_parameters,parameters,
1147 q+=(ptrdiff_t) GetPixelChannels(image);
1149 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1151 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1156#if defined(MAGICKCORE_OPENMP_SUPPORT)
1160 proceed=SetImageProgress(image,FunctionImageTag,progress,image->rows);
1161 if (proceed == MagickFalse)
1165 image_view=DestroyCacheView(image_view);
1196MagickExport MagickBooleanType GetImageEntropy(
const Image *image,
1200 *channel_statistics;
1202 assert(image != (
Image *) NULL);
1203 assert(image->signature == MagickCoreSignature);
1204 if (IsEventLogging() != MagickFalse)
1205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1206 channel_statistics=GetImageStatistics(image,exception);
1210 return(MagickFalse);
1212 *entropy=channel_statistics[CompositePixelChannel].entropy;
1214 channel_statistics);
1247MagickExport MagickBooleanType GetImageExtrema(
const Image *image,
1257 assert(image != (
Image *) NULL);
1258 assert(image->signature == MagickCoreSignature);
1259 if (IsEventLogging() != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1261 status=GetImageRange(image,&min,&max,exception);
1262 *minima=(size_t) ceil(min-0.5);
1263 *maxima=(size_t) floor(max+0.5);
1297MagickExport MagickBooleanType GetImageKurtosis(
const Image *image,
1301 *channel_statistics;
1303 assert(image != (
Image *) NULL);
1304 assert(image->signature == MagickCoreSignature);
1305 if (IsEventLogging() != MagickFalse)
1306 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1307 channel_statistics=GetImageStatistics(image,exception);
1312 return(MagickFalse);
1314 *kurtosis=channel_statistics[CompositePixelChannel].kurtosis;
1315 *skewness=channel_statistics[CompositePixelChannel].skewness;
1317 channel_statistics);
1351MagickExport MagickBooleanType GetImageMean(
const Image *image,
double *mean,
1355 *channel_statistics;
1357 assert(image != (
Image *) NULL);
1358 assert(image->signature == MagickCoreSignature);
1359 if (IsEventLogging() != MagickFalse)
1360 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1361 channel_statistics=GetImageStatistics(image,exception);
1365 *standard_deviation=NAN;
1366 return(MagickFalse);
1368 *mean=channel_statistics[CompositePixelChannel].mean;
1369 *standard_deviation=
1370 channel_statistics[CompositePixelChannel].standard_deviation;
1372 channel_statistics);
1403MagickExport MagickBooleanType GetImageMedian(
const Image *image,
double *median,
1407 *channel_statistics;
1409 assert(image != (
Image *) NULL);
1410 assert(image->signature == MagickCoreSignature);
1411 if (IsEventLogging() != MagickFalse)
1412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1413 channel_statistics=GetImageStatistics(image,exception);
1417 return(MagickFalse);
1419 *median=channel_statistics[CompositePixelChannel].median;
1421 channel_statistics);
1454#define MaxNumberImageMoments 8
1464 M00[2*MaxPixelChannels+1],
1465 M01[2*MaxPixelChannels+1],
1466 M02[2*MaxPixelChannels+1],
1467 M03[2*MaxPixelChannels+1],
1468 M10[2*MaxPixelChannels+1],
1469 M11[2*MaxPixelChannels+1],
1470 M12[2*MaxPixelChannels+1],
1471 M20[2*MaxPixelChannels+1],
1472 M21[2*MaxPixelChannels+1],
1473 M22[2*MaxPixelChannels+1],
1474 M30[2*MaxPixelChannels+1];
1477 centroid[2*MaxPixelChannels+1];
1483 assert(image != (
Image *) NULL);
1484 assert(image->signature == MagickCoreSignature);
1485 if (IsEventLogging() != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1487 channel_moments=(
ChannelMoments *) AcquireQuantumMemory(MaxPixelChannels+1,
1488 sizeof(*channel_moments));
1490 return(channel_moments);
1491 (void) memset(channel_moments,0,(MaxPixelChannels+1)*
1492 sizeof(*channel_moments));
1493 (void) memset(centroid,0,
sizeof(centroid));
1494 (void) memset(M00,0,
sizeof(M00));
1495 (void) memset(M01,0,
sizeof(M01));
1496 (void) memset(M02,0,
sizeof(M02));
1497 (void) memset(M03,0,
sizeof(M03));
1498 (void) memset(M10,0,
sizeof(M10));
1499 (void) memset(M11,0,
sizeof(M11));
1500 (void) memset(M12,0,
sizeof(M12));
1501 (void) memset(M20,0,
sizeof(M20));
1502 (void) memset(M21,0,
sizeof(M21));
1503 (void) memset(M22,0,
sizeof(M22));
1504 (void) memset(M30,0,
sizeof(M30));
1505 image_view=AcquireVirtualCacheView(image,exception);
1506 for (y=0; y < (ssize_t) image->rows; y++)
1517 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1518 if (p == (
const Quantum *) NULL)
1520 for (x=0; x < (ssize_t) image->columns; x++)
1525 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1527 PixelChannel channel = GetPixelChannelChannel(image,i);
1528 PixelTrait traits = GetPixelChannelTraits(image,channel);
1529 if (traits == UndefinedPixelTrait)
1531 if ((traits & UpdatePixelTrait) == 0)
1533 M00[channel]+=QuantumScale*(double) p[i];
1534 M00[MaxPixelChannels]+=QuantumScale*(double) p[i];
1535 M10[channel]+=x*QuantumScale*(double) p[i];
1536 M10[MaxPixelChannels]+=x*QuantumScale*(double) p[i];
1537 M01[channel]+=y*QuantumScale*(double) p[i];
1538 M01[MaxPixelChannels]+=y*QuantumScale*(double) p[i];
1540 p+=(ptrdiff_t) GetPixelChannels(image);
1543 for (c=0; c <= MaxPixelChannels; c++)
1548 centroid[c].x=M10[c]*PerceptibleReciprocal(M00[c]);
1549 centroid[c].y=M01[c]*PerceptibleReciprocal(M00[c]);
1551 for (y=0; y < (ssize_t) image->rows; y++)
1562 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1563 if (p == (
const Quantum *) NULL)
1565 for (x=0; x < (ssize_t) image->columns; x++)
1570 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1572 PixelChannel channel = GetPixelChannelChannel(image,i);
1573 PixelTrait traits = GetPixelChannelTraits(image,channel);
1574 if (traits == UndefinedPixelTrait)
1576 if ((traits & UpdatePixelTrait) == 0)
1578 M11[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1579 QuantumScale*(double) p[i];
1580 M11[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1581 QuantumScale*(double) p[i];
1582 M20[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1583 QuantumScale*(double) p[i];
1584 M20[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1585 QuantumScale*(double) p[i];
1586 M02[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1587 QuantumScale*(double) p[i];
1588 M02[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1589 QuantumScale*(double) p[i];
1590 M21[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1591 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1592 M21[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1593 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1594 M12[channel]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1595 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1596 M12[MaxPixelChannels]+=(x-centroid[channel].x)*(y-centroid[channel].y)*
1597 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1598 M22[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1599 (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*(double)
1601 M22[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1602 (y-centroid[channel].y)*(y-centroid[channel].y)*QuantumScale*(double)
1604 M30[channel]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1605 (x-centroid[channel].x)*QuantumScale*(
double) p[i];
1606 M30[MaxPixelChannels]+=(x-centroid[channel].x)*(x-centroid[channel].x)*
1607 (x-centroid[channel].x)*QuantumScale*(
double) p[i];
1608 M03[channel]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1609 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1610 M03[MaxPixelChannels]+=(y-centroid[channel].y)*(y-centroid[channel].y)*
1611 (y-centroid[channel].y)*QuantumScale*(
double) p[i];
1613 p+=(ptrdiff_t) GetPixelChannels(image);
1616 channels=(double) GetImageChannels(image);
1617 M00[MaxPixelChannels]/=channels;
1618 M01[MaxPixelChannels]/=channels;
1619 M02[MaxPixelChannels]/=channels;
1620 M03[MaxPixelChannels]/=channels;
1621 M10[MaxPixelChannels]/=channels;
1622 M11[MaxPixelChannels]/=channels;
1623 M12[MaxPixelChannels]/=channels;
1624 M20[MaxPixelChannels]/=channels;
1625 M21[MaxPixelChannels]/=channels;
1626 M22[MaxPixelChannels]/=channels;
1627 M30[MaxPixelChannels]/=channels;
1628 for (c=0; c <= MaxPixelChannels; c++)
1633 channel_moments[c].centroid=centroid[c];
1634 channel_moments[c].ellipse_axis.x=sqrt((2.0*PerceptibleReciprocal(M00[c]))*
1635 ((M20[c]+M02[c])+sqrt(4.0*M11[c]*M11[c]+(M20[c]-M02[c])*(M20[c]-M02[c]))));
1636 channel_moments[c].ellipse_axis.y=sqrt((2.0*PerceptibleReciprocal(M00[c]))*
1637 ((M20[c]+M02[c])-sqrt(4.0*M11[c]*M11[c]+(M20[c]-M02[c])*(M20[c]-M02[c]))));
1638 channel_moments[c].ellipse_angle=RadiansToDegrees(1.0/2.0*atan(2.0*
1639 M11[c]*PerceptibleReciprocal(M20[c]-M02[c])));
1640 if (fabs(M11[c]) < 0.0)
1642 if ((fabs(M20[c]-M02[c]) >= 0.0) &&
1643 ((M20[c]-M02[c]) < 0.0))
1644 channel_moments[c].ellipse_angle+=90.0;
1649 if (fabs(M20[c]-M02[c]) >= 0.0)
1651 if ((M20[c]-M02[c]) < 0.0)
1652 channel_moments[c].ellipse_angle+=90.0;
1654 channel_moments[c].ellipse_angle+=180.0;
1658 if ((fabs(M20[c]-M02[c]) >= 0.0) && ((M20[c]-M02[c]) < 0.0))
1659 channel_moments[c].ellipse_angle+=90.0;
1660 channel_moments[c].ellipse_eccentricity=sqrt(1.0-(
1661 channel_moments[c].ellipse_axis.y*
1662 channel_moments[c].ellipse_axis.y*PerceptibleReciprocal(
1663 channel_moments[c].ellipse_axis.x*
1664 channel_moments[c].ellipse_axis.x)));
1665 channel_moments[c].ellipse_intensity=M00[c]*
1666 PerceptibleReciprocal(MagickPI*channel_moments[c].ellipse_axis.x*
1667 channel_moments[c].ellipse_axis.y+MagickEpsilon);
1669 for (c=0; c <= MaxPixelChannels; c++)
1676 M11[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(1.0+1.0)/2.0));
1677 M20[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(2.0+0.0)/2.0));
1678 M02[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(0.0+2.0)/2.0));
1679 M21[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(2.0+1.0)/2.0));
1680 M12[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(1.0+2.0)/2.0));
1681 M22[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(2.0+2.0)/2.0));
1682 M30[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(3.0+0.0)/2.0));
1683 M03[c]*=PerceptibleReciprocal(pow(M00[c],1.0+(0.0+3.0)/2.0));
1686 image_view=DestroyCacheView(image_view);
1687 for (c=0; c <= MaxPixelChannels; c++)
1692 channel_moments[c].invariant[0]=M20[c]+M02[c];
1693 channel_moments[c].invariant[1]=(M20[c]-M02[c])*(M20[c]-M02[c])+4.0*M11[c]*
1695 channel_moments[c].invariant[2]=(M30[c]-3.0*M12[c])*(M30[c]-3.0*M12[c])+
1696 (3.0*M21[c]-M03[c])*(3.0*M21[c]-M03[c]);
1697 channel_moments[c].invariant[3]=(M30[c]+M12[c])*(M30[c]+M12[c])+
1698 (M21[c]+M03[c])*(M21[c]+M03[c]);
1699 channel_moments[c].invariant[4]=(M30[c]-3.0*M12[c])*(M30[c]+M12[c])*
1700 ((M30[c]+M12[c])*(M30[c]+M12[c])-3.0*(M21[c]+M03[c])*(M21[c]+M03[c]))+
1701 (3.0*M21[c]-M03[c])*(M21[c]+M03[c])*(3.0*(M30[c]+M12[c])*(M30[c]+M12[c])-
1702 (M21[c]+M03[c])*(M21[c]+M03[c]));
1703 channel_moments[c].invariant[5]=(M20[c]-M02[c])*((M30[c]+M12[c])*
1704 (M30[c]+M12[c])-(M21[c]+M03[c])*(M21[c]+M03[c]))+4.0*M11[c]*
1705 (M30[c]+M12[c])*(M21[c]+M03[c]);
1706 channel_moments[c].invariant[6]=(3.0*M21[c]-M03[c])*(M30[c]+M12[c])*
1707 ((M30[c]+M12[c])*(M30[c]+M12[c])-3.0*(M21[c]+M03[c])*(M21[c]+M03[c]))-
1708 (M30[c]-3*M12[c])*(M21[c]+M03[c])*(3.0*(M30[c]+M12[c])*(M30[c]+M12[c])-
1709 (M21[c]+M03[c])*(M21[c]+M03[c]));
1710 channel_moments[c].invariant[7]=M11[c]*((M30[c]+M12[c])*(M30[c]+M12[c])-
1711 (M03[c]+M21[c])*(M03[c]+M21[c]))-(M20[c]-M02[c])*(M30[c]+M12[c])*
1714 if (y < (ssize_t) image->rows)
1715 channel_moments=(
ChannelMoments *) RelinquishMagickMemory(channel_moments);
1716 return(channel_moments);
1766 MaxPixelChannels+1UL,
sizeof(*perceptual_hash));
1769 artifact=GetImageArtifact(image,
"phash:colorspaces");
1770 if (artifact != (
const char *) NULL)
1771 colorspaces=AcquireString(artifact);
1773 colorspaces=AcquireString(
"xyY,HSB");
1774 perceptual_hash[0].number_colorspaces=0;
1775 perceptual_hash[0].number_channels=0;
1777 for (i=0; (p=StringToken(
",",&q)) != (
char *) NULL; i++)
1792 if (i >= MaximumNumberOfPerceptualColorspaces)
1794 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,p);
1797 perceptual_hash[0].colorspace[i]=(ColorspaceType) colorspace;
1798 hash_image=BlurImage(image,0.0,1.0,exception);
1799 if (hash_image == (
Image *) NULL)
1801 hash_image->depth=8;
1802 status=TransformImageColorspace(hash_image,(ColorspaceType) colorspace,
1804 if (status == MagickFalse)
1806 moments=GetImageMoments(hash_image,exception);
1807 perceptual_hash[0].number_colorspaces++;
1808 perceptual_hash[0].number_channels+=GetImageChannels(hash_image);
1809 hash_image=DestroyImage(hash_image);
1812 for (channel=0; channel <= MaxPixelChannels; channel++)
1813 for (j=0; j < MaximumNumberOfImageMoments; j++)
1814 perceptual_hash[channel].phash[i][j]=
1815 (-MagickLog10(moments[channel].invariant[j]));
1818 colorspaces=DestroyString(colorspaces);
1819 return(perceptual_hash);
1851MagickExport MagickBooleanType GetImageRange(
const Image *image,
double *minima,
1863 assert(image != (
Image *) NULL);
1864 assert(image->signature == MagickCoreSignature);
1865 if (IsEventLogging() != MagickFalse)
1866 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1868 *maxima=MagickMinimumValue;
1869 *minima=MagickMaximumValue;
1870 image_view=AcquireVirtualCacheView(image,exception);
1871#if defined(MAGICKCORE_OPENMP_SUPPORT)
1872 #pragma omp parallel for schedule(static) shared(status) \
1873 magick_number_threads(image,image,image->rows,1)
1875 for (y=0; y < (ssize_t) image->rows; y++)
1878 row_maxima = MagickMinimumValue,
1879 row_minima = MagickMaximumValue;
1887 if (status == MagickFalse)
1889 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1890 if (p == (
const Quantum *) NULL)
1895 row_maxima=(double) p[0];
1896 row_minima=(double) p[0];
1897 for (x=0; x < (ssize_t) image->columns; x++)
1902 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1904 PixelChannel channel = GetPixelChannelChannel(image,i);
1905 PixelTrait traits = GetPixelChannelTraits(image,channel);
1906 if (traits == UndefinedPixelTrait)
1908 if ((traits & UpdatePixelTrait) == 0)
1910 if ((
double) p[i] < row_minima)
1911 row_minima=(double) p[i];
1912 if ((
double) p[i] > row_maxima)
1913 row_maxima=(double) p[i];
1915 p+=(ptrdiff_t) GetPixelChannels(image);
1917#if defined(MAGICKCORE_OPENMP_SUPPORT)
1918 #pragma omp critical (MagickCore_GetImageRange)
1921 if (row_minima < *minima)
1923 if (row_maxima > *maxima)
1927 image_view=DestroyCacheView(image_view);
1965static ssize_t GetMedianPixel(Quantum *pixels,
const size_t n)
1967#define SwapPixels(alpha,beta) \
1969 Quantum gamma=(alpha); \
1970 (alpha)=(beta);(beta)=gamma; \
1975 high = (ssize_t) n-1,
1976 median = (low+high)/2;
1987 if (high == (low+1))
1989 if (pixels[low] > pixels[high])
1990 SwapPixels(pixels[low],pixels[high]);
1993 if (pixels[mid] > pixels[high])
1994 SwapPixels(pixels[mid],pixels[high]);
1995 if (pixels[low] > pixels[high])
1996 SwapPixels(pixels[low], pixels[high]);
1997 if (pixels[mid] > pixels[low])
1998 SwapPixels(pixels[mid],pixels[low]);
1999 SwapPixels(pixels[mid],pixels[low+1]);
2002 do l++;
while (pixels[low] > pixels[l]);
2003 do h--;
while (pixels[h] > pixels[low]);
2006 SwapPixels(pixels[l],pixels[h]);
2008 SwapPixels(pixels[low],pixels[h]);
2016static inline long double PerceptibleReciprocalLD(
const long double x)
2024 sign=x < 0.0 ? -1.0 : 1.0;
2025 if ((sign*x) >= MagickEpsilon)
2027 return(sign/MagickEpsilon);
2034 *channel_statistics;
2062 assert(image != (
Image *) NULL);
2063 assert(image->signature == MagickCoreSignature);
2064 if (IsEventLogging() != MagickFalse)
2065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2066 histogram=(
double *) AcquireQuantumMemory(MaxMap+1UL,
2067 MagickMax(GetPixelChannels(image),1)*
sizeof(*histogram));
2069 MaxPixelChannels+1,
sizeof(*channel_statistics));
2071 (histogram == (
double *) NULL))
2073 if (histogram != (
double *) NULL)
2074 histogram=(
double *) RelinquishMagickMemory(histogram);
2077 channel_statistics);
2078 (void) ThrowMagickException(exception,GetMagickModule(),
2079 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2080 return(channel_statistics);
2082 (void) memset(channel_statistics,0,(MaxPixelChannels+1)*
2083 sizeof(*channel_statistics));
2084 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
2089 cs->maxima=(-MagickMaximumValue);
2090 cs->minima=MagickMaximumValue;
2094 cs->standard_deviation=0.0;
2100 (void) memset(histogram,0,(MaxMap+1)*GetPixelChannels(image)*
2101 sizeof(*histogram));
2102 for (y=0; y < (ssize_t) image->rows; y++)
2113 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2114 if (p == (
const Quantum *) NULL)
2116 for (x=0; x < (ssize_t) image->columns; x++)
2118 if (GetPixelReadMask(image,p) <= (QuantumRange/2))
2120 p+=(ptrdiff_t) GetPixelChannels(image);
2123 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2128 PixelChannel channel = GetPixelChannelChannel(image,i);
2129 PixelTrait traits = GetPixelChannelTraits(image,channel);
2130 if (traits == UndefinedPixelTrait)
2132 cs=channel_statistics+channel;
2133 if (cs->depth != MAGICKCORE_QUANTUM_DEPTH)
2136 range=GetQuantumRange(depth);
2137 status=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range) ?
2138 MagickTrue : MagickFalse;
2139 if (status != MagickFalse)
2142 if (cs->depth > channel_statistics[CompositePixelChannel].depth)
2143 channel_statistics[CompositePixelChannel].depth=cs->depth;
2149 if ((
double) p[i] < cs->minima)
2150 cs->minima=(double) p[i];
2151 if ((
double) p[i] > cs->maxima)
2152 cs->maxima=(double) p[i];
2153 histogram[(ssize_t) GetPixelChannels(image)*ScaleQuantumToMap(
2154 ClampToQuantum((
double) p[i]))+i]++;
2155 cs->sumLD+=(
long double) p[i];
2161 cs->sum_squared+=(double) p[i]*(
double) p[i];
2162 cs->sum_cubed+=(double) p[i]*(
double) p[i]*(double) p[i];
2163 cs->sum_fourth_power+=(double) p[i]*(
double) p[i]*(double) p[i]*
2178 delta=(double) p[i]-cs->M1;
2180 delta_n2=delta_n*delta_n;
2181 term1=delta*delta_n*n1;
2182 cs->M4+=term1*delta_n2*(n*n-3.0*n+3.0)+6.0*delta_n2*cs->M2-4.0*
2184 cs->M3+=term1*delta_n*(n-2.0)-3.0*delta_n*cs->M2;
2189 p+=(ptrdiff_t) GetPixelChannels(image);
2192 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2197 PixelChannel channel = GetPixelChannelChannel(image,i);
2198 PixelTrait traits = GetPixelChannelTraits(image,channel);
2199 double AdjArea = 1.0;
2200 if (traits == UndefinedPixelTrait)
2202 cs=channel_statistics+channel;
2206 cs->mean=(double) (cs->sumLD/(
long double) cs->area);
2208 AdjArea=cs->area/(cs->area-1.0);
2210 cs->sum=(double) cs->sum;
2213 cs->standard_deviation=0.0;
2221 cs->standard_deviation=(double) sqrtl(cs->M2/((
long double) cs->area-1.0));
2223 cs->standard_deviation=(double) sqrtl(cs->M2/((
long double) cs->area));
2224 cs->variance=cs->standard_deviation*cs->standard_deviation;
2225 cs->skewness=(double) (sqrtl(cs->area)*cs->M3/powl(cs->M2*AdjArea,1.5));
2226 cs->kurtosis=(double) (cs->area*cs->M4/(cs->M2*cs->M2*AdjArea*AdjArea)-3.0);
2230 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2238 PixelChannel channel = GetPixelChannelChannel(image,i);
2243 cs->sum_squared/=cs->area;
2244 cs->sum_cubed/=cs->area;
2245 cs->sum_fourth_power/=cs->area;
2251 for (j=0; j <= (ssize_t) MaxMap; j++)
2252 if (histogram[(ssize_t) GetPixelChannels(image)*j+i] > 0.0)
2254 area=PerceptibleReciprocalLD(channel_statistics[channel].area);
2255 for (j=0; j <= (ssize_t) MaxMap; j++)
2260 count=(double) (area*histogram[(ssize_t) GetPixelChannels(image)*j+i]);
2261 channel_statistics[channel].entropy+=((
long double) -count*
2262 MagickLog10(count)*PerceptibleReciprocalLD((
long double)
2263 MagickLog10(number_bins)));
2264 channel_statistics[CompositePixelChannel].entropy+=((
long double) -count*
2265 MagickLog10(count)*PerceptibleReciprocalLD((
long double)
2266 MagickLog10(number_bins))/GetPixelChannels(image));
2269 histogram=(
double *) RelinquishMagickMemory(histogram);
2270 median_info=AcquireVirtualMemory(image->columns,image->rows*
sizeof(*median));
2272 (void) ThrowMagickException(exception,GetMagickModule(),
2273 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2276 median=(Quantum *) GetVirtualMemoryBlob(median_info);
2277 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2285 PixelChannel channel = GetPixelChannelChannel(image,i);
2286 PixelTrait traits = GetPixelChannelTraits(image,channel);
2287 if (traits == UndefinedPixelTrait)
2289 if ((traits & UpdatePixelTrait) == 0)
2291 for (y=0; y < (ssize_t) image->rows; y++)
2299 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2300 if (p == (
const Quantum *) NULL)
2302 for (x=0; x < (ssize_t) image->columns; x++)
2304 if (GetPixelReadMask(image,p) <= (QuantumRange/2))
2306 p+=(ptrdiff_t) GetPixelChannels(image);
2310 p+=(ptrdiff_t) GetPixelChannels(image);
2313 channel_statistics[channel].median=(double) median[
2314 GetMedianPixel(median,n)];
2316 median_info=RelinquishVirtualMemory(median_info);
2321 csComp->sum_squared=0.0;
2322 csComp->sum_cubed=0.0;
2323 csComp->sum_fourth_power=0.0;
2324 csComp->maxima=(-MagickMaximumValue);
2325 csComp->minima=MagickMaximumValue;
2329 csComp->variance=0.0;
2330 csComp->standard_deviation=0.0;
2331 csComp->entropy=0.0;
2332 csComp->skewness=0.0;
2333 csComp->kurtosis=0.0;
2334 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2339 PixelChannel channel = GetPixelChannelChannel(image,i);
2340 PixelTrait traits = GetPixelChannelTraits(image,channel);
2341 if (traits == UndefinedPixelTrait)
2343 if ((traits & UpdatePixelTrait) == 0)
2345 cs=channel_statistics+channel;
2346 if (csComp->maxima < cs->maxima)
2347 csComp->maxima=cs->maxima;
2348 if (csComp->minima > cs->minima)
2349 csComp->minima=cs->minima;
2350 csComp->sum+=cs->sum;
2351 csComp->sum_squared+=cs->sum_squared;
2352 csComp->sum_cubed+=cs->sum_cubed;
2353 csComp->sum_fourth_power+=cs->sum_fourth_power;
2354 csComp->median+=cs->median;
2355 csComp->area+=cs->area;
2356 csComp->mean+=cs->mean;
2357 csComp->variance+=cs->variance;
2358 csComp->standard_deviation+=cs->standard_deviation;
2359 csComp->skewness+=cs->skewness;
2360 csComp->kurtosis+=cs->kurtosis;
2361 csComp->entropy+=cs->entropy;
2363 channels=(double) GetImageChannels(image);
2364 csComp->sum/=channels;
2365 csComp->sum_squared/=channels;
2366 csComp->sum_cubed/=channels;
2367 csComp->sum_fourth_power/=channels;
2368 csComp->median/=channels;
2369 csComp->area/=channels;
2370 csComp->mean/=channels;
2371 csComp->variance/=channels;
2372 csComp->standard_deviation/=channels;
2373 csComp->skewness/=channels;
2374 csComp->kurtosis/=channels;
2375 csComp->entropy/=channels;
2377 if (y < (ssize_t) image->rows)
2379 channel_statistics);
2380 return(channel_statistics);
2416MagickExport
Image *PolynomialImage(
const Image *images,
2417 const size_t number_terms,
const double *terms,
ExceptionInfo *exception)
2419#define PolynomialImageTag "Polynomial/Image"
2434 **magick_restrict polynomial_pixels;
2442 assert(images != (
Image *) NULL);
2443 assert(images->signature == MagickCoreSignature);
2444 if (IsEventLogging() != MagickFalse)
2445 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",images->filename);
2447 assert(exception->signature == MagickCoreSignature);
2448 image=AcquireImageCanvas(images,exception);
2449 if (image == (
Image *) NULL)
2450 return((
Image *) NULL);
2451 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2453 image=DestroyImage(image);
2454 return((
Image *) NULL);
2456 number_images=GetImageListLength(images);
2457 polynomial_pixels=AcquirePixelTLS(images);
2460 image=DestroyImage(image);
2461 (void) ThrowMagickException(exception,GetMagickModule(),
2462 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",images->filename);
2463 return((
Image *) NULL);
2470 polynomial_view=AcquireAuthenticCacheView(image,exception);
2471#if defined(MAGICKCORE_OPENMP_SUPPORT)
2472 #pragma omp parallel for schedule(static) shared(progress,status) \
2473 magick_number_threads(image,image,image->rows,1)
2475 for (y=0; y < (ssize_t) image->rows; y++)
2484 id = GetOpenMPThreadId();
2497 if (status == MagickFalse)
2499 q=QueueCacheViewAuthenticPixels(polynomial_view,0,y,image->columns,1,
2501 if (q == (Quantum *) NULL)
2506 polynomial_pixel=polynomial_pixels[id];
2507 for (j=0; j < (ssize_t) image->columns; j++)
2508 for (i=0; i < MaxPixelChannels; i++)
2509 polynomial_pixel[j].channel[i]=0.0;
2511 for (j=0; j < (ssize_t) number_images; j++)
2516 if (j >= (ssize_t) number_terms)
2518 image_view=AcquireVirtualCacheView(next,exception);
2519 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2520 if (p == (
const Quantum *) NULL)
2522 image_view=DestroyCacheView(image_view);
2525 for (x=0; x < (ssize_t) image->columns; x++)
2527 for (i=0; i < (ssize_t) GetPixelChannels(next); i++)
2533 PixelChannel channel = GetPixelChannelChannel(image,i);
2534 PixelTrait traits = GetPixelChannelTraits(next,channel);
2535 PixelTrait polynomial_traits=GetPixelChannelTraits(image,channel);
2536 if ((traits == UndefinedPixelTrait) ||
2537 (polynomial_traits == UndefinedPixelTrait))
2539 if ((traits & UpdatePixelTrait) == 0)
2541 coefficient=(MagickRealType) terms[2*j];
2542 degree=(MagickRealType) terms[(j << 1)+1];
2543 polynomial_pixel[x].channel[i]+=coefficient*
2544 pow(QuantumScale*(
double) GetPixelChannel(image,channel,p),degree);
2546 p+=(ptrdiff_t) GetPixelChannels(next);
2548 image_view=DestroyCacheView(image_view);
2549 next=GetNextImageInList(next);
2551 for (x=0; x < (ssize_t) image->columns; x++)
2553 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2555 PixelChannel channel = GetPixelChannelChannel(image,i);
2556 PixelTrait traits = GetPixelChannelTraits(image,channel);
2557 if (traits == UndefinedPixelTrait)
2559 if ((traits & UpdatePixelTrait) == 0)
2561 q[i]=ClampToQuantum((
double) QuantumRange*
2562 polynomial_pixel[x].channel[i]);
2564 q+=(ptrdiff_t) GetPixelChannels(image);
2566 if (SyncCacheViewAuthenticPixels(polynomial_view,exception) == MagickFalse)
2568 if (images->progress_monitor != (MagickProgressMonitor) NULL)
2573#if defined(MAGICKCORE_OPENMP_SUPPORT)
2577 proceed=SetImageProgress(images,PolynomialImageTag,progress,
2579 if (proceed == MagickFalse)
2583 polynomial_view=DestroyCacheView(polynomial_view);
2584 polynomial_pixels=DestroyPixelTLS(images,polynomial_pixels);
2585 if (status == MagickFalse)
2586 image=DestroyImage(image);
2657 if (pixel_list->skip_list.nodes != (
SkipNode *) NULL)
2658 pixel_list->skip_list.nodes=(
SkipNode *) RelinquishAlignedMemory(
2659 pixel_list->skip_list.nodes);
2660 pixel_list=(
PixelList *) RelinquishMagickMemory(pixel_list);
2669 assert(pixel_list != (
PixelList **) NULL);
2670 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2671 if (pixel_list[i] != (
PixelList *) NULL)
2672 pixel_list[i]=DestroyPixelList(pixel_list[i]);
2673 pixel_list=(
PixelList **) RelinquishMagickMemory(pixel_list);
2677static PixelList *AcquirePixelList(
const size_t width,
const size_t height)
2682 pixel_list=(
PixelList *) AcquireMagickMemory(
sizeof(*pixel_list));
2685 (void) memset((
void *) pixel_list,0,
sizeof(*pixel_list));
2686 pixel_list->length=width*height;
2687 pixel_list->skip_list.nodes=(
SkipNode *) AcquireAlignedMemory(65537UL,
2688 sizeof(*pixel_list->skip_list.nodes));
2689 if (pixel_list->skip_list.nodes == (
SkipNode *) NULL)
2690 return(DestroyPixelList(pixel_list));
2691 (void) memset(pixel_list->skip_list.nodes,0,65537UL*
2692 sizeof(*pixel_list->skip_list.nodes));
2693 pixel_list->signature=MagickCoreSignature;
2697static PixelList **AcquirePixelListTLS(
const size_t width,
2698 const size_t height)
2709 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2710 pixel_list=(
PixelList **) AcquireQuantumMemory(number_threads,
2711 sizeof(*pixel_list));
2714 (void) memset(pixel_list,0,number_threads*
sizeof(*pixel_list));
2715 for (i=0; i < (ssize_t) number_threads; i++)
2717 pixel_list[i]=AcquirePixelList(width,height);
2718 if (pixel_list[i] == (
PixelList *) NULL)
2719 return(DestroyPixelListTLS(pixel_list));
2724static void AddNodePixelList(
PixelList *pixel_list,
const size_t color)
2739 p=(&pixel_list->skip_list);
2740 p->nodes[color].signature=pixel_list->signature;
2741 p->nodes[color].count=1;
2746 (void) memset(update,0,
sizeof(update));
2747 for (level=p->level; level >= 0; level--)
2749 while (p->nodes[search].next[level] < color)
2750 search=p->nodes[search].next[level];
2751 update[level]=search;
2756 for (level=0; ; level++)
2758 pixel_list->seed=(pixel_list->seed*42893621L)+1L;
2759 if ((pixel_list->seed & 0x300) != 0x300)
2764 if (level > (p->level+2))
2769 while (level > p->level)
2772 update[p->level]=65536UL;
2779 p->nodes[color].next[level]=p->nodes[update[level]].next[level];
2780 p->nodes[update[level]].next[level]=color;
2781 }
while (level-- > 0);
2784static inline void GetMedianPixelList(
PixelList *pixel_list,Quantum *pixel)
2798 p=(&pixel_list->skip_list);
2803 color=p->nodes[color].next[0];
2804 count+=(ssize_t) p->nodes[color].count;
2805 }
while (count <= (ssize_t) (pixel_list->length >> 1));
2806 *pixel=ScaleShortToQuantum((
unsigned short) color);
2809static inline void GetModePixelList(
PixelList *pixel_list,Quantum *pixel)
2825 p=(&pixel_list->skip_list);
2828 max_count=p->nodes[mode].count;
2832 color=p->nodes[color].next[0];
2833 if (p->nodes[color].count > max_count)
2836 max_count=p->nodes[mode].count;
2838 count+=(ssize_t) p->nodes[color].count;
2839 }
while (count < (ssize_t) pixel_list->length);
2840 *pixel=ScaleShortToQuantum((
unsigned short) mode);
2843static inline void GetNonpeakPixelList(
PixelList *pixel_list,Quantum *pixel)
2859 p=(&pixel_list->skip_list);
2861 next=p->nodes[color].next[0];
2867 next=p->nodes[color].next[0];
2868 count+=(ssize_t) p->nodes[color].count;
2869 }
while (count <= (ssize_t) (pixel_list->length >> 1));
2870 if ((previous == 65536UL) && (next != 65536UL))
2873 if ((previous != 65536UL) && (next == 65536UL))
2875 *pixel=ScaleShortToQuantum((
unsigned short) color);
2878static inline void InsertPixelList(
const Quantum pixel,
PixelList *pixel_list)
2886 index=ScaleQuantumToShort(pixel);
2887 signature=pixel_list->skip_list.nodes[index].signature;
2888 if (signature == pixel_list->signature)
2890 pixel_list->skip_list.nodes[index].count++;
2893 AddNodePixelList(pixel_list,index);
2896static void ResetPixelList(
PixelList *pixel_list)
2910 p=(&pixel_list->skip_list);
2911 root=p->nodes+65536UL;
2913 for (level=0; level < 9; level++)
2914 root->next[level]=65536UL;
2915 pixel_list->seed=pixel_list->signature++;
2918MagickExport
Image *StatisticImage(
const Image *image,
const StatisticType type,
2919 const size_t width,
const size_t height,
ExceptionInfo *exception)
2921#define StatisticImageTag "Statistic/Image"
2937 **magick_restrict pixel_list;
2946 assert(image != (
Image *) NULL);
2947 assert(image->signature == MagickCoreSignature);
2948 if (IsEventLogging() != MagickFalse)
2949 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2951 assert(exception->signature == MagickCoreSignature);
2952 statistic_image=CloneImage(image,0,0,MagickTrue,
2954 if (statistic_image == (
Image *) NULL)
2955 return((
Image *) NULL);
2956 status=SetImageStorageClass(statistic_image,DirectClass,exception);
2957 if (status == MagickFalse)
2959 statistic_image=DestroyImage(statistic_image);
2960 return((
Image *) NULL);
2962 pixel_list=AcquirePixelListTLS(MagickMax(width,1),MagickMax(height,1));
2965 statistic_image=DestroyImage(statistic_image);
2966 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2971 center=(ssize_t) GetPixelChannels(image)*((ssize_t) image->columns+
2972 MagickMax((ssize_t) width,1L))*(MagickMax((ssize_t) height,1)/2L)+(ssize_t)
2973 GetPixelChannels(image)*(MagickMax((ssize_t) width,1L)/2L);
2976 image_view=AcquireVirtualCacheView(image,exception);
2977 statistic_view=AcquireAuthenticCacheView(statistic_image,exception);
2978#if defined(MAGICKCORE_OPENMP_SUPPORT)
2979 #pragma omp parallel for schedule(static) shared(progress,status) \
2980 magick_number_threads(image,statistic_image,statistic_image->rows,1)
2982 for (y=0; y < (ssize_t) statistic_image->rows; y++)
2985 id = GetOpenMPThreadId();
2996 if (status == MagickFalse)
2998 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) MagickMax(width,1)/2L),y-
2999 (ssize_t) (MagickMax(height,1)/2L),image->columns+MagickMax(width,1),
3000 MagickMax(height,1),exception);
3001 q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns, 1,exception);
3002 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3007 for (x=0; x < (ssize_t) statistic_image->columns; x++)
3012 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3025 *magick_restrict pixels;
3033 PixelChannel channel = GetPixelChannelChannel(image,i);
3034 PixelTrait traits = GetPixelChannelTraits(image,channel);
3035 PixelTrait statistic_traits=GetPixelChannelTraits(statistic_image,
3037 if ((traits == UndefinedPixelTrait) ||
3038 (statistic_traits == UndefinedPixelTrait))
3040 if (((statistic_traits & CopyPixelTrait) != 0) ||
3041 (GetPixelWriteMask(image,p) <= (QuantumRange/2)))
3043 SetPixelChannel(statistic_image,channel,p[center+i],q);
3046 if ((statistic_traits & UpdatePixelTrait) == 0)
3054 ResetPixelList(pixel_list[
id]);
3055 for (v=0; v < (ssize_t) MagickMax(height,1); v++)
3057 for (u=0; u < (ssize_t) MagickMax(width,1); u++)
3059 if ((type == MedianStatistic) || (type == ModeStatistic) ||
3060 (type == NonpeakStatistic))
3062 InsertPixelList(pixels[i],pixel_list[
id]);
3063 pixels+=(ptrdiff_t) GetPixelChannels(image);
3067 if ((
double) pixels[i] < minimum)
3068 minimum=(double) pixels[i];
3069 if ((
double) pixels[i] > maximum)
3070 maximum=(double) pixels[i];
3071 sum+=(double) pixels[i];
3072 sum_squared+=(double) pixels[i]*(
double) pixels[i];
3073 pixels+=(ptrdiff_t) GetPixelChannels(image);
3075 pixels+=(ptrdiff_t) GetPixelChannels(image)*image->columns;
3079 case ContrastStatistic:
3081 pixel=ClampToQuantum(MagickAbsoluteValue((maximum-minimum)*
3082 PerceptibleReciprocal(maximum+minimum)));
3085 case GradientStatistic:
3087 pixel=ClampToQuantum(MagickAbsoluteValue(maximum-minimum));
3090 case MaximumStatistic:
3092 pixel=ClampToQuantum(maximum);
3098 pixel=ClampToQuantum(sum/area);
3101 case MedianStatistic:
3103 GetMedianPixelList(pixel_list[
id],&pixel);
3106 case MinimumStatistic:
3108 pixel=ClampToQuantum(minimum);
3113 GetModePixelList(pixel_list[
id],&pixel);
3116 case NonpeakStatistic:
3118 GetNonpeakPixelList(pixel_list[
id],&pixel);
3121 case RootMeanSquareStatistic:
3123 pixel=ClampToQuantum(sqrt(sum_squared/area));
3126 case StandardDeviationStatistic:
3128 pixel=ClampToQuantum(sqrt(sum_squared/area-(sum/area*sum/area)));
3132 SetPixelChannel(statistic_image,channel,pixel,q);
3134 p+=(ptrdiff_t) GetPixelChannels(image);
3135 q+=(ptrdiff_t) GetPixelChannels(statistic_image);
3137 if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
3139 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3144#if defined(MAGICKCORE_OPENMP_SUPPORT)
3148 proceed=SetImageProgress(image,StatisticImageTag,progress,image->rows);
3149 if (proceed == MagickFalse)
3153 statistic_view=DestroyCacheView(statistic_view);
3154 image_view=DestroyCacheView(image_view);
3155 pixel_list=DestroyPixelListTLS(pixel_list);
3156 if (status == MagickFalse)
3157 statistic_image=DestroyImage(statistic_image);
3158 return(statistic_image);