]> granicus.if.org Git - imagemagick/commitdiff
...
authorCristy <urban-warrior@imagemagick.org>
Fri, 10 Feb 2017 18:03:10 +0000 (13:03 -0500)
committerCristy <urban-warrior@imagemagick.org>
Fri, 10 Feb 2017 18:03:10 +0000 (13:03 -0500)
ChangeLog
MagickCore/fx.c
MagickCore/statistic.c

index 312a7fd9929781374c4e3e6938c91ef0ac965ecb..79cf1fe94c5316a58ba084f9fbe65e155f5e79d4 100644 (file)
--- 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  <quetzlzacatenango@image...>
+2017-02-09  7.0.4-8 Cristy  <quetzlzacatenango@image...>
   * 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  <quetzlzacatenango@image...>
   * Release ImageMagick version 7.0.4-7, GIT revision 19513:5783e57:20170204.
index 8188cca86781ef6f1a0a1a7171f85c9fc6cff477..bb035e5293555da74d69d45b30a539e9b23a3e5f 100644 (file)
@@ -133,8 +133,7 @@ struct _FxInfo
   ExceptionInfo
     *exception;
 };
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -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);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -408,8 +406,7 @@ MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
     noise_image=DestroyImage(noise_image);
   return(noise_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -564,8 +561,7 @@ MagickExport Image *BlueShiftImage(const Image *image,const double factor,
     shift_image=DestroyImage(shift_image);
   return(shift_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -627,8 +623,7 @@ MagickExport Image *CharcoalImage(const Image *image,const double radius,
   (void) GrayscaleImage(charcoal_image,image->intensity,exception);
   return(charcoal_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -810,8 +805,7 @@ MagickExport Image *ColorizeImage(const Image *image,const char *blend,
     colorize_image=DestroyImage(colorize_image);
   return(colorize_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -1033,8 +1027,7 @@ MagickExport Image *ColorMatrixImage(const Image *image,
     color_image=DestroyImage(color_image);
   return(color_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -1073,8 +1066,7 @@ MagickPrivate FxInfo *DestroyFxInfo(FxInfo *fx_info)
   fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
   return(fx_info);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -2984,8 +2976,7 @@ MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
     &beta,exception);
   return(exception->severity == OptionError ? MagickFalse : MagickTrue);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -3205,8 +3196,7 @@ MagickExport Image *FxImage(const Image *image,const char *expression,
     fx_image=DestroyImage(fx_image);
   return(fx_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -3417,8 +3407,7 @@ MagickExport Image *ImplodeImage(const Image *image,const double amount,
     implode_image=DestroyImage(implode_image);
   return(implode_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -3654,8 +3643,7 @@ MagickExport Image *MorphImages(const Image *image,const size_t number_frames,
     }
   return(GetFirstImageInList(morph_images));
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -3949,8 +3937,7 @@ MagickExport MagickBooleanType PlasmaImage(Image *image,
   image_view=DestroyCacheView(image_view);
   return(status);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -4142,8 +4129,7 @@ MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
   polaroid_image=trim_image;
   return(polaroid_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -4292,8 +4278,7 @@ MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
     sepia_image=DestroyImage(sepia_image);
   return(sepia_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -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);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -4607,8 +4591,7 @@ MagickExport Image *SketchImage(const Image *image,const double radius,
   blend_image=DestroyImage(blend_image);
   return(sketch_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -4745,8 +4728,7 @@ MagickExport MagickBooleanType SolarizeImage(Image *image,
   image_view=DestroyCacheView(image_view);
   return(status);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -4917,8 +4899,7 @@ MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
     stegano_image=DestroyImage(stegano_image);
   return(stegano_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -5061,8 +5042,7 @@ MagickExport Image *StereoAnaglyphImage(const Image *left_image,
     stereo_image=DestroyImage(stereo_image);
   return(stereo_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -5268,8 +5248,7 @@ MagickExport Image *SwirlImage(const Image *image,double degrees,
     swirl_image=DestroyImage(swirl_image);
   return(swirl_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -5481,8 +5460,7 @@ MagickExport Image *TintImage(const Image *image,const char *blend,
     tint_image=DestroyImage(tint_image);
   return(tint_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -5583,8 +5561,7 @@ MagickExport Image *VignetteImage(const Image *image,const double radius,
     (void) TransformImageColorspace(vignette_image,image->colorspace,exception);
   return(vignette_image);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
index 17a1e40add3ca71992777397eddcbe9881c22cd2..a63d1d72c4d46139cd933d49323ee59e7b3c4ccc 100644 (file)
@@ -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;