]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Fri, 18 Mar 2011 18:26:08 +0000 (18:26 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Fri, 18 Mar 2011 18:26:08 +0000 (18:26 +0000)
magick/effect.c
magick/effect.h
magick/option.c
magick/option.h
utilities/convert.1.in
utilities/mogrify.1.in
wand/convert.c
wand/mogrify.c

index 92334cbfba123c5ba7a756f3d5024d31a750ffb8..7fbcd8c1c7a8a6b7e7f3d4ebf348aee7f74d595b 100644 (file)
@@ -5453,6 +5453,211 @@ MagickExport Image *SpreadImage(const Image *image,const double radius,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%     S t a t i s t i c I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StatisticImage() makes each pixel the min / max / median / mode / etc. of
+%  the neighborhood of the specified radius.
+%
+%  The format of the StatisticImage method is:
+%
+%      Image *StatisticImage(const Image *image,const StatisticType type,
+%        const double radius,ExceptionInfo *exception)
+%      Image *StatisticImageChannel(const Image *image,
+%        const ChannelType channel,const StatisticType type,
+%        const double radius,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the image channel.
+%
+%    o type: the statistic type (median, mode, etc.).
+%
+%    o radius: the radius of the pixel neighborhood.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
+  const double radius,ExceptionInfo *exception)
+{
+  return(StatisticImageChannel(image,DefaultChannels,type,radius,exception));
+}
+
+MagickExport Image *StatisticImageChannel(const Image *image,
+  const ChannelType channel,const StatisticType type,const double radius,
+  ExceptionInfo *exception)
+{
+#define StatisticImageTag  "Statistic/Image"
+
+  CacheView
+    *image_view,
+    *statistic_view;
+
+  Image
+    *statistic_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelList
+    **restrict pixel_list;
+
+  size_t
+    width;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize statistics image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth2D(radius,0.5);
+  statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (statistic_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&statistic_image->exception);
+      statistic_image=DestroyImage(statistic_image);
+      return((Image *) NULL);
+    }
+  pixel_list=AcquirePixelListThreadSet(width);
+  if (pixel_list == (PixelList **) NULL)
+    {
+      statistic_image=DestroyImage(statistic_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Reduce statistics image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  statistic_view=AcquireCacheView(statistic_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) statistic_image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register const IndexPacket
+      *restrict indexes;
+
+    register const PixelPacket
+      *restrict p;
+
+    register IndexPacket
+      *restrict statistic_indexes;
+
+    register PixelPacket
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+      (width/2L),image->columns+width,width,exception);
+    q=QueueCacheViewAuthenticPixels(statistic_view,0,y,
+      statistic_image->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    statistic_indexes=GetCacheViewAuthenticIndexQueue(statistic_view);
+    for (x=0; x < (ssize_t) statistic_image->columns; x++)
+    {
+      MagickPixelPacket
+        pixel;
+
+      register const PixelPacket
+        *restrict r;
+
+      register const IndexPacket
+        *restrict s;
+
+      register ssize_t
+        u,
+        v;
+
+      r=p;
+      s=indexes+x;
+      ResetPixelList(pixel_list[id]);
+      for (v=0; v < (ssize_t) width; v++)
+      {
+        for (u=0; u < (ssize_t) width; u++)
+          InsertPixelList(image,r+u,s+u,pixel_list[id]);
+        r+=image->columns+width;
+        s+=image->columns+width;
+      }
+      switch (type)
+      {
+        case ModeStatistic: pixel=GetModePixelList(pixel_list[id]);
+        default: break;
+      }
+      if ((channel & RedChannel) != 0)
+        q->red=ClampToQuantum(pixel.red);
+      if ((channel & GreenChannel) != 0)
+        q->green=ClampToQuantum(pixel.green);
+      if ((channel & BlueChannel) != 0)
+        q->blue=ClampToQuantum(pixel.blue);
+      if ((image->matte != MagickFalse) && ((channel & OpacityChannel) != 0))
+        q->opacity=ClampToQuantum(pixel.opacity);
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        statistic_indexes[x]=(IndexPacket) ClampToQuantum(pixel.index);
+      p++;
+      q++;
+    }
+    if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_StatisticImage)
+#endif
+        proceed=SetImageProgress(image,StatisticImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  statistic_view=DestroyCacheView(statistic_view);
+  image_view=DestroyCacheView(image_view);
+  pixel_list=DestroyPixelListThreadSet(pixel_list);
+  return(statistic_image);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %     U n s h a r p M a s k I m a g e                                         %
 %                                                                             %
 %                                                                             %
index 0bd50e3f95c1bb183b6193deeb6e644713110332..9643d588e3314adffafaa4ad3e7e20007ed9f025 100644 (file)
@@ -58,6 +58,16 @@ typedef enum
   JPEGPreview
 } PreviewType;
 
+typedef enum
+{
+  UndefinedStatistic,
+  MaximumStatistic,
+  MedianStatistic,
+  MinimumStatistic,
+  ModeStatistic,
+  ReduceNoiseStatistic
+} StatisticType;
+
 extern MagickExport Image
   *AdaptiveBlurImage(const Image *,const double,const double,ExceptionInfo *),
   *AdaptiveBlurImageChannel(const Image *,const ChannelType,const double,
@@ -102,6 +112,9 @@ extern MagickExport Image
   *SharpenImageChannel(const Image *,const ChannelType,const double,
     const double,ExceptionInfo *),
   *SpreadImage(const Image *,const double,ExceptionInfo *),
+  *StatisticImage(const Image *,const StatisticType,const double,ExceptionInfo *),
+  *StatisticImageChannel(const Image *,const ChannelType,const StatisticType,
+    const double,ExceptionInfo *),
   *UnsharpMaskImage(const Image *,const double,const double,const double,
     const double,ExceptionInfo *),
   *UnsharpMaskImageChannel(const Image *,const ChannelType,const double,
index 81ef7cd86b1fc314665d8ee90b910c8259194124..cd96dff2649f58d3d697ae8ab8c0200e7336b28c 100644 (file)
@@ -597,6 +597,8 @@ static const OptionInfo
     { "-sparse-color", 2L, MagickFalse },
     { "+spread", 0L, MagickFalse },
     { "-spread", 1L, MagickFalse },
+    { "+statistic", 2L, MagickFalse },
+    { "-statistic", 2L, MagickFalse },
     { "+stegano", 0L, MagickFalse },
     { "-stegano", 1L, MagickFalse },
     { "+stereo", 0L, MagickFalse },
@@ -1442,6 +1444,15 @@ static const OptionInfo
     { "Voronoi", (ssize_t) VoronoiColorInterpolate, MagickFalse },
     { (char *) NULL, (ssize_t) UndefinedResource, MagickFalse }
   },
+  StatisticOptions[] =
+  {
+    { "Undefined", (ssize_t) UndefinedStatistic, MagickTrue },
+    { "Maximum", (ssize_t) MaximumStatistic, MagickFalse },
+    { "Median", (ssize_t) MedianStatistic, MagickFalse },
+    { "Minimum", (ssize_t) MinimumStatistic, MagickFalse },
+    { "Mode", (ssize_t) ModeStatistic, MagickFalse },
+    { (char *) NULL, (ssize_t) UndefinedMethod, MagickFalse }
+  },
   StorageOptions[] =
   {
     { "Undefined", (ssize_t) UndefinedPixel, MagickTrue },
@@ -1809,6 +1820,7 @@ static const OptionInfo *GetOptionInfo(const MagickOption option)
     case MagickResolutionOptions: return(ResolutionOptions);
     case MagickResourceOptions: return(ResourceOptions);
     case MagickSparseColorOptions: return(SparseColorOptions);
+    case MagickStatisticOptions: return(StatisticOptions);
     case MagickStorageOptions: return(StorageOptions);
     case MagickStretchOptions: return(StretchOptions);
     case MagickStyleOptions: return(StyleOptions);
index 3e05183f50e11896c62f6631a36b0231a74a2819..d9dff496216df6d471d5b78b9563a11924d1bc67 100644 (file)
@@ -85,6 +85,7 @@ typedef enum
   MagickResolutionOptions,
   MagickResourceOptions,
   MagickSparseColorOptions,
+  MagickStatisticOptions,
   MagickStorageOptions,
   MagickStretchOptions,
   MagickStyleOptions,
index 42dfeed576492aebaf5cd9849a8f1ac0a7094310..045b8c30467c55c3a77bc3de50e44675e14a755a 100644 (file)
@@ -76,6 +76,8 @@ Image Settings:
   \-scene value         image scene number
   \-seed value          seed a new sequence of pseudo-random numbers
   \-size geometry       width and height of image
+  \-statistic type radius
+                       replace each pixel with corresponding statistic from the neighborhood
   \-stretch type        render text with this font stretch
   \-stroke color        graphic primitive stroke color
   \-strokewidth value   graphic primitive stroke width
index 571267c011bbe96fb05a59196bd30bf427b8622b..cbdba4d0894d87187428d0551d897186b65c5f05 100644 (file)
@@ -206,6 +206,8 @@ Image Operators:
   \-solarize threshold  negate all pixels above the threshold level
   \-splice geometry     splice the background color into the image
   \-spread amount       displace image pixels by a random amount
+  \-statistic type radius
+                       replace each pixel with corresponding statistic from the neighborhood
   \-strip               strip image of all profiles and comments
   \-swirl degrees       swirl image pixels about the center
   \-threshold value     threshold the image
index df3ad1ad753363ba1234ac6813950f97d324f7a6..32f68152e9dfcfbc43dc35ffababb1f7eb119576 100644 (file)
@@ -269,6 +269,8 @@ static MagickBooleanType ConvertUsage(void)
       "                     fill in a image based on a few color points",
       "-splice geometry     splice the background color into the image",
       "-spread radius       displace image pixels by a random amount",
+      "-statistic type radius",
+      "                     replace each pixel with corresponding statistic from the neighborhood",
       "-strip               strip image of all profiles and comments",
       "-swirl degrees       swirl image pixels about the center",
       "-threshold value     threshold the image",
@@ -2605,6 +2607,27 @@ WandExport MagickBooleanType ConvertImageCommand(ImageInfo *image_info,
               ThrowConvertException(OptionError,"MissingArgument",option);
             break;
           }
+        if (LocaleCompare("statistic",option+1) == 0)
+          {
+            ssize_t
+              op;
+
+            if (*option == '+')
+              break;
+            i++;
+            if (i == (ssize_t) argc)
+              ThrowConvertException(OptionError,"MissingArgument",option);
+            op=ParseMagickOption(MagickStatisticOptions,MagickFalse,argv[i]);
+            if (op < 0)
+              ThrowConvertException(OptionError,"UnrecognizedStatisticType",
+                argv[i]);
+            i++;
+            if (i == (ssize_t) (argc-1))
+              ThrowConvertException(OptionError,"MissingArgument",option);
+            if (IsGeometry(argv[i]) == MagickFalse)
+              ThrowConvertInvalidArgumentException(option,argv[i]);
+            break;
+          }
         if (LocaleCompare("stretch",option+1) == 0)
           {
             ssize_t
index 8d592d1039dacb841915bbeee1c1653a06b7c9e0..40d037d6877108ebf3ecfde280b016dea6ccd714 100644 (file)
@@ -3156,6 +3156,26 @@ WandExport MagickBooleanType MogrifyImage(ImageInfo *image_info,const int argc,
             *image=spread_image;
             break;
           }
+        if (LocaleCompare("statistic",option+1) == 0)
+          {
+            Image
+              *statistic_image;
+
+            StatisticType
+              type;
+
+            (void) SyncImageSettings(mogrify_info,*image);
+            type=(StatisticType) ParseMagickOption(MagickStatisticOptions,
+              MagickFalse,argv[i+1]);
+            (void) ParseGeometry(argv[i+2],&geometry_info);
+            statistic_image=StatisticImageChannel(*image,channel,type,
+              geometry_info.rho,exception);
+            if (statistic_image == (Image *) NULL)
+              break;
+            *image=DestroyImage(*image);
+            *image=statistic_image;
+            break;
+          }
         if (LocaleCompare("stretch",option+1) == 0)
           {
             if (*option == '+')
@@ -3765,6 +3785,8 @@ static MagickBooleanType MogrifyUsage(void)
       "                     fill in a image based on a few color points",
       "-splice geometry     splice the background color into the image",
       "-spread radius       displace image pixels by a random amount",
+      "-statistic type radius",
+      "                     replace each pixel with corresponding statistic from the neighborhood",
       "-strip               strip image of all profiles and comments",
       "-swirl degrees       swirl image pixels about the center",
       "-threshold value     threshold the image",
@@ -6046,6 +6068,27 @@ WandExport MagickBooleanType MogrifyImageCommand(ImageInfo *image_info,
               ThrowMogrifyInvalidArgumentException(option,argv[i]);
             break;
           }
+        if (LocaleCompare("statistic",option+1) == 0)
+          {
+            ssize_t
+              op;
+
+            if (*option == '+')
+              break;
+            i++;
+            if (i == (ssize_t) argc)
+              ThrowMogrifyException(OptionError,"MissingArgument",option);
+            op=ParseMagickOption(MagickStatisticOptions,MagickFalse,argv[i]);
+            if (op < 0)
+              ThrowMogrifyException(OptionError,"UnrecognizedStatisticType",
+                argv[i]);
+            i++;
+            if (i == (ssize_t) (argc-1))
+              ThrowMogrifyException(OptionError,"MissingArgument",option);
+            if (IsGeometry(argv[i]) == MagickFalse)
+              ThrowMogrifyInvalidArgumentException(option,argv[i]);
+            break;
+          }
         if (LocaleCompare("stretch",option+1) == 0)
           {
             ssize_t