]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Sat, 11 Dec 2010 02:17:57 +0000 (02:17 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Sat, 11 Dec 2010 02:17:57 +0000 (02:17 +0000)
ChangeLog
magick/compare.c
magick/compare.h
magick/option.c
wand/compare.c

index d9d96812115a54e2b2aab4fd5f0cbc28030c08ac..43399b3ee4be7cd2a1060445d3bd01f3c63e0368 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
   * Account for virtual canvas for the -flip / -flop options (reference
     http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=17626).
   * Also for -transpose and transverse options
+  * Support -metric fuzz option.
 
 2010-12-09  6.6.6-4 Anthony Thyssen <A.Thyssen@griffith...>
   * Replace IsMagickColorSimilar() which provides the Fuzz Factor threshold
index 890f14ac39c834716a59a1fe8f42123146d9fd19..f54875480a09c89cc52748a940505732a855364b 100644 (file)
@@ -467,6 +467,133 @@ static size_t GetNumberChannels(const Image *image,
   return(channels);
 }
 
+static MagickBooleanType GetFuzzDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  ssize_t
+    y;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[AllChannels+1];
+
+    register const IndexPacket
+      *restrict indexes,
+      *restrict reconstruct_indexes;
+
+    register const PixelPacket
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,
+      reconstruct_image->columns,1,exception);
+    if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    indexes=GetCacheViewVirtualIndexQueue(image_view);
+    reconstruct_indexes=GetCacheViewVirtualIndexQueue(reconstruct_view);
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance,
+        scale;
+
+      scale=1.0;
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte != MagickFalse)
+            scale*=QuantumScale*GetAlphaPixelComponent(p);
+          if (reconstruct_image->matte != MagickFalse)
+            scale*=QuantumScale*GetAlphaPixelComponent(q);
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          scale*=(MagickRealType) (QuantumScale*(QuantumRange-indexes[x]));
+          scale*=(MagickRealType) (QuantumScale*(QuantumRange-
+            reconstruct_indexes[x]));
+        }
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*(p->red-(MagickRealType) q->red);
+          channel_distortion[RedChannel]+=scale*distance*distance;
+          channel_distortion[AllChannels]+=scale*distance*distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*(p->green-(MagickRealType) q->green);
+          channel_distortion[GreenChannel]+=scale*distance*distance;
+          channel_distortion[AllChannels]+=scale*distance*distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*(p->blue-(MagickRealType) q->blue);
+          channel_distortion[BlueChannel]+=scale*distance*distance;
+          channel_distortion[AllChannels]+=scale*distance*distance;
+        }
+      if (((channel & OpacityChannel) != 0) && ((image->matte != MagickFalse) ||          (reconstruct_image->matte != MagickFalse)))
+        {
+          distance=QuantumScale*((image->matte != MagickFalse ? p->opacity :
+            OpaqueOpacity)-(reconstruct_image->matte != MagickFalse ?
+            q->opacity : OpaqueOpacity));
+          channel_distortion[OpacityChannel]+=QuantumScale*distance*distance;
+          channel_distortion[AllChannels]+=QuantumScale*distance*distance;
+        }
+      if (((channel & IndexChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*(indexes[x]-(MagickRealType)
+            reconstruct_indexes[x]);
+          channel_distortion[BlackChannel]+=scale*distance*distance;
+          channel_distortion[AllChannels]+=scale*distance*distance;
+        }
+      p++;
+      q++;
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanSquaredError)
+#endif
+    for (i=0; i <= (ssize_t) AllChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (ssize_t) AllChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[AllChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
 static MagickBooleanType GetMeanAbsoluteDistortion(const Image *image,
   const Image *reconstruct_image,const ChannelType channel,
   double *distortion,ExceptionInfo *exception)
@@ -1172,6 +1299,12 @@ MagickExport MagickBooleanType GetImageChannelDistortion(Image *image,
         channel_distortion,exception);
       break;
     }
+    case FuzzErrorMetric:
+    {
+      status=GetFuzzDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
     case MeanAbsoluteErrorMetric:
     {
       status=GetMeanAbsoluteDistortion(image,reconstruct_image,channel,
@@ -1299,6 +1432,12 @@ MagickExport double *GetImageChannelDistortions(Image *image,
         channel_distortion,exception);
       break;
     }
+    case FuzzErrorMetric:
+    {
+      status=GetFuzzDistortion(image,reconstruct_image,AllChannels,
+        channel_distortion,exception);
+      break;
+    }
     case MeanAbsoluteErrorMetric:
     {
       status=GetMeanAbsoluteDistortion(image,reconstruct_image,AllChannels,
index 4710e1e0275279e29e0d75d70b10c180fb402c86..a0439d27307918a90ecfa84f5fd6303c78a4d0c8 100644 (file)
@@ -34,7 +34,8 @@ typedef enum
   PeakAbsoluteErrorMetric,
   PeakSignalToNoiseRatioMetric,
   RootMeanSquaredErrorMetric,
-  NormalizedCrossCorrelationErrorMetric
+  NormalizedCrossCorrelationErrorMetric,
+  FuzzErrorMetric
 } MetricType;
 
 extern MagickExport double
index f5f80858c3bcc9f759771fb35cba710f6b2f4361..24b65949170b33604f0ef87961e9201100ff1181 100644 (file)
@@ -1242,6 +1242,7 @@ static const OptionInfo
   {
     { "Undefined", (ssize_t) UndefinedMetric, MagickTrue },
     { "AE", (ssize_t) AbsoluteErrorMetric, MagickFalse },
+    { "Fuzz", (ssize_t) FuzzErrorMetric, MagickFalse },
     { "MAE", (ssize_t) MeanAbsoluteErrorMetric, MagickFalse },
     { "MEPP", (ssize_t) MeanErrorPerPixelMetric, MagickFalse },
     { "MSE", (ssize_t) MeanSquaredErrorMetric, MagickFalse },
index 3034d0a1db7ab0f87875ecea5f8f1aa180bd42f4..23040fc2a51f2200b4de9612b254ac43f00c45c9 100644 (file)
@@ -996,6 +996,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
         {
           switch (metric)
           {
+            case FuzzErrorMetric:
             case MeanAbsoluteErrorMetric:
             case MeanSquaredErrorMetric:
             case RootMeanSquaredErrorMetric:
@@ -1054,6 +1055,7 @@ WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
             MagickOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
           switch (metric)
           {
+            case FuzzErrorMetric:
             case MeanAbsoluteErrorMetric:
             case MeanSquaredErrorMetric:
             case RootMeanSquaredErrorMetric: