From 3a5f10d7baf244eb49707d6759bc94eef14c567d Mon Sep 17 00:00:00 2001 From: Cristy Date: Fri, 10 Feb 2017 13:03:10 -0500 Subject: [PATCH] ... --- ChangeLog | 6 ++- MagickCore/fx.c | 77 +++++++++++------------------- MagickCore/statistic.c | 106 ++++++++++++++++++++++++++--------------- 3 files changed, 100 insertions(+), 89 deletions(-) diff --git a/ChangeLog b/ChangeLog index 312a7fd99..79cf1fe94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,9 +2,13 @@ * Fixed memory leak when creating nested exceptions in Magick++ (reference https://www.imagemagick.org/discourse-server/viewtopic.php?f=23&p=142634) -2017-02-07 7.0.4-8 Cristy +2017-02-09 7.0.4-8 Cristy * Unbreak build without JPEG support (reference https://github.com/ImageMagick/ImageMagick/pull/373). + * Document behavior change in the security policy (thanks to yoya @ + https://blog.awm.jp/2017/02/09/imagemagick-en/). + * Return unbiased standard deviation for image statistics (reference + https://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=31377). 2017-02-04 7.0.4-7 Cristy * Release ImageMagick version 7.0.4-7, GIT revision 19513:5783e57:20170204. diff --git a/MagickCore/fx.c b/MagickCore/fx.c index 8188cca86..bb035e529 100644 --- a/MagickCore/fx.c +++ b/MagickCore/fx.c @@ -133,8 +133,7 @@ struct _FxInfo ExceptionInfo *exception; }; - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -150,19 +149,19 @@ struct _FxInfo % % The format of the AcquireFxInfo method is: % -% FxInfo *AcquireFxInfo(Image *image,const char *expression, +% FxInfo *AcquireFxInfo(Image *images,const char *expression, % ExceptionInfo *exception) % % A description of each parameter follows: % -% o image: the image. +% o images: the image sequence. % % o expression: the expression. % % o exception: return any errors or warnings in this structure. % */ -MagickPrivate FxInfo *AcquireFxInfo(const Image *image,const char *expression, +MagickPrivate FxInfo *AcquireFxInfo(const Image *images,const char *expression, ExceptionInfo *exception) { char @@ -182,7 +181,7 @@ MagickPrivate FxInfo *AcquireFxInfo(const Image *image,const char *expression, ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info)); fx_info->exception=AcquireExceptionInfo(); - fx_info->images=image; + fx_info->images=images; fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory, RelinquishAlignedMemory); fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory, @@ -233,8 +232,7 @@ MagickPrivate FxInfo *AcquireFxInfo(const Image *image,const char *expression, (void) SubstituteString(&fx_info->expression,"**",fx_op); return(fx_info); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -408,8 +406,7 @@ MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type, noise_image=DestroyImage(noise_image); return(noise_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -564,8 +561,7 @@ MagickExport Image *BlueShiftImage(const Image *image,const double factor, shift_image=DestroyImage(shift_image); return(shift_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -627,8 +623,7 @@ MagickExport Image *CharcoalImage(const Image *image,const double radius, (void) GrayscaleImage(charcoal_image,image->intensity,exception); return(charcoal_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -810,8 +805,7 @@ MagickExport Image *ColorizeImage(const Image *image,const char *blend, colorize_image=DestroyImage(colorize_image); return(colorize_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -1033,8 +1027,7 @@ MagickExport Image *ColorMatrixImage(const Image *image, color_image=DestroyImage(color_image); return(color_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -1073,8 +1066,7 @@ MagickPrivate FxInfo *DestroyFxInfo(FxInfo *fx_info) fx_info=(FxInfo *) RelinquishMagickMemory(fx_info); return(fx_info); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -2984,8 +2976,7 @@ MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info, &beta,exception); return(exception->severity == OptionError ? MagickFalse : MagickTrue); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -3205,8 +3196,7 @@ MagickExport Image *FxImage(const Image *image,const char *expression, fx_image=DestroyImage(fx_image); return(fx_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -3417,8 +3407,7 @@ MagickExport Image *ImplodeImage(const Image *image,const double amount, implode_image=DestroyImage(implode_image); return(implode_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -3654,8 +3643,7 @@ MagickExport Image *MorphImages(const Image *image,const size_t number_frames, } return(GetFirstImageInList(morph_images)); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -3949,8 +3937,7 @@ MagickExport MagickBooleanType PlasmaImage(Image *image, image_view=DestroyCacheView(image_view); return(status); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4142,8 +4129,7 @@ MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info, polaroid_image=trim_image; return(polaroid_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4292,8 +4278,7 @@ MagickExport Image *SepiaToneImage(const Image *image,const double threshold, sepia_image=DestroyImage(sepia_image); return(sepia_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4439,8 +4424,7 @@ MagickExport Image *ShadowImage(const Image *image,const double alpha, shadow_image->page.y+=y_offset-(ssize_t) border_info.height; return(shadow_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4607,8 +4591,7 @@ MagickExport Image *SketchImage(const Image *image,const double radius, blend_image=DestroyImage(blend_image); return(sketch_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4745,8 +4728,7 @@ MagickExport MagickBooleanType SolarizeImage(Image *image, image_view=DestroyCacheView(image_view); return(status); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -4917,8 +4899,7 @@ MagickExport Image *SteganoImage(const Image *image,const Image *watermark, stegano_image=DestroyImage(stegano_image); return(stegano_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -5061,8 +5042,7 @@ MagickExport Image *StereoAnaglyphImage(const Image *left_image, stereo_image=DestroyImage(stereo_image); return(stereo_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -5268,8 +5248,7 @@ MagickExport Image *SwirlImage(const Image *image,double degrees, swirl_image=DestroyImage(swirl_image); return(swirl_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -5481,8 +5460,7 @@ MagickExport Image *TintImage(const Image *image,const char *blend, tint_image=DestroyImage(tint_image); return(tint_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % @@ -5583,8 +5561,7 @@ MagickExport Image *VignetteImage(const Image *image,const double radius, (void) TransformImageColorspace(vignette_image,image->colorspace,exception); return(vignette_image); } - - + /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % diff --git a/MagickCore/statistic.c b/MagickCore/statistic.c index 17a1e40ad..a63d1d72c 100644 --- a/MagickCore/statistic.c +++ b/MagickCore/statistic.c @@ -1142,16 +1142,11 @@ MagickExport MagickBooleanType GetImageEntropy(const Image *image, if ((traits & UpdatePixelTrait) == 0) continue; channel_statistics[CompositePixelChannel].entropy+= - channel_statistics[i].entropy; + channel_statistics[channel].entropy; area++; } - if (area > MagickEpsilon) - { - channel_statistics[CompositePixelChannel].entropy/=area; - channel_statistics[CompositePixelChannel].standard_deviation= - sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area); - } - *entropy=channel_statistics[CompositePixelChannel].entropy; + area=PerceptibleReciprocal(area); + *entropy=area*channel_statistics[CompositePixelChannel].entropy; channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( channel_statistics); return(MagickTrue); @@ -1323,13 +1318,11 @@ MagickExport MagickBooleanType GetImageKurtosis(const Image *image, } } image_view=DestroyCacheView(image_view); - if (area != 0.0) - { - mean/=area; - sum_squares/=area; - sum_cubes/=area; - sum_fourth_power/=area; - } + area=PerceptibleReciprocal(area); + mean*=area; + sum_squares*=area; + sum_cubes*=area; + sum_fourth_power*=area; standard_deviation=sqrt(sum_squares-(mean*mean)); if (standard_deviation != 0.0) { @@ -1404,20 +1397,15 @@ MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean, continue; if ((traits & UpdatePixelTrait) == 0) continue; - channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean; + channel_statistics[CompositePixelChannel].mean+= + channel_statistics[channel].mean; channel_statistics[CompositePixelChannel].standard_deviation+= - channel_statistics[i].variance-channel_statistics[i].mean* - channel_statistics[i].mean; + channel_statistics[channel].standard_deviation; area++; } - if (area > MagickEpsilon) - { - channel_statistics[CompositePixelChannel].mean/=area; - channel_statistics[CompositePixelChannel].standard_deviation= - sqrt(channel_statistics[CompositePixelChannel].standard_deviation/area); - } - *mean=channel_statistics[CompositePixelChannel].mean; - *standard_deviation= + area=PerceptibleReciprocal(area); + *mean=area*channel_statistics[CompositePixelChannel].mean; + *standard_deviation=area* channel_statistics[CompositePixelChannel].standard_deviation; channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( channel_statistics); @@ -1820,7 +1808,6 @@ MagickExport ChannelPerceptualHash *GetImagePerceptualHash(const Image *image, Image *hash_image; - size_t j; @@ -2088,6 +2075,9 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, register ssize_t x; + /* + Compute general statistics. + */ p=GetVirtualPixels(image,0,y,image->columns,1,exception); if (p == (const Quantum *) NULL) break; @@ -2137,6 +2127,51 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, } } for (i=0; i < (ssize_t) MaxPixelChannels; i++) + { + /* + Compute mean statistic. + */ + double area=PerceptibleReciprocal(channel_statistics[i].area); + channel_statistics[i].mean=area*channel_statistics[i].sum; + } + for (y=0; y < (ssize_t) image->rows; y++) + { + register const Quantum + *magick_restrict p; + + register ssize_t + x; + + /* + Compute variance statistic. + */ + p=GetVirtualPixels(image,0,y,image->columns,1,exception); + if (p == (const Quantum *) NULL) + break; + for (x=0; x < (ssize_t) image->columns; x++) + { + register ssize_t + i; + + if (GetPixelWriteMask(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; + channel_statistics[channel].variance+= + (p[i]-channel_statistics[channel].mean)* + (p[i]-channel_statistics[channel].mean); + } + p+=GetPixelChannels(image); + } + } + for (i=0; i < (ssize_t) MaxPixelChannels; i++) { double area, @@ -2150,11 +2185,6 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, channel_statistics[i].sum_squared*=area; channel_statistics[i].sum_cubed*=area; channel_statistics[i].sum_fourth_power*=area; - channel_statistics[i].mean=channel_statistics[i].sum; - channel_statistics[i].variance=channel_statistics[i].sum_squared; - channel_statistics[i].standard_deviation=sqrt( - channel_statistics[i].variance-(channel_statistics[i].mean* - channel_statistics[i].mean)); number_bins=0.0; for (j=0; j < (ssize_t) (MaxMap+1U); j++) if (histogram[GetPixelChannels(image)*j+i] > 0.0) @@ -2169,6 +2199,9 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, channel_statistics[i].entropy+=-count*MagickLog10(count)/ MagickLog10(number_bins); } + area=PerceptibleReciprocal(channel_statistics[i].area-1.0); + channel_statistics[i].standard_deviation=sqrt(area* + channel_statistics[i].variance); } for (i=0; i < (ssize_t) MaxPixelChannels; i++) { @@ -2191,11 +2224,9 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, channel_statistics[i].sum_fourth_power; channel_statistics[CompositePixelChannel].mean+=channel_statistics[i].mean; channel_statistics[CompositePixelChannel].variance+= - channel_statistics[i].variance-channel_statistics[i].mean* - channel_statistics[i].mean; + channel_statistics[i].variance; channel_statistics[CompositePixelChannel].standard_deviation+= - channel_statistics[i].variance-channel_statistics[i].mean* - channel_statistics[i].mean; + channel_statistics[i].standard_deviation; if (channel_statistics[i].entropy > MagickEpsilon) channel_statistics[CompositePixelChannel].entropy+= channel_statistics[i].entropy; @@ -2208,8 +2239,7 @@ MagickExport ChannelStatistics *GetImageStatistics(const Image *image, channel_statistics[CompositePixelChannel].sum_fourth_power/=channels; channel_statistics[CompositePixelChannel].mean/=channels; channel_statistics[CompositePixelChannel].variance/=channels; - channel_statistics[CompositePixelChannel].standard_deviation= - sqrt(channel_statistics[CompositePixelChannel].standard_deviation/channels); + channel_statistics[CompositePixelChannel].standard_deviation/=channels; channel_statistics[CompositePixelChannel].kurtosis/=channels; channel_statistics[CompositePixelChannel].skewness/=channels; channel_statistics[CompositePixelChannel].entropy/=channels; -- 2.40.0