return(n);
}
+static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
+ const char *name,const ChannelMoments *channel_moments)
+{
+ ssize_t
+ n;
+
+ n=FormatLocaleFile(file,"%s:\n",name);
+ n+=FormatLocaleFile(file," i1: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I1);
+ n+=FormatLocaleFile(file," i2: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I2);
+ n+=FormatLocaleFile(file," i3: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I3);
+ n+=FormatLocaleFile(file," i4: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I4);
+ n+=FormatLocaleFile(file," i5: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I5);
+ n+=FormatLocaleFile(file," i6: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I6);
+ n+=FormatLocaleFile(file," i7: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I7);
+ n+=FormatLocaleFile(file," i8: %.*g",GetMagickPrecision(),
+ channel_moments[channel].I8);
+ return(n);
+}
+
static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel,
const char *name,const double scale,
const ChannelStatistics *channel_statistics)
ChannelFeatures
*channel_features;
+ ChannelMoments
+ *channel_moments;
+
ChannelStatistics
*channel_statistics;
(void) FormatLocaleFile(file," Colorspace: %s\n",CommandOptionToMnemonic(
MagickColorspaceOptions,(ssize_t) image->colorspace));
channel_statistics=(ChannelStatistics *) NULL;
+ channel_moments=(ChannelMoments *) NULL;
channel_features=(ChannelFeatures *) NULL;
colorspace=image->colorspace;
scale=1;
channel_statistics=GetImageStatistics(image,exception);
if (channel_statistics == (ChannelStatistics *) NULL)
return(MagickFalse);
+ artifact=GetImageArtifact(image,"identify:moments");
+ if (artifact != (const char *) NULL)
+ channel_moments=GetImageMoments(image,exception);
artifact=GetImageArtifact(image,"identify:features");
if (artifact != (const char *) NULL)
{
channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
channel_statistics);
}
+ if (channel_moments != (ChannelMoments *) NULL)
+ {
+ (void) FormatLocaleFile(file," Channel moments\n");
+ switch (colorspace)
+ {
+ case RGBColorspace:
+ default:
+ {
+ (void) PrintChannelMoments(file,RedPixelChannel,"Red",
+ channel_moments);
+ (void) PrintChannelMoments(file,GreenPixelChannel,"Green",
+ channel_moments);
+ (void) PrintChannelMoments(file,BluePixelChannel,"Blue",
+ channel_moments);
+ break;
+ }
+ case CMYKColorspace:
+ {
+ (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",
+ channel_moments);
+ (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta",
+ channel_moments);
+ (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow",
+ channel_moments);
+ (void) PrintChannelMoments(file,BlackPixelChannel,"Black",
+ channel_moments);
+ break;
+ }
+ case GRAYColorspace:
+ {
+ (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",
+ channel_moments);
+ break;
+ }
+ }
+ if (image->alpha_trait == BlendPixelTrait)
+ (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",
+ channel_moments);
+ channel_moments=(ChannelMoments *) RelinquishMagickMemory(
+ channel_moments);
+ }
if (channel_features != (ChannelFeatures *) NULL)
{
(void) FormatLocaleFile(file," Channel features (horizontal, vertical, "
{ "-metric", 1L, ListOperatorFlag | FireOptionFlag, MagickFalse },
{ "+minimum", 0L, DeprecateOptionFlag | FireOptionFlag, MagickTrue },
{ "-minimum", 0L, DeprecateOptionFlag | FireOptionFlag, MagickTrue },
+ { "+moments", 0L, SimpleOperatorFlag | FireOptionFlag, MagickFalse },
+ { "-moments", 0L, SimpleOperatorFlag | FireOptionFlag, MagickFalse },
{ "+mode", 1L, NonMagickOptionFlag, MagickFalse },
{ "-mode", 1L, ReplacedOptionFlag | SimpleOperatorFlag, MagickTrue },
{ "+modulate", 1L, DeprecateOptionFlag, MagickTrue },
% %
% %
% %
+% G e t I m a g e K u r t o s i s %
+% %
+% %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% GetImageKurtosis() returns the kurtosis and skewness of one or more image
+% channels.
+%
+% The format of the GetImageKurtosis method is:
+%
+% MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
+% double *skewness,ExceptionInfo *exception)
+%
+% A description of each parameter follows:
+%
+% o image: the image.
+%
+% o kurtosis: the kurtosis of the channel.
+%
+% o skewness: the skewness of the channel.
+%
+% o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
+ double *kurtosis,double *skewness,ExceptionInfo *exception)
+{
+ CacheView
+ *image_view;
+
+ double
+ area,
+ mean,
+ standard_deviation,
+ sum_squares,
+ sum_cubes,
+ sum_fourth_power;
+
+ MagickBooleanType
+ status;
+
+ ssize_t
+ y;
+
+ assert(image != (Image *) NULL);
+ assert(image->signature == MagickSignature);
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+ status=MagickTrue;
+ *kurtosis=0.0;
+ *skewness=0.0;
+ area=0.0;
+ mean=0.0;
+ standard_deviation=0.0;
+ sum_squares=0.0;
+ sum_cubes=0.0;
+ sum_fourth_power=0.0;
+ image_view=AcquireVirtualCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(static,4) shared(status) \
+ magick_threads(image,image,image->rows,1)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register const Quantum
+ *restrict p;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+ if (p == (const Quantum *) NULL)
+ {
+ status=MagickFalse;
+ continue;
+ }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ register ssize_t
+ i;
+
+ if (GetPixelReadMask(image,p) == 0)
+ {
+ p+=GetPixelChannels(image);
+ continue;
+ }
+ for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+ {
+ PixelChannel channel=GetPixelChannelChannel(image,i);
+ PixelTrait traits=GetPixelChannelTraits(image,channel);
+ if (traits == UndefinedPixelTrait)
+ continue;
+ if ((traits & UpdatePixelTrait) == 0)
+ continue;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_GetImageKurtosis)
+#endif
+ {
+ mean+=p[i];
+ sum_squares+=(double) p[i]*p[i];
+ sum_cubes+=(double) p[i]*p[i]*p[i];
+ sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
+ area++;
+ }
+ }
+ p+=GetPixelChannels(image);
+ }
+ }
+ image_view=DestroyCacheView(image_view);
+ if (area != 0.0)
+ {
+ mean/=area;
+ sum_squares/=area;
+ sum_cubes/=area;
+ sum_fourth_power/=area;
+ }
+ standard_deviation=sqrt(sum_squares-(mean*mean));
+ if (standard_deviation != 0.0)
+ {
+ *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
+ 3.0*mean*mean*mean*mean;
+ *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
+ standard_deviation;
+ *kurtosis-=3.0;
+ *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
+ *skewness/=standard_deviation*standard_deviation*standard_deviation;
+ }
+ return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% %
+% %
% G e t I m a g e M e a n %
% %
% %
% %
% %
% %
-% G e t I m a g e K u r t o s i s %
+% G e t I m a g e M o m e n t s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% GetImageKurtosis() returns the kurtosis and skewness of one or more image
-% channels.
+% GetImageMoments() returns the moments of one or more image channels.
%
-% The format of the GetImageKurtosis method is:
+% The format of the GetImageMoments method is:
%
-% MagickBooleanType GetImageKurtosis(const Image *image,double *kurtosis,
-% double *skewness,ExceptionInfo *exception)
+% ChannelMoments *GetImageMoments(const Image *image,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: the image.
%
-% o kurtosis: the kurtosis of the channel.
-%
-% o skewness: the skewness of the channel.
-%
% o exception: return any errors or warnings in this structure.
%
*/
-MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
- double *kurtosis,double *skewness,ExceptionInfo *exception)
+MagickExport ChannelMoments *GetImageMoments(const Image *image,
+ ExceptionInfo *exception)
{
+#define MaxNumberImageMoments 8
+
CacheView
*image_view;
- double
- area,
- mean,
- standard_deviation,
- sum_squares,
- sum_cubes,
- sum_fourth_power;
+ ChannelMoments
+ *channel_moments;
MagickBooleanType
+ initialize,
status;
+ register ssize_t
+ i;
+
ssize_t
y;
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+ channel_moments=(ChannelMoments *) AcquireQuantumMemory(MaxPixelChannels+1,
+ sizeof(*channel_moments));
+ if (channel_moments == (ChannelMoments *) NULL)
+ return(channel_moments);
+ (void) ResetMagickMemory(channel_moments,0,length*sizeof(*channel_moments));
+ for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
+ {
+ channel_moments[i].I1=0.0;
+ channel_moments[i].I2=0.0;
+ channel_moments[i].I3=0.0;
+ channel_moments[i].I4=0.0;
+ channel_moments[i].I5=0.0;
+ channel_moments[i].I6=0.0;
+ channel_moments[i].I7=0.0;
+ channel_moments[i].I8=0.0;
+ }
status=MagickTrue;
- *kurtosis=0.0;
- *skewness=0.0;
- area=0.0;
- mean=0.0;
- standard_deviation=0.0;
- sum_squares=0.0;
- sum_cubes=0.0;
- sum_fourth_power=0.0;
+ initialize=MagickTrue;
image_view=AcquireVirtualCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp parallel for schedule(static,4) shared(status) \
+ #pragma omp parallel for schedule(static,4) shared(status,initialize) \
magick_threads(image,image,image->rows,1)
#endif
for (y=0; y < (ssize_t) image->rows; y++)
if ((traits & UpdatePixelTrait) == 0)
continue;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
- #pragma omp critical (MagickCore_GetImageKurtosis)
+ #pragma omp critical (MagickCore_GetImageMoments)
#endif
{
- mean+=p[i];
- sum_squares+=(double) p[i]*p[i];
- sum_cubes+=(double) p[i]*p[i]*p[i];
- sum_fourth_power+=(double) p[i]*p[i]*p[i]*p[i];
- area++;
+ if (initialize != MagickFalse)
+ {
+ initialize=MagickFalse;
+ }
+ else
+ {
+ }
}
}
p+=GetPixelChannels(image);
}
}
image_view=DestroyCacheView(image_view);
- if (area != 0.0)
- {
- mean/=area;
- sum_squares/=area;
- sum_cubes/=area;
- sum_fourth_power/=area;
- }
- standard_deviation=sqrt(sum_squares-(mean*mean));
- if (standard_deviation != 0.0)
- {
- *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
- 3.0*mean*mean*mean*mean;
- *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
- standard_deviation;
- *kurtosis-=3.0;
- *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
- *skewness/=standard_deviation*standard_deviation*standard_deviation;
- }
- return(status);
+ if (status == MagickFalse)
+ channel_moments=(ChannelMoments *) RelinquishMagickMemory(channel_moments);
+ return(channel_moments);
}
\f
/*
skewness;
} ChannelStatistics;
+typedef struct _ChannelMoments
+{
+ double
+ I1,
+ I2,
+ I3,
+ I4,
+ I5,
+ I6,
+ I7,
+ I8;
+} ChannelMoments;
+
typedef enum
{
UndefinedEvaluateOperator,
extern MagickExport ChannelStatistics
*GetImageStatistics(const Image *,ExceptionInfo *);
+extern MagickExport ChannelMoments
+ *GetImageMoments(const Image *,ExceptionInfo *);
+
extern MagickExport Image
*EvaluateImages(const Image *,const MagickEvaluateOperator,ExceptionInfo *),
*PolynomialImage(const Image *,const size_t,const double *,ExceptionInfo *),
"-limit type value pixel cache resource limit",
"-mask filename associate a mask with the image",
"-matte store matte channel if the image has one",
+ "-moments report image moments",
"-monitor monitor progress",
"-ping efficiently determine image attributes",
"-precision value maximum number of significant digits to print",
(void) ModulateImage(*image,argv[i+1],exception);
break;
}
+ if (LocaleCompare("moments",option+1) == 0)
+ {
+ if (*option == '+')
+ {
+ (void) DeleteImageArtifact(*image,"identify:moments");
+ break;
+ }
+ (void) SetImageArtifact(*image,"identify:moments",argv[i+1]);
+ break;
+ }
if (LocaleCompare("monitor",option+1) == 0)
{
if (*option == '+')
(void) SetImageOption(_image_info,option+1,ArgOption(NULL));
break;
}
+ if (LocaleCompare("moments",option+1) == 0)
+ {
+ (void) SetImageOption(_image_info,"identify:moments",
+ ArgBooleanString);
+ if (IfSetOption)
+ (void) SetImageArtifact(_image,"verbose","true");
+ break;
+ }
if (LocaleCompare("monitor",option+1) == 0)
{
(void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
Resource, or Type
\-mask filename associate a mask with the image
\-matte store matte channel if the image has one
+ \-moments report image moments
\-monitor monitor progress
\-ping efficiently determine image attributes
\-precision value maximum number of significant digits to print